Skip to content

Commit 55c3989

Browse files
committed
Add option to link statically against GNUStep's libobjc2
1 parent f9d2b82 commit 55c3989

File tree

3 files changed

+114
-50
lines changed

3 files changed

+114
-50
lines changed

libobjc2_src/src/lib.rs

Lines changed: 95 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -11,62 +11,101 @@ need to fetch the submodule's contents from
1111
https://github.com/gnustep/libobjc2
1212
"#;
1313

14-
#[non_exhaustive]
15-
pub enum LibKind {
16-
Dynamic,
17-
Static,
18-
// Framework,
19-
}
20-
21-
pub struct Artifacts {
22-
include_dir: PathBuf,
23-
lib_dir: PathBuf,
14+
pub struct Builder {
2415
lib_kind: LibKind,
25-
lib_name: &'static str,
16+
objcxx: bool,
2617
}
2718

28-
pub fn build() -> Artifacts {
29-
// GNUStep only compiles with clang, so try that first.
30-
// (But let the user specify a different path if they need to).
31-
if env::var_os("CC").is_none() {
32-
env::set_var("CC", "clang");
19+
impl Builder {
20+
pub fn new() -> Self {
21+
Self {
22+
lib_kind: LibKind::Dynamic,
23+
objcxx: true,
24+
}
3325
}
34-
if env::var_os("CXX").is_none() {
35-
env::set_var("CXX", "clang++");
26+
27+
/// Set the type of library to be built, and how linking is performed.
28+
///
29+
/// Possible options are [`LibKind::Static`] and [`LibKind::Dynamic`].
30+
///
31+
/// Defaults to [`LibKind::Dynamic`].
32+
pub fn lib_kind(&mut self, kind: LibKind) -> &mut Self {
33+
self.lib_kind = kind;
34+
self
3635
}
3736

38-
let source_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("libobjc2");
39-
if !source_dir.join("objc/objc.h").exists() {
40-
panic!("{}", NO_SOURCES_MSG);
37+
/// Enable support for Objective-C++.
38+
///
39+
/// Namely interoperability between Objective-C and C++ exceptions.
40+
///
41+
/// Defaults to [`true`].
42+
pub fn objcxx(&mut self, objcxx: bool) -> &mut Self {
43+
self.objcxx = objcxx;
44+
self
4145
}
4246

43-
let dst = cmake::Config::new(source_dir)
44-
// Default to ignoring `gnustep-config` presence, since they usually
45-
// want to install the libraries globally (which requires root).
46-
// Users that want systemwide installation should just install it
47-
// themselves, and shouldn't need to vendor GNUStep.
48-
.define("GNUSTEP_INSTALL_TYPE", "NONE")
49-
.define("BUILD_STATIC_LIBOBJC", "OFF") // Default
50-
.define("DEBUG_ARC_COMPAT", "OFF") // Default
51-
.define("ENABLE_OBJCXX", "ON") // Default (NO_OBJCXX in code)
52-
.define("ENABLE_TRACING", "OFF") // Default (WITH_TRACING in code)
53-
.define("LEGACY_COMPAT", "OFF") // Default (NO_LEGACY in code)
54-
// .define("OLDABI_COMPAT", "?") // Default depends on WIN32
55-
.define("TESTS", "OFF")
56-
.define("TYPE_DEPENDENT_DISPATCH", "ON") // Default
57-
// .always_configure(false) // TODO
58-
// .static_crt(?)
59-
.build_target("install")
60-
.build();
61-
62-
Artifacts {
63-
include_dir: dst.join("include"),
64-
lib_dir: dst.join("lib"),
65-
lib_kind: LibKind::Dynamic,
66-
lib_name: "objc",
47+
pub fn build(&mut self) -> Artifacts {
48+
// GNUStep only compiles with clang, so try that first.
49+
// (But let the user specify a different path if they need to).
50+
if env::var_os("CC").is_none() {
51+
env::set_var("CC", "clang");
52+
}
53+
if env::var_os("CXX").is_none() {
54+
env::set_var("CXX", "clang++");
55+
}
56+
57+
let source_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("libobjc2");
58+
if !source_dir.join("objc/objc.h").exists() {
59+
panic!("{}", NO_SOURCES_MSG);
60+
}
61+
62+
let dst = cmake::Config::new(source_dir)
63+
// Default to ignoring `gnustep-config` presence, since they
64+
// usually want to install the libraries globally (which requires
65+
// root). Users that want systemwide installation should just
66+
// install it themselves, and shouldn't need to vendor GNUStep.
67+
.define("GNUSTEP_INSTALL_TYPE", "NONE")
68+
// Don't bother building tests, we're not gonna run them anyways
69+
// (and they're not available when packaged, see Cargo.toml).
70+
.define("TESTS", "OFF")
71+
// Having this on also builds the dynamic library, but not really
72+
// anything we can do to change that.
73+
.define(
74+
"BUILD_STATIC_LIBOBJC",
75+
match self.lib_kind {
76+
LibKind::Static => "ON",
77+
LibKind::Dynamic => "OFF",
78+
},
79+
)
80+
.define("ENABLE_OBJCXX", if self.objcxx { "ON" } else { "OFF" })
81+
// Various other defaults
82+
// .define("OLDABI_COMPAT", "ON")
83+
// .define("DEBUG_ARC_COMPAT", "OFF")
84+
// .define("ENABLE_TRACING", "OFF")
85+
// .define("LEGACY_COMPAT", "OFF")
86+
// .define("LIBOBJC_NAME", "objc")
87+
// .define("TYPE_DEPENDENT_DISPATCH", "ON")
88+
// .define("STRICT_APPLE_COMPATIBILITY", "0") // Default none
89+
// TODO: .static_crt(?)
90+
.build_target("install")
91+
.build();
92+
93+
Artifacts {
94+
include_dir: dst.join("include"),
95+
lib_dir: dst.join("lib"),
96+
lib_kind: self.lib_kind,
97+
lib_name: "objc",
98+
}
6799
}
68100
}
69101

102+
pub struct Artifacts {
103+
include_dir: PathBuf,
104+
lib_dir: PathBuf,
105+
lib_kind: LibKind,
106+
lib_name: &'static str,
107+
}
108+
70109
impl Artifacts {
71110
pub fn include_dir(&self) -> &Path {
72111
&self.include_dir
@@ -76,8 +115,8 @@ impl Artifacts {
76115
&self.lib_dir
77116
}
78117

79-
pub fn lib_kind(&self) -> &LibKind {
80-
&self.lib_kind
118+
pub fn lib_kind(&self) -> LibKind {
119+
self.lib_kind
81120
}
82121

83122
pub fn lib_name(&self) -> &str {
@@ -86,7 +125,7 @@ impl Artifacts {
86125

87126
pub fn print_cargo_metadata(&self) {
88127
let kind = match self.lib_kind {
89-
LibKind::Dynamic => "dynamic",
128+
LibKind::Dynamic => "dylib",
90129
LibKind::Static => "static",
91130
};
92131
println!("cargo:rustc-link-search=native={}", self.lib_dir.display());
@@ -95,3 +134,11 @@ impl Artifacts {
95134
println!("cargo:lib={}", self.lib_dir.display());
96135
}
97136
}
137+
138+
#[non_exhaustive]
139+
#[derive(Clone, Copy)]
140+
pub enum LibKind {
141+
Dynamic,
142+
Static,
143+
// Framework,
144+
}

objc2_sys/Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,13 @@ links = "objc"
2929
build = "build.rs"
3030

3131
[features]
32-
# If enabled, GNUStep's libobjc2 will be compiled and linked from source
32+
# If enabled, GNUStep's libobjc2 will be compiled and linked from source.
3333
vendor_gnustep = ["libobjc2_src"]
34+
# Whether to link to libobjc statically.
35+
#
36+
# Only supported for vendored dependencies, it will trigger a compile-time
37+
# error when venoring is not enabled.
38+
static = []
3439

3540
[build-dependencies]
3641
libobjc2_src = { path = "../libobjc2_src", optional = true }

objc2_sys/build.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
#[cfg(feature = "vendor_gnustep")]
22
fn main() {
3-
let artifacts = libobjc2_src::build();
3+
let mut builder = libobjc2_src::Builder::new();
4+
5+
#[cfg(feature = "static")]
6+
builder.lib_kind(libobjc2_src::LibKind::Static);
7+
#[cfg(not(feature = "static"))]
8+
builder.lib_kind(libobjc2_src::LibKind::Dynamic);
9+
10+
let artifacts = builder.build();
411
artifacts.print_cargo_metadata();
12+
13+
// Add #[cfg(gnustep)] directive
514
println!("cargo:rustc-cfg=gnustep");
615
}
716

817
#[cfg(not(feature = "vendor_gnustep"))]
918
fn main() {
19+
#[cfg(feature = "static")]
20+
compile_error!("Can only link statically to libobjc when vendoring is enabled.");
21+
1022
// Only rerun if this file changes; the script doesn't depend on our code
1123
println!("cargo:rerun-if-changed=build.rs");
1224

0 commit comments

Comments
 (0)