Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Path for ICU_DAT_FILE_PATH when targeting iOS inside an XCTest bundle #88835

Closed
lemonmojo opened this issue Jul 13, 2023 · 12 comments
Closed

Path for ICU_DAT_FILE_PATH when targeting iOS inside an XCTest bundle #88835

lemonmojo opened this issue Jul 13, 2023 · 12 comments
Assignees
Milestone

Comments

@lemonmojo
Copy link

lemonmojo commented Jul 13, 2023

Description

As commented here the recently introduced change to relatively locate the icudt.dat file inside an app bundle works fine.

However, when a NativeAOT'd library is included and called from an XCTest bundle, -[NSBundle mainBundle] returns a path inside Xcode instead of the test bundle:

let mainPath = Bundle.main.bundlePath
// /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Agents

let testPath = Bundle(for: SomeTypeInTheTestBundle.self).bundlePath
// ~/Library/Developer/Xcode/DerivedData/TestBundle/Build/Products/Variant-ASan/Debug-iphonesimulator/TestBundle.xctest

Of course this causes the load to fail because the icudt.dat will never be in Xcode's app bundle.
If the XCTest project is however set up to copy this file to it's bundle resources folder, it would be there waiting to be consumed by the .NET runtime but currently fails because the logic of locating it just targets the main bundle.

@dotnet-issue-labeler dotnet-issue-labeler bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Jul 13, 2023
@ghost ghost added the untriaged New issue has not been triaged by the area owner label Jul 13, 2023
@akoeplinger akoeplinger changed the title Path for ICU_DAT_FILE_PATH when targeting iOS with NativeAOT inside an XCTest bundle Path for ICU_DAT_FILE_PATH when targeting iOS inside an XCTest bundle Jul 13, 2023
@akoeplinger
Copy link
Member

This shouldn't be NativeAOT specific and happen on Mono as well, guess nobody tried that yet :)

@akoeplinger akoeplinger added area-CoreLib-mono os-ios Apple iOS and removed untriaged New issue has not been triaged by the area owner needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Jul 13, 2023
@akoeplinger akoeplinger added this to the 8.0.0 milestone Jul 13, 2023
@akoeplinger akoeplinger self-assigned this Jul 13, 2023
@ghost
Copy link

ghost commented Jul 13, 2023

Tagging subscribers to 'os-ios': @steveisok, @akoeplinger, @kotlarmilos
See info in area-owners.md if you want to be subscribed.

Issue Details

Description

As commented here the recently introduced change to relatively locate the icudt.dat file inside an app bundle works fine.

However, when a NativeAOT'd library is included and called from an XCTest bundle, -[NSBundle mainBundle] returns a path inside Xcode instead of the test bundle:

let mainPath = Bundle.main.bundlePath
// /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Agents

let testPath = Bundle(for: SomeTypeInTheTestBundle.self).bundlePath
// ~/Library/Developer/Xcode/DerivedData/TestBundle/Build/Products/Variant-ASan/Debug-iphonesimulator/TestBundle.xctest

Of course this causes the load to fail because the icudt.dat will never be in Xcode's app bundle.
If the XCTest project is however set up to copy this file to it's bundle resources folder, it would be there waiting to be consumed by the .NET runtime but currently fails because the logic of locating it just targets the main bundle.

Author: lemonmojo
Assignees: -
Labels:

area-CoreLib-mono, os-ios

Milestone: -

@lemonmojo
Copy link
Author

lemonmojo commented Jul 13, 2023

@akoeplinger I guess so. Unfortunately I currently have no idea what a proper fix might look like as the location of the file heavily depends on the project/bundle structure.

I mean, even if -[NSBundle mainBundle] would return the XCTest bundle, the icudt.dat file might instead be included in some framework, potentially deeply nested.

Is there some way/hack to set the path at runtime?

@akoeplinger
Copy link
Member

akoeplinger commented Jul 13, 2023

hmm not right now, we have the ICU_DAT_FILE_PATH app context key but NativeAOT compiles that into the app "hardcoded" during the build time.

