Skip to content

Create djls-dev crate and centralize Python linking build scripts #119

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ and this project attempts to adhere to [Semantic Versioning](https://semver.org/

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

## [5.2.0a0]

Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ resolver = "2"
[workspace.dependencies]
djls = { path = "crates/djls" }
djls-conf = { path = "crates/djls-conf" }
djls-dev = { path = "crates/djls-dev" }
djls-project = { path = "crates/djls-project" }
djls-server = { path = "crates/djls-server" }
djls-templates = { path = "crates/djls-templates" }
Expand Down
8 changes: 8 additions & 0 deletions crates/djls-dev/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "djls-dev"
version = "0.1.0"
edition = "2021"
publish = false

[dependencies]
pyo3-build-config = { workspace = true, features = ["resolve-config"] }
47 changes: 47 additions & 0 deletions crates/djls-dev/src/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/// Sets up the necessary Cargo directives for linking against the Python library.
///
/// This function should be called from the `build.rs` script of any crate
/// within the workspace whose compiled artifact (e.g., test executable, binary)
/// needs to link against the Python C API at compile time and find the
/// corresponding shared library at runtime. This is typically required for
/// crates using `pyo3` features like `Python::with_gil` or defining `#[pyfunction]`s
/// directly in their test or binary code.
///
/// It uses `pyo3-build-config` to detect the active Python installation and
/// prints the required `cargo:rustc-link-search` and `cargo:rustc-link-lib`
/// directives to Cargo, enabling the linker to find and link against the
/// appropriate Python library (e.g., libpythonX.Y.so).
///
/// It also adds an RPATH linker argument on Unix-like systems (`-Wl,-rpath,...`)
/// to help the resulting executable find the Python shared library at runtime
/// without needing manual `LD_LIBRARY_PATH` adjustments in typical scenarios.
pub fn setup_python_linking() {
// Instruct Cargo to rerun the calling build script if the Python config changes.
// Using PYO3_CONFIG_FILE is a reliable way to detect changes in the active Python env.
println!("cargo:rerun-if-changed=build.rs");

// Set up #[cfg] flags first (useful for conditional compilation)
pyo3_build_config::use_pyo3_cfgs();

// Get the Python interpreter configuration directly
let config = pyo3_build_config::get();

// Add the library search path if available
if let Some(lib_dir) = &config.lib_dir {
println!("cargo:rustc-link-search=native={}", lib_dir);

// Add RPATH linker argument for Unix-like systems (Linux, macOS)
// This helps the test executable find the Python library at runtime.
#[cfg(not(windows))]
println!("cargo:rustc-link-arg=-Wl,-rpath,{}", lib_dir);
} else {
println!("cargo:warning=Python library directory not found in config.");
}

// Add the library link directive if available
if let Some(lib_name) = &config.lib_name {
println!("cargo:rustc-link-lib=dylib={}", lib_name);
} else {
println!("cargo:warning=Python library name not found in config.");
}
}
3 changes: 3 additions & 0 deletions crates/djls-dev/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod build;

pub use build::setup_python_linking;
2 changes: 1 addition & 1 deletion crates/djls-project/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ tower-lsp-server = { workspace = true, features = ["proposed"] }
which = "7.0.1"

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

[dev-dependencies]
tempfile = { workspace = true }
44 changes: 1 addition & 43 deletions crates/djls-project/build.rs
Original file line number Diff line number Diff line change
@@ -1,45 +1,3 @@
/// Build script to configure linking against the Python library.
///
/// This script is necessary when the crate's code, particularly tests
/// that interact with the Python interpreter via `pyo3` (e.g., using
/// `Python::with_gil`, importing modules, calling Python functions),
/// needs symbols from the Python C API at link time.
///
/// It uses `pyo3-build-config` to detect the Python installation and
/// prints the required `cargo:rustc-link-search` and `cargo:rustc-link-lib`
/// directives to Cargo, enabling the linker to find and link against the
/// appropriate Python library (e.g., libpythonX.Y.so).
///
/// It also adds an RPATH linker argument on Unix-like systems so the
/// resulting test executable can find the Python library at runtime.
///
/// Note: Each crate whose test target requires Python linking needs its
/// own `build.rs` with this logic.
fn main() {
println!("cargo:rerun-if-changed=build.rs");

// Set up #[cfg] flags first (useful for conditional compilation)
pyo3_build_config::use_pyo3_cfgs();

// Get the Python interpreter configuration directly
let config = pyo3_build_config::get();

// Add the library search path if available
if let Some(lib_dir) = &config.lib_dir {
println!("cargo:rustc-link-search=native={}", lib_dir);

// Add RPATH linker argument for Unix-like systems (Linux, macOS)
// This helps the test executable find the Python library at runtime.
#[cfg(not(windows))]
println!("cargo:rustc-link-arg=-Wl,-rpath,{}", lib_dir);
} else {
println!("cargo:warning=Python library directory not found in config.");
}

// Add the library link directive if available
if let Some(lib_name) = &config.lib_name {
println!("cargo:rustc-link-lib=dylib={}", lib_name);
} else {
println!("cargo:warning=Python library name not found in config.");
}
djls_dev::setup_python_linking();
}
2 changes: 1 addition & 1 deletion crates/djls-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ tower-lsp-server = { workspace = true }
percent-encoding = "2.3"

[build-dependencies]
pyo3-build-config = { workspace = true, features = ["resolve-config"] }
djls-dev = { workspace = true }
44 changes: 1 addition & 43 deletions crates/djls-server/build.rs
Original file line number Diff line number Diff line change
@@ -1,45 +1,3 @@
/// Build script to configure linking against the Python library.
///
/// This script is necessary when the crate's code, particularly tests
/// that interact with the Python interpreter via `pyo3` (e.g., using
/// `Python::with_gil`, importing modules, calling Python functions),
/// needs symbols from the Python C API at link time.
///
/// It uses `pyo3-build-config` to detect the Python installation and
/// prints the required `cargo:rustc-link-search` and `cargo:rustc-link-lib`
/// directives to Cargo, enabling the linker to find and link against the
/// appropriate Python library (e.g., libpythonX.Y.so).
///
/// It also adds an RPATH linker argument on Unix-like systems so the
/// resulting test executable can find the Python library at runtime.
///
/// Note: Each crate whose test target requires Python linking needs its
/// own `build.rs` with this logic.
fn main() {
println!("cargo:rerun-if-changed=build.rs");

// Set up #[cfg] flags first (useful for conditional compilation)
pyo3_build_config::use_pyo3_cfgs();

// Get the Python interpreter configuration directly
let config = pyo3_build_config::get();

// Add the library search path if available
if let Some(lib_dir) = &config.lib_dir {
println!("cargo:rustc-link-search=native={}", lib_dir);

// Add RPATH linker argument for Unix-like systems (Linux, macOS)
// This helps the test executable find the Python library at runtime.
#[cfg(not(windows))]
println!("cargo:rustc-link-arg=-Wl,-rpath,{}", lib_dir);
} else {
println!("cargo:warning=Python library directory not found in config.");
}

// Add the library link directive if available
if let Some(lib_name) = &config.lib_name {
println!("cargo:rustc-link-lib=dylib={}", lib_name);
} else {
println!("cargo:warning=Python library name not found in config.");
}
djls_dev::setup_python_linking();
}
2 changes: 1 addition & 1 deletion crates/djls/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ tower-lsp-server = { workspace = true }
clap = { version = "4.5", features = ["derive"] }

[build-dependencies]
pyo3-build-config = { workspace = true, features = ["resolve-config"] }
djls-dev = { workspace = true }
44 changes: 1 addition & 43 deletions crates/djls/build.rs
Original file line number Diff line number Diff line change
@@ -1,45 +1,3 @@
/// Build script to configure linking against the Python library.
///
/// This script is necessary when the crate's code, particularly tests
/// that interact with the Python interpreter via `pyo3` (e.g., using
/// `Python::with_gil`, importing modules, calling Python functions),
/// needs symbols from the Python C API at link time.
///
/// It uses `pyo3-build-config` to detect the Python installation and
/// prints the required `cargo:rustc-link-search` and `cargo:rustc-link-lib`
/// directives to Cargo, enabling the linker to find and link against the
/// appropriate Python library (e.g., libpythonX.Y.so).
///
/// It also adds an RPATH linker argument on Unix-like systems so the
/// resulting test executable can find the Python library at runtime.
///
/// Note: Each crate whose test target requires Python linking needs its
/// own `build.rs` with this logic.
fn main() {
println!("cargo:rerun-if-changed=build.rs");

// Set up #[cfg] flags first (useful for conditional compilation)
pyo3_build_config::use_pyo3_cfgs();

// Get the Python interpreter configuration directly
let config = pyo3_build_config::get();

// Add the library search path if available
if let Some(lib_dir) = &config.lib_dir {
println!("cargo:rustc-link-search=native={}", lib_dir);

// Add RPATH linker argument for Unix-like systems (Linux, macOS)
// This helps the test executable find the Python library at runtime.
#[cfg(not(windows))]
println!("cargo:rustc-link-arg=-Wl,-rpath,{}", lib_dir);
} else {
println!("cargo:warning=Python library directory not found in config.");
}

// Add the library link directive if available
if let Some(lib_name) = &config.lib_name {
println!("cargo:rustc-link-lib=dylib={}", lib_name);
} else {
println!("cargo:warning=Python library name not found in config.");
}
djls_dev::setup_python_linking();
}
Loading