From d86af6fb16af01d56c2cc8f92004408696445269 Mon Sep 17 00:00:00 2001 From: Gregory LEOCADIE Date: Fri, 30 Oct 2026 14:16:23 +0000 Subject: [PATCH] Bump to v47 --- .github/workflows/build-platform.yml | 13 ++++-- .github/workflows/release.yml | 55 ++++++++++++++++++-------- AGENTS.md | 18 +++++---- LIBDATADOG_VERSION | 2 +- README.md | 15 ++++--- build.ps1 | 39 +++++++++++++++--- tools/docker/Dockerfile.centos-aarch64 | 2 +- tools/docker/Dockerfile.musl-aarch64 | 2 +- tools/docker/Dockerfile.musl-x64 | 2 +- 9 files changed, 105 insertions(+), 43 deletions(-) diff --git a/.github/workflows/build-platform.yml b/.github/workflows/build-platform.yml index 485cec4..37292a8 100644 --- a/.github/workflows/build-platform.yml +++ b/.github/workflows/build-platform.yml @@ -20,6 +20,11 @@ on: required: false type: boolean default: false + file_version: + description: 'libdatadog-dotnet release version (major.minor.patch) embedded as the Windows DLL FileVersion via release --file-version. Empty omits the flag, so FileVersion falls back to the upstream libdatadog version. Has no effect on non-Windows targets.' + required: false + type: string + default: '' permissions: contents: read @@ -74,8 +79,8 @@ jobs: # subtle codegen / inlining differences between releases. - name: Setup Rust run: | - rustup install 1.87.0 - rustup default 1.87.0 + rustup install 1.91.1 + rustup default 1.91.1 - name: Add Windows target if: runner.os == 'Windows' @@ -109,7 +114,9 @@ jobs: CARGO_BUILD_TARGET: ${{ matrix.target }} run: | if [ "$RUNNER_OS" == "Windows" ]; then - pwsh -Command "./build.ps1 -Platform '${{ matrix.platform }}' -Features '${{ inputs.features }}' -Clean" + # -FileVersion is this repo's release (e.g. 1.3.5), not LIBDATADOG_VERSION. + # Empty on PR builds; the Release workflow always sets it. + pwsh -Command "./build.ps1 -Platform '${{ matrix.platform }}' -Features '${{ inputs.features }}' -FileVersion '${{ inputs.file_version }}' -Clean" else chmod +x build.sh ./build.sh --platform "${{ matrix.platform }}" --features "${{ inputs.features }}" --clean diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7b43ae2..73c1cdb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -29,23 +29,16 @@ permissions: contents: read jobs: - build: - name: Build all platforms - uses: ./.github/workflows/build-platform.yml - permissions: - contents: read - with: - verify_artifacts: false - features: 'profiling,crashtracker,symbolizer,library-config' - - create-release: - name: Create GitHub Release - needs: build + # Resolve the libdatadog-dotnet release tag before the build so Windows + # DLLs can embed it as FileVersion. This is this repo's own tag (v1.3.5), + # not LIBDATADOG_VERSION — Windows Installer compares FileVersion when + # deciding whether to replace the DLL on upgrade. + resolve-version: + name: Resolve release version runs-on: ubuntu-latest - permissions: - contents: write - id-token: write # OIDC — required for dd-octo-sts token minting - + outputs: + release_tag: ${{ steps.setup_release.outputs.RELEASE_TAG }} + file_version: ${{ steps.setup_release.outputs.FILE_VERSION }} steps: - name: Checkout code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -106,8 +99,36 @@ jobs: exit 1 fi + # major.minor.patch, no leading v — what `release --file-version` expects. + FILE_VERSION="${RELEASE_TAG#v}" + echo "RELEASE_TAG=$RELEASE_TAG" >> $GITHUB_OUTPUT + echo "FILE_VERSION=$FILE_VERSION" >> $GITHUB_OUTPUT echo "Release tag: $RELEASE_TAG" + echo "Windows FileVersion: $FILE_VERSION" + + build: + name: Build all platforms + needs: resolve-version + uses: ./.github/workflows/build-platform.yml + permissions: + contents: read + with: + verify_artifacts: false + features: 'profiling,crashtracker,symbolizer,library-config' + file_version: ${{ needs.resolve-version.outputs.file_version }} + + create-release: + name: Create GitHub Release + needs: [build, resolve-version] + runs-on: ubuntu-latest + permissions: + contents: write + id-token: write # OIDC — required for dd-octo-sts token minting + + steps: + - name: Checkout code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Download all artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 @@ -259,7 +280,7 @@ jobs: - name: Create or Update Release uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 env: - RELEASE_TAG: ${{ steps.setup_release.outputs.RELEASE_TAG }} + RELEASE_TAG: ${{ needs.resolve-version.outputs.release_tag }} with: # octo-sts token (see step above) has ruleset-bypass rights, so # createRelease() can create the tag when it does not yet exist. diff --git a/AGENTS.md b/AGENTS.md index 191e079..dc8a192 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -18,11 +18,13 @@ cargo install \ --no-default-features \ --features "profiling,crashtracker,symbolizer,library-config" \ builder -release --out --target +release --out --target [--file-version ] ``` The builder handles the FFI cargo build, header generation (cbindgen + dedup), library stripping, and packaging. We just orchestrate per-platform Docker containers and (on Windows) reshape the resulting zip to match what dd-trace-dotnet expects. +`--file-version` is Windows-only. It must be **this repo's release version** (`1.3.5`, from tag `v1.3.5`) — not `LIBDATADOG_VERSION`. The builder forwards it as `LIBDATADOG_PACKAGE_VERSION` and embeds it as the DLL `FileVersion`, which Windows Installer compares on upgrade. `ProductVersion` stays the upstream libdatadog version. Omit the flag and `FileVersion` falls back to that upstream version. `build.ps1 -FileVersion` is the local entry point; the Release workflow passes it automatically. PR builds leave it empty. + ## Version Pinning `LIBDATADOG_VERSION` (single file, no `v` prefix, e.g. `32.0.0`) is the **upstream** libdatadog version this repo builds from. It is distinct from libdatadog-dotnet's own release tag (e.g. `v1.3.5`) that dd-trace-dotnet pins — don't expect the two numbers to be equal. @@ -61,9 +63,9 @@ include/datadog/… cmake/DatadogConfig.cmake LICENSE NOTICE LICENSE-3rdpart ``` So `build.ps1`: -1. Runs the builder twice — once with `PROFILE=release`, once with `PROFILE=debug`. +1. Runs the builder twice — once with `PROFILE=release`, once with `PROFILE=debug`. When `-FileVersion` is set, each invocation gets `--file-version`, which the builder forwards to cargo as `LIBDATADOG_PACKAGE_VERSION` so the DLL's `VERSIONINFO` `FileVersion` is the libdatadog-dotnet release (not `LIBDATADOG_VERSION`). 2. Pulls headers / license / cmake from the release-builder output. -3. Pulls `.dll`, `.dll.lib`, `.lib` (static), `.pdb` **directly from `target/$Target/{release,debug}/`** because cargo there has the original `_ffi` names AND the `.dll.lib` import library that the builder doesn't copy. +3. Pulls `.dll`, `.dll.lib`, `.lib` (static), `.pdb` **directly from `target/$Target/{release,debug}/`** because cargo there has the original `_ffi` names AND the `.dll.lib` import library that the builder doesn't copy. The `FileVersion` resource is already in that DLL. 4. Renames `.dll.lib` → `.lib` in each `dynamic/` slot. ## Gotchas @@ -78,7 +80,7 @@ So `build.ps1`: 5. **cmake-rs needs cargo build-script env on macOS**: the builder calls `cmake::Config::build()` for the crashtracker C++ receiver outside a cargo build-script context. cmake-rs / cc-rs read `HOST` / `OUT_DIR` / `OPT_LEVEL` / `DEBUG` / `NUM_JOBS`. The macOS branch of `build.sh` sets all of them; missing any one panics with `environment variable 'X' not defined`. (Windows doesn't hit this — `BUILD_CRASHTRACKER = false` in the builder's `arch/windows.rs`.) -6. **Toolchain pinned to upstream libdatadog's**: Rust `1.87.0` (matches libdatadog's workspace `rust-version`) and macOS runners `macos-14` / `macos-14-large` (Sonoma, matches libdatadog's libddprof-build pipeline). When upstream libdatadog bumps its MSRV or its macOS build version, update both here — building with a different toolchain than upstream can introduce subtle codegen / ABI differences. The pin lives in: `build-platform.yml` (Setup Rust step + matrix `os:` fields), `Dockerfile.centos-aarch64` (rustup-init `--default-toolchain`), and `Dockerfile.musl-*` (`ARG RUST_VERSION` consumed by the rustup install). +6. **Toolchain pinned to upstream libdatadog's**: Rust `1.91.1` (matches libdatadog's workspace `rust-version`) and macOS runners `macos-14` / `macos-14-large` (Sonoma, matches libdatadog's libddprof-build pipeline). When upstream libdatadog bumps its MSRV or its macOS build version, update both here — building with a different toolchain than upstream can introduce subtle codegen / ABI differences. The pin lives in: `build-platform.yml` (Setup Rust step + matrix `os:` fields), `Dockerfile.centos-aarch64` (rustup-init `--default-toolchain`), and `Dockerfile.musl-*` (`ARG RUST_VERSION` consumed by the rustup install). 7. **Release workflow auth (dd-octo-sts, keyless)**: the repo's ref-creation ruleset blocks `GITHUB_TOKEN` from creating new tags. `release.yml` mints a short-lived token via **DataDog's octo-sts** (OIDC federation — no stored secret) in the `octo-sts` step, and the `actions/github-script` publish step authenticates with `github-token: ${{ steps.octo-sts.outputs.token }}`. The octo-sts identity is on the ruleset's **bypass list**, so it can create the tag ref. This matches how **dd-trace-dotnet and upstream libdatadog** authenticate their release workflows — and because it's OIDC-federated there's **no token to store or rotate** (this replaced the old `RELEASE_TOKEN` PAT, which DataDog policy capped at ~30 days, forcing monthly rotation). @@ -125,7 +127,7 @@ libdatadog-dotnet/ - **`build-platform.yml`** — reusable matrix workflow. Steps: checkout → setup Rust → cache `~/.cargo/{registry,git}` → setup QEMU (only for aarch64 Linux targets) → run `build.{sh,ps1}` → verify output → upload artifact. - **`build.yml`** — calls `build-platform.yml` on PR / push to main with `verify_artifacts: true`. -- **`release.yml`** — manual dispatch (from `main`). Builds all 8 platforms (no verify), archives them, computes SHA256 + SHA512, creates a GitHub release with assets and a checksums-in-the-body note. Publish step auth via dd-octo-sts (OIDC; policy in `.github/chainguard/self.release.sts.yaml`). +- **`release.yml`** — manual dispatch (from `main`). Resolves this repo's release tag first, passes it to the Windows build as `file_version` (`release --file-version`, the DLL `FileVersion`), builds all 8 platforms (no verify), archives them, computes SHA256 + SHA512, creates a GitHub release with assets and a checksums-in-the-body note. Publish step auth via dd-octo-sts (OIDC; policy in `.github/chainguard/self.release.sts.yaml`). ## Testing Locally @@ -133,8 +135,8 @@ libdatadog-dotnet/ # Linux GNU (x86_64), full clean build ./build.sh --platform x86_64-unknown-linux-gnu --clean -# Windows -./build.ps1 -Platform x64-windows -Clean +# Windows. -FileVersion is the libdatadog-dotnet release, not LIBDATADOG_VERSION. +./build.ps1 -Platform x64-windows -Clean -FileVersion 1.3.5 # macOS ./build.sh --platform aarch64-apple-darwin --clean @@ -144,6 +146,8 @@ Output lands in `output/libdatadog-/`. For aarch64 Linux targets you n ## Recent Changes (Reverse Chronological) +- **2026-10**: Windows release builds pass `release --file-version` set to the libdatadog-dotnet release (not `LIBDATADOG_VERSION`), so the DLL `FileVersion` is what Windows Installer compares on upgrade. `ProductVersion` stays the upstream libdatadog version. +- **2026-10**: Bumped to libdatadog v47 (from v38). Rust toolchain pin moved from `1.87.0` to `1.91.1` to match v47's MSRV. macOS runners stay on `macos-14` / `macos-14-large` (Sonoma); libddprof-build still builds on the Sonoma AMI. - **2026-07**: Bumped to libdatadog v38 (from v36). Rust toolchain pin already at `1.87.0`, which matches v38's MSRV, so no toolchain change was needed. - **2026-06**: Bumped to libdatadog v36 (from v32). Rust toolchain pin already at `1.87.0`, which matches v36's MSRV, so no toolchain change was needed. - **2026-05**: aarch64-gnu switched from cross-rs cross-compile to QEMU + native manylinux2014_aarch64. Necessary because libdd-libunwind-sys (v30) can't be cross-compiled. diff --git a/LIBDATADOG_VERSION b/LIBDATADOG_VERSION index 531d2a4..645a41f 100644 --- a/LIBDATADOG_VERSION +++ b/LIBDATADOG_VERSION @@ -1 +1 @@ -38.0.0 +47.0.0 diff --git a/README.md b/README.md index 09ab704..4644fb9 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ A thin packaging layer over upstream libdatadog. Ships only the FFI components t ### Prerequisites -- Rust 1.87.0 or newer (CI pins to 1.87.0 to match libdatadog's MSRV) +- Rust 1.91.1 or newer (CI pins to 1.91.1 to match libdatadog's MSRV) - Git - PowerShell on Windows; Bash + Docker (with buildx and QEMU for aarch64 Linux builds) elsewhere @@ -23,8 +23,9 @@ A thin packaging layer over upstream libdatadog. Ships only the FFI components t # macOS arm64 ./build.sh --platform aarch64-apple-darwin --clean -# Windows -./build.ps1 -Platform x64-windows -Clean +# Windows. -FileVersion is this repo's release (major.minor.patch), embedded +# as the DLL FileVersion. Omit it for a local build that isn't a release. +./build.ps1 -Platform x64-windows -Clean -FileVersion 1.3.5 ``` Output lands in `output/libdatadog-/`. @@ -53,12 +54,14 @@ cargo install \ --no-default-features \ --features "" \ builder -release --out --target +release --out --target [--file-version ] ``` The builder handles the FFI cargo build, header generation (cbindgen + dedup), library stripping, and packaging. -**Windows quirk**: the builder produces a flat `lib/datadog_profiling.{dll,lib,pdb}` layout, but dd-trace-dotnet's vcpkg portfile expects the legacy `release/{dynamic,static}` + `debug/{dynamic,static}` tree with `_ffi`-suffixed filenames. `build.ps1` runs the builder twice (release + debug) and reassembles that layout from cargo's raw `target/` output. +**Windows `FileVersion`**: `--file-version` is the libdatadog-dotnet release (`1.3.5` from tag `v1.3.5`), not `LIBDATADOG_VERSION`. The builder forwards it as `LIBDATADOG_PACKAGE_VERSION` and embeds it as the DLL `FileVersion` — the field Windows Installer compares when deciding whether to replace the file on upgrade. `ProductVersion` stays the upstream libdatadog version, so that pin is still recoverable from the shipped DLL. The flag does nothing on non-Windows targets. The Release workflow passes it automatically; omit it and `FileVersion` falls back to the upstream libdatadog version. + +**Windows quirk**: the builder produces a flat `lib/datadog_profiling.{dll,lib,pdb}` layout, but dd-trace-dotnet's vcpkg portfile expects the legacy `release/{dynamic,static}` + `debug/{dynamic,static}` tree with `_ffi`-suffixed filenames. `build.ps1` runs the builder twice (release + debug) and reassembles that layout from cargo's raw `target/` output. The `VERSIONINFO` resource is embedded during that cargo build, so the reassembled DLL keeps the `FileVersion` set by `--file-version`. ## GLIBC Compatibility @@ -82,7 +85,7 @@ Manual dispatch: **Actions → Release → Run workflow**. The workflow builds a | `version_increment` | `patch` | `patch` / `minor` / `major` — ignored if `release_version` is set | | `release_version` | _(empty)_ | Manual override, e.g. `v1.4.0` | -The upstream libdatadog version isn't a workflow input — it's pinned in the `LIBDATADOG_VERSION` file at the time of the release commit. +The upstream libdatadog version isn't a workflow input — it's pinned in the `LIBDATADOG_VERSION` file at the time of the release commit. The workflow resolves this repo's own release tag first and passes it to the Windows build as `--file-version`, so the DLL `FileVersion` matches the release (for example `1.4.0`) rather than `LIBDATADOG_VERSION`. For CI runs without publishing a release, use the **Build** workflow (auto-triggered on every PR and push to `main`). diff --git a/build.ps1 b/build.ps1 index 9101adb..36bc2ac 100644 --- a/build.ps1 +++ b/build.ps1 @@ -29,6 +29,13 @@ param( [string]$Platform = "x64-windows", [string]$OutputDir = "output", [string]$Features = "profiling,crashtracker,symbolizer,library-config", + # libdatadog-dotnet release version (major.minor.patch, optional leading "v"), + # embedded as the DLL FileVersion. Distinct from LIBDATADOG_VERSION: Windows + # Installer compares FileVersion when deciding whether to replace the file + # on upgrade, so it has to change with this repo's release, not with the + # upstream libdatadog pin. Empty omits --file-version and the builder falls + # back to the upstream version. Ignored by the builder on non-Windows targets. + [string]$FileVersion = "", [switch]$Clean ) @@ -50,12 +57,24 @@ $Target = if ($env:CARGO_BUILD_TARGET) { # Read the libdatadog version. Update LIBDATADOG_VERSION to upgrade. $Version = (Get-Content LIBDATADOG_VERSION).Trim() +# --file-version wants major.minor.patch. Accept a leading "v" so callers can +# pass the release tag (v1.3.5) directly. +$NormalizedFileVersion = "" +if ($FileVersion) { + $NormalizedFileVersion = $FileVersion -replace '^v', '' + if ($NormalizedFileVersion -notmatch '^\d+\.\d+\.\d+$') { + Write-Host "Error: -FileVersion must be major.minor.patch (got '$FileVersion'). This is the libdatadog-dotnet release version, not LIBDATADOG_VERSION." -ForegroundColor Red + exit 1 + } +} + Write-Host "Building libdatadog-dotnet" -ForegroundColor Cyan -Write-Host " Platform : $Platform" -ForegroundColor Gray -Write-Host " Target : $Target" -ForegroundColor Gray -Write-Host " Features : $Features" -ForegroundColor Gray -Write-Host " Output : $OutputDir" -ForegroundColor Gray -Write-Host " Version : $Version" -ForegroundColor Gray +Write-Host " Platform : $Platform" -ForegroundColor Gray +Write-Host " Target : $Target" -ForegroundColor Gray +Write-Host " Features : $Features" -ForegroundColor Gray +Write-Host " Output : $OutputDir" -ForegroundColor Gray +Write-Host " Libdatadog : $Version" -ForegroundColor Gray +Write-Host " FileVersion : $(if ($NormalizedFileVersion) { $NormalizedFileVersion } else { '(upstream libdatadog version)' })" -ForegroundColor Gray if (-not (Get-Command cargo -ErrorAction SilentlyContinue)) { Write-Host "Error: cargo not found. Install Rust from https://rustup.rs/" -ForegroundColor Red @@ -126,8 +145,16 @@ function Invoke-Builder { # is bulletproof. $stdoutFile = Join-Path $OutputDir "_builder-$BuildProfile.stdout.log" $stderrFile = Join-Path $OutputDir "_builder-$BuildProfile.stderr.log" + # --file-version is forwarded to the cargo build as + # LIBDATADOG_PACKAGE_VERSION and embedded in the DLL VERSIONINFO. + # ProductVersion stays the upstream libdatadog version. + $releaseArgs = @("--out", $BuilderOut, "--target", $Target) + if ($NormalizedFileVersion) { + $releaseArgs += @("--file-version", $NormalizedFileVersion) + } + $proc = Start-Process -FilePath ".\.builder\bin\release.exe" ` - -ArgumentList "--out", "$BuilderOut", "--target", "$Target" ` + -ArgumentList $releaseArgs ` -NoNewWindow -PassThru -Wait ` -RedirectStandardOutput $stdoutFile ` -RedirectStandardError $stderrFile diff --git a/tools/docker/Dockerfile.centos-aarch64 b/tools/docker/Dockerfile.centos-aarch64 index 7c3dd87..8d859f2 100644 --- a/tools/docker/Dockerfile.centos-aarch64 +++ b/tools/docker/Dockerfile.centos-aarch64 @@ -24,7 +24,7 @@ FROM quay.io/pypa/manylinux2014_aarch64 ENV CARGO_HOME=/root/.cargo \ RUSTUP_HOME=/root/.rustup RUN curl -fsSL https://sh.rustup.rs -o /tmp/rustup-init.sh \ - && sh /tmp/rustup-init.sh -y --default-toolchain 1.87.0 --profile minimal --no-modify-path \ + && sh /tmp/rustup-init.sh -y --default-toolchain 1.91.1 --profile minimal --no-modify-path \ && rm /tmp/rustup-init.sh ENV PATH="/root/.cargo/bin:${PATH}" diff --git a/tools/docker/Dockerfile.musl-aarch64 b/tools/docker/Dockerfile.musl-aarch64 index 5a30cf7..bc9733f 100644 --- a/tools/docker/Dockerfile.musl-aarch64 +++ b/tools/docker/Dockerfile.musl-aarch64 @@ -29,7 +29,7 @@ ENV RUSTUP_HOME=/usr/local/rustup \ CARGO_HOME=/usr/local/cargo \ PATH=/usr/local/cargo/bin:$PATH -ARG RUST_VERSION=1.87.0 +ARG RUST_VERSION=1.91.1 RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \ | sh -s -- --default-toolchain ${RUST_VERSION} --profile minimal -y --no-modify-path \ && rustc --version \ diff --git a/tools/docker/Dockerfile.musl-x64 b/tools/docker/Dockerfile.musl-x64 index adbad2b..28dd584 100644 --- a/tools/docker/Dockerfile.musl-x64 +++ b/tools/docker/Dockerfile.musl-x64 @@ -28,7 +28,7 @@ ENV RUSTUP_HOME=/usr/local/rustup \ CARGO_HOME=/usr/local/cargo \ PATH=/usr/local/cargo/bin:$PATH -ARG RUST_VERSION=1.87.0 +ARG RUST_VERSION=1.91.1 RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \ | sh -s -- --default-toolchain ${RUST_VERSION} --profile minimal -y --no-modify-path \ && rustc --version \