Skip to content

Commit

Permalink
Feature flags to configure linking (dynamic or static) (#82)
Browse files Browse the repository at this point in the history
* add feature flags to configure linking

* prefer dynamic linking for macOS targets.

* attempt to remove RUSTFLAGS for unit tests in CI.

---------

Co-authored-by: Rachid Mzannar <[email protected]>
  • Loading branch information
g0ldminer and Rachid Mzannar authored Dec 4, 2024
1 parent 882e5a0 commit 3016c47
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 12 deletions.
16 changes: 8 additions & 8 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ jobs:
- name: Packages
run: brew install llvm@15
- name: Build
run: RUSTFLAGS="-L$(brew --prefix zstd)/lib" NYXSTONE_LLVM_PREFIX="$(brew --prefix llvm@15)" NYXSTONE_LINK_FFI=1 cargo build
run: NYXSTONE_LLVM_PREFIX="$(brew --prefix llvm@15)" NYXSTONE_LINK_FFI=1 cargo build
working-directory: ${{ env.working-dir }}
- name: Run tests
run: RUSTFLAGS="-L$(brew --prefix zstd)/lib" RUSTDOCFLAGS="-L$(brew --prefix zstd)/lib" NYXSTONE_LLVM_PREFIX="$(brew --prefix llvm@15)" NYXSTONE_LINK_FFI=1 cargo test
run: NYXSTONE_LLVM_PREFIX="$(brew --prefix llvm@15)" NYXSTONE_LINK_FFI=1 cargo test
working-directory: ${{ env.working-dir }}

mac-llvm-16:
Expand All @@ -58,10 +58,10 @@ jobs:
- name: Packages
run: brew install llvm@16
- name: Build
run: RUSTFLAGS="-L$(brew --prefix zstd)/lib" NYXSTONE_LLVM_PREFIX="$(brew --prefix llvm@16)" NYXSTONE_LINK_FFI=1 cargo build
run: NYXSTONE_LLVM_PREFIX="$(brew --prefix llvm@16)" NYXSTONE_LINK_FFI=1 cargo build
working-directory: ${{ env.working-dir }}
- name: Run tests
run: RUSTFLAGS="-L$(brew --prefix zstd)/lib" RUSTDOCFLAGS="-L$(brew --prefix zstd)/lib" NYXSTONE_LLVM_PREFIX="$(brew --prefix llvm@16)" NYXSTONE_LINK_FFI=1 cargo test
run: NYXSTONE_LLVM_PREFIX="$(brew --prefix llvm@16)" NYXSTONE_LINK_FFI=1 cargo test
working-directory: ${{ env.working-dir }}

mac-llvm-17:
Expand All @@ -73,10 +73,10 @@ jobs:
- name: Packages
run: brew install llvm@17
- name: Build
run: RUSTFLAGS="-L$(brew --prefix zstd)/lib" NYXSTONE_LLVM_PREFIX="$(brew --prefix llvm@17)" NYXSTONE_LINK_FFI=1 cargo build
run: NYXSTONE_LLVM_PREFIX="$(brew --prefix llvm@17)" NYXSTONE_LINK_FFI=1 cargo build
working-directory: ${{ env.working-dir }}
- name: Run tests
run: RUSTFLAGS="-L$(brew --prefix zstd)/lib" RUSTDOCFLAGS="-L$(brew --prefix zstd)/lib" NYXSTONE_LLVM_PREFIX="$(brew --prefix llvm@17)" NYXSTONE_LINK_FFI=1 cargo test
run: NYXSTONE_LLVM_PREFIX="$(brew --prefix llvm@17)" NYXSTONE_LINK_FFI=1 cargo test
working-directory: ${{ env.working-dir }}

mac-llvm-18:
Expand All @@ -88,9 +88,9 @@ jobs:
- name: Packages
run: brew install llvm@18
- name: Build
run: RUSTFLAGS="-L$(brew --prefix zstd)/lib" NYXSTONE_LLVM_PREFIX="$(brew --prefix llvm@18)" NYXSTONE_LINK_FFI=1 cargo build
run: NYXSTONE_LLVM_PREFIX="$(brew --prefix llvm@18)" NYXSTONE_LINK_FFI=1 cargo build
working-directory: ${{ env.working-dir }}
- name: Run tests
run: RUSTFLAGS="-L$(brew --prefix zstd)/lib" RUSTDOCFLAGS="-L$(brew --prefix zstd)/lib" NYXSTONE_LLVM_PREFIX="$(brew --prefix llvm@18)" NYXSTONE_LINK_FFI=1 cargo test
run: NYXSTONE_LLVM_PREFIX="$(brew --prefix llvm@18)" NYXSTONE_LINK_FFI=1 cargo test
working-directory: ${{ env.working-dir }}

13 changes: 13 additions & 0 deletions bindings/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,18 @@ clap = { version = "4.5", features = ["derive"] }
cxx-build = "1.0.94"
anyhow = { version = "1.0.68", default-features = true }

[features]
# Linking preference.
# If none of these is selected, it defaults to force static linking to match
# the behaviour before this feature is introduced.
# Prefer dynamic linking to LLVM library if possible.
prefer-dynamic = []
# Force dynamic linking.
force-dynamic = []
# Prefer static linking to LLVM library if possible.
prefer-static = []
# Force static linking
force-static = []

[lib]
path = "src/lib.rs"
61 changes: 57 additions & 4 deletions bindings/rust/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,16 @@ fn main() {
println!("cargo:config_path={}", llvm_config_path.display()); // will be DEP_LLVM_CONFIG_PATH
println!("cargo:libdir={}", libdir); // DEP_LLVM_LIBDIR

let preferences = LinkingPreferences::init();

// Link LLVM libraries
println!("cargo:rustc-link-search=native={}", libdir);
for link_search_dir in get_system_library_dirs() {
println!("cargo:rustc-link-search=native={}", link_search_dir);
}
// We need to take note of what kind of libraries we linked to, so that
// we can link to the same kind of system libraries
let (kind, libs) = get_link_libraries(&llvm_config_path);
let (kind, libs) = get_link_libraries(&llvm_config_path, &preferences);
for name in libs {
println!("cargo:rustc-link-lib={}={}", kind.string(), name);
}
Expand Down Expand Up @@ -384,8 +386,50 @@ impl LibraryKind {
}
}

#[derive(Debug, Clone, Copy)]
struct LinkingPreferences {
/// Prefer static linking over dynamic linking.
prefer_static: bool,
/// Force the use of the preferred kind of linking.
force: bool,
}

impl LinkingPreferences {
fn init() -> LinkingPreferences {
let prefer_static = cfg!(feature = "prefer-static");
let prefer_dynamic = cfg!(feature = "prefer-dynamic");
let force_static = cfg!(feature = "force-static");
let force_dynamic = cfg!(feature = "force-dynamic");

// more than one preference is an error
if [prefer_static, prefer_dynamic, force_static, force_dynamic]
.iter()
.filter(|&&x| x)
.count()
> 1
{
panic!(
"Only one of the features `prefer-static`, `prefer-dynamic`, `force-static`, \
`force-dynamic` can be enabled at once"
);
}

// if no preference is given, default to prefer static linking or dynamic linking for macOS
// targets
let prefer_static = match target_os_is("macos") {
true => false,
false => prefer_static || !(prefer_dynamic || force_static || force_dynamic),
};

LinkingPreferences {
prefer_static: force_static || prefer_static,
force: force_static || force_dynamic,
}
}
}

/// Get the names of libraries to link against, along with whether it is static or shared library.
fn get_link_libraries(llvm_config_path: &Path) -> (LibraryKind, Vec<String>) {
fn get_link_libraries(llvm_config_path: &Path, preferences: &LinkingPreferences) -> (LibraryKind, Vec<String>) {
// Using --libnames in conjunction with --libdir is particularly important
// for MSVC when LLVM is in a path with spaces, but it is generally less of
// a hack than parsing linker flags output from --libs and --ldflags.
Expand All @@ -404,8 +448,17 @@ fn get_link_libraries(llvm_config_path: &Path) -> (LibraryKind, Vec<String>) {
llvm_config_ex(llvm_config_path, ["--libnames", link_arg])
}

// Prefer static linking
let preferences = [LibraryKind::Static, LibraryKind::Dynamic];
let LinkingPreferences { prefer_static, force } = preferences;
let one = [*prefer_static];
let both = [*prefer_static, !*prefer_static];

let preferences = if *force { &one[..] } else { &both[..] }.iter().map(|is_static| {
if *is_static {
LibraryKind::Static
} else {
LibraryKind::Dynamic
}
});

for kind in preferences {
match get_link_libraries_impl(llvm_config_path, kind) {
Expand Down

0 comments on commit 3016c47

Please sign in to comment.