Skip to content

Commit

Permalink
Add option to link statically against GNUStep's libobjc2
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Oct 7, 2021
1 parent f9d2b82 commit 55c3989
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 50 deletions.
143 changes: 95 additions & 48 deletions libobjc2_src/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 {
Expand All @@ -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());
Expand All @@ -95,3 +134,11 @@ impl Artifacts {
println!("cargo:lib={}", self.lib_dir.display());
}
}

#[non_exhaustive]
#[derive(Clone, Copy)]
pub enum LibKind {
Dynamic,
Static,
// Framework,
}
7 changes: 6 additions & 1 deletion objc2_sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ["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]
libobjc2_src = { path = "../libobjc2_src", optional = true }
14 changes: 13 additions & 1 deletion objc2_sys/build.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
#[cfg(feature = "vendor_gnustep")]
fn main() {
let artifacts = libobjc2_src::build();
let mut builder = libobjc2_src::Builder::new();

#[cfg(feature = "static")]
builder.lib_kind(libobjc2_src::LibKind::Static);
#[cfg(not(feature = "static"))]
builder.lib_kind(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");

Expand Down

0 comments on commit 55c3989

Please sign in to comment.