diff --git a/CMakeLists.txt b/CMakeLists.txt index 5faef8e1..2afb5c81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,10 @@ endif() set(DD_ENABLE_SANITIZERS "${DD_ENABLE_SANITIZERS}" CACHE STRING "Comma-separated list of sanitizers to enable, e.g. 'ASan,UBSan', 'MSan,UBSan', 'TSan'") option(DD_ENABLE_ASSERTS "Enable assertions in Datadog SDK implementation" ${DD_DEVELOPMENT}) option(DD_ENABLE_TEST_ALLOCATION_TRACKING "Enable allocation tracking (via instrumented new/delete) in test binaries" ON) +option(DD_ENABLE_PROFILER "Enable integration with Datadog Windows Profiler" OFF) +if(DD_ENABLE_PROFILER AND NOT WIN32) + message(FATAL_ERROR "DD_ENABLE_PROFILER is only supported on Windows") +endif() # C API targets C99; C++ API targets C++17 if(DD_IS_TOP_LEVEL) @@ -57,9 +61,9 @@ if(DD_IS_TOP_LEVEL) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) - # Crashpad requires C++20, so building the SDK with crashpad support requires - # targeting C++20 - if(DD_CRASH_MODE STREQUAL "crashpad") + # Crashpad and dd-win-prof both require C++20, so building the SDK with either + # enabled requires targeting C++20 + if(DD_CRASH_MODE STREQUAL "crashpad" OR DD_ENABLE_PROFILER) set(CMAKE_CXX_STANDARD 20) endif() endif() diff --git a/cmake/DatadogConfig.cmake.in b/cmake/DatadogConfig.cmake.in index 4e4a12bf..74a33b5e 100644 --- a/cmake/DatadogConfig.cmake.in +++ b/cmake/DatadogConfig.cmake.in @@ -27,6 +27,10 @@ if(DATADOG_BUILT_WITH_DD_HTTP_USE_SYSTEM_LIBCURL) find_dependency(CURL REQUIRED) endif() +# If the SDK was built with profiler support, expose this to consumers so that +# datadog_enable() can invoke dd_win_prof_copy_runtime_deps() as needed +set(DATADOG_BUILT_WITH_DD_ENABLE_PROFILER @DD_ENABLE_PROFILER@) + # If the SDK was built with Crashpad support, include CrashpadConfig.cmake, ensuring # that crashpad::client and crashpad::handler targets are defined set(DATADOG_BUILT_WITH_DD_CRASH_MODE "@DD_CRASH_MODE@") diff --git a/cmake/DatadogConvenience.cmake b/cmake/DatadogConvenience.cmake index 6ec9fce1..1cd80c5c 100644 --- a/cmake/DatadogConvenience.cmake +++ b/cmake/DatadogConvenience.cmake @@ -39,18 +39,32 @@ function(datadog_enable target) message(FATAL_ERROR "datadog_enable(): target crashpad::handler does not exist") endif() endif() + + # If the SDK was built with profiler support, copy the required runtime DLLs + # (dd-win-prof.dll and datadog_profiling_ffi.dll) alongside the application + # binary so they can be found at runtime. + if(DD_ENABLE_PROFILER OR DATADOG_BUILT_WITH_DD_ENABLE_PROFILER) + if(COMMAND dd_win_prof_copy_runtime_deps) + dd_win_prof_copy_runtime_deps(${target}) + else() + message(FATAL_ERROR + "datadog_enable(): dd_win_prof_copy_runtime_deps is not available; " + "ensure dd-win-prof was fetched before calling datadog_enable()") + endif() + endif() endfunction() -# datadog_install(bin): +# datadog_install(destination): # -# - (if Crashpad support is enabled) ensures that the crashpad_handler executable will -# be copied to bin/ alongside your application +# Installs runtime dependencies required by the SDK alongside your application: +# - (if Crashpad support is enabled) copies the crashpad_handler executable +# - (if Profiler support is enabled) copies dd-win-prof.dll and datadog_profiling_ffi.dll # # Call this function after defining `install(TARGETS my-app ...)` for your app, -# specifying the destination directory for your application's binaries in lieu of `bin`. -# You may elect not to call this function if a.) your project does not use CMake -# installation rules, b.) you don't need Crashpad support, or c.) you are ensuring that -# the crashpad_handler exectuable makes its way into your builds through other means. +# specifying the destination directory for your application's binaries (typically "bin"). +# You may elect not to call this function if: a.) your project does not use CMake +# installation rules, b.) you don't need Crashpad or Profiler support, or c.) you are +# handling runtime dependencies through other means. # function(datadog_install destination) # If the SDK was built with crashpad support, install the crashpad_handler @@ -63,4 +77,30 @@ function(datadog_install destination) message(FATAL_ERROR "datadog_install(): target crashpad::handler does not exist") endif() endif() + + # If the SDK was built with profiler support, install the required runtime DLLs + # to the destination directory + if((DD_ENABLE_PROFILER) OR (DATADOG_BUILT_WITH_DD_ENABLE_PROFILER)) + if(TARGET dd-win-prof) + # Try to get imported location (for find_package case) + get_target_property(DD_WIN_PROF_DLL dd-win-prof IMPORTED_LOCATION) + + if(DD_WIN_PROF_DLL AND NOT DD_WIN_PROF_DLL MATCHES "-NOTFOUND$") + # Imported target case: install the DLL from its imported location + install(PROGRAMS ${DD_WIN_PROF_DLL} DESTINATION ${destination}) + + # Also install datadog_profiling_ffi.dll from the same directory + get_filename_component(DD_WIN_PROF_DIR ${DD_WIN_PROF_DLL} DIRECTORY) + install(PROGRAMS "${DD_WIN_PROF_DIR}/datadog_profiling_ffi.dll" DESTINATION ${destination}) + else() + # FetchContent case: use generator expressions to get target files + install(FILES "$" DESTINATION ${destination}) + if(TARGET libdatadog_dynamic) + install(FILES "$" DESTINATION ${destination}) + endif() + endif() + else() + message(FATAL_ERROR "datadog_install(): target dd-win-prof does not exist") + endif() + endif() endfunction() diff --git a/cmake/deps/catch2.cmake b/cmake/deps/catch2.cmake index 0b5208b8..222bd779 100644 --- a/cmake/deps/catch2.cmake +++ b/cmake/deps/catch2.cmake @@ -15,3 +15,11 @@ FetchContent_Declare( DOWNLOAD_EXTRACT_TIMESTAMP true ) FetchContent_MakeAvailable(Catch2) + +# Mark Catch2 includes as SYSTEM to suppress warnings from its headers +set_target_properties(Catch2 PROPERTIES + INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $ +) +set_target_properties(Catch2WithMain PROPERTIES + INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $ +) diff --git a/cmake/profiler.cmake b/cmake/profiler.cmake new file mode 100644 index 00000000..fe69d876 --- /dev/null +++ b/cmake/profiler.cmake @@ -0,0 +1,39 @@ +include(FetchContent) + +# Allow overriding the GitHub fetch with a local clone of dd-win-prof. When +# set, CMake skips the network fetch and uses the local source directory +# directly. +set(DD_WIN_PROF_SOURCE_DIR "" CACHE PATH + "Local path to dd-win-prof source tree (overrides GitHub fetch)") + +if(DD_WIN_PROF_SOURCE_DIR) + FetchContent_Declare( + dd-win-prof + SOURCE_DIR "${DD_WIN_PROF_SOURCE_DIR}" + ) +else() + FetchContent_Declare( + dd-win-prof + GIT_REPOSITORY https://github.com/DataDog/dd-win-prof.git + GIT_TAG aforsythe/cmake + ) +endif() + +FetchContent_MakeAvailable(dd-win-prof) + +# Link dd-win-prof into the SDK. For the time being, we don't wrap dd-win-prof in an SDK +# feature: the application is just expected to include dd-win-prof.h and call the +# profiling API directly. Therefore, it's declared as a PUBLIC dependency. +target_link_libraries(dd_native PUBLIC dd-win-prof) + +if(DD_BUILD_INSTALL) + # Install dd-win-prof.dll to bin/ so it ships alongside the SDK. Include it in + # the DatadogTargets export set since dd_native depends on it. + install(TARGETS dd-win-prof + EXPORT DatadogTargets + RUNTIME DESTINATION bin + ) + + # Install datadog_profiling_ffi.dll, which dd-win-prof.dll loads at runtime. + install(FILES "$" DESTINATION bin) +endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 74c55845..9046adb7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -234,3 +234,10 @@ if(DD_BUILD_INSTALL) RUNTIME DESTINATION bin ) endif() + +# If profiling support is enabled, fetch dd-win-prof and link it into the SDK. +# This must come after dd_native is fully configured so that the profiler module +# can read and modify its compile/link settings. +if(DD_ENABLE_PROFILER) + include(${DD_SDK_ROOT_DIR}/cmake/profiler.cmake) +endif() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e9818fa4..111fdf3d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -122,6 +122,11 @@ target_link_libraries(dd_native_tests Catch2::Catch2WithMain ) +# Suppress unreachable code warnings from Catch2 headers on MSVC +if(MSVC) + target_compile_options(dd_native_tests PRIVATE /wd4702) +endif() + # Register tests with CTest include(CTest) include(Catch)