xcode_script.rs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. use super::{env, init_dot_cargo, with_config, Error};
  2. use crate::Result;
  3. use clap::Parser;
  4. use cargo_mobile::{
  5. apple::target::Target,
  6. opts::{NoiseLevel, Profile},
  7. util,
  8. };
  9. use std::{collections::HashMap, ffi::OsStr, path::PathBuf};
  10. #[derive(Debug, Parser)]
  11. pub struct Options {
  12. /// Value of `PLATFORM_DISPLAY_NAME` env var
  13. #[clap(long)]
  14. platform: String,
  15. /// Value of `SDKROOT` env var
  16. #[clap(long)]
  17. sdk_root: PathBuf,
  18. /// Value of `CONFIGURATION` env var
  19. #[clap(long)]
  20. configuration: String,
  21. /// Value of `FORCE_COLOR` env var
  22. #[clap(long)]
  23. force_color: bool,
  24. /// Value of `ARCHS` env var
  25. #[clap(index = 1, required = true)]
  26. arches: Vec<String>,
  27. }
  28. pub fn command(options: Options) -> Result<()> {
  29. fn macos_from_platform(platform: &str) -> bool {
  30. platform == "macOS"
  31. }
  32. fn profile_from_configuration(configuration: &str) -> Profile {
  33. if configuration == "release" {
  34. Profile::Release
  35. } else {
  36. Profile::Debug
  37. }
  38. }
  39. let profile = profile_from_configuration(&options.configuration);
  40. let macos = macos_from_platform(&options.platform);
  41. let noise_level = NoiseLevel::Polite;
  42. with_config(None, |root_conf, config, metadata| {
  43. let env = env()?;
  44. init_dot_cargo(root_conf, None).map_err(Error::InitDotCargo)?;
  45. // The `PATH` env var Xcode gives us is missing any additions
  46. // made by the user's profile, so we'll manually add cargo's
  47. // `PATH`.
  48. let env = env.prepend_to_path(
  49. util::home_dir()
  50. .map_err(Error::NoHomeDir)?
  51. .join(".cargo/bin"),
  52. );
  53. if !options.sdk_root.is_dir() {
  54. return Err(Error::SdkRootInvalid {
  55. sdk_root: options.sdk_root,
  56. });
  57. }
  58. let include_dir = options.sdk_root.join("usr/include");
  59. if !include_dir.is_dir() {
  60. return Err(Error::IncludeDirInvalid { include_dir });
  61. }
  62. let mut host_env = HashMap::<&str, &OsStr>::new();
  63. // Host flags that are used by build scripts
  64. let (macos_isysroot, library_path) = {
  65. let macos_sdk_root = options
  66. .sdk_root
  67. .join("../../../../MacOSX.platform/Developer/SDKs/MacOSX.sdk");
  68. if !macos_sdk_root.is_dir() {
  69. return Err(Error::MacosSdkRootInvalid { macos_sdk_root });
  70. }
  71. (
  72. format!("-isysroot {}", macos_sdk_root.display()),
  73. format!("{}/usr/lib", macos_sdk_root.display()),
  74. )
  75. };
  76. host_env.insert("MAC_FLAGS", macos_isysroot.as_ref());
  77. host_env.insert("CFLAGS_x86_64_apple_darwin", macos_isysroot.as_ref());
  78. host_env.insert("CXXFLAGS_x86_64_apple_darwin", macos_isysroot.as_ref());
  79. host_env.insert(
  80. "OBJC_INCLUDE_PATH_x86_64_apple_darwin",
  81. include_dir.as_os_str(),
  82. );
  83. host_env.insert("RUST_BACKTRACE", "1".as_ref());
  84. let macos_target = Target::macos();
  85. let isysroot = format!("-isysroot {}", options.sdk_root.display());
  86. for arch in options.arches {
  87. // Set target-specific flags
  88. let triple = match arch.as_str() {
  89. "arm64" => "aarch64_apple_ios",
  90. "x86_64" => "x86_64_apple_ios",
  91. _ => return Err(Error::ArchInvalid { arch }),
  92. };
  93. let cflags = format!("CFLAGS_{}", triple);
  94. let cxxflags = format!("CFLAGS_{}", triple);
  95. let objc_include_path = format!("OBJC_INCLUDE_PATH_{}", triple);
  96. let mut target_env = host_env.clone();
  97. target_env.insert(cflags.as_ref(), isysroot.as_ref());
  98. target_env.insert(cxxflags.as_ref(), isysroot.as_ref());
  99. target_env.insert(objc_include_path.as_ref(), include_dir.as_ref());
  100. // Prevents linker errors in build scripts and proc macros:
  101. // https://github.com/signalapp/libsignal-client/commit/02899cac643a14b2ced7c058cc15a836a2165b6d
  102. target_env.insert("LIBRARY_PATH", library_path.as_ref());
  103. let target = if macos {
  104. &macos_target
  105. } else {
  106. Target::for_arch(&arch).ok_or_else(|| Error::ArchInvalid {
  107. arch: arch.to_owned(),
  108. })?
  109. };
  110. target
  111. .compile_lib(
  112. config,
  113. metadata,
  114. noise_level,
  115. true,
  116. profile,
  117. &env,
  118. target_env,
  119. )
  120. .map_err(Error::CompileLibFailed)?;
  121. }
  122. Ok(())
  123. })
  124. .map_err(Into::into)
  125. }