From 7f107cd22c625e47e6f1e10461eec2f02e3ff433 Mon Sep 17 00:00:00 2001 From: Steve Gordon Date: Wed, 3 Jul 2024 05:48:19 +0100 Subject: [PATCH] Fix linux build dependency of glibc --- .../workflows/install-dependencies/action.yml | 161 ++++++++++-------- CONTRIBUTING.md | 12 +- Makefile.toml | 10 +- build/scripts/Build.fs | 37 ++-- docs/setup-auto-instrumentation.asciidoc | 8 +- src/profiler/elastic_apm_profiler/Cargo.toml | 2 +- .../ProfiledApplication.cs | 4 +- 7 files changed, 132 insertions(+), 102 deletions(-) diff --git a/.github/workflows/install-dependencies/action.yml b/.github/workflows/install-dependencies/action.yml index 10552af919..df05f3bdea 100644 --- a/.github/workflows/install-dependencies/action.yml +++ b/.github/workflows/install-dependencies/action.yml @@ -1,78 +1,89 @@ --- -name: Install Dependencies -description: Ensures an action has the appropiate non .NET dependencies installed - -inputs: - rust: - description: 'Install rust toolchain ("true" or "false")' - required: false - default: "false" - azure: - description: 'Install azure functions tool chain ("true" or "false")' - required: false - default: "false" - tc-cloud: - description: 'Bootstrap TestContainers Cloud (TOKEN or "false")' - required: false - default: "false" - -runs: - using: "composite" - steps: - # RUST - - name: Rustup - if: "${{ inputs.rust == 'true' }}" - shell: bash - run: rustup default 1.69.0 - - # - name: Cargo make - # if: "${{ inputs.rust == 'true' }}" - # shell: bash - # run: cargo install --force cargo-make - - - name: Install cargo-make using cache - if: "${{ inputs.rust == 'true' }}" - uses: baptiste0928/cargo-install@v3 - with: - crate: cargo-make - version: "^0.36.8" - - - uses: Swatinem/rust-cache@v2 - if: "${{ inputs.rust == 'true' }}" - with: - cache-targets: "false" - cache-all-crates: "true" - + name: Install Dependencies + description: Ensures an action has the appropiate non .NET dependencies installed + + inputs: + rust: + description: 'Install rust toolchain ("true" or "false")' + required: false + default: "false" + azure: + description: 'Install azure functions tool chain ("true" or "false")' + required: false + default: "false" + tc-cloud: + description: 'Bootstrap TestContainers Cloud (TOKEN or "false")' + required: false + default: "false" - # AZURE - - name: 'Linux: Azure functions core tools' - if: "${{ inputs.azure == 'true' && runner.os == 'Linux' }}" - shell: bash - run: | - wget -q https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb - sudo dpkg -i packages-microsoft-prod.deb - sudo apt-get update - sudo apt-get install azure-functions-core-tools-4 + runs: + using: "composite" + steps: + # ZIG + - name: Zig + if: "${{ inputs.rust == 'true' && runner.os == 'Linux' }}" + shell: bash + run: sudo snap install zig --beta --classic + + # RUST + - name: Rustup + if: "${{ inputs.rust == 'true' }}" + shell: bash + run: rustup default 1.79.0 + + # - name: Cargo make + # if: "${{ inputs.rust == 'true' }}" + # shell: bash + # run: cargo install --force cargo-make + + - name: Install cargo-make using cache + if: "${{ inputs.rust == 'true' }}" + uses: baptiste0928/cargo-install@v3 + with: + crate: cargo-make + version: "^0.36.8" + + - name: Install cargo zigbuild + if: "${{ inputs.rust == 'true' && runner.os == 'Linux' }}" + shell: bash + run: cargo install --force cargo-zigbuild + + - uses: Swatinem/rust-cache@v2 + if: "${{ inputs.rust == 'true' }}" + with: + cache-targets: "false" + cache-all-crates: "true" + + # AZURE + - name: 'Linux: Azure functions core tools' + if: "${{ inputs.azure == 'true' && runner.os == 'Linux' }}" + shell: bash + run: | + wget -q https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb + sudo dpkg -i packages-microsoft-prod.deb + sudo apt-get update + sudo apt-get install azure-functions-core-tools-4 + + - name: 'Windows: Azure functions core tools' + if: "${{ inputs.azure == 'true' && runner.os == 'Windows' }}" + shell: cmd + run: choco install azure-functions-core-tools -y --no-progress -r --version 4.0.4829 - - name: 'Windows: Azure functions core tools' - if: "${{ inputs.azure == 'true' && runner.os == 'Windows' }}" - shell: cmd - run: choco install azure-functions-core-tools -y --no-progress -r --version 4.0.4829 - - # TEST CONTAINERS CLOUD - # If no PR event or if a PR event that's caused by a non-fork and non dependabot actor - - name: Setup TestContainers Cloud Client - if: | - inputs.tc-cloud != 'false' - && (github.event_name != 'pull_request' - || (github.event_name == 'pull_request' - && github.event.pull_request.head.repo.fork == false - && github.actor != 'dependabot[bot]' - ) - ) - uses: atomicjar/testcontainers-cloud-setup-action@c335bdbb570ec7c48f72c7d450c077f0a002293e # v1.3.0 - with: - token: ${{ inputs.tc-cloud }} - - - + # TEST CONTAINERS CLOUD + # If no PR event or if a PR event that's caused by a non-fork and non dependabot actor + - name: Setup TestContainers Cloud Client + if: | + inputs.tc-cloud != 'false' + && (github.event_name != 'pull_request' + || (github.event_name == 'pull_request' + && github.event.pull_request.head.repo.fork == false + && github.actor != 'dependabot[bot]' + ) + ) + uses: atomicjar/testcontainers-cloud-setup-action@c335bdbb570ec7c48f72c7d450c077f0a002293e # v1.3.0 + with: + token: ${{ inputs.tc-cloud }} + + + + \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b3a24839d4..ce9e9c06c2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,18 +15,22 @@ feedback and ideas are always welcome. ### .NET source In order to build the .NET source code, you'll need - * [.NET 6.0 or later](https://dotnet.microsoft.com/download/dotnet/6.0) + * [.NET 8.0 or later](https://dotnet.microsoft.com/download/dotnet/8.0) * **If** you're running on Windows **and** also wish to build projects that target .NET Framework, -you'll need a minimum of .NET Framework 4.6.1 installed. +you'll need a minimum of .NET Framework 4.6.2 installed. You can use any IDE that supports .NET development, and you can use any OS that is supported by .NET. ### Rust source -In order to build the CLR profiler source code, you'll need - * [Rust 1.54 or later](https://www.rust-lang.org/tools/install) +In order to build the CLR profiler source code, you'll need: + * [Rust 1.79 or later](https://www.rust-lang.org/tools/install) * [Cargo make](https://github.com/sagiegurari/cargo-make#installation) + On Linux, you will also require: + * [Cargo zigbuild](https://github.com/rust-cross/cargo-zigbuild) + * [Zig](https://github.com/ziglang/zig) + You can use any IDE that supports Rust development; we typically use [CLion](https://www.jetbrains.com/clion/) with the [Rust plugin](https://plugins.jetbrains.com/plugin/8182-rust/docs), or [VS Code](https://code.visualstudio.com/) diff --git a/Makefile.toml b/Makefile.toml index 20bcfe1ae5..1a86393645 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -35,6 +35,14 @@ description = "Builds CLR Profiler for release" # loader assembly is embedded in the profiler dependencies = ["build-loader"] +[tasks.build-release-linux] +description = "Builds CLR Profiler for release against a known version of glibc" +install_crate = false +toolchain = "${CARGO_MAKE_RUST_DEFAULT_TOOLCHAIN}" +args = ["zigbuild", "--release", "--target", "x86_64-unknown-linux-gnu.2.14", "@@split(CARGO_MAKE_CARGO_BUILD_TEST_FLAGS, )"] +# loader assembly is embedded in the profiler +dependencies = ["build-loader"] + [tasks.build-integrations] description = "Builds Managed Profiler .NET integrations" command = "dotnet" @@ -83,7 +91,7 @@ cargo expand --manifest-path src/profiler/elastic_apm_profiler/Cargo.toml --colo [tasks.set-profiler-env] private = true -env = { "CORECLR_PROFILER_PATH" = "${CARGO_MAKE_WORKING_DIRECTORY}/target/release/libelastic_apm_profiler.so" } +env = { "CORECLR_PROFILER_PATH" = "${CARGO_MAKE_WORKING_DIRECTORY}/target/x86_64-unknown-linux-gnu/release/release/libelastic_apm_profiler.so" } [tasks.set-profiler-env.mac] env = { "CORECLR_PROFILER_PATH" = "${CARGO_MAKE_WORKING_DIRECTORY}/target/release/libelastic_apm_profiler.dylib" } diff --git a/build/scripts/Build.fs b/build/scripts/Build.fs index 58af804bfa..e6f9954fb8 100644 --- a/build/scripts/Build.fs +++ b/build/scripts/Build.fs @@ -186,20 +186,20 @@ module Build = @ ["--"; "RunConfiguration.CollectSourceInformation=true"] DotNet.ExecWithTimeout command (TimeSpan.FromMinutes 30) - - + /// Builds the CLR profiler and supporting .NET managed assemblies let BuildProfiler () = dotnet "build" (Paths.ProfilerProjFile "Elastic.Apm.Profiler.Managed") - Cargo.Exec [ "make"; "build-release"; "--disable-check-for-update"] - + if isWindows then Cargo.Exec [ "make"; "build-release"; "--disable-check-for-update"] + else Cargo.Exec [ "make"; "build-release-linux"; "--disable-check-for-update"] + /// Publishes all projects with framework versions - let Publish targets = + let Publish targets = let projs = match targets with | Some t -> t | None -> allSrcProjects - + projs |> Seq.map getAllTargetFrameworks |> Seq.iter (fun (proj, frameworks) -> @@ -290,7 +290,6 @@ module Build = // include version in the zip file name ZipFile.CreateFromDirectory(agentDir.FullName, Paths.BuildOutput versionedName + ".zip") - let ProfilerIntegrations () = DotNet.Exec ["run"; "--project"; Paths.ProfilerProjFile "Elastic.Apm.Profiler.IntegrationsGenerator"; "--" "-i"; Paths.SrcProfiler "Elastic.Apm.Profiler.Managed/bin/Release/netstandard2.0/Elastic.Apm.Profiler.Managed.dll" @@ -299,20 +298,25 @@ module Build = /// Creates versioned elastic_apm_profiler.zip file containing all components needed for profiler auto-instrumentation let ProfilerZip () = let name = "elastic_apm_profiler" + let directory = Paths.BuildOutput name + + if Directory.Exists(directory) then + Directory.Delete(directory, true) + let currentAssemblyVersion = Versioning.CurrentVersion.FileVersion let versionedName = let os = if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then "win-x64" - else "linux-x64" + else "linux-x64" sprintf "%s_%s-%s" name (currentAssemblyVersion.ToString()) os - let profilerDir = Paths.BuildOutput name |> DirectoryInfo + let profilerDir = directory |> DirectoryInfo profilerDir.Create() - + seq { Paths.SrcProfiler "Elastic.Apm.Profiler.Managed/integrations.yml" "target/release/elastic_apm_profiler.dll" - "target/release/libelastic_apm_profiler.so" + "target/x86_64-unknown-linux-gnu/release/libelastic_apm_profiler.so" Paths.SrcProfiler "elastic_apm_profiler/NOTICE" Paths.SrcProfiler "elastic_apm_profiler/README" "LICENSE" @@ -321,12 +325,13 @@ module Build = |> Seq.filter (fun file -> file.Exists) |> Seq.iter (fun file -> let destination = Path.combine profilerDir.FullName file.Name - let newFile = file.CopyTo(destination, true) + let newFile = file.CopyTo(destination, true) if newFile.Name = "README" then File.applyReplace (fun s -> s.Replace("${VERSION}", sprintf "%i.%i" currentAssemblyVersion.Major currentAssemblyVersion.Minor)) newFile.FullName ) - + Directory.GetDirectories((Paths.BuildOutput "Elastic.Apm.Profiler.Managed"), "*", SearchOption.TopDirectoryOnly) + |> Array.filter (fun dir -> isWindows || not (dir.EndsWith("net462"))) |> Seq.map DirectoryInfo |> Seq.iter (fun sourceDir -> copyDllsAndPdbs (profilerDir.CreateSubdirectory(sourceDir.Name)) sourceDir) @@ -335,8 +340,4 @@ module Build = if File.exists zip then printf $"%s{zip} already exists on disk" File.delete zip - ZipFile.CreateFromDirectory(profilerDir.FullName, zip) - - - - \ No newline at end of file + ZipFile.CreateFromDirectory(profilerDir.FullName, zip) \ No newline at end of file diff --git a/docs/setup-auto-instrumentation.asciidoc b/docs/setup-auto-instrumentation.asciidoc index ca5e49b77e..19ae587240 100644 --- a/docs/setup-auto-instrumentation.asciidoc +++ b/docs/setup-auto-instrumentation.asciidoc @@ -16,7 +16,7 @@ This approach works with the following |=== | 2.+^|**Operating system** -|**Architecture** |**Windows** |**Linux** +|**Architecture** |**Windows** |**Linux** ** |x64 @@ -33,7 +33,11 @@ This approach works with the following _* Due to binding issues introduced by Microsoft, we recommend at least .NET Framework 4.7.2 for best compatibility._ -NOTE: The Profiler based agent only supports 64-bit applications. 32-bit applications aren't supported. +_** Minimum GLIBC version 2.14._ + +NOTE: The profiler-based agent only supports 64-bit applications. 32-bit applications aren't supported. + +NOTE: The profiler-based agent does not currently support ARM. It instruments the following assemblies: diff --git a/src/profiler/elastic_apm_profiler/Cargo.toml b/src/profiler/elastic_apm_profiler/Cargo.toml index 61c594288d..b5e1e8551e 100644 --- a/src/profiler/elastic_apm_profiler/Cargo.toml +++ b/src/profiler/elastic_apm_profiler/Cargo.toml @@ -14,7 +14,7 @@ c_vec = "2.0.0" com = { version = "0.6.0", features = ["production"] } hex = "0.4.3" log = "0.4.14" -log4rs = { version = "1.0.0", default_features = false, features = ["console_appender", "rolling_file_appender", "compound_policy", "size_trigger", "fixed_window_roller"] } +log4rs = { version = "1.0.0", default-features = false, features = ["console_appender", "rolling_file_appender", "compound_policy", "size_trigger", "fixed_window_roller"] } num-derive = "0.3" num-traits = "0.2" once_cell = "1.8.0" diff --git a/test/profiler/Elastic.Apm.Profiler.Managed.Tests/ProfiledApplication.cs b/test/profiler/Elastic.Apm.Profiler.Managed.Tests/ProfiledApplication.cs index 274ed38586..354fecad57 100644 --- a/test/profiler/Elastic.Apm.Profiler.Managed.Tests/ProfiledApplication.cs +++ b/test/profiler/Elastic.Apm.Profiler.Managed.Tests/ProfiledApplication.cs @@ -55,7 +55,9 @@ protected ProfiledApplication(string projectName, params string[] folders) else profilerFile = "libelastic_apm_profiler.dylib"; - _profilerPath = Path.Combine(SolutionPaths.Root, "target", "release", profilerFile); + _profilerPath = TestEnvironment.IsLinux ? + Path.Combine(SolutionPaths.Root, "target", "x86_64-unknown-linux-gnu/release", "release", profilerFile) : + Path.Combine(SolutionPaths.Root, "target", "release", profilerFile); if (!File.Exists(_profilerPath)) {