build.rs

  1use serde::Deserialize;
  2use std::{
  3    env,
  4    path::{Path, PathBuf},
  5    process::Command,
  6};
  7
  8const SWIFT_PACKAGE_NAME: &'static str = "LiveKitBridge";
  9
 10#[derive(Debug, Deserialize)]
 11#[serde(rename_all = "camelCase")]
 12pub struct SwiftTargetInfo {
 13    pub triple: String,
 14    pub unversioned_triple: String,
 15    pub module_triple: String,
 16    pub swift_runtime_compatibility_version: String,
 17    #[serde(rename = "librariesRequireRPath")]
 18    pub libraries_require_rpath: bool,
 19}
 20
 21#[derive(Debug, Deserialize)]
 22#[serde(rename_all = "camelCase")]
 23pub struct SwiftPaths {
 24    pub runtime_library_paths: Vec<String>,
 25    pub runtime_library_import_paths: Vec<String>,
 26    pub runtime_resource_path: String,
 27}
 28
 29#[derive(Debug, Deserialize)]
 30pub struct SwiftTarget {
 31    pub target: SwiftTargetInfo,
 32    pub paths: SwiftPaths,
 33}
 34
 35const MACOS_TARGET_VERSION: &str = "10.15";
 36
 37fn main() {
 38    let swift_target = get_swift_target();
 39
 40    build_bridge(&swift_target);
 41    link_swift_stdlib(&swift_target);
 42    link_webrtc_framework(&swift_target);
 43}
 44
 45fn build_bridge(swift_target: &SwiftTarget) {
 46    println!("cargo:rerun-if-changed={}/Sources", SWIFT_PACKAGE_NAME);
 47    println!(
 48        "cargo:rerun-if-changed={}/Package.swift",
 49        SWIFT_PACKAGE_NAME
 50    );
 51    println!(
 52        "cargo:rerun-if-changed={}/Package.resolved",
 53        SWIFT_PACKAGE_NAME
 54    );
 55    let swift_package_root = swift_package_root();
 56    if !Command::new("swift")
 57        .arg("build")
 58        .args(&["--configuration", &env::var("PROFILE").unwrap()])
 59        .args(&["--triple", &swift_target.target.triple])
 60        .current_dir(&swift_package_root)
 61        .status()
 62        .unwrap()
 63        .success()
 64    {
 65        panic!(
 66            "Failed to compile swift package in {}",
 67            swift_package_root.display()
 68        );
 69    }
 70
 71    println!(
 72        "cargo:rustc-link-search=native={}",
 73        swift_target.out_dir_path().display()
 74    );
 75    println!("cargo:rustc-link-lib=static={}", SWIFT_PACKAGE_NAME);
 76}
 77
 78fn link_swift_stdlib(swift_target: &SwiftTarget) {
 79    swift_target
 80        .paths
 81        .runtime_library_paths
 82        .iter()
 83        .for_each(|path| {
 84            println!("cargo:rustc-link-search=native={}", path);
 85        });
 86}
 87
 88fn link_webrtc_framework(swift_target: &SwiftTarget) {
 89    let swift_out_dir_path = swift_target.out_dir_path();
 90    println!("cargo:rustc-link-lib=framework=WebRTC");
 91    println!(
 92        "cargo:rustc-link-search=framework={}",
 93        swift_out_dir_path.display()
 94    );
 95    // Find WebRTC.framework as a sibling of the executable when running tests.
 96    println!("cargo:rustc-link-arg=-Wl,-rpath,@executable_path");
 97
 98    let source_path = swift_out_dir_path.join("WebRTC.framework");
 99    let deps_dir_path =
100        PathBuf::from(env::var("OUT_DIR").unwrap()).join("../../../deps/WebRTC.framework");
101    let target_dir_path =
102        PathBuf::from(env::var("OUT_DIR").unwrap()).join("../../../WebRTC.framework");
103    copy_dir(&source_path, &deps_dir_path);
104    copy_dir(&source_path, &target_dir_path);
105}
106
107fn get_swift_target() -> SwiftTarget {
108    let mut arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
109    if arch == "aarch64" {
110        arch = "arm64".into();
111    }
112    let target = format!("{}-apple-macosx{}", arch, MACOS_TARGET_VERSION);
113
114    let swift_target_info_str = Command::new("swift")
115        .args(&["-target", &target, "-print-target-info"])
116        .output()
117        .unwrap()
118        .stdout;
119
120    serde_json::from_slice(&swift_target_info_str).unwrap()
121}
122
123fn swift_package_root() -> PathBuf {
124    env::current_dir().unwrap().join(SWIFT_PACKAGE_NAME)
125}
126
127fn copy_dir(source: &Path, destination: &Path) {
128    assert!(
129        Command::new("cp")
130            .arg("-r")
131            .args(&[source, destination])
132            .status()
133            .unwrap()
134            .success(),
135        "could not copy {:?} to {:?}",
136        source,
137        destination
138    );
139}
140
141impl SwiftTarget {
142    fn out_dir_path(&self) -> PathBuf {
143        swift_package_root()
144            .join(".build")
145            .join(&self.target.unversioned_triple)
146            .join(env::var("PROFILE").unwrap())
147    }
148}