we could probably add an environment variable override.

another idea might be calling AppContext.SetData("ICU_DAT_FILE_PATH", "<path>") early on in startup so that it overrides the value that NativeAOT compiled into the app

@lemonmojo
Copy link
Author

@akoeplinger I can confirm that using AppContext to set the file path at runtime does indeed work.

I think it's still a good idea to change the loading code in the runtime to use -[NSBundle bundleForClass:] and provide a way to overwrite the path using an env var in case the bundle is structured in another way.

@lemonmojo
Copy link
Author

@akoeplinger Any chance that the switch to -[NSBundle bundleForClass:] will make it into .NET 8?

@akoeplinger
Copy link
Member

akoeplinger commented Aug 9, 2023

@lemonmojo I was planning to but we recently hit an issue in our so called "library mode" where linking the runtime into two libraries causes an issue because of duplicate Objective-C classes and we got rid of the classes: #89956

So the bundleForClass won't work since we don't have a class to point it to.

I think the env var is the only good option we have left, do you think that'd still help or is the AppContext solution good enough?

@akoeplinger
Copy link
Member

Actually, can you try setting ICU_DAT_FILE_PATH as an environment variable? it looks like AppContext will read from the environment if it's not set already.

@akoeplinger akoeplinger modified the milestones: 8.0.0, 9.0.0 Aug 9, 2023
@akoeplinger
Copy link
Member

For XCTest we could probably look at XCTestBundlePath to find the bundle path but we'd hit the same issue when we're embedded inside a .framework.

Alternatively we could make the build pass in the bundle identifier via AppContext and then use +[NSBundle bundleWithIdentifier] (see the perf optimizations Flutter had to do with that approach: flutter/engine#39975)

I wonder if the easiest solution is embedding the icudt.dat file itself somehow.

@lemonmojo
Copy link
Author

@akoeplinger Sorry for the delay. I just tried setting the ICU_DAT_FILE_PATH as an environment variable instead of writing it to AppContext but that didn't work unfortunately.

At least for my case, just looking at XCTestBundlePath won't do the trick as I use nested frameworks and the ICU file could be deep inside the framework tree.

I'm not sure I understand your second suggestion regarding passing in the bundle identifier. Could you please elaborate?

Is embedding the icudt.dat file a viable option at that level? If so, that would absolutely be the easiest approach from a .NET user's perspective. To be honest, I didn't even know what that file is and why it's required until I hit some issues because I wasn't embedding it. So yeah, if you can make that work I'd be awesome.

@ghost
Copy link

ghost commented Jan 26, 2024

Tagging subscribers to this area: @dotnet/area-system-globalization
See info in area-owners.md if you want to be subscribed.

Issue Details

Description

As commented here the recently introduced change to relatively locate the icudt.dat file inside an app bundle works fine.

However, when a NativeAOT'd library is included and called from an XCTest bundle, -[NSBundle mainBundle] returns a path inside Xcode instead of the test bundle:

let mainPath = Bundle.main.bundlePath
// /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Agents

let testPath = Bundle(for: SomeTypeInTheTestBundle.self).bundlePath
// ~/Library/Developer/Xcode/DerivedData/TestBundle/Build/Products/Variant-ASan/Debug-iphonesimulator/TestBundle.xctest

Of course this causes the load to fail because the icudt.dat will never be in Xcode's app bundle.
If the XCTest project is however set up to copy this file to it's bundle resources folder, it would be there waiting to be consumed by the .NET runtime but currently fails because the logic of locating it just targets the main bundle.

Author: lemonmojo
Assignees: akoeplinger
Labels:

area-System.Globalization, os-ios

Milestone: 9.0.0

@akoeplinger akoeplinger modified the milestones: 9.0.0, Future Jul 4, 2024
@akoeplinger akoeplinger modified the milestones: Future, 9.0.0 Jul 22, 2024
@akoeplinger
Copy link
Member

.NET 9 uses "hybrid globalization" on iOS which doesn't rely on bundling ICU with the app anymore so this should no longer be needed.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants