-
Notifications
You must be signed in to change notification settings - Fork 20
feat: cross-language LTO to inline C TLS shim into Rust FFI #1982
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
base: main
Are you sure you want to change the base?
Changes from 10 commits
ac4ac3c
1ab1e73
16e7302
bdd680e
6de3ad2
6a44342
88d7f6d
d98d13d
9227252
7a5bbe3
dffcd9a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| # libdd-otel-thread-ctx-ffi | ||
|
|
||
| FFI bindings for the OTel thread-level context publisher. Exposes a C API for | ||
| attaching, detaching, and updating per-thread OpenTelemetry context records | ||
| that external readers (e.g. the eBPF profiler) can discover. | ||
|
|
||
| Currently Linux-only (x86-64 and aarch64). | ||
|
|
||
| ## Optimized build (cross-language inlining) | ||
|
|
||
| The OTel thread-level context sharing specification requires the use of the | ||
| TLSDESC dialect for the thread-local variable that holds the current context. | ||
| Because (stable) `rustc` doesn't currently provide a way to control the TLS | ||
| dialect, we need to use a small C shim that defines the variable and expose a | ||
| one-line getter. This unfortunately adds one level of indirection (a function | ||
| call) when attaching or detaching a context. | ||
|
|
||
| With the right toolchain, it's possible to use Link-Time Optimization (LTO) to | ||
| inline the C wrapper at link time. The requirements are: | ||
|
|
||
| - `clang` is available to compile the C shim to LLVM IR (version requirements | ||
| aren't clear -- tested with clang18 and clang20, but ideally the version | ||
| should be the same or close to the LLVM version shipped with `rustc`) | ||
| - Either the Rust toolchain ships `lld` or there's a system-wide `lld` install | ||
| (Rust has been shipping `rust-lld` for a long time now, something like since | ||
| 1.53+, however some musl-based distro like Alpine might have the Rust | ||
| toolchain without `rust-lld`) | ||
| - `lld` version is at least 18.1 (TLSDESC support) | ||
|
|
||
| If those requirements are met, you can use the small wrapper script provided in | ||
| this directory to build an optimized release version where the C shim is | ||
| inlined. A wrapper script is needed because cross-language LTO requires two | ||
| `rustc` codegen flags (`-Clinker-plugin-lto` and `-Clinker=clang`) that cannot | ||
| be set from a Cargo build script: they must come from `RUSTFLAGS` or | ||
| `.cargo/config.toml`, which can't be entirely automated from Rust only. The | ||
| script sets them via the target-scoped `CARGO_TARGET_<TRIPLE>_RUSTFLAGS` env | ||
| var so they don't leak to build scripts or proc-macros if cross-compiling. | ||
|
|
||
| ### Example usage | ||
|
|
||
| ```bash | ||
| ./build-optimized.sh | ||
| ``` | ||
|
|
||
| The script auto-detects the host triple. To cross-compile: | ||
|
|
||
| ```bash | ||
| ./build-optimized.sh --target aarch64-unknown-linux-gnu | ||
| ``` | ||
|
|
||
| Extra arguments are forwarded to `cargo build`. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It might be useful to document a way for downstreams to validate that the optimized build did happen. E.g. I'd love to be able to add a check in https://github.com/DataDog/libdatadog-rb/blob/main/spec/gem_packaging.rb to validate that the LTO was correctly in use.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is already automatically verified in the script, but I can surely reproduce the steps here in the readme, if you think that's useful.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My thinking is -- the script checks, but who's checking that the script is in use? ;) Maybe someone redid the ruby build build entirely and forgot to even add the script -- that's the thing I was thinking of catching. |
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So... I'm curious (and this is not a blocker for the PR) -- does this script need to exist? That is, do the environment variables need to be defined before I'm thinking that if we could move stuff to rust code, it would probably be a bit more ergonomic for users + easier to maintain and validate.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunately, I think we need the script (or something similar that sets the flags from outside of the build) and can't be fully automatic. This is indeed annoying. Quoting this PR's description:
My understanding is that by design (for reasons I'm not sure to understand, to be honest), the
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was wondering this too. I put a comment further down that we might be able to do this with .cargo/config.toml, but that would be project wide if it did work
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Good point, this is why I didn't do it in libdatadog, but if you're having a
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, I missed that bit in the PR description, although I'd say that it very much deserves to live in a why does this script need to exist in the script itself :) Having said that, I understand the limitation around
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not familiar with the builder crate, but all it takes is to set two env variable before cargo starts (
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Afaik right now the builder crate is the recommended way ™️ to build libdatadog if you're not consuming it from rust.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Although supporting it is not a blocker for this PR, to be clear, although it is a really nice to have ™️) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| #!/usr/bin/env bash | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I haven’t looked deeply into this and it may be a rabbit hole, but could
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, indeed
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might be worth smoking it out on the CI for this repo just to see what breaks? Adds weight to the "here's why we have a separate script" thing 🤷 don't feel super strongly about this
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The CI is annoying but can probably get sorted? The thing I'm more worried about with this is downstream users like dd-trace-php. I can try on the CI, but I think it's insufficient. We would have to make sure it doesn't break any downstream consumer of libdatadog, all the dd-trace-xxx. Even worse, with dd-trace-rs, we impose constraints on the toolchain of end-users/customers directly by transitivity. We can discuss it in the component team but my gut feeling is that it's a a bold move to force everyone to use our specific configuration and clang.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yeah, I'd +1 that as well. Ideally we can make it as turn-key and easy to do and hard to miss as possible, but not go as far as making it a hard requirement. |
||
| # Copyright 2026-Present Datadog, Inc. https://www.datadoghq.com/ | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # | ||
| # Build libdd-otel-thread-ctx-ffi with cross-language LTO so the C TLS shim is | ||
| # inlined into the Rust FFI functions, eliminating a function-call indirection | ||
| # on every TLS access. | ||
| # | ||
| # Requirements: clang, lld (rust-lld from the toolchain is used automatically). | ||
| # The requirements are checked by the build.rs script. | ||
| # | ||
| # Usage: | ||
| # # auto-detect host triple | ||
| # ./build-optimized.sh | ||
| # # explicit target | ||
| # ./build-optimized.sh --target aarch64-unknown-linux-gnu | ||
| # | ||
| # Any extra arguments are forwarded to `cargo build`. | ||
| set -euo pipefail | ||
|
|
||
| # Parse --target from args, or auto-detect the host triple. | ||
| TARGET="" | ||
| EXTRA_ARGS=() | ||
| while [[ $# -gt 0 ]]; do | ||
| case "$1" in | ||
| --target) | ||
| TARGET="$2"; shift 2 ;; | ||
| --target=*) | ||
| TARGET="${1#--target=}"; shift ;; | ||
| *) | ||
| EXTRA_ARGS+=("$1"); shift ;; | ||
| esac | ||
| done | ||
|
|
||
| if [[ -z "$TARGET" ]]; then | ||
| TARGET=$(rustc -vV | sed -n 's/host: //p') | ||
| fi | ||
|
|
||
| # CARGO_TARGET_<TRIPLE>_RUSTFLAGS scopes the flags to the target only, keeping | ||
| # build scripts and proc-macros unaffected. | ||
| TARGET_ENV=$(echo "$TARGET" | tr 'a-z-' 'A-Z_') | ||
| export "CARGO_TARGET_${TARGET_ENV}_RUSTFLAGS=-Clinker-plugin-lto -Clinker=clang" | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we try preserve existing
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair! |
||
| export LIBDD_OTEL_THREAD_CTX_INLINE=1 | ||
|
|
||
| cargo build --release \ | ||
| --target "$TARGET" \ | ||
| -p libdd-otel-thread-ctx-ffi \ | ||
| "${EXTRA_ARGS[@]}" | ||
|
|
||
| # Sanity-check that the C shim was actually inlined, if `nm` is available. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Will this be the case in our CI build pipeline for the repo?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, and this is the point: I don't want to fight against CentOS and Alpine with the requirements for LTO (clang, lld, LLVM 18+, ...). I think this will be on the build workflow of the final dynamic library to check that. |
||
| if ! command -v nm &>/dev/null; then | ||
| echo >&2 "WARNING: skipping sanity check that the C TLS shim was inlined (\`nm\` not found)" | ||
| else | ||
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" | ||
| SO="$REPO_ROOT/target/$TARGET/release/liblibdd_otel_thread_ctx_ffi.so" | ||
|
|
||
| if [[ -f "$SO" ]] && nm "$SO" 2>/dev/null | grep -q 'libdd_get_otel_thread_ctx'; then | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: if
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. annnnd I was meant to replace that TODO with a concrete suggestion |
||
| echo >&2 "WARNING: build succeeded but the C TLS shim (libdd_get_otel_thread_ctx_v1) was NOT inlined." | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very minor: Since we have the (And I think having the |
||
| echo >&2 "Cross-language LTO may not be working. Check that clang and lld versions are recent enough and compatible with the Rust toolchain's LLVM." | ||
| exit 1 | ||
| fi | ||
|
yannham marked this conversation as resolved.
|
||
| fi | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -2,42 +2,85 @@ | |||||
| // SPDX-License-Identifier: Apache-2.0 | ||||||
| extern crate build_common; | ||||||
|
|
||||||
| use build_common::generate_and_configure_header; | ||||||
| use std::env; | ||||||
| use std::path::PathBuf; | ||||||
| use std::process::Command; | ||||||
| use build_common::{find_rust_lld_dir, generate_and_configure_header}; | ||||||
| use std::{env, fmt::Display, path::PathBuf, process::Command}; | ||||||
|
|
||||||
| /// Locate the `gcc-ld/` shim directory shipped with the Rust toolchain. | ||||||
| #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)] | ||||||
| struct LldVersion { | ||||||
| major: u32, | ||||||
| minor: u32, | ||||||
| } | ||||||
|
|
||||||
| impl Display for LldVersion { | ||||||
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||
| write!(f, "{}.{}", self.major, self.minor) | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| /// Parse the major and minor version from `ld.lld --version` output. | ||||||
| /// | ||||||
| /// This directory contains an `ld.lld` wrapper that delegates to `rust-lld`. | ||||||
| /// Passing it via `-B` to the C compiler driver makes it discover rust-lld | ||||||
| /// before any system-wide lld, which | ||||||
| /// Typical formats: | ||||||
| /// "LLD 18.1.3 (compatible with GNU linkers)" | ||||||
| /// "LLD 19.1.0" | ||||||
| fn system_lld_version() -> Option<LldVersion> { | ||||||
| let output = Command::new("ld.lld").arg("--version").output().ok()?; | ||||||
| if !output.status.success() { | ||||||
| return None; | ||||||
| } | ||||||
| String::from_utf8_lossy(&output.stdout) | ||||||
| .split_whitespace() | ||||||
| .find_map(|tok| { | ||||||
| let mut splitted = tok.split('.'); | ||||||
| let major = splitted.next()?.parse::<u32>().ok()?; | ||||||
| let minor = splitted.next()?.parse::<u32>().ok()?; | ||||||
|
|
||||||
| Some(LldVersion { major, minor }) | ||||||
| }) | ||||||
| } | ||||||
|
|
||||||
| /// TLSDESC is supported in LLD from version 18.1. | ||||||
| const MIN_LLD_VERSION_FOR_TLSDESC: LldVersion = LldVersion { | ||||||
| major: 18, | ||||||
| minor: 1, | ||||||
| }; | ||||||
|
|
||||||
| /// Validate that a suitable LLD is available for cross-language LTO. | ||||||
| /// | ||||||
| /// 1. Avoid the need of a system-wide LLD install | ||||||
| /// 2. Pick a recent LLD, as opposed to e.g. CentOS 7' LLVM7 which is too old to handle TLSDESC | ||||||
| /// relocations properly. | ||||||
| fn find_rust_lld_dir() -> Option<PathBuf> { | ||||||
| let rustc = env::var("RUSTC").unwrap_or_else(|_| "rustc".into()); | ||||||
| let target = env::var("TARGET").ok()?; | ||||||
|
|
||||||
| let output = Command::new(&rustc) | ||||||
| .arg("--print") | ||||||
| .arg("sysroot") | ||||||
| .output() | ||||||
| .ok()?; | ||||||
|
|
||||||
| let sysroot = std::str::from_utf8(&output.stdout).ok()?.trim(); | ||||||
| let dir = PathBuf::from(sysroot) | ||||||
| .join("lib/rustlib") | ||||||
| .join(&target) | ||||||
| .join("bin/gcc-ld"); | ||||||
|
|
||||||
| dir.join("ld.lld").exists().then_some(dir) | ||||||
| /// Returns the rust-lld `gcc-ld/` directory if found; `None` means the system | ||||||
| /// `ld.lld` will be used instead. Panics with a clear message when the | ||||||
| /// requirements are not met. | ||||||
| fn require_lld_for_inline(target_arch: &str) -> Option<PathBuf> { | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The name reads a little funny to me in terms of what the function does; maybe resolve works better?
Suggested change
|
||||||
| if let Some(dir) = find_rust_lld_dir() { | ||||||
| return Some(dir); | ||||||
| } | ||||||
|
|
||||||
| match system_lld_version() { | ||||||
| Some(v) if target_arch != "x86_64" || v >= MIN_LLD_VERSION_FOR_TLSDESC => None, | ||||||
| Some(v) => panic!( | ||||||
| "LIBDD_OTEL_THREAD_CTX_INLINE requires LLD >= {MIN_LLD_VERSION_FOR_TLSDESC} on \ | ||||||
| x86-64 (for -mllvm -enable-tlsdesc), but system ld.lld is version {v}. \ | ||||||
| Install a newer LLD or use a Rust toolchain that bundles rust-lld." | ||||||
| ), | ||||||
| None => panic!( | ||||||
| "LIBDD_OTEL_THREAD_CTX_INLINE requires LLD for cross-language LTO, but neither \ | ||||||
| rust-lld nor a system ld.lld was found." | ||||||
| ), | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| fn main() { | ||||||
| generate_and_configure_header("otel-thread-ctx.h"); | ||||||
|
|
||||||
| let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); | ||||||
| if target_os != "linux" { | ||||||
| return; | ||||||
| } | ||||||
|
|
||||||
| println!("cargo:rerun-if-env-changed=LIBDD_OTEL_THREAD_CTX_INLINE"); | ||||||
|
|
||||||
| let inline_mode = env::var("LIBDD_OTEL_THREAD_CTX_INLINE").is_ok_and(|v| v == "1"); | ||||||
| let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); | ||||||
| let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); | ||||||
|
|
||||||
| // Export the TLSDESC thread-local variable to the dynamic symbol table so external readers | ||||||
| // (e.g. the eBPF profiler) can discover it. Rust's cdylib linker applies a version script with | ||||||
|
|
@@ -50,15 +93,34 @@ fn main() { | |||||
| // Merging multiple version scripts is not supported by GNU ld, so we need lld. We prefer the | ||||||
| // toolchain's bundled rust-lld (LLD 19+ since Rust 1.84) over the system lld (if it even | ||||||
| // exists). If rust-lld is not found we fall back to whatever `lld` the system provides. | ||||||
| if target_os == "linux" { | ||||||
| let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); | ||||||
|
|
||||||
| // If `LIBDD_OTEL_THREAD_CTX_INLINE` is set to `1`, we try to inline the C shim. See the README | ||||||
| // for more details. | ||||||
| if inline_mode { | ||||||
| let rust_lld_dir = require_lld_for_inline(&target_arch); | ||||||
|
|
||||||
| // Emit link args for ALL link types (not just cdylib) so that test binaries also link | ||||||
| // correctly when RUSTFLAGS sets clang as the linker (in practice we should only build/care | ||||||
| // about the shared object file in inline mode). | ||||||
| if let Some(dir) = rust_lld_dir { | ||||||
| println!("cargo:rustc-link-arg=-B{}", dir.display()); | ||||||
| } | ||||||
| println!("cargo:rustc-link-arg=-fuse-ld=lld"); | ||||||
|
|
||||||
| // On x86-64, tell the LLVM backend to use TLSDESC during LTO codegen. | ||||||
| // On aarch64 TLSDESC is the default and the only model. | ||||||
| if target_arch == "x86_64" { | ||||||
| println!("cargo:rustc-link-arg=-Wl,-mllvm,-enable-tlsdesc"); | ||||||
| } | ||||||
| } else { | ||||||
| // Default mode: only the cdylib needs lld (for the version script). | ||||||
| if let Some(gcc_ld_dir) = find_rust_lld_dir() { | ||||||
| println!("cargo:rustc-cdylib-link-arg=-B{}", gcc_ld_dir.display()); | ||||||
| } | ||||||
| println!("cargo:rustc-cdylib-link-arg=-fuse-ld=lld"); | ||||||
| println!( | ||||||
| "cargo:rustc-cdylib-link-arg=-Wl,--version-script={manifest_dir}/tls-dynamic-list.txt" | ||||||
| ); | ||||||
| } | ||||||
|
|
||||||
| println!( | ||||||
| "cargo:rustc-cdylib-link-arg=-Wl,--version-script={manifest_dir}/tls-dynamic-list.txt" | ||||||
| ); | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,20 +1,64 @@ | ||
| // Copyright 2026-Present Datadog, Inc. https://www.datadoghq.com/ | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| extern crate build_common; | ||
|
|
||
| use std::env; | ||
| use std::process::Command; | ||
|
|
||
| fn clang_is_available() -> bool { | ||
| Command::new("clang") | ||
| .arg("--version") | ||
| .output() | ||
| .map(|o| o.status.success()) | ||
| .unwrap_or(false) | ||
| } | ||
|
|
||
| fn main() { | ||
| // Only compile the TLS shim on Linux. | ||
| #[cfg(target_os = "linux")] | ||
| { | ||
| let mut build = cc::Build::new(); | ||
| let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); | ||
| let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); | ||
|
|
||
| if target_os != "linux" { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change is somehow unrelated, but using static |
||
| return; | ||
| } | ||
|
|
||
| println!("cargo:rerun-if-env-changed=LIBDD_OTEL_THREAD_CTX_INLINE"); | ||
| println!("cargo:rerun-if-changed=src/tls_shim.c"); | ||
|
|
||
| // The otel-thread-ctx FFI crate has a special flag to inline the C shim inside the final | ||
| // library. This setup has additional requirements for the build of this crate, which are | ||
| // enforced below when the flag is set. | ||
| let inline_mode = env::var_os("LIBDD_OTEL_THREAD_CTX_INLINE").is_some_and(|v| v == "1"); | ||
|
|
||
| let mut build = cc::Build::new(); | ||
|
|
||
| if inline_mode { | ||
| assert!( | ||
| clang_is_available(), | ||
| "LIBDD_OTEL_THREAD_CTX_INLINE is set but `clang` was not found. \ | ||
| Cross-language LTO requires clang as the C compiler." | ||
| ); | ||
| build.compiler("clang"); | ||
| build.flag("-flto=thin"); | ||
|
|
||
| // Any binary linking this crate in inline mode (including test | ||
| // binaries) needs lld, because -Clinker-plugin-lto passes LTO plugin | ||
| // options that only lld understands. | ||
| if let Some(dir) = build_common::find_rust_lld_dir() { | ||
| println!("cargo:rustc-link-arg=-B{}", dir.display()); | ||
| } | ||
| println!("cargo:rustc-link-arg=-fuse-ld=lld"); | ||
|
|
||
| // Note: in the inline setup, TLS dialect selection is handled by the linker and is taken | ||
| // care of by the build script of otel-thread-ctx-ffi | ||
| } else { | ||
| // - On aarch64, TLSDESC is already the only dynamic TLS model so no flag is needed. | ||
| // - On x86-64, we use `-mtls-dialect=gnu2` (supported since GCC 4.4 and Clang 19+) to force | ||
| // the use of TLSDESC as mandated by the spec. If it's not supported, this build will | ||
| // fail. | ||
| #[cfg(target_arch = "x86_64")] | ||
| build.flag("-mtls-dialect=gnu2"); | ||
|
|
||
| build.file("src/tls_shim.c").compile("tls_shim"); | ||
| println!("cargo:rerun-if-changed=src/tls_shim.c"); | ||
| if target_arch == "x86_64" { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't really related to this PR, but should we throw if we see Linux with a different architecture from these two? That way in the future if some enterprising engineer adds risc-v or whatever, we'll know that we have to address this. I figure the linker flags to specify dialect differ between architectures anyway, so it is unlikely this will just work out of the box. |
||
| build.flag("-mtls-dialect=gnu2"); | ||
| } | ||
| } | ||
|
|
||
| build.file("src/tls_shim.c").compile("tls_shim"); | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.