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

Fix cross-compiling ios targets with cmake 3.14 #88

Closed
wants to merge 4 commits into from

Conversation

kylefleming
Copy link
Contributor

Summary

This PR fixes iOS cross-compilation support when using Cmake 3.14+. The issue is described in more detail here: #87

Implementation

This PR checks the target triplet (either the target member variable if it's set, otherwise the TARGET environment variable) and looks for an ending of -apple-ios to determine if we're cross-compiling for iOS or not.

If we are cross-compiling for iOS, it disables the default compiler flags for the cc-rs build config, and proceeds to set the required flags to allow cmake itself to set them:

  • If CMAKE_SYSTEM_NAME is not set, set it to iOS.
  • If CMAKE_OSX_ARCHITECTURES is not set, set it to the cmake equivalent of the target architecture pulled from the target variable. (cmake equivalents are: arm64, armv7, armv7s, i386, or x86_64)
  • If CMAKE_OSX_DEPLOYMENT_TARGET is not set, we look for the IPHONEOS_DEPLOYMENT_TARGET environment variable (which is what cc-rs, llvm, rustc, etc use). If that doesn't exist, we default to 7.0, which is what cc-rs defaults to (note that cmake defaults to 9.0, but in my opinion, it's better to have consistency across the whole project than to have vertical consistency within a particular tool).
  • If CMAKE_OSX_SYSROOT isn't set, set it to either iphoneos or iphonesimulator to match the (canonical, version-less) sdk name xcode uses (xcodebuild -showsdks). This could also be set to a path to an SDK, but by setting it to the name of an SDK, cmake automatically selects the path to the most recent version it can find for that sdk.

I set the variables up so that it only sets them if they weren't previously defined, which should allow users to override them however they want.

-fPIC and -fembed-bitcode are added, as those were previously added by cc-rs (which we disabled, as noted above) but are not currently added by cmake. (I couldn't find documentation stating whether -fPIC is necessary, but I've left it in for continuity)

(I only have minimal rust experience at the moment, so if there are any conventions you'd like me to follow that I might not know about, feel free to suggest.)

Questions

Cmake <3.14

One caveat is that I've only tested this with cmake 3.15. I'm assuming it works with cmake 3.14 since the code in question within cmake hasn't changed. However, I don't know how it handles cmake <3.14.

Prior to cmake 3.14, I believe the procedure was to set CMAKE_OSX_SYSROOT (same as above) and CMAKE_OSX_SYSROOT (same as above). CMAKE_SYSTEM_NAME will be set to Darwin automatically within cmake.

I'm not sure 100% how cmake <3.14 handled CMAKE_OSX_DEPLOYMENT_TARGET/IPHONEOS_DEPLOYMENT_TARGET so I can't speak to that.

Do you want cmake-rs to support versions <3.14? If so we will need a way to determine which cmake version is installed. An easier middle option would be to have the above variables set only for 3.14+ and do nothing for versions <3.14, which in theory might facilitate backwards compatibility with existing projects using cmake-rs.

I don't currently have a good understanding of the needs of cmake-rs and the community using it, so I leave that up to your discretion. How do you want to handle introducing this feature?

Config variables

Do you want the deploymentTarget to be a Config variable? Practically speaking, it can currently be set by defining the cmake variable CMAKE_OSX_DEPLOYMENT_TARGET. (Although, I imagine deployment target might be a configuration option that other targets might have, which is why I mention deploymentTarget instead of osxDeploymentTarget or iosDeploymentTarget.)

This gets a bit hairy though because CMAKE_OSX_DEPLOYMENT_TARGET is also the variable for setting the macOS deployment target when building for a macOS target. Cmake automatically sets CMAKE_OSX_DEPLOYMENT_TARGET from MACOSX_DEPLOYMENT_TARGET when CMAKE_SYSTEM_NAME is set to Darwin but not when it's set to iOS.

My point is mainly just that a) if environment variables for the deployment target are namespaced per platform, it could suggest that if a cmake-rs Config parameter were to be added, it might want to do the same. And b) I could see a future where cmake adds support for CMAKE_OSX_DEPLOYMENT_TARGET defaulting to IPHONEOS_DEPLOYMENT_TARGET, in which case using environment variables as the canonical way to set the deployment target might be the way to go anyways, rather than a Config variable (with the added benefit that it takes cmake-rs out of the loop).

