From 2023d482a202c1fd28f4007280c6fb82f789ee1b Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Fri, 8 Oct 2021 19:42:31 +0200 Subject: [PATCH 1/8] Add initial gnustep_libobjc2_src crate for vendoring GNUStep's libobjc2 We're including it as a submodule (and not e.g. a subtree) because libobjc2 itself uses submodules for a third-party dependency. --- .gitmodules | 4 ++++ Cargo.toml | 1 + README.md | 7 +++++++ gnustep_libobjc2_src/Cargo.toml | 24 ++++++++++++++++++++++++ gnustep_libobjc2_src/README.md | 3 +++ gnustep_libobjc2_src/libobjc2 | 1 + gnustep_libobjc2_src/src/lib.rs | 31 +++++++++++++++++++++++++++++++ 7 files changed, 71 insertions(+) create mode 100644 .gitmodules create mode 100644 gnustep_libobjc2_src/Cargo.toml create mode 100644 gnustep_libobjc2_src/README.md create mode 160000 gnustep_libobjc2_src/libobjc2 create mode 100644 gnustep_libobjc2_src/src/lib.rs diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..a05352be5 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "libobjc2"] + path = gnustep_libobjc2_src/libobjc2 + url = https://github.com/gnustep/libobjc2.git + branch = 2.1 diff --git a/Cargo.toml b/Cargo.toml index cdd936995..6fcb44379 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = [ + "gnustep_libobjc2_src", "objc2", "objc2_block", "objc2_encode", diff --git a/README.md b/README.md index f58da4de5..44fad94ee 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,10 @@ [![License](https://badgen.net/badge/license/MIT/blue)](../LICENSE.txt) [![CI Status](https://github.com/madsmtm/objc2/workflows/CI/badge.svg)](https://github.com/madsmtm/objc2/actions) + +## Submodules + +This project uses `git` submodules for vendored dependencies, remember to update them after pulling: +```sh +$ git submodule update --init --recursive +``` diff --git a/gnustep_libobjc2_src/Cargo.toml b/gnustep_libobjc2_src/Cargo.toml new file mode 100644 index 000000000..f9f3052aa --- /dev/null +++ b/gnustep_libobjc2_src/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "gnustep_libobjc2_src" +version = "0.0.1" +authors = ["Mads Marquart "] +edition = "2018" + +description = "Source of GNUStep's libobjc2 and logic to build it" +keywords = ["gnustep", "objc", "libobjc2", "build-dependencies"] +categories = [ + "development-tools::build-utils", +] +readme = "README.md" +repository = "https://github.com/madsmtm/gnustep_libobjc2_src" +documentation = "https://docs.rs/gnustep_libobjc2_src/" +license = "MIT/Apache-2.0" + +exclude = [ + "libobjc2/ABIDoc/*", + "libobjc2/Test/*", + "libobjc2/third_party/robin-map/tests/*", +] + +[dependencies] +cmake = "0.1.45" diff --git a/gnustep_libobjc2_src/README.md b/gnustep_libobjc2_src/README.md new file mode 100644 index 000000000..b7f52a2d0 --- /dev/null +++ b/gnustep_libobjc2_src/README.md @@ -0,0 +1,3 @@ +# `gnustep_libobjc2_src` + +Source of GNUStep's libobjc2 and logic to build it for Rust. diff --git a/gnustep_libobjc2_src/libobjc2 b/gnustep_libobjc2_src/libobjc2 new file mode 160000 index 000000000..f648903db --- /dev/null +++ b/gnustep_libobjc2_src/libobjc2 @@ -0,0 +1 @@ +Subproject commit f648903dbd6835c84519bc3f23a41efd3aee216b diff --git a/gnustep_libobjc2_src/src/lib.rs b/gnustep_libobjc2_src/src/lib.rs new file mode 100644 index 000000000..186b5fc41 --- /dev/null +++ b/gnustep_libobjc2_src/src/lib.rs @@ -0,0 +1,31 @@ +use std::path::{Path, PathBuf}; + +const NO_SOURCES_MSG: &'static str = r#" +libobjc2 sources not present, please run: + +$ git submodule update --init --recursive + +If you did not checkout via git, you will +need to fetch the submodule's contents from +https://github.com/gnustep/libobjc2 +"#; + +pub fn build() -> PathBuf { + let source_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("libobjc2"); + if !source_dir.join("objc/objc.h").exists() { + panic!("{}", NO_SOURCES_MSG); + } + cmake::Config::new(source_dir) + .define("BUILD_STATIC_LIBOBJC", "OFF") // Default + .define("DEBUG_ARC_COMPAT", "OFF") // Default + .define("ENABLE_OBJCXX", "ON") // Default (NO_OBJCXX in code) + .define("ENABLE_TRACING", "OFF") // Default (WITH_TRACING in code) + .define("LEGACY_COMPAT", "OFF") // Default (NO_LEGACY in code) + // .define("OLDABI_COMPAT", "?") // Default depends on WIN32 + .define("TESTS", "OFF") + .define("TYPE_DEPENDENT_DISPATCH", "ON") // Default + // .always_configure(false) // TODO + // .static_crt(?) + .build_target("install") + .build() +} From 21ce6c1c2e5c048b2c1e614fef717a1c98fe94df Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 7 Oct 2021 09:56:45 +0200 Subject: [PATCH 2/8] Use clang (> 8 recommended) per default for building libobjc2 --- gnustep_libobjc2_src/README.md | 2 ++ gnustep_libobjc2_src/src/lib.rs | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/gnustep_libobjc2_src/README.md b/gnustep_libobjc2_src/README.md index b7f52a2d0..baccda5a2 100644 --- a/gnustep_libobjc2_src/README.md +++ b/gnustep_libobjc2_src/README.md @@ -1,3 +1,5 @@ # `gnustep_libobjc2_src` Source of GNUStep's libobjc2 and logic to build it for Rust. + +Using `clang` with at least version `8.0.0` is recommended. You can specify your desired compiler using the `CC` and `CXX` environment variables. diff --git a/gnustep_libobjc2_src/src/lib.rs b/gnustep_libobjc2_src/src/lib.rs index 186b5fc41..a80a3f209 100644 --- a/gnustep_libobjc2_src/src/lib.rs +++ b/gnustep_libobjc2_src/src/lib.rs @@ -1,3 +1,4 @@ +use std::env; use std::path::{Path, PathBuf}; const NO_SOURCES_MSG: &'static str = r#" @@ -11,10 +12,20 @@ https://github.com/gnustep/libobjc2 "#; pub fn build() -> PathBuf { + // GNUStep only compiles with clang, so try that first. + // (But let the user specify a different path if they need to). + if env::var_os("CC").is_none() { + env::set_var("CC", "clang"); + } + if env::var_os("CXX").is_none() { + env::set_var("CXX", "clang++"); + } + let source_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("libobjc2"); if !source_dir.join("objc/objc.h").exists() { panic!("{}", NO_SOURCES_MSG); } + cmake::Config::new(source_dir) .define("BUILD_STATIC_LIBOBJC", "OFF") // Default .define("DEBUG_ARC_COMPAT", "OFF") // Default From f0c72ff1ca13fff6484f337fb40bfcebd64bb176 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 7 Oct 2021 01:23:31 +0200 Subject: [PATCH 3/8] Set GNUSTEP_INSTALL_TYPE=NONE to prevent systemwide installation --- gnustep_libobjc2_src/src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gnustep_libobjc2_src/src/lib.rs b/gnustep_libobjc2_src/src/lib.rs index a80a3f209..163374184 100644 --- a/gnustep_libobjc2_src/src/lib.rs +++ b/gnustep_libobjc2_src/src/lib.rs @@ -27,6 +27,11 @@ pub fn build() -> PathBuf { } cmake::Config::new(source_dir) + // Default to ignoring `gnustep-config` presence, since they usually + // want to install the libraries globally (which requires root). + // Users that want systemwide installation should just install it + // themselves, and shouldn't need to vendor GNUStep. + .define("GNUSTEP_INSTALL_TYPE", "NONE") .define("BUILD_STATIC_LIBOBJC", "OFF") // Default .define("DEBUG_ARC_COMPAT", "OFF") // Default .define("ENABLE_OBJCXX", "ON") // Default (NO_OBJCXX in code) From ac5ff5502f60a4f5124d9d335defa8879cb6da84 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 7 Oct 2021 09:54:11 +0200 Subject: [PATCH 4/8] Add better return type for libobjc2_src `build` function --- gnustep_libobjc2_src/src/lib.rs | 56 +++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/gnustep_libobjc2_src/src/lib.rs b/gnustep_libobjc2_src/src/lib.rs index 163374184..b0b5a7fcf 100644 --- a/gnustep_libobjc2_src/src/lib.rs +++ b/gnustep_libobjc2_src/src/lib.rs @@ -11,7 +11,21 @@ need to fetch the submodule's contents from https://github.com/gnustep/libobjc2 "#; -pub fn build() -> PathBuf { +#[non_exhaustive] +pub enum LibKind { + Dynamic, + Static, + // Framework, +} + +pub struct Artifacts { + include_dir: PathBuf, + lib_dir: PathBuf, + lib_kind: LibKind, + lib_name: &'static str, +} + +pub fn build() -> Artifacts { // GNUStep only compiles with clang, so try that first. // (But let the user specify a different path if they need to). if env::var_os("CC").is_none() { @@ -26,7 +40,7 @@ pub fn build() -> PathBuf { panic!("{}", NO_SOURCES_MSG); } - cmake::Config::new(source_dir) + let dst = cmake::Config::new(source_dir) // Default to ignoring `gnustep-config` presence, since they usually // want to install the libraries globally (which requires root). // Users that want systemwide installation should just install it @@ -43,5 +57,41 @@ pub fn build() -> PathBuf { // .always_configure(false) // TODO // .static_crt(?) .build_target("install") - .build() + .build(); + + Artifacts { + include_dir: dst.join("include"), + lib_dir: dst.join("lib"), + lib_kind: LibKind::Dynamic, + lib_name: "objc", + } +} + +impl Artifacts { + pub fn include_dir(&self) -> &Path { + &self.include_dir + } + + pub fn lib_dir(&self) -> &Path { + &self.lib_dir + } + + pub fn lib_kind(&self) -> &LibKind { + &self.lib_kind + } + + pub fn lib_name(&self) -> &str { + &self.lib_name + } + + pub fn print_cargo_metadata(&self) { + let kind = match self.lib_kind { + LibKind::Dynamic => "dynamic", + LibKind::Static => "static", + }; + println!("cargo:rustc-link-search=native={}", self.lib_dir.display()); + println!("cargo:rustc-link-lib={}={}", kind, self.lib_name); + println!("cargo:include={}", self.include_dir.display()); + println!("cargo:lib={}", self.lib_dir.display()); + } } From f4fa04b859ff9c1f478bef38ccd89bdbb4b0fe6b Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Fri, 8 Oct 2021 19:43:24 +0200 Subject: [PATCH 5/8] Use gnustep_libobjc2_src in objc2_sys when the vendor_gnustep feature is enabled --- .github/workflows/ci.yml | 14 +------------- gnustep_libobjc2_src/README.md | 6 +++++- objc2_sys/Cargo.toml | 7 +++++++ objc2_sys/build.rs | 23 ++++++++++++++--------- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2bb08710a..33e5115d4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,18 +77,6 @@ jobs: command: check args: --verbose --no-default-features - - name: Install GNUStep libobjc2 - if: contains(matrix.platform.os, 'ubuntu') - run: | - wget https://github.com/gnustep/libobjc2/archive/refs/tags/v1.9.tar.gz - tar -xzf v1.9.tar.gz - mkdir libobjc2-1.9/build - cd libobjc2-1.9/build - export CC="clang" - export CXX="clang++" - cmake ../ - sudo make install - - name: Install GNUStep make if: contains(matrix.platform.os, 'ubuntu') run: | @@ -122,7 +110,7 @@ jobs: with: command: test # Temporary fix - args: --verbose --no-fail-fast --no-default-features --package objc2_sys --package objc2 --package objc2_encode --package objc2_foundation + args: --verbose --no-fail-fast --no-default-features --features objc2_sys/vendor_gnustep --package objc2_sys --package objc2 --package objc2_encode --package objc2_foundation - name: Test if: ${{ !contains(matrix.platform.os, 'ubuntu') }} diff --git a/gnustep_libobjc2_src/README.md b/gnustep_libobjc2_src/README.md index baccda5a2..941353a70 100644 --- a/gnustep_libobjc2_src/README.md +++ b/gnustep_libobjc2_src/README.md @@ -2,4 +2,8 @@ Source of GNUStep's libobjc2 and logic to build it for Rust. -Using `clang` with at least version `8.0.0` is recommended. You can specify your desired compiler using the `CC` and `CXX` environment variables. +You probably want to use `objc2_sys`, but this is kept separate from that so +that users don't download the entire GNUStep source when they don't need to. + +Using `clang` with at least version `8.0.0` is recommended. You can specify +your desired compiler using the `CC` and `CXX` environment variables. diff --git a/objc2_sys/Cargo.toml b/objc2_sys/Cargo.toml index 88f897d5d..910a81ab6 100644 --- a/objc2_sys/Cargo.toml +++ b/objc2_sys/Cargo.toml @@ -27,3 +27,10 @@ readme = "README.md" # See https://doc.rust-lang.org/cargo/reference/build-scripts.html#overriding-build-scripts links = "objc" build = "build.rs" + +[features] +# If enabled, GNUStep's libobjc2 will be compiled and linked from source +vendor_gnustep = ["gnustep_libobjc2_src"] + +[build-dependencies] +gnustep_libobjc2_src = { path = "../gnustep_libobjc2_src", optional = true } diff --git a/objc2_sys/build.rs b/objc2_sys/build.rs index c2db6ca95..f957585fe 100644 --- a/objc2_sys/build.rs +++ b/objc2_sys/build.rs @@ -1,23 +1,28 @@ -use std::env; +#[cfg(feature = "vendor_gnustep")] +fn main() { + let artifacts = gnustep_libobjc2_src::build(); + artifacts.print_cargo_metadata(); + println!("cargo:rustc-cfg=gnustep"); +} +#[cfg(not(feature = "vendor_gnustep"))] fn main() { // Only rerun if this file changes; the script doesn't depend on our code println!("cargo:rerun-if-changed=build.rs"); - // Link to libobjc - println!("cargo:rustc-link-lib=dylib=objc"); - let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); + let target_vendor = std::env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); - // Adds useful #[cfg(apple)] and #[cfg(gnustep)] directives if target_vendor == "apple" { + // Add #[cfg(apple)] directive println!("cargo:rustc-cfg=apple"); } else { // TODO: Are there other possibilities than GNUStep? Airyx? Is it // possible to use Apple's open source objc4 on other platforms? + + // Add #[cfg(gnustep)] directive println!("cargo:rustc-cfg=gnustep"); - // TODO: Should we vendor GNUStep's libobjc2? - // Using Cargo.toml: - // [target.'cfg(not(target_vendor = "apple"))'.build-dependencies] - // cc = "1.0" } + + // Link to libobjc + println!("cargo:rustc-link-lib=dylib=objc"); } From a4352ad9d1159322e3fed90905797a22fae5424c Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 7 Oct 2021 10:57:24 +0200 Subject: [PATCH 6/8] Add option to link statically against GNUStep's libobjc2 --- gnustep_libobjc2_src/src/lib.rs | 143 +++++++++++++++++++++----------- objc2_sys/Cargo.toml | 7 +- objc2_sys/build.rs | 14 +++- 3 files changed, 114 insertions(+), 50 deletions(-) diff --git a/gnustep_libobjc2_src/src/lib.rs b/gnustep_libobjc2_src/src/lib.rs index b0b5a7fcf..69dc5965e 100644 --- a/gnustep_libobjc2_src/src/lib.rs +++ b/gnustep_libobjc2_src/src/lib.rs @@ -11,62 +11,101 @@ need to fetch the submodule's contents from https://github.com/gnustep/libobjc2 "#; -#[non_exhaustive] -pub enum LibKind { - Dynamic, - Static, - // Framework, -} - -pub struct Artifacts { - include_dir: PathBuf, - lib_dir: PathBuf, +pub struct Builder { lib_kind: LibKind, - lib_name: &'static str, + objcxx: bool, } -pub fn build() -> Artifacts { - // GNUStep only compiles with clang, so try that first. - // (But let the user specify a different path if they need to). - if env::var_os("CC").is_none() { - env::set_var("CC", "clang"); +impl Builder { + pub fn new() -> Self { + Self { + lib_kind: LibKind::Dynamic, + objcxx: true, + } } - if env::var_os("CXX").is_none() { - env::set_var("CXX", "clang++"); + + /// Set the type of library to be built, and how linking is performed. + /// + /// Possible options are [`LibKind::Static`] and [`LibKind::Dynamic`]. + /// + /// Defaults to [`LibKind::Dynamic`]. + pub fn lib_kind(&mut self, kind: LibKind) -> &mut Self { + self.lib_kind = kind; + self } - let source_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("libobjc2"); - if !source_dir.join("objc/objc.h").exists() { - panic!("{}", NO_SOURCES_MSG); + /// Enable support for Objective-C++. + /// + /// Namely interoperability between Objective-C and C++ exceptions. + /// + /// Defaults to [`true`]. + pub fn objcxx(&mut self, objcxx: bool) -> &mut Self { + self.objcxx = objcxx; + self } - let dst = cmake::Config::new(source_dir) - // Default to ignoring `gnustep-config` presence, since they usually - // want to install the libraries globally (which requires root). - // Users that want systemwide installation should just install it - // themselves, and shouldn't need to vendor GNUStep. - .define("GNUSTEP_INSTALL_TYPE", "NONE") - .define("BUILD_STATIC_LIBOBJC", "OFF") // Default - .define("DEBUG_ARC_COMPAT", "OFF") // Default - .define("ENABLE_OBJCXX", "ON") // Default (NO_OBJCXX in code) - .define("ENABLE_TRACING", "OFF") // Default (WITH_TRACING in code) - .define("LEGACY_COMPAT", "OFF") // Default (NO_LEGACY in code) - // .define("OLDABI_COMPAT", "?") // Default depends on WIN32 - .define("TESTS", "OFF") - .define("TYPE_DEPENDENT_DISPATCH", "ON") // Default - // .always_configure(false) // TODO - // .static_crt(?) - .build_target("install") - .build(); - - Artifacts { - include_dir: dst.join("include"), - lib_dir: dst.join("lib"), - lib_kind: LibKind::Dynamic, - lib_name: "objc", + pub fn build(&mut self) -> Artifacts { + // GNUStep only compiles with clang, so try that first. + // (But let the user specify a different path if they need to). + if env::var_os("CC").is_none() { + env::set_var("CC", "clang"); + } + if env::var_os("CXX").is_none() { + env::set_var("CXX", "clang++"); + } + + let source_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("libobjc2"); + if !source_dir.join("objc/objc.h").exists() { + panic!("{}", NO_SOURCES_MSG); + } + + let dst = cmake::Config::new(source_dir) + // Default to ignoring `gnustep-config` presence, since they + // usually want to install the libraries globally (which requires + // root). Users that want systemwide installation should just + // install it themselves, and shouldn't need to vendor GNUStep. + .define("GNUSTEP_INSTALL_TYPE", "NONE") + // Don't bother building tests, we're not gonna run them anyways + // (and they're not available when packaged, see Cargo.toml). + .define("TESTS", "OFF") + // Having this on also builds the dynamic library, but not really + // anything we can do to change that. + .define( + "BUILD_STATIC_LIBOBJC", + match self.lib_kind { + LibKind::Static => "ON", + LibKind::Dynamic => "OFF", + }, + ) + .define("ENABLE_OBJCXX", if self.objcxx { "ON" } else { "OFF" }) + // Various other defaults + // .define("OLDABI_COMPAT", "ON") + // .define("DEBUG_ARC_COMPAT", "OFF") + // .define("ENABLE_TRACING", "OFF") + // .define("LEGACY_COMPAT", "OFF") + // .define("LIBOBJC_NAME", "objc") + // .define("TYPE_DEPENDENT_DISPATCH", "ON") + // .define("STRICT_APPLE_COMPATIBILITY", "0") // Default none + // TODO: .static_crt(?) + .build_target("install") + .build(); + + Artifacts { + include_dir: dst.join("include"), + lib_dir: dst.join("lib"), + lib_kind: self.lib_kind, + lib_name: "objc", + } } } +pub struct Artifacts { + include_dir: PathBuf, + lib_dir: PathBuf, + lib_kind: LibKind, + lib_name: &'static str, +} + impl Artifacts { pub fn include_dir(&self) -> &Path { &self.include_dir @@ -76,8 +115,8 @@ impl Artifacts { &self.lib_dir } - pub fn lib_kind(&self) -> &LibKind { - &self.lib_kind + pub fn lib_kind(&self) -> LibKind { + self.lib_kind } pub fn lib_name(&self) -> &str { @@ -86,7 +125,7 @@ impl Artifacts { pub fn print_cargo_metadata(&self) { let kind = match self.lib_kind { - LibKind::Dynamic => "dynamic", + LibKind::Dynamic => "dylib", LibKind::Static => "static", }; println!("cargo:rustc-link-search=native={}", self.lib_dir.display()); @@ -95,3 +134,11 @@ impl Artifacts { println!("cargo:lib={}", self.lib_dir.display()); } } + +#[non_exhaustive] +#[derive(Clone, Copy)] +pub enum LibKind { + Dynamic, + Static, + // Framework, +} diff --git a/objc2_sys/Cargo.toml b/objc2_sys/Cargo.toml index 910a81ab6..feafe2cb6 100644 --- a/objc2_sys/Cargo.toml +++ b/objc2_sys/Cargo.toml @@ -29,8 +29,13 @@ links = "objc" build = "build.rs" [features] -# If enabled, GNUStep's libobjc2 will be compiled and linked from source +# If enabled, GNUStep's libobjc2 will be compiled and linked from source. vendor_gnustep = ["gnustep_libobjc2_src"] +# Whether to link to libobjc statically. +# +# Only supported for vendored dependencies, it will trigger a compile-time +# error when venoring is not enabled. +static = [] [build-dependencies] gnustep_libobjc2_src = { path = "../gnustep_libobjc2_src", optional = true } diff --git a/objc2_sys/build.rs b/objc2_sys/build.rs index f957585fe..b53b672f5 100644 --- a/objc2_sys/build.rs +++ b/objc2_sys/build.rs @@ -1,12 +1,24 @@ #[cfg(feature = "vendor_gnustep")] fn main() { - let artifacts = gnustep_libobjc2_src::build(); + let mut builder = gnustep_libobjc2_src::Builder::new(); + + #[cfg(feature = "static")] + builder.lib_kind(gnustep_libobjc2_src::LibKind::Static); + #[cfg(not(feature = "static"))] + builder.lib_kind(gnustep_libobjc2_src::LibKind::Dynamic); + + let artifacts = builder.build(); artifacts.print_cargo_metadata(); + + // Add #[cfg(gnustep)] directive println!("cargo:rustc-cfg=gnustep"); } #[cfg(not(feature = "vendor_gnustep"))] fn main() { + #[cfg(feature = "static")] + compile_error!("Can only link statically to libobjc when vendoring is enabled."); + // Only rerun if this file changes; the script doesn't depend on our code println!("cargo:rerun-if-changed=build.rs"); From 38da1f3615f57bf7825680001d3c1d5ff40c6244 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 7 Oct 2021 15:01:46 +0200 Subject: [PATCH 7/8] Print rerun-if-changed in objc2_sys --- gnustep_libobjc2_src/src/lib.rs | 24 +++++++++++++++++++++++- objc2_sys/build.rs | 1 + 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/gnustep_libobjc2_src/src/lib.rs b/gnustep_libobjc2_src/src/lib.rs index 69dc5965e..ff3ed4fa2 100644 --- a/gnustep_libobjc2_src/src/lib.rs +++ b/gnustep_libobjc2_src/src/lib.rs @@ -59,7 +59,7 @@ impl Builder { panic!("{}", NO_SOURCES_MSG); } - let dst = cmake::Config::new(source_dir) + let dst = cmake::Config::new(&source_dir) // Default to ignoring `gnustep-config` presence, since they // usually want to install the libraries globally (which requires // root). Users that want systemwide installation should just @@ -91,6 +91,7 @@ impl Builder { .build(); Artifacts { + source_dir, include_dir: dst.join("include"), lib_dir: dst.join("lib"), lib_kind: self.lib_kind, @@ -100,6 +101,7 @@ impl Builder { } pub struct Artifacts { + source_dir: PathBuf, include_dir: PathBuf, lib_dir: PathBuf, lib_kind: LibKind, @@ -107,6 +109,10 @@ pub struct Artifacts { } impl Artifacts { + pub fn source_dir(&self) -> &Path { + &self.source_dir + } + pub fn include_dir(&self) -> &Path { &self.include_dir } @@ -133,6 +139,22 @@ impl Artifacts { println!("cargo:include={}", self.include_dir.display()); println!("cargo:lib={}", self.lib_dir.display()); } + + pub fn print_cargo_rerun_if_changed(&self) { + println!("cargo:rerun-if-env-changed=CC"); + println!("cargo:rerun-if-env-changed=CXX"); + rerun_if(&self.source_dir); + } +} + +fn rerun_if(path: &Path) { + if path.is_dir() { + for entry in std::fs::read_dir(path).expect("read_dir") { + rerun_if(&entry.expect("entry").path()); + } + } else { + println!("cargo:rerun-if-changed={}", path.display()); + } } #[non_exhaustive] diff --git a/objc2_sys/build.rs b/objc2_sys/build.rs index b53b672f5..0f13dbd45 100644 --- a/objc2_sys/build.rs +++ b/objc2_sys/build.rs @@ -9,6 +9,7 @@ fn main() { let artifacts = builder.build(); artifacts.print_cargo_metadata(); + artifacts.print_cargo_rerun_if_changed(); // Add #[cfg(gnustep)] directive println!("cargo:rustc-cfg=gnustep"); From 9cbece0815897fe44566b090351b4e81e4362f10 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Fri, 8 Oct 2021 19:42:48 +0200 Subject: [PATCH 8/8] Add initial gnustep_base_src --- .gitmodules | 3 + Cargo.toml | 1 + gnustep_base_src/Cargo.toml | 15 +++++ gnustep_base_src/libs-base | 1 + gnustep_base_src/src/lib.rs | 99 +++++++++++++++++++++++++++++++++ gnustep_libobjc2_src/src/lib.rs | 12 ++++ 6 files changed, 131 insertions(+) create mode 100644 gnustep_base_src/Cargo.toml create mode 160000 gnustep_base_src/libs-base create mode 100644 gnustep_base_src/src/lib.rs diff --git a/.gitmodules b/.gitmodules index a05352be5..65a5effb4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,3 +2,6 @@ path = gnustep_libobjc2_src/libobjc2 url = https://github.com/gnustep/libobjc2.git branch = 2.1 +[submodule "gnustep-base"] + path = gnustep_base_src/libs-base + url = https://github.com/gnustep/libs-base.git diff --git a/Cargo.toml b/Cargo.toml index 6fcb44379..4e9515f30 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ "gnustep_libobjc2_src", + "gnustep_base_src", "objc2", "objc2_block", "objc2_encode", diff --git a/gnustep_base_src/Cargo.toml b/gnustep_base_src/Cargo.toml new file mode 100644 index 000000000..a1f54b845 --- /dev/null +++ b/gnustep_base_src/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "gnustep_base_src" +version = "0.0.1" +authors = ["Mads Marquart "] +edition = "2018" + +description = "Source of The GNUstep Base Library and logic to build it" +keywords = ["gnustep", "objc", "gnustep-base", "build-dependencies"] +categories = [ + "development-tools::build-utils", +] +readme = "README.md" +repository = "https://github.com/madsmtm/gnustep_base_src" +documentation = "https://docs.rs/gnustep_base_src/" +license = "MIT/Apache-2.0" diff --git a/gnustep_base_src/libs-base b/gnustep_base_src/libs-base new file mode 160000 index 000000000..326dc210a --- /dev/null +++ b/gnustep_base_src/libs-base @@ -0,0 +1 @@ +Subproject commit 326dc210a4fca396489d6527d4649d61dff4bed5 diff --git a/gnustep_base_src/src/lib.rs b/gnustep_base_src/src/lib.rs new file mode 100644 index 000000000..04a3a31d6 --- /dev/null +++ b/gnustep_base_src/src/lib.rs @@ -0,0 +1,99 @@ +use std::env; +use std::path::{Path, PathBuf}; +use std::process::Command; + +const NO_SOURCES_MSG: &'static str = r#" +GNUStep Base sources not present, please run: + +$ git submodule update --init --recursive + +If you did not checkout via git, you will +need to fetch the submodule's contents from +https://github.com/gnustep/libs-base +"#; + +pub struct Builder {} + +impl Builder { + pub fn new() -> Self { + Self {} + } + + pub fn build(&mut self) -> Artifacts { + // GNUStep only compiles with clang, so try that first. + // (But let the user specify a different path if they need to). + if env::var_os("CC").is_none() { + env::set_var("CC", "clang"); + } + if env::var_os("CXX").is_none() { + env::set_var("CXX", "clang++"); + } + + let source_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("libs-base"); + if !source_dir.join("Headers/Foundation/Foundation.h").exists() { + panic!("{}", NO_SOURCES_MSG); + } + + let mut configure = Command::new(source_dir.join("configure")); + // .arg("--with-config-file=") + // .arg("--enable-libffi") + // .arg("--with-default-config=") + // .arg("--prefix") // Or GNUSTEP_SYSTEM_ROOT ? + + // run `make` and `make install` + + let dst: PathBuf = todo!(); + + Artifacts { + source_dir, + include_dir: dst.join("include"), + lib_dir: dst.join("lib"), + lib_name: "gnustep-base", + } + } +} + +pub struct Artifacts { + source_dir: PathBuf, + include_dir: PathBuf, + lib_dir: PathBuf, + lib_name: &'static str, +} + +impl Artifacts { + pub fn include_dir(&self) -> &Path { + &self.include_dir + } + + pub fn lib_dir(&self) -> &Path { + &self.lib_dir + } + + pub fn lib_name(&self) -> &str { + &self.lib_name + } + + pub fn print_cargo_metadata(&self) { + println!("cargo:rustc-link-search=native={}", self.lib_dir.display()); + println!("cargo:rustc-link-lib=dylib={}", self.lib_name); + println!("cargo:include={}", self.include_dir.display()); + println!("cargo:lib={}", self.lib_dir.display()); + } + + pub fn print_cargo_rerun_if_changed(&self) { + println!("cargo:rerun-if-env-changed=CC"); + println!("cargo:rerun-if-env-changed=CXX"); + rerun_if(&self.source_dir); + } +} + +// https://github.com/rust-lang/git2-rs/blob/0.13.23/libgit2-sys/build.rs#L228-L236 +fn rerun_if(path: &Path) { + if path.is_dir() { + for entry in std::fs::read_dir(path).expect("read_dir") { + rerun_if(&entry.expect("entry").path()); + } + } else { + println!("cargo:rerun-if-changed={}", path.display()); + } +} diff --git a/gnustep_libobjc2_src/src/lib.rs b/gnustep_libobjc2_src/src/lib.rs index ff3ed4fa2..feefa9c76 100644 --- a/gnustep_libobjc2_src/src/lib.rs +++ b/gnustep_libobjc2_src/src/lib.rs @@ -1,3 +1,15 @@ +//! TODO +//! +//! See +//! - https://github.com/gnustep/libs-base/blob/base-1_28_0/INSTALL +//! - https://github.com/blas-lapack-rs/blis-src/blob/main/blis-src/build.rs +//! - https://github.com/alexcrichton/openssl-src-rs/blob/master/src/lib.rs +//! - https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.70/autoconf.html#Running-configure-Scripts +//! +//! And gnustep-make would also have to be installed: +//! - https://github.com/gnustep/tools-make/blob/master/Documentation/gnustep-make.texi +//! - http://www.gnustep.org/resources/documentation/Developer/Make/Manual/DESIGN + use std::env; use std::path::{Path, PathBuf};