Skip to content

Commit e91d729

Browse files
committed
initial approach
1 parent 95753bb commit e91d729

4 files changed

Lines changed: 99 additions & 16 deletions

File tree

Makefile.pre.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3379,7 +3379,7 @@ Python/thread.o: @THREADHEADERS@ $(srcdir)/Python/condvar.h
33793379
# Module dependencies and platform-specific files
33803380

33813381
cpython-sys: Modules/cpython-sys/Cargo.toml Modules/cpython-sys/build.rs Modules/cpython-sys/wrapper.h Modules/cpython-sys/parser.h
3382-
CARGO_TARGET_DIR=$(abs_builddir)/target PYTHON_BUILD_DIR=$(abs_builddir) PY_CC="$(CC)" PY_CPPFLAGS="$(CPPFLAGS)" PY_CFLAGS="$(CFLAGS)" LLVM_TARGET="$(LLVM_TARGET)" $(CARGO_HOME)/bin/cargo build --lib --locked --package cpython-sys --profile $(CARGO_PROFILE) $(if $(CARGO_TARGET),--target=$(CARGO_TARGET)) --manifest-path $(srcdir)/Cargo.toml
3382+
CARGO_TARGET_DIR=$(abs_builddir)/target PYTHON_BUILD_DIR=$(abs_builddir) PY_CC="$(CC)" PY_CPPFLAGS="$(CPPFLAGS)" PY_CFLAGS="$(CFLAGS)" LLVM_TARGET="$(LLVM_TARGET)" IPHONEOS_DEPLOYMENT_TARGET=$(IPHONEOS_DEPLOYMENT_TARGET) $(CARGO_HOME)/bin/cargo build --lib --locked --package cpython-sys --profile $(CARGO_PROFILE) $(if $(CARGO_TARGET),--target=$(CARGO_TARGET)) --manifest-path $(srcdir)/Cargo.toml
33833383

33843384
RUST_STATICLIB_A= target/$(if $(CARGO_TARGET),$(CARGO_TARGET)/$(CARGO_TARGET_DIR),$(CARGO_TARGET_DIR))/libcpython_rust_staticlib.a
33853385

Modules/cpython-build-helper/src/lib.rs