@kylefleming kylefleming force-pushed the cmake-ios branch 3 times, most recently from e7b8828 to e15260a Compare October 2, 2019 23:55
src/lib.rs Outdated
@@ -383,7 +385,7 @@ impl Config {
if let Some(ref generator) = self.generator {
is_ninja = generator.to_string_lossy().contains("Ninja");
}
if target.contains("windows-gnu") {
if target_triplet.contains("windows-gnu") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a Target type is being added here, perhaps these methods that all use contains could be moved to methods? Alternatively could the methods on Target just be used inline where they're used here? (it just seems weird to do half for some and half for others)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that would be a good direction for this codebase to move towards. I don't have the bandwidth to refactor it though. My thinking is basically that by providing the base structure for organization of targets, it can slowly move in that direction. However, let me know if you'd prefer I get rid of Target and inline everything instead.

src/lib.rs Outdated
Comment on lines 885 to 891
if parts.len() < 3 {
fail(&format!(
"target triplet not in the form arch-vendor-platform: {}",
target_triplet
));
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this may want to be a bit less strict for platforms like wasm32-wasi which could show up here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've moved this check into an Apple-specific AppleTarget.

src/lib.rs Outdated Show resolved Hide resolved
src/lib.rs Outdated
&self.rust_target_vendor == "apple" && &self.rust_target_platform == "darwin"
}

fn is_cross_compiling(&self) -> bool {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems not quite right perhaps? This is where I think it might be better to inline the definition here above because is_cross_compiling doesn't only take into account iOS

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed the is_cross_compiling method.

src/lib.rs Outdated
self.is_ios_target()
}

fn cmake_system_name(&self) -> Option<String> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similar to above, this sort of seems too general to only handle iOS, so it may be best to inline the definition above where it's called?

@kylefleming
Copy link
Contributor Author

I pushed a new revision. The biggest changes are:

  • I created an AppleTarget struct to hold the Apple-specific logic
  • Default compiler flags from cc-rs are no longer disabled. Instead it filters out the specific compiler flags that cmake will be providing (namely -m<platform>-min-version=<deployment_target>, -arch <arch>, and -isysroot <sysroot_path>). This alleviates some duplication logic between cmake-rs and cc-rs that was in my earlier revision.
  • macOS is now supported by fully specifying the OSX cmake variables when compiling for a macOS target. This is in contrast to letting LLVM choose defaults, which is how it is currently done (which works fine in practice, as long as you don't need to change from the defaults).
  • Environment variables with the potential to confuse LLVM are filtered out. (This includes IPHONEOS_DEPLOYMENT_TARGET, MACOSX_DEPLOYMENT_TARGET, SDKROOT, etc.)

@kylefleming
Copy link
Contributor Author

It occurred to me that filter_compiler_args should probably only apply to compiler flags supplied by cc-rs and not to ones supplied by the user via the cflag/cxxflag/asmflag methods, so I've pushed a revision to account for that.

@alexcrichton
Copy link
Member

Thanks for this, and sorry for taking awhile to get back to this!

This is getting to be a pretty significant PR, I would personally prefer to not pick up regex/lazy_static dependencies for example. If using cmake on iOS is so different from all other platforms should there perhaps be a separate crate for that?

@simlay
Copy link
Contributor

simlay commented Feb 24, 2020

This is getting to be a pretty significant PR, I would personally prefer to not pick up regex/lazy_static dependencies for example. If using cmake on iOS is so different from all other platforms should there perhaps be a separate crate for that?

I've ran into this issue across a number of different projects I've attempted to compile to iOS. I admit that it's a never ending battle to make things work cross platform but I think that doing it here will save a lot of leg work for other crates using cmake that want to support multiple platforms. That being said, I'm also not big on picking up regex/lazy_static as a dependency for this project. I'd be up to help remove it.

Anyway, it's been a while since this PR was commented on or updated. I just wanted to share my interest and offer to continue the work on it because it'll fix issues with rendy, shaderc and the examples in wgpu. I'm sure there are others but that's just what I was working on this evening.

@kylefleming
Copy link
Contributor Author

@simlay Thanks for offering to continue working on it. Feel free to make whatever changes you see fit. To the best of my knowledge, all the logic in the PR is correct, but it needs refactoring to address @alexcrichton's comments.

@aloucks
Copy link
Contributor

aloucks commented Mar 23, 2020

The regular expressions seem simple enough that you could just parse it by hand. Adding regex as a dependency doesn't seem like a good idea.

@simlay
Copy link
Contributor

simlay commented Mar 24, 2020

So, I'm not sure the best way to take over a PR via github but I've addressed the regex and lazy_static dependencies in simlay@7566053. I've got mixed feelings about it as the logic makes some assumptions on input.

Anyway, I'd like to move forward and hopefully get this PR merged at some point. Is there anything I can do to unblock this?

@alexcrichton
Copy link
Member

It's fine to send a new PR, and when that one's merged I can close this one.

alexcrichton pushed a commit that referenced this pull request Mar 31, 2020
* Rename target variable to target_triple

* Remove a bit of code duplication

* Add GenericTarget with several override points

* Add support for cross-compiling Apple targets with cmake 3.14

* Removed lazy_static and regex

Co-authored-by: Kyle Fleming <kyle@kylefleming.net>
@alexcrichton
Copy link
Member

Now landed in #93

alexcrichton added a commit that referenced this pull request May 18, 2020
Dushistov added a commit to Dushistov/cmake-rs that referenced this pull request Jun 3, 2020
Dushistov added a commit to Dushistov/cmake-rs that referenced this pull request Jun 9, 2020
MichaelHills pushed a commit to MichaelHills/cmake-rs that referenced this pull request Sep 13, 2020
rust-lang#93)

* Rename target variable to target_triple

* Remove a bit of code duplication

* Add GenericTarget with several override points

* Add support for cross-compiling Apple targets with cmake 3.14

* Removed lazy_static and regex

Co-authored-by: Kyle Fleming <kyle@kylefleming.net>
Dushistov added a commit to Dushistov/cmake-rs that referenced this pull request Feb 12, 2021
rust-lang#93)

    * Rename target variable to target_triple
    * Remove a bit of code duplication
    * Add GenericTarget with several override points
    * Add support for cross-compiling Apple targets with cmake 3.14

Co-authored-by: simlay <simlay@users.noreply.github.com>
Co-authored-by: Kyle Fleming <kyle@kylefleming.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants