xcode_script.rs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. use super::{env, with_config};
  2. use crate::Result;
  3. use clap::Parser;
  4. use cargo_mobile::{apple::target::Target, opts::Profile, util};
  5. use std::{collections::HashMap, ffi::OsStr, path::PathBuf};
  6. #[derive(Debug, Parser)]
  7. pub struct Options {
  8. /// Value of `PLATFORM_DISPLAY_NAME` env var
  9. #[clap(long)]
  10. platform: String,
  11. /// Value of `SDKROOT` env var
  12. #[clap(long)]
  13. sdk_root: PathBuf,
  14. /// Value of `FRAMEWORK_SEARCH_PATHS` env var
  15. #[clap(long)]
  16. framework_search_paths: String,
  17. /// Value of `GCC_PREPROCESSOR_DEFINITIONS` env var
  18. #[clap(long)]
  19. gcc_preprocessor_definitions: String,
  20. /// Value of `HEADER_SEARCH_PATHS` env var
  21. #[clap(long)]
  22. header_search_paths: String,
  23. /// Value of `CONFIGURATION` env var
  24. #[clap(long)]
  25. configuration: String,
  26. /// Value of `FORCE_COLOR` env var
  27. #[clap(long)]
  28. force_color: bool,
  29. /// Value of `ARCHS` env var
  30. #[clap(index = 1, required = true)]
  31. arches: Vec<String>,
  32. }
  33. pub fn command(options: Options) -> Result<()> {
  34. fn macos_from_platform(platform: &str) -> bool {
  35. platform == "macOS"
  36. }
  37. fn profile_from_configuration(configuration: &str) -> Profile {
  38. if configuration == "release" {
  39. Profile::Release
  40. } else {
  41. Profile::Debug
  42. }
  43. }
  44. // `xcode-script` is ran from the `gen/apple` folder.
  45. std::env::set_current_dir(
  46. std::env::current_dir()
  47. .unwrap()
  48. .parent()
  49. .unwrap()
  50. .parent()
  51. .unwrap(),
  52. )
  53. .unwrap();
  54. let profile = profile_from_configuration(&options.configuration);
  55. let macos = macos_from_platform(&options.platform);
  56. with_config(None, |_root_conf, config, metadata, cli_options| {
  57. let env = env()?;
  58. // The `PATH` env var Xcode gives us is missing any additions
  59. // made by the user's profile, so we'll manually add cargo's
  60. // `PATH`.
  61. let env = env
  62. .explicit_env_vars(cli_options.vars)
  63. .prepend_to_path(util::home_dir()?.join(".cargo/bin"));
  64. if !options.sdk_root.is_dir() {
  65. return Err(anyhow::anyhow!(
  66. "SDK root provided by Xcode was invalid. {} doesn't exist or isn't a directory",
  67. options.sdk_root.display(),
  68. ));
  69. }
  70. let include_dir = options.sdk_root.join("usr/include");
  71. if !include_dir.is_dir() {
  72. return Err(anyhow::anyhow!(
  73. "Include dir was invalid. {} doesn't exist or isn't a directory",
  74. include_dir.display()
  75. ));
  76. }
  77. // Host flags that are used by build scripts
  78. let macos_isysroot = {
  79. let macos_sdk_root = options
  80. .sdk_root
  81. .join("../../../../MacOSX.platform/Developer/SDKs/MacOSX.sdk");
  82. if !macos_sdk_root.is_dir() {
  83. return Err(anyhow::anyhow!(
  84. "Invalid SDK root {}",
  85. macos_sdk_root.display()
  86. ));
  87. }
  88. format!("-isysroot {}", macos_sdk_root.display())
  89. };
  90. let mut host_env = HashMap::<&str, &OsStr>::new();
  91. host_env.insert("RUST_BACKTRACE", "1".as_ref());
  92. host_env.insert("CFLAGS_x86_64_apple_darwin", macos_isysroot.as_ref());
  93. host_env.insert("CXXFLAGS_x86_64_apple_darwin", macos_isysroot.as_ref());
  94. host_env.insert(
  95. "OBJC_INCLUDE_PATH_x86_64_apple_darwin",
  96. include_dir.as_os_str(),
  97. );
  98. host_env.insert(
  99. "FRAMEWORK_SEARCH_PATHS",
  100. options.framework_search_paths.as_ref(),
  101. );
  102. host_env.insert(
  103. "GCC_PREPROCESSOR_DEFINITIONS",
  104. options.gcc_preprocessor_definitions.as_ref(),
  105. );
  106. host_env.insert("HEADER_SEARCH_PATHS", options.header_search_paths.as_ref());
  107. let macos_target = Target::macos();
  108. let isysroot = format!("-isysroot {}", options.sdk_root.display());
  109. for arch in options.arches {
  110. // Set target-specific flags
  111. let triple = match arch.as_str() {
  112. "arm64" => "aarch64_apple_ios",
  113. "arm64-sim" => "aarch64_apple_ios_sim",
  114. "x86_64" => "x86_64_apple_ios",
  115. "Simulator" => continue,
  116. _ => {
  117. return Err(anyhow::anyhow!(
  118. "Arch specified by Xcode was invalid. {} isn't a known arch",
  119. arch
  120. ))
  121. }
  122. };
  123. let cflags = format!("CFLAGS_{}", triple);
  124. let cxxflags = format!("CFLAGS_{}", triple);
  125. let objc_include_path = format!("OBJC_INCLUDE_PATH_{}", triple);
  126. let mut target_env = host_env.clone();
  127. target_env.insert(cflags.as_ref(), isysroot.as_ref());
  128. target_env.insert(cxxflags.as_ref(), isysroot.as_ref());
  129. target_env.insert(objc_include_path.as_ref(), include_dir.as_ref());
  130. let target = if macos {
  131. &macos_target
  132. } else {
  133. Target::for_arch(&arch).ok_or_else(|| {
  134. anyhow::anyhow!(
  135. "Arch specified by Xcode was invalid. {} isn't a known arch",
  136. arch
  137. )
  138. })?
  139. };
  140. target.compile_lib(
  141. config,
  142. metadata,
  143. cli_options.noise_level,
  144. true,
  145. profile,
  146. &env,
  147. target_env,
  148. )?;
  149. }
  150. Ok(())
  151. })
  152. .map_err(Into::into)
  153. }