Lines changed: 62 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,40 @@ use std::env;
33
/// Print necessary link arguments for the library depending on the build
44
/// configuration (static or shared)
55
pub fn print_linker_args() {
6-
let target = env::var("TARGET").unwrap_or_default();
6+
println!("cargo:rerun-if-env-changed=RUST_SHARED_BUILD");
7+
println!("cargo:rerun-if-env-changed=BLDSHARED_EXE");
8+
println!("cargo:rerun-if-env-changed=BLDSHARED_ARGS");
9+
println!("cargo:rerun-if-env-changed=LIBPYTHON");
10+
println!("cargo:rerun-if-env-changed=PYTHON_BUILD_DIR");
11+
println!("cargo:rerun-if-env-changed=CARGO_CFG_TARGET_OS");
12+
13+
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
14+
let shared_build =
15+
env::var("RUST_SHARED_BUILD").unwrap_or_default() == "1" || target_os == "ios";
716

817
// On Apple platforms (macOS, iOS), Cargo's cdylib produces a Mach-O
918
// dynamiclib (via -dynamiclib), but CPython's C extensions are built as
1019
// bundles (via -bundle). Unlike bundles, dynamiclibs require all symbols
1120
// to be resolved at link time. Pass -undefined dynamic_lookup so that
1221
// Python C API symbols are resolved at load time by the interpreter.
13-
if target.contains("apple") {
22+
if target_os == "macos" || target_os == "ios" {
1423
println!("cargo:rustc-cdylib-link-arg=-undefined");
1524
println!("cargo:rustc-cdylib-link-arg=dynamic_lookup");
1625
}
1726

27+
// Apple framework builds for iOS encode framework search/link flags in
28+
// BLDSHARED_EXE. Skip the linker executable itself and filter out flags
29+
// that conflict with Cargo's own cdylib invocation.
30+
if shared_build
31+
&& let Ok(args) = env::var("BLDSHARED_EXE")
32+
{
33+
print_link_args(&args, true);
34+
}
35+
1836
// Pass platform-specific shared link arguments (e.g. PY_CORE_LDFLAGS)
1937
// from the CPython build system.
2038
if let Ok(args) = env::var("BLDSHARED_ARGS") {
21-
let args = shlex::split(&args).expect("Invalid BLDSHARED_ARGS");
22-
let mut iter = args.iter();
23-
while let Some(arg) = iter.next() {
24-
// -bundle_loader is incompatible with Cargo's cdylib on macOS
25-
// (it only works with -bundle, not -dynamiclib). Skip it and
26-
// its argument.
27-
if arg == "-bundle_loader" {
28-
iter.next(); // skip the path argument
29-
continue;
30-
}
31-
println!("cargo:rustc-cdylib-link-arg={}", arg);
32-
}
39+
print_link_args(&args, false);
3340
}
3441

3542
// On Android (and Cygwin), extension modules must link against libpython.
@@ -52,3 +59,44 @@ pub fn print_linker_args() {
5259

5360
// Static linker configuration is in cpython-rust-staticlib
5461
}
62+
63+
fn print_link_args(raw: &str, skip_first: bool) {
64+
let mut args = shlex::split(raw).expect("Invalid linker args");
65+
if skip_first && !args.is_empty() {
66+
args.remove(0);
67+
}
68+
69+
let build_dir = env::var("PYTHON_BUILD_DIR").ok();
70+
let mut i = 0;
71+
while i < args.len() {
72+
match args[i].as_str() {
73+
// -bundle_loader only works with -bundle, not with Cargo's
74+
// cdylib mode (-dynamiclib).
75+
"-bundle_loader" => {
76+
i += 2;
77+
}
78+
// Cargo chooses the Mach-O output type for cdylib already.
79+
"-bundle" | "-dynamiclib" => {
80+
i += 1;
81+
}
82+
// dynamic_lookup is added explicitly for Apple targets above.
83+
"-undefined" if i + 1 < args.len() && args[i + 1] == "dynamic_lookup" => {
84+
i += 2;
85+
}
86+
"-F" if i + 1 < args.len() => {
87+
let value = if args[i + 1] == "." {
88+
build_dir.clone().unwrap_or_else(|| ".".to_string())
89+
} else {
90+
args[i + 1].clone()
91+
};
92+
println!("cargo:rustc-cdylib-link-arg=-F");
93+
println!("cargo:rustc-cdylib-link-arg={value}");
94+
i += 2;
95+
}
96+
_ => {
97+
println!("cargo:rustc-cdylib-link-arg={}", args[i]);
98+
i += 1;
99+
}
100+
}
101+
}
102+
}

Modules/cpython-sys/build.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ fn generate_c_api_bindings(srcdir: &Path, builddir: Option<&str>, out_path: &Pat
129129
for dir in include_dirs {
130130
builder = builder.clang_arg(format!("-I{}", dir.display()));
131131
}
132+
builder = add_target_clang_args(builder, builddir);
132133

133134
let bindings = builder
134135
.allowlist_function("_?Py.*")
@@ -145,3 +146,37 @@ fn generate_c_api_bindings(srcdir: &Path, builddir: Option<&str>, out_path: &Pat
145146
.write_to_file(out_path.join("c_api.rs"))
146147
.expect("Couldn't write bindings!");
147148
}
149+
150+
fn add_target_clang_args(mut builder: bindgen::Builder, builddir: Option<&str>) -> bindgen::Builder {
151+
let target = env::var("TARGET").unwrap_or_default();
152+
if !target.contains("apple-ios") {
153+
return builder;
154+
}
155+
156+
// For iOS targets, bindgen may parse headers with an iOS simulator/device
157+
// target but without a deployment minimum, which disables TLS support.
158+
let deployment_target = ios_deployment_target(builddir).unwrap_or_else(|| "13.0".to_string());
159+
builder = builder.clang_arg(format!("-mios-version-min={deployment_target}"));
160+
builder
161+
}
162+
163+
fn ios_deployment_target(builddir: Option<&str>) -> Option<String> {
164+
if let Ok(value) = env::var("IPHONEOS_DEPLOYMENT_TARGET")
165+
&& !value.is_empty()
166+
{
167+
return Some(value);
168+
}
169+
170+
let builddir = builddir?;
171+
let makefile = Path::new(builddir).join("Makefile");
172+
let text = std::fs::read_to_string(makefile).ok()?;
173+
for line in text.lines() {
174+
if let Some(value) = line.strip_prefix("IPHONEOS_DEPLOYMENT_TARGET=") {
175+
let value = value.trim();
176+
if !value.is_empty() {
177+
return Some(value.to_string());
178+
}
179+
}
180+
}
181+
None
182+
}

Modules/makesetup

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ sed -e 's/[ ]*#.*//' -e '/^[ ]*$/d' |
307307
BUILT_SHARED="$BUILT_SHARED $mod"
308308
# depends on the headers through cpython-sys
309309
rule="$rust_shared: cpython-sys \$(srcdir)/Cargo.toml \$(srcdir)/Cargo.lock \$(srcdir)/$srcdir/$manifest $prefixed_srcs \$(PYTHON_HEADERS) \$(MODULE_${mods_upper}_LDEPS) \$(LIBRARY)"
310-
rule="$rule; CARGO_TARGET_DIR=\$(abs_builddir)/target PYTHON_BUILD_DIR=\$(abs_builddir) BLDSHARED_ARGS=\"\$(BLDSHARED_ARGS)\" LIBPYTHON=\"\$(LIBPYTHON)\" \$(if \$(CARGO_TARGET_LINKER_ENV),\$(CARGO_TARGET_LINKER_ENV)=\$(CC)) \$(CARGO_HOME)/bin/cargo build -vvv --lib --locked --package ${mod} --profile \$(CARGO_PROFILE) \$(if \$(CARGO_TARGET),--target=\$(CARGO_TARGET)) --manifest-path \$(srcdir)/Cargo.toml"
310+
rule="$rule; CARGO_TARGET_DIR=\$(abs_builddir)/target PYTHON_BUILD_DIR=\$(abs_builddir) RUST_SHARED_BUILD=\$(PY_ENABLE_SHARED) IPHONEOS_DEPLOYMENT_TARGET=\$(IPHONEOS_DEPLOYMENT_TARGET) BLDSHARED_EXE=\"\$(BLDSHARED_EXE)\" BLDSHARED_ARGS=\"\$(BLDSHARED_ARGS)\" LIBPYTHON=\"\$(LIBPYTHON)\" \$(if \$(CARGO_TARGET_LINKER_ENV),\$(CARGO_TARGET_LINKER_ENV)=\$(CC)) \$(CARGO_HOME)/bin/cargo build -vvv --lib --locked --package ${mod} --profile \$(CARGO_PROFILE) \$(if \$(CARGO_TARGET),--target=\$(CARGO_TARGET)) --manifest-path \$(srcdir)/Cargo.toml"
311311
echo "$rule" >>$rulesf
312312
echo "$file: $rust_shared; mv $rust_shared $file" >>$rulesf
313313
done

0 commit comments

Comments
 (0)