Skip to content

Commit 7eb9580

Browse files
Create djls-dev crate and centralize Python linking build scripts (#119)
1 parent c09d654 commit 7eb9580

File tree

11 files changed

+66
-132
lines changed

11 files changed

+66
-132
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ and this project attempts to adhere to [Semantic Versioning](https://semver.org/
2828

2929
- **Internal**: Moved task queueing functionality to `djls-server` crate, renamed from `Worker` to `Queue`, and simplified API.
3030
- **Internal**: Improved Python environment handling, including refactored activation logic.
31+
- **Internal**: Centralized Python linking build logic into a shared `djls-dev` crate to reduce duplication.
3132

3233
## [5.2.0a0]
3334

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ resolver = "2"
55
[workspace.dependencies]
66
djls = { path = "crates/djls" }
77
djls-conf = { path = "crates/djls-conf" }
8+
djls-dev = { path = "crates/djls-dev" }
89
djls-project = { path = "crates/djls-project" }
910
djls-server = { path = "crates/djls-server" }
1011
djls-templates = { path = "crates/djls-templates" }

crates/djls-dev/Cargo.toml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "djls-dev"
3+
version = "0.1.0"
4+
edition = "2021"
5+
publish = false
6+
7+
[dependencies]
8+
pyo3-build-config = { workspace = true, features = ["resolve-config"] }

crates/djls-dev/src/build.rs

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/// Sets up the necessary Cargo directives for linking against the Python library.
2+
///
3+
/// This function should be called from the `build.rs` script of any crate
4+
/// within the workspace whose compiled artifact (e.g., test executable, binary)
5+
/// needs to link against the Python C API at compile time and find the
6+
/// corresponding shared library at runtime. This is typically required for
7+
/// crates using `pyo3` features like `Python::with_gil` or defining `#[pyfunction]`s
8+
/// directly in their test or binary code.
9+
///
10+
/// It uses `pyo3-build-config` to detect the active Python installation and
11+
/// prints the required `cargo:rustc-link-search` and `cargo:rustc-link-lib`
12+
/// directives to Cargo, enabling the linker to find and link against the
13+
/// appropriate Python library (e.g., libpythonX.Y.so).
14+
///
15+
/// It also adds an RPATH linker argument on Unix-like systems (`-Wl,-rpath,...`)
16+
/// to help the resulting executable find the Python shared library at runtime
17+
/// without needing manual `LD_LIBRARY_PATH` adjustments in typical scenarios.
18+
pub fn setup_python_linking() {
19+
// Instruct Cargo to rerun the calling build script if the Python config changes.
20+
// Using PYO3_CONFIG_FILE is a reliable way to detect changes in the active Python env.
21+
println!("cargo:rerun-if-changed=build.rs");
22+
23+
// Set up #[cfg] flags first (useful for conditional compilation)
24+
pyo3_build_config::use_pyo3_cfgs();
25+
26+
// Get the Python interpreter configuration directly
27+
let config = pyo3_build_config::get();
28+
29+
// Add the library search path if available
30+
if let Some(lib_dir) = &config.lib_dir {
31+
println!("cargo:rustc-link-search=native={}", lib_dir);
32+
33+
// Add RPATH linker argument for Unix-like systems (Linux, macOS)
34+
// This helps the test executable find the Python library at runtime.
35+
#[cfg(not(windows))]
36+
println!("cargo:rustc-link-arg=-Wl,-rpath,{}", lib_dir);
37+
} else {
38+
println!("cargo:warning=Python library directory not found in config.");
39+
}
40+
41+
// Add the library link directive if available
42+
if let Some(lib_name) = &config.lib_name {
43+
println!("cargo:rustc-link-lib=dylib={}", lib_name);
44+
} else {
45+
println!("cargo:warning=Python library name not found in config.");
46+
}
47+
}

crates/djls-dev/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
mod build;
2+
3+
pub use build::setup_python_linking;

crates/djls-project/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ tower-lsp-server = { workspace = true, features = ["proposed"] }
1010
which = "7.0.1"
1111

1212
[build-dependencies]
13-
pyo3-build-config = { workspace = true, features = ["resolve-config"] }
13+
djls-dev = { workspace = true }
1414

1515
[dev-dependencies]
1616
tempfile = { workspace = true }

crates/djls-project/build.rs

+1-43
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,3 @@
1-
/// Build script to configure linking against the Python library.
2-
///
3-
/// This script is necessary when the crate's code, particularly tests
4-
/// that interact with the Python interpreter via `pyo3` (e.g., using
5-
/// `Python::with_gil`, importing modules, calling Python functions),
6-
/// needs symbols from the Python C API at link time.
7-
///
8-
/// It uses `pyo3-build-config` to detect the Python installation and
9-
/// prints the required `cargo:rustc-link-search` and `cargo:rustc-link-lib`
10-
/// directives to Cargo, enabling the linker to find and link against the
11-
/// appropriate Python library (e.g., libpythonX.Y.so).
12-
///
13-
/// It also adds an RPATH linker argument on Unix-like systems so the
14-
/// resulting test executable can find the Python library at runtime.
15-
///
16-
/// Note: Each crate whose test target requires Python linking needs its
17-
/// own `build.rs` with this logic.
181
fn main() {
19-
println!("cargo:rerun-if-changed=build.rs");
20-
21-
// Set up #[cfg] flags first (useful for conditional compilation)
22-
pyo3_build_config::use_pyo3_cfgs();
23-
24-
// Get the Python interpreter configuration directly
25-
let config = pyo3_build_config::get();
26-
27-
// Add the library search path if available
28-
if let Some(lib_dir) = &config.lib_dir {
29-
println!("cargo:rustc-link-search=native={}", lib_dir);
30-
31-
// Add RPATH linker argument for Unix-like systems (Linux, macOS)
32-
// This helps the test executable find the Python library at runtime.
33-
#[cfg(not(windows))]
34-
println!("cargo:rustc-link-arg=-Wl,-rpath,{}", lib_dir);
35-
} else {
36-
println!("cargo:warning=Python library directory not found in config.");
37-
}
38-
39-
// Add the library link directive if available
40-
if let Some(lib_name) = &config.lib_name {
41-
println!("cargo:rustc-link-lib=dylib={}", lib_name);
42-
} else {
43-
println!("cargo:warning=Python library name not found in config.");
44-
}
2+
djls_dev::setup_python_linking();
453
}

crates/djls-server/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ tower-lsp-server = { workspace = true }
1818
percent-encoding = "2.3"
1919

2020
[build-dependencies]
21-
pyo3-build-config = { workspace = true, features = ["resolve-config"] }
21+
djls-dev = { workspace = true }

crates/djls-server/build.rs

+1-43
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,3 @@
1-
/// Build script to configure linking against the Python library.
2-
///
3-
/// This script is necessary when the crate's code, particularly tests
4-
/// that interact with the Python interpreter via `pyo3` (e.g., using
5-
/// `Python::with_gil`, importing modules, calling Python functions),
6-
/// needs symbols from the Python C API at link time.
7-
///
8-
/// It uses `pyo3-build-config` to detect the Python installation and
9-
/// prints the required `cargo:rustc-link-search` and `cargo:rustc-link-lib`
10-
/// directives to Cargo, enabling the linker to find and link against the
11-
/// appropriate Python library (e.g., libpythonX.Y.so).
12-
///
13-
/// It also adds an RPATH linker argument on Unix-like systems so the
14-
/// resulting test executable can find the Python library at runtime.
15-
///
16-
/// Note: Each crate whose test target requires Python linking needs its
17-
/// own `build.rs` with this logic.
181
fn main() {
19-
println!("cargo:rerun-if-changed=build.rs");
20-
21-
// Set up #[cfg] flags first (useful for conditional compilation)
22-
pyo3_build_config::use_pyo3_cfgs();
23-
24-
// Get the Python interpreter configuration directly
25-
let config = pyo3_build_config::get();
26-
27-
// Add the library search path if available
28-
if let Some(lib_dir) = &config.lib_dir {
29-
println!("cargo:rustc-link-search=native={}", lib_dir);
30-
31-
// Add RPATH linker argument for Unix-like systems (Linux, macOS)
32-
// This helps the test executable find the Python library at runtime.
33-
#[cfg(not(windows))]
34-
println!("cargo:rustc-link-arg=-Wl,-rpath,{}", lib_dir);
35-
} else {
36-
println!("cargo:warning=Python library directory not found in config.");
37-
}
38-
39-
// Add the library link directive if available
40-
if let Some(lib_name) = &config.lib_name {
41-
println!("cargo:rustc-link-lib=dylib={}", lib_name);
42-
} else {
43-
println!("cargo:warning=Python library name not found in config.");
44-
}
2+
djls_dev::setup_python_linking();
453
}

crates/djls/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ tower-lsp-server = { workspace = true }
2020
clap = { version = "4.5", features = ["derive"] }
2121

2222
[build-dependencies]
23-
pyo3-build-config = { workspace = true, features = ["resolve-config"] }
23+
djls-dev = { workspace = true }

crates/djls/build.rs

+1-43
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,3 @@
1-
/// Build script to configure linking against the Python library.
2-
///
3-
/// This script is necessary when the crate's code, particularly tests
4-
/// that interact with the Python interpreter via `pyo3` (e.g., using
5-
/// `Python::with_gil`, importing modules, calling Python functions),
6-
/// needs symbols from the Python C API at link time.
7-
///
8-
/// It uses `pyo3-build-config` to detect the Python installation and
9-
/// prints the required `cargo:rustc-link-search` and `cargo:rustc-link-lib`
10-
/// directives to Cargo, enabling the linker to find and link against the
11-
/// appropriate Python library (e.g., libpythonX.Y.so).
12-
///
13-
/// It also adds an RPATH linker argument on Unix-like systems so the
14-
/// resulting test executable can find the Python library at runtime.
15-
///
16-
/// Note: Each crate whose test target requires Python linking needs its
17-
/// own `build.rs` with this logic.
181
fn main() {
19-
println!("cargo:rerun-if-changed=build.rs");
20-
21-
// Set up #[cfg] flags first (useful for conditional compilation)
22-
pyo3_build_config::use_pyo3_cfgs();
23-
24-
// Get the Python interpreter configuration directly
25-
let config = pyo3_build_config::get();
26-
27-
// Add the library search path if available
28-
if let Some(lib_dir) = &config.lib_dir {
29-
println!("cargo:rustc-link-search=native={}", lib_dir);
30-
31-
// Add RPATH linker argument for Unix-like systems (Linux, macOS)
32-
// This helps the test executable find the Python library at runtime.
33-
#[cfg(not(windows))]
34-
println!("cargo:rustc-link-arg=-Wl,-rpath,{}", lib_dir);
35-
} else {
36-
println!("cargo:warning=Python library directory not found in config.");
37-
}
38-
39-
// Add the library link directive if available
40-
if let Some(lib_name) = &config.lib_name {
41-
println!("cargo:rustc-link-lib=dylib={}", lib_name);
42-
} else {
43-
println!("cargo:warning=Python library name not found in config.");
44-
}
2+
djls_dev::setup_python_linking();
453
}

0 commit comments

Comments
 (0)