diff --git a/.cargo/config.github b/.cargo/config.github
new file mode 100644
index 000000000..59320e8f2
--- /dev/null
+++ b/.cargo/config.github
@@ -0,0 +1,5 @@
+[target.aarch64-unknown-linux-gnu]
+linker = "aarch64-linux-gnu-gcc"
+
+[target.aarch64-unknown-linux-musl]
+linker = "aarch64-linux-musl-gcc"
\ No newline at end of file
diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
new file mode 100644
index 000000000..b46430e75
--- /dev/null
+++ b/.github/workflows/dotnet.yml
@@ -0,0 +1,318 @@
+name: .NET
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+ branches:
+ - main
+
+permissions:
+ contents: read
+
+env:
+ OUTPUT_DIR: bin
+ PACKAGES_DIR: packages
+ NUGET_NAME: ganeshnj.libdatadog
+
+jobs:
+ build:
+ runs-on: ${{ matrix.os }}
+
+ # container: ${{ matrix.container }}
+
+ env:
+ ACTIONS_RUNNER_FORCE_ACTIONS_NODE_VERSION: node16
+ ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
+
+ strategy:
+ matrix:
+ include:
+ - os: windows-latest
+ target: x86_64-pc-windows-msvc
+ - os: windows-latest
+ target: i686-pc-windows-msvc
+ - os: ubuntu-latest
+ target: x86_64-unknown-linux-gnu
+ container: centos:7
+# - os: ubuntu-24.04 #TODO why doesn't this work
+# target: aarch64-unknown-linux-gnu
+# container: centos:7
+ # - os: ubuntu-latest
+ # target: x86_64-unknown-linux-musl
+ # container: alpine:3.19
+ # - os: arm-4core-linux-ubuntu24.04
+ # target: aarch64-unknown-linux-musl
+ # container: alpine:3.19
+ - os: macos-latest
+ target: aarch64-apple-darwin
+ - os: macos-latest
+ target: x86_64-apple-darwin
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: centos:7
+ uses: addnab/docker-run-action@v3
+ if: matrix.container == 'centos:7'
+ with:
+ image: ${{ matrix.container }}
+ options: -v ${{ github.workspace }}:/workspace
+ run: |
+ sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
+ sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
+
+ yum install epel-release -y
+
+ yum clean all -y && yum makecache -y && yum update -y
+
+ yum install -y centos-release-scl \
+ && sed -i s/mirror.centos.org/buildlogs.centos.org/g /etc/yum.repos.d/CentOS-SCLo-*.repo \
+ && sed -i s/^#.*baseurl=http/baseurl=http/g /etc/yum.repos.d/CentOS-SCLo-*.repo \
+ && sed -i s/^mirrorlist=http/#mirrorlist=http/g /etc/yum.repos.d/CentOS-SCLo-*.repo \
+ && yum install -y --setopt=tsflags=nodocs --nogpgcheck \
+ curl \
+ devtoolset-9 \
+ git \
+ make \
+ pkg-config \
+ unzip \
+ strace \
+ zlib-devel \
+ jq \
+ && yum clean all --enablerepo='*' \
+
+ # switch to GCC9 environment for the duration of the script
+ source scl_source enable devtoolset-9
+
+ gcc --version
+ ldd --version
+
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
+ source $HOME/.cargo/env
+ rustup target add ${{ matrix.target }}
+ rustup default ${{ matrix.target }}
+ cargo install --force cbindgen
+
+ cd /workspace
+ ./windows/build-artifacts.sh ${{ env.OUTPUT_DIR }} ${{ matrix.target }}
+
+ - name: alpine:3.19
+ uses: addnab/docker-run-action@v3
+ if: matrix.container == 'alpine:3.19'
+ with:
+ image: ${{ matrix.container }}
+ options: -v ${{ github.workspace }}:/workspace
+ run: |
+ apk update \
+ && apk add --no-cache \
+ build-base \
+ cargo \
+ cmake \
+ curl \
+ git \
+ make \
+ patchelf \
+ protoc \
+ pkgconf \
+ unzip \
+ bash \
+ jq \
+ clang16-libclang \
+ && mkdir /usr/local/src \
+
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
+ source $HOME/.cargo/env
+ rustup target add ${{ matrix.target }}
+ rustup default ${{ matrix.target }}
+ cargo install --force cbindgen
+
+ gcc --version
+ ldd --version
+
+ cd /workspace
+ ./windows/build-artifacts.sh ${{ env.OUTPUT_DIR }} ${{ matrix.target }}
+
+ - name: Windows
+ if: matrix.os == 'windows-latest'
+ run: |
+ $ProgressPreference = "SilentlyContinue"
+ Invoke-WebRequest https://win.rustup.rs/ -OutFile rustup-init.exe
+ .\rustup-init.exe -y --default-host=${{ matrix.target }} --default-toolchain stable --profile minimal
+ del rustup-init.exe
+ rustup target add ${{ matrix.target }}
+ ./windows/build-artifacts.ps1 ${{ env.OUTPUT_DIR }} ${{ matrix.target }}
+ shell: powershell
+
+ - name: macOS
+ if: matrix.os == 'macos-latest'
+ run: |
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
+ source $HOME/.cargo/env
+ rustup target add ${{ matrix.target }}
+ cargo install --force cbindgen
+ ./windows/build-artifacts.sh ${{ env.OUTPUT_DIR }} ${{ matrix.target }}
+ shell: bash
+
+ - name: Upload artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: ${{ env.OUTPUT_DIR }}-${{ matrix.target }}
+ path: |
+ bin/*
+ !bin/*/*/build
+ !bin/*/*/deps
+ !bin/*/*/examples
+ !bin/*/*/incremental
+ !bin/*/*/.fingerprint
+ !bin/debug
+ !bin/release
+
+ pack:
+ runs-on: windows-latest
+ needs: build
+ outputs:
+ NUGET_VERSION: ${{ steps.dotnet-pack.outputs.NUGET_VERSION }}
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Download x86_64-pc-windows-msvc
+ uses: actions/download-artifact@v4
+ with:
+ name: ${{ env.OUTPUT_DIR }}-x86_64-pc-windows-msvc
+ path: bin
+
+ - name: Download i686-pc-windows-msvc
+ uses: actions/download-artifact@v4
+ with:
+ name: ${{ env.OUTPUT_DIR }}-i686-pc-windows-msvc
+ path: bin
+
+ - name: Download x86_64-unknown-linux-gnu
+ uses: actions/download-artifact@v4
+ with:
+ name: ${{ env.OUTPUT_DIR }}-x86_64-unknown-linux-gnu
+ path: bin
+
+ - name: Download aarch64-unknown-linux-gnu
+ uses: actions/download-artifact@v4
+ with:
+ name: ${{ env.OUTPUT_DIR }}-aarch64-unknown-linux-gnu
+ path: bin
+
+ # - name: Download x86_64-unknown-linux-musl
+ # uses: actions/download-artifact@v4
+ # with:
+ # name: ${{ env.OUTPUT_DIR }}-x86_64-unknown-linux-musl
+ # path: bin
+
+ # - name: Download aarch64-unknown-linux-musl
+ # uses: actions/download-artifact@v4
+ # with:
+ # name: ${{ env.OUTPUT_DIR }}-aarch64-unknown-linux-musl
+ # path: bin
+
+ - name: Download aarch64-apple-darwin
+ uses: actions/download-artifact@v4
+ with:
+ name: ${{ env.OUTPUT_DIR }}-aarch64-apple-darwin
+ path: bin
+
+ - name: Download x86_64-apple-darwin
+ uses: actions/download-artifact@v4
+ with:
+ name: ${{ env.OUTPUT_DIR }}-x86_64-apple-darwin
+ path: bin
+
+ - name: dotnet pack
+ id: dotnet-pack
+ run: |
+ $cargo_content=Get-Content Cargo.toml -Raw
+ $cargo_content -match '(?m)^version += +"([^"]+)"'
+ $current_version=$Matches[1]
+ $version_suffix="ci.${{ github.event.number }}.${{ github.run_number }}"
+ $version="$current_version-$version_suffix"
+ echo "NUGET_VERSION=$version" >> $env:GITHUB_OUTPUT
+ dotnet pack windows/libdatadog.csproj -p:LibDatadogBinariesOutputDir=../${{ env.OUTPUT_DIR }} -p:LibDatadogVersion=$version -p:PackageID=${{ env.NUGET_NAME }} -o ${{ env.PACKAGES_DIR }}
+
+ - name: Upload package
+ uses: actions/upload-artifact@v4 # v4
+ with:
+ name: ${{ env.PACKAGES_DIR }}
+ path: ${{ env.PACKAGES_DIR }}
+
+ test:
+ runs-on: ${{ matrix.os }}
+ needs: pack
+
+ strategy:
+ matrix:
+ include:
+ - os: windows-latest
+ - os: ubuntu-latest
+ container: centos:7
+ - os: macos-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Download package
+ uses: actions/download-artifact@v4
+ with:
+ name: ${{ env.PACKAGES_DIR }}
+ path: ${{ env.PACKAGES_DIR }}
+
+ - name: ${{ matrix.container }} Test
+ uses: addnab/docker-run-action@v3
+ if: matrix.container == 'centos:7' || matrix.container == 'alpine:3.19'
+ with:
+ image: ${{ matrix.container }}
+ options: -v ${{ github.workspace }}:/workspace
+ run: |
+ curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --channel 6.0
+ export PATH=$PATH:~/.dotnet
+ dotnet --info
+
+ cd /workspace/tests/nuget_package
+ export DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
+ dotnet add nuget_package.csproj package ${{ env.NUGET_NAME }} --version ${{ needs.pack.outputs.NUGET_VERSION }}
+ dotnet run
+
+ - name: Install .NET SDK
+ if: matrix.os == 'windows-latest' || matrix.os == 'macos-latest'
+ uses: actions/setup-dotnet@3e891b0cb619bf60e2c25674b222b8940e2c1c25 #v4
+ with:
+ dotnet-version: 6.0.X
+
+ - name: Test
+ if: matrix.os == 'windows-latest' || matrix.os == 'macos-latest'
+ run: |
+ cd tests/nuget_package
+ dotnet add nuget_package.csproj package ${{ env.NUGET_NAME }} --version ${{ needs.pack.outputs.NUGET_VERSION }}
+
+ dotnet run
+
+ nuget-push:
+ runs-on: windows-latest
+ needs: test
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Download package
+ uses: actions/download-artifact@v4
+ with:
+ name: ${{ env.PACKAGES_DIR }}
+ path: ${{ env.PACKAGES_DIR }}
+
+ - name: Install .NET SDK
+ uses: actions/setup-dotnet@3e891b0cb619bf60e2c25674b222b8940e2c1c25 #v4
+ with:
+ dotnet-version: 6.0.X
+
+ - name: NuGet push
+ run: |
+ cd ${{ env.PACKAGES_DIR }}
+ dotnet nuget push *.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
diff --git a/build-profiling-ffi.sh b/build-profiling-ffi.sh
index 46094b4d1..f1401270f 100755
--- a/build-profiling-ffi.sh
+++ b/build-profiling-ffi.sh
@@ -17,18 +17,20 @@ set -eu
ARG_FEATURES=""
run_tests=true
+target=""
usage() {
- echo "Usage: `basename "$0"` [-h] [-f FEATURES] [-T] dest-dir"
+ echo "Usage: `basename "$0"` [-h] [-f FEATURES] [-T] [-t TARGET] dest-dir"
echo
echo "Options:"
echo " -h This help text"
echo " -f FEATURES Enable specified features (comma separated if more than one)"
echo " -T Skip checks after building"
+ echo " -t TARGET Specify the target platform"
exit $1
}
-while getopts f:hT flag
+while getopts f:hTt: flag
do
case "${flag}" in
f)
@@ -43,6 +45,11 @@ do
run_tests=false
shift
;;
+ t)
+ target=${OPTARG}
+ shift
+ shift
+ ;;
esac
done
@@ -59,7 +66,10 @@ fi
mkdir -v -p "$destdir/include/datadog" "$destdir/lib/pkgconfig" "$destdir/cmake"
version=$(awk -F\" '$1 ~ /^version/ { print $2 }' < profiling-ffi/Cargo.toml)
-target="$(rustc -vV | awk '/^host:/ { print $2 }')"
+if [ -z "${target:-}" ]; then
+ target="$(rustc -vV | awk '/^host:/ { print $2 }')"
+fi
+echo "Building for target: $target"
shared_library_suffix=".so"
static_library_suffix=".a"
library_prefix="lib"
@@ -77,7 +87,7 @@ symbolizer=0
# provided. At least on Alpine, libgcc_s may not even exist in the users'
# images, so -static-libgcc is recommended there.
case "$target" in
- "x86_64-alpine-linux-musl"|"aarch64-alpine-linux-musl")
+ "x86_64-alpine-linux-musl"|"aarch64-alpine-linux-musl"|"x86_64-unknown-linux-musl"|"aarch64-unknown-linux-musl")
expected_native_static_libs=" -lssp_nonshared -lgcc_s -lc"
native_static_libs=" -lssp_nonshared -lc"
# on alpine musl, Rust adds some weird runpath to cdylibs
diff --git a/nuget.config b/nuget.config
new file mode 100644
index 000000000..8b9945591
--- /dev/null
+++ b/nuget.config
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/tests/nuget_package/Program.cs b/tests/nuget_package/Program.cs
new file mode 100644
index 000000000..1f9c63d58
--- /dev/null
+++ b/tests/nuget_package/Program.cs
@@ -0,0 +1,279 @@
+// See https://aka.ms/new-console-template for more information
+
+using System;
+using System.Runtime.InteropServices;
+
+class Program
+{
+ public static int Main(string[] args)
+ {
+ var url = new CharSlice("http://localhost:8126");
+ var tracerVersion = new CharSlice("1.0.0");
+ var language = new CharSlice(".NET");
+ var languageVersion = new CharSlice("5.0.0");
+ var languageInterpreter = new CharSlice(".NET");
+ var hostname = new CharSlice("localhost");
+ var env = new CharSlice("development");
+ var service = new CharSlice("dotnet-test");
+ var serviceVersion = new CharSlice("1.0.0");
+
+ Console.WriteLine("Creating config");
+ Native.ddog_trace_exporter_config_new(out var config);
+ Console.WriteLine("Config created");
+
+ Console.WriteLine("Setting config values");
+ SetConfig(config, url, Native.ddog_trace_exporter_config_set_url);
+ SetConfig(config, tracerVersion, Native.ddog_trace_exporter_config_set_tracer_version);
+ SetConfig(config, tracerVersion, Native.ddog_trace_exporter_config_set_tracer_version);
+ SetConfig(config, language, Native.ddog_trace_exporter_config_set_language);
+ SetConfig(config, languageVersion, Native.ddog_trace_exporter_config_set_lang_version);
+ SetConfig(config, languageInterpreter, Native.ddog_trace_exporter_config_set_lang_interpreter);
+ SetConfig(config, hostname, Native.ddog_trace_exporter_config_set_hostname);
+ SetConfig(config, env, Native.ddog_trace_exporter_config_set_env);
+ SetConfig(config, service, Native.ddog_trace_exporter_config_set_service);
+ SetConfig(config, serviceVersion, Native.ddog_trace_exporter_config_set_version);
+ Console.WriteLine("Config values set");
+
+ var newError = Native.ddog_trace_exporter_new(out var handle, config);
+ if (newError != IntPtr.Zero)
+ {
+ Console.WriteLine("Error creating exporter");
+ var error = GetError(newError);
+ Console.WriteLine(error.Value.Code);
+ Console.WriteLine(error.Value.ToString());
+ Native.ddog_trace_exporter_config_free(config);
+ return -1;
+ }
+
+ Console.WriteLine("Exporter created");
+
+ Console.WriteLine("Sending traces");
+ var traces = new byte[]
+ {
+ 0x90
+ };
+
+ // pin traces
+ var traceSlice = new ByteSlice
+ {
+ Ptr = Marshal.UnsafeAddrOfPinnedArrayElement(traces, 0),
+ Len = (UIntPtr)traces.Length,
+ };
+ var traceCount = (UIntPtr)1;
+
+ var responsePtr = IntPtr.Zero;
+ var sendError = Native.ddog_trace_exporter_send(handle, traceSlice, traceCount, ref responsePtr);
+ if (sendError != IntPtr.Zero)
+ {
+ Console.WriteLine("Error sending traces");
+ var error = GetError(sendError);
+ Console.WriteLine(error.Value.Code);
+ Console.WriteLine(error.Value.ToString());
+ Native.ddog_trace_exporter_error_free(sendError);
+
+ // this is expected when agent is not running
+ if (error.Value.Code != TraceExporterError.ErrorCode.IoError)
+ {
+ return -1;
+ }
+ }
+
+ if (sendError == IntPtr.Zero)
+ {
+ // marshal the response struct
+ var response = Marshal.PtrToStructure(responsePtr);
+ Console.WriteLine("Response rate: " + response.Rate);
+ }
+
+ Console.WriteLine("Traces sent");
+
+ Console.WriteLine("Freeing exporter");
+ Native.ddog_trace_exporter_free(handle);
+ Console.WriteLine("Exporter freed");
+ Console.WriteLine("Done");
+ return 0;
+ }
+
+ static TraceExporterError? GetError(IntPtr errorPtr)
+ {
+ if (errorPtr == IntPtr.Zero)
+ return null;
+
+ return Marshal.PtrToStructure(errorPtr);
+ }
+
+ static void SetConfig(IntPtr config, CharSlice value, Func setter)
+ {
+ Console.WriteLine("Setting config value for " + value);
+ var error = setter(config, value);
+
+ if (error == IntPtr.Zero)
+ {
+ return;
+ }
+
+ // marshal the error struct
+ var errorStruct = Marshal.PtrToStructure(error);
+ Console.WriteLine("Error setting config value: " + errorStruct);
+ Native.ddog_trace_exporter_error_free(error);
+ }
+
+ internal enum TraceExporterInputFormat
+ {
+ Proxy = 0,
+ V04 = 1,
+ }
+
+ internal enum TraceExporterOutputFormat
+ {
+ V04 = 0,
+ V07 = 1,
+ }
+
+ internal static class Native
+ {
+ private const string DllName = "datadog_profiling_ffi";
+
+ [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern void ddog_trace_exporter_error_free(IntPtr error);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern void ddog_trace_exporter_config_new(out IntPtr outHandle);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern void ddog_trace_exporter_config_free(IntPtr handle);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern IntPtr ddog_trace_exporter_config_set_url(IntPtr config, CharSlice url);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern IntPtr ddog_trace_exporter_config_set_tracer_version(IntPtr config, CharSlice version);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern IntPtr ddog_trace_exporter_config_set_language(IntPtr config, CharSlice lang);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern IntPtr ddog_trace_exporter_config_set_lang_version(IntPtr config, CharSlice version);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern IntPtr ddog_trace_exporter_config_set_lang_interpreter(IntPtr config,
+ CharSlice interpreter);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern IntPtr ddog_trace_exporter_config_set_hostname(IntPtr config, CharSlice hostname);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern IntPtr ddog_trace_exporter_config_set_env(IntPtr config, CharSlice env);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern IntPtr ddog_trace_exporter_config_set_version(IntPtr config, CharSlice version);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern IntPtr ddog_trace_exporter_config_set_service(IntPtr config, CharSlice service);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern IntPtr ddog_trace_exporter_new(out IntPtr outHandle, IntPtr config);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern void ddog_trace_exporter_free(IntPtr handle);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern IntPtr ddog_trace_exporter_send(IntPtr handle, ByteSlice trace, UIntPtr traceCount,
+ ref IntPtr response);
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct AgentResponse
+ {
+ internal double Rate;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct ByteSlice
+ {
+ internal IntPtr Ptr;
+ internal UIntPtr Len;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct CharSlice
+ {
+ internal IntPtr Ptr;
+ internal UIntPtr Len;
+
+ internal CharSlice(string str)
+ {
+ var bytes = System.Text.Encoding.UTF8.GetBytes(str);
+ Ptr = Marshal.AllocHGlobal(bytes.Length);
+ Marshal.Copy(bytes, 0, Ptr, bytes.Length);
+ Len = (UIntPtr)bytes.Length;
+ }
+ }
+
+/*
+ * typedef struct ddog_TraceExporterError {
+ enum ddog_TraceExporterErrorCode code;
+ char *msg;
+ } ddog_TraceExporterError;
+ */
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct TraceExporterError
+ {
+ internal ErrorCode Code;
+ internal IntPtr Msg;
+
+ internal enum ErrorCode
+ {
+ AddressInUse = 0,
+ ConnectionAborted = 1,
+ ConnectionRefused = 2,
+ ConnectionReset = 3,
+ HttpBodyFormat = 4,
+ HttpBodyTooLong = 5,
+ HttpClient = 6,
+ HttpParse = 7,
+ HttpServer = 8,
+ HttpUnknown = 9,
+ HttpWrongStatus = 10,
+ InvalidArgument = 11,
+ InvalidData = 12,
+ InvalidInput = 13,
+ InvalidUrl = 14,
+ IoError = 15,
+ NetworkUnknown = 16,
+ Serde = 17,
+ TimedOut = 18,
+ }
+
+ public override string ToString()
+ {
+ return IntPtrExtension.ToUtf8String(Msg);
+ }
+ }
+
+ class IntPtrExtension
+ {
+ public static string ToUtf8String(IntPtr ptr)
+ {
+ if (ptr == IntPtr.Zero)
+ {
+ return string.Empty;
+ }
+
+ var len = 0;
+ while (Marshal.ReadByte(ptr, len) != 0)
+ {
+ len++;
+ }
+
+ if (len == 0)
+ {
+ return string.Empty;
+ }
+
+ var buffer = new byte[len];
+ Marshal.Copy(ptr, buffer, 0, buffer.Length);
+ return System.Text.Encoding.UTF8.GetString(buffer);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/nuget_package/nuget_package.csproj b/tests/nuget_package/nuget_package.csproj
new file mode 100644
index 000000000..679e0dd9d
--- /dev/null
+++ b/tests/nuget_package/nuget_package.csproj
@@ -0,0 +1,15 @@
+
+
+
+ Exe
+ net6.0
+ enable
+ enable
+ 8.0
+ disable
+
+
+
+
+
+
diff --git a/windows/README.md b/windows/README.md
new file mode 100644
index 000000000..5d521634c
--- /dev/null
+++ b/windows/README.md
@@ -0,0 +1,67 @@
+# libdatadog
+
+## About
+
+This package is binary distribution of [libdatadog](https://github.com/DataDog/libdatadog). It supports both native (C/C++) and .NET projects.
+
+## Getting started
+
+### Native (C/C++) projects
+
+For Native projects, `libdatadog` supports both static and dynamic linking. The dynamic linking is the default option. To use the static linking, you need to disable the dynamic linking by setting the msbuild property `LibDatadogDynamicLink` to `false`. Both `debug` and `release` congfiguration libraries are provided to allow better debugging experience.
+
+Depending on the target platform, binaries are compied to project output directory.
+
+### .NET projects
+
+For .NET projects, `libdatadog` supports only dynamic linking targetting .NET Standard 2.0.
+
+Depending on the target platform, binaries are copied to project output directory under `runtimes` directory as per [.NET conventions](https://learn.microsoft.com/en-us/nuget/create-packages/native-files-in-net-packages#native-assets) (`runtimes/{RID}/native`).
+
+> [!IMPORTANT]
+> `nuget` fails to resolve the shared library if same directory is not used in the nuget package and the project output directory. Hence, only `release` configuration is supported for .NET projects.
+
+## Package content
+
+```
+libdatadog.14.3.1-ci.771.90/
+├── build
+│ ├── native
+│ │ ├── lib
+│ │ │ ├── x64
+│ │ │ │ ├── debug
+│ │ │ │ │ ├── libdatadog win-x64 shared library and pdb (debug)
+│ │ │ │ │ └── static
+│ │ │ │ │ └── libdatadog win-x64 static library (debug)
+│ │ │ │ └── release
+│ │ │ │ ├── libdatadog win-x64 shared library and pdb (release)
+│ │ │ │ └── static
+│ │ │ │ └── libdatadog win-x64 static library (release)
+│ │ │ └── x86
+│ │ │ ├── debug
+│ │ │ │ ├── libdatadog win-x86 shared library and pdb (debug)
+│ │ │ │ └── static
+│ │ │ │ └── libdatadog win-x86 static library (debug)
+│ │ │ └── release
+│ │ │ ├── libdatadog win-x86 shared library and pdb (release)
+│ │ │ └── static
+│ │ │ └── libdatadog win-x86 static library (release)
+│ │ └── libdatadog.props
+│ └── netstandard2.0
+│ └── libdatadog.props
+├── include
+│ └── native
+│ └── datadog
+│ ├── C headers
+└── runtimes
+ ├── win-x64
+ │ └── native
+ │ └── libdatadog win-x64 shared library and pdb
+ └── win-x86
+ └── native
+ └── libdatadog win-x86 shared library and pdb
+```
+
+## License
+
+Apache-2.0
\ No newline at end of file
diff --git a/windows/build-artifacts.ps1 b/windows/build-artifacts.ps1
index a6d3b80dd..a7dbcca22 100644
--- a/windows/build-artifacts.ps1
+++ b/windows/build-artifacts.ps1
@@ -9,11 +9,17 @@ function Invoke-Call {
}
$output_dir = $args[0]
+$target = $args[1]
if ([string]::IsNullOrEmpty($output_dir)) {
throw "You must specify an output directory. Ex: $($myInvocation.InvocationName) my_rust_project/ bin"
}
+$targets = @("i686-pc-windows-msvc", "x86_64-pc-windows-msvc")
+if (![string]::IsNullOrEmpty($target)) {
+ $targets = @($target)
+}
+
if (![System.IO.Path]::IsPathRooted($output_dir)) {
$output_dir = [System.IO.Path]::Combine($(Get-Location), $output_dir)
}
@@ -32,10 +38,10 @@ $features = @(
Write-Host "Building for features: $features" -ForegroundColor Magenta
pushd profiling-ffi
-Invoke-Call -ScriptBlock { cargo build --features $features --target i686-pc-windows-msvc --release --target-dir $output_dir }
-Invoke-Call -ScriptBlock { cargo build --features $features --target i686-pc-windows-msvc --target-dir $output_dir }
-Invoke-Call -ScriptBlock { cargo build --features $features --target x86_64-pc-windows-msvc --release --target-dir $output_dir }
-Invoke-Call -ScriptBlock { cargo build --features $features --target x86_64-pc-windows-msvc --target-dir $output_dir }
+foreach ($target in $targets) {
+ Invoke-Call -ScriptBlock { cargo build --features $features --target $target --release --target-dir $output_dir }
+ Invoke-Call -ScriptBlock { cargo build --features $features --target $target --target-dir $output_dir }
+}
popd
Write-Host "Building tools" -ForegroundColor Magenta
diff --git a/windows/build-artifacts.sh b/windows/build-artifacts.sh
new file mode 100755
index 000000000..549651bd9
--- /dev/null
+++ b/windows/build-artifacts.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+# Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/
+# SPDX-License-Identifier: Apache-2.0
+
+set -e
+
+output_dir=$1
+target=$2
+
+if [ -z "$output_dir" ]; then
+ echo "You must specify an output directory. Ex: $0 my_rust_project/ bin"
+ exit 1
+fi
+
+targets=("i686-pc-windows-msvc" "x86_64-pc-windows-msvc")
+if [ -n "$target" ]; then
+ targets=("$target")
+fi
+
+if [[ "$output_dir" != /* ]]; then
+ output_dir=$(pwd)/"$output_dir"
+fi
+
+echo -e "Building project into $output_dir"
+
+features="data-pipeline-ffi,datadog-profiling-ffi/crashtracker-collector,datadog-profiling-ffi/crashtracker-receiver,datadog-profiling-ffi/ddtelemetry-ffi,datadog-profiling-ffi/demangler"
+
+echo -e "Building for features: $features"
+
+pushd profiling-ffi > /dev/null
+for target in "${targets[@]}"; do
+ cargo build --features "$features" --target "$target" --release --target-dir "$output_dir"
+ cargo build --features "$features" --target "$target" --target-dir "$output_dir"
+done
+popd > /dev/null
+
+echo -e "Building tools"
+cd tools
+cargo build --release
+cd ..
+
+echo -e "Generating headers"
+cbindgen --crate ddcommon-ffi --config ddcommon-ffi/cbindgen.toml --output "$output_dir/common.h"
+cbindgen --crate datadog-profiling-ffi --config profiling-ffi/cbindgen.toml --output "$output_dir/profiling.h"
+cbindgen --crate ddtelemetry-ffi --config ddtelemetry-ffi/cbindgen.toml --output "$output_dir/telemetry.h"
+cbindgen --crate data-pipeline-ffi --config data-pipeline-ffi/cbindgen.toml --output "$output_dir/data-pipeline.h"
+cbindgen --crate datadog-crashtracker-ffi --config crashtracker-ffi/cbindgen.toml --output "$output_dir/crashtracker.h"
+./target/release/dedup_headers "$output_dir/common.h" "$output_dir/profiling.h" "$output_dir/telemetry.h" "$output_dir/data-pipeline.h" "$output_dir/crashtracker.h"
+
+echo -e "Build finished"
diff --git a/windows/libdatadog.csproj b/windows/libdatadog.csproj
index 8de12382c..e3eaf9fcd 100644
--- a/windows/libdatadog.csproj
+++ b/windows/libdatadog.csproj
@@ -23,9 +23,10 @@
true
-
+
-
+
+
@@ -38,7 +39,7 @@
-
@@ -72,6 +73,42 @@
+ Pack="true" PackagePath="build\native\lib\x86\release\datadog_profiling_ffi.pdb" /> -->
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/windows/libdatadog.props b/windows/libdatadog.props
index 41474ea3c..4fcdf5cc5 100644
--- a/windows/libdatadog.props
+++ b/windows/libdatadog.props
@@ -50,4 +50,4 @@
Importance="high"
Condition="'@(FilesToDelete)' != ''" />
-
\ No newline at end of file
+
diff --git a/windows/netstandard2.0/libdatadog.props b/windows/netstandard2.0/libdatadog.props
new file mode 100644
index 000000000..d9e4740c8
--- /dev/null
+++ b/windows/netstandard2.0/libdatadog.props
@@ -0,0 +1,10 @@
+
+
+
+
+
+ runtimes\%(RecursiveDir)%(FileName)%(Extension)
+ PreserveNewest
+
+
+
\ No newline at end of file