diff --git a/Cargo.lock b/Cargo.lock index 6a7065dfc0..5ace1f51bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -764,6 +764,7 @@ dependencies = [ "build_common", "cmake", "pico-args", + "regex", "serde", "tar", "toml", diff --git a/builder/Cargo.toml b/builder/Cargo.toml index fbbfe6a6b2..264e4c8599 100644 --- a/builder/Cargo.toml +++ b/builder/Cargo.toml @@ -44,6 +44,7 @@ tar = "0.4.41" tools = { path = "../tools" } toml = "0.8.19" serde = "1.0.209" +regex = "1.10" [[bin]] name = "release" diff --git a/builder/src/common.rs b/builder/src/common.rs index f778b51600..a9d3cb1eed 100644 --- a/builder/src/common.rs +++ b/builder/src/common.rs @@ -3,9 +3,8 @@ use crate::arch; use crate::module::Module; -use crate::utils::project_root; +use crate::utils::{adjust_extern_symbols, project_root}; use anyhow::Result; -use std::fs; use std::path::PathBuf; use std::process::Command; use std::rc::Rc; @@ -41,7 +40,8 @@ impl Module for Common { let target_path: PathBuf = [self.target_include.as_ref(), "common.h"].iter().collect(); let origin_path: PathBuf = [self.source_include.as_ref(), "common.h"].iter().collect(); - fs::copy(origin_path, target_path).expect("Failed to copy common.h"); + adjust_extern_symbols(&origin_path, &target_path).expect("Failed to adjust extern symbols"); + Ok(()) } } diff --git a/builder/src/crashtracker.rs b/builder/src/crashtracker.rs index 45737829e8..7bb5a45570 100644 --- a/builder/src/crashtracker.rs +++ b/builder/src/crashtracker.rs @@ -3,7 +3,7 @@ use crate::arch; use crate::module::Module; -use crate::utils::project_root; +use crate::utils::{adjust_extern_symbols, project_root}; use anyhow::Result; use std::fs; use std::path::PathBuf; @@ -106,7 +106,8 @@ impl CrashTracker { .collect(); let headers = vec![target_path.to_str().unwrap()]; - fs::copy(origin_path, &target_path).expect("Failed to copy crashtracker.h"); + adjust_extern_symbols(&origin_path, &target_path) + .expect("Failed to adjust extern symbols for crashtracker.h"); dedup_headers(self.base_header.as_ref(), &headers); diff --git a/builder/src/profiling.rs b/builder/src/profiling.rs index a2b3f7fa35..77a190bc1f 100644 --- a/builder/src/profiling.rs +++ b/builder/src/profiling.rs @@ -3,7 +3,7 @@ use crate::arch; use crate::module::Module; -use crate::utils::{file_replace, project_root}; +use crate::utils::{adjust_extern_symbols, file_replace, project_root}; use anyhow::Result; use serde::Deserialize; use std::ffi::OsStr; @@ -67,7 +67,8 @@ impl Profiling { for header in &headers { origin_path.set_file_name(header); target_path.set_file_name(header); - fs::copy(&origin_path, &target_path).expect("Failed to copy the header"); + adjust_extern_symbols(&origin_path, &target_path) + .expect("Failed to adjust extern symbols"); // Exclude blazesym header from deduplication if !target_path.to_str().unwrap().contains("blazesym.h") { diff --git a/builder/src/utils.rs b/builder/src/utils.rs index 89200fb022..6b9bca2445 100644 --- a/builder/src/utils.rs +++ b/builder/src/utils.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use anyhow::{anyhow, Result}; +use regex::Regex; use std::fs::{self, OpenOptions}; use std::io::Write; use std::path::{Path, PathBuf}; @@ -26,3 +27,37 @@ pub fn project_root() -> PathBuf { .unwrap() .to_path_buf() } + +pub(crate) fn adjust_extern_symbols( + file_in: impl AsRef, + file_out: impl AsRef, +) -> Result<()> { + let content = fs::read_to_string(file_in)?; + let re = Regex::new(r#"(?m)^(\s*)extern\s+(.+;)$"#).unwrap(); + + // Replace function using captures + let new_content = re.replace_all(&content, |caps: ®ex::Captures| { + let full_match = caps.get(0).unwrap().as_str(); + let indent = &caps[1]; + let declaration = &caps[2]; + + // Skip if it's extern "C", already has LIBDD_DLLIMPORT, or contains '(' (function) + if full_match.contains("extern \"C\"") + || full_match.contains("LIBDD_DLLIMPORT") + || full_match.contains('(') + { + return full_match.to_string(); + } + + // Keep indent + "extern " + "LIBDD_DLL_IMPORT " + declaration + format!("{}extern LIBDD_DLLIMPORT {}", indent, declaration) + }); + + let mut file = OpenOptions::new() + .write(true) + .truncate(true) + .create(true) + .open(file_out)?; + file.write_all(new_content.as_bytes()) + .map_err(|err| anyhow!("failed to write file: {}", err)) +} diff --git a/libdd-common-ffi/cbindgen.toml b/libdd-common-ffi/cbindgen.toml index 02c4fc6449..a5bef244de 100644 --- a/libdd-common-ffi/cbindgen.toml +++ b/libdd-common-ffi/cbindgen.toml @@ -42,6 +42,12 @@ after_includes = """ # define DDOG_CHECK_RETURN __attribute__((__warn_unused_result__)) #else # define DDOG_CHECK_RETURN +#endif + +#ifdef _WIN32 +#define LIBDD_DLLIMPORT __declspec(dllimport) +#else +#define LIBDD_DLLIMPORT #endif""" [export] diff --git a/windows/build-artifacts.ps1 b/windows/build-artifacts.ps1 index 551d68815c..90a64dbef6 100644 --- a/windows/build-artifacts.ps1 +++ b/windows/build-artifacts.ps1 @@ -8,6 +8,23 @@ function Invoke-Call { } } +function Add-DllImportToGlobals { + param ( + [string]$HeaderPath + ) + $content = [System.IO.File]::ReadAllText($HeaderPath) + $pattern = '(?m)^(\s*)extern\s+(?!\"C\")(?!.*LIBDD_DLLIMPORT)(?!.*\()(.+;)$' + $updated = [System.Text.RegularExpressions.Regex]::Replace( + $content, + $pattern, + '$1extern LIBDD_DLLIMPORT $2' + ) + if ($updated -ne $content) { + $utf8NoBom = New-Object System.Text.UTF8Encoding($false) + [System.IO.File]::WriteAllText($HeaderPath, $updated, $utf8NoBom) + } +} + $output_dir = $args[0] if ([string]::IsNullOrEmpty($output_dir)) { @@ -61,6 +78,12 @@ Invoke-Call -ScriptBlock { cbindgen --crate libdd-telemetry-ffi --config libdd-t Invoke-Call -ScriptBlock { cbindgen --crate libdd-data-pipeline-ffi --config libdd-data-pipeline-ffi/cbindgen.toml --output $output_dir"\data-pipeline.h" } Invoke-Call -ScriptBlock { cbindgen --crate libdd-crashtracker-ffi --config libdd-crashtracker-ffi/cbindgen.toml --output $output_dir"\crashtracker.h" } Invoke-Call -ScriptBlock { cbindgen --crate libdd-library-config-ffi --config libdd-library-config-ffi/cbindgen.toml --output $output_dir"\library-config.h" } +Add-DllImportToGlobals $output_dir"\common.h" +Add-DllImportToGlobals $output_dir"\profiling.h" +Add-DllImportToGlobals $output_dir"\telemetry.h" +Add-DllImportToGlobals $output_dir"\data-pipeline.h" +Add-DllImportToGlobals $output_dir"\crashtracker.h" +Add-DllImportToGlobals $output_dir"\library-config.h" Invoke-Call -ScriptBlock { .\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" $output_dir"\library-config.h"} Write-Host "Build finished" -ForegroundColor Magenta