Repository: DynamoRIO/dynamorio (2025-07-22T01:40:04Z)

Issue:
drmemtrace tracer libraries not exported
The analyzer libraries are all exported, and we have a test of that.
But the drmemtrace{,_static} libraries are not exported.
This was hit by a user: https://groups.google.com/g/dynamorio-users/c/kZHTGiIUn8Y/m/rSurDOWeAQAJ
Adding to our build-and-test test reproduces:
```
$ ctest -V -R drmemtrace_proj
<...>
30: Run Build Command(s): /usr/bin/ninja
30: [1/4] Building CXX object CMakeFiles/burst_separate.dir/burst_static.cpp.o
30: [2/4] Linking CXX executable burst_separate
30: FAILED: burst_separate
30: : && /usr/bin/c++ -g -Wl,--as-needed -rdynamic  -Wl,--dependency-file=CMakeFiles/burst_separate.dir/link.d CMakeFiles/burst_separate.dir/burst_static.cpp.o -o burst_separate  /.../dr/git/build_x64_dbg_tests/lib64/debug/libdynamorio_static.a  -Wl,--whole-archive  -ldrmemtrace_static  -Wl,--no-whole-archive  /.../dr/git/build_x64_dbg_tests/lib64/libdrlibc.a  -ldl && :
30: /usr/bin/ld: cannot find -ldrmemtrace_static: No such file or directory
30: collect2: error: ld returned 1 exit status
30: [3/4] Building CXX object CMakeFiles/analyzer_separate.dir/analyzer_separate.cpp.o
30: ninja: build stopped: subcommand failed.
30:
1/1 Test #30: drmemtrace_proj ..................***Failed    1.02 sec
```



Discussion:
I had to remove this from DynamoRIOConfig.cmake.in:
```
# Not really an extension, just for including drmemtrace.h
# via use_DynamoRIO_extension(target, drmemtrace_static)
set(DynamoRIO_EXT_drmemtrace_static_NOLIB ON)
```
Should use_DynamoRIO_drmemtrace_tracer() instead so I think that's
no longer needed.

I had to also copy libelftc.a to ext/lib/debug/ in build dir (already there
in install dir).

Now drmemtrace_proj works, and it runs:
```
$ ./clients/drcachesim/tests/build_and_test/burst_separate

$ ls  -lt | head
total 7508
drwxr-x--- 26 bruening primarygroup   16384 Jul 21 18:33 ./
drwxr-x---  3 bruening primarygroup    4096 Jul 21 18:33 drmemtrace.burst_separate.603408.0394.dir/
drwxr-x---  3 bruening primarygroup    4096 Jul 21 18:33 drmemtrace.burst_separate.603408.0190.dir/
drwxr-x---  3 bruening primarygroup    4096 Jul 21 18:33 drmemtrace.burst_separate.603408.2922.dir/
-rw-r--r--  1 bruening primarygroup  278902 Jul 21 18:33 .ninja_log
-rw-r-----  1 bruening primarygroup 2366016 Jul 21 18:33 .ninja_deps
drwxr-x---  2 bruening primarygroup    4096 Jul 21 18:32 bin64/
drwxr-x--- 20 bruening primarygroup    4096 Jul 21 18:32 ext/
-rw-r--r--  1 bruening primarygroup 4388475 Jul 21 18:32 build.ninja
```




Patch:
diff --git a/clients/drcachesim/CMakeLists.txt b/clients/drcachesim/CMakeLists.txt
index cf0fbf9396b..724998839ff 100644
--- a/clients/drcachesim/CMakeLists.txt
+++ b/clients/drcachesim/CMakeLists.txt
@@ -581,7 +581,8 @@ macro(add_drmemtrace name type static_DR no_main)
     target_link_libraries(${name} atomic)
   endif ()
   add_dependencies(${name} api_headers)
-  install_target(${name} ${INSTALL_CLIENTS_LIB})
+  DR_export_target(${name})
+  install_exported_target(${name} ${INSTALL_CLIENTS_LIB})
 endmacro()
 
 add_drmemtrace(drmemtrace SHARED OFF OFF)
diff --git a/ext/drsyms/CMakeLists.txt b/ext/drsyms/CMakeLists.txt
index 7531ac9e4cf..797500ec871 100644
--- a/ext/drsyms/CMakeLists.txt
+++ b/ext/drsyms/CMakeLists.txt
@@ -332,17 +332,20 @@ if (NOT USE_ELFUTILS)
   set_property(TARGET dwarf PROPERTY IMPORTED_LOCATION "${dwarf_libpath}")
   target_link_libraries(drsyms_static dwarf)
   target_link_libraries(drsyms_drstatic dwarf)
+  file(COPY "${dwarf_libpath}" DESTINATION ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
   if (LINUX)
     add_library(elf STATIC IMPORTED)
     set_property(TARGET elf PROPERTY IMPORTED_LOCATION "${elf_libpath}")
     target_link_libraries(drsyms_static elf)
     target_link_libraries(drsyms_drstatic elf)
+    file(COPY "${elf_libpath}" DESTINATION ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
   endif (LINUX)
 endif ()
 add_library(elftc STATIC IMPORTED)
 set_property(TARGET elftc PROPERTY IMPORTED_LOCATION "${elftc_libpath}")
 target_link_libraries(drsyms_static elftc)
 target_link_libraries(drsyms_drstatic elftc)
+file(COPY "${elftc_libpath}" DESTINATION ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
 if (UNIX)
   # Avoid missing symbols in static library build from g++ libs when
   # drsyms_bench is linked with gcc instead of g++ (i#715, happens w/ cmake
diff --git a/make/DynamoRIOConfig.cmake.in b/make/DynamoRIOConfig.cmake.in
index 95e0e673247..b04a1983675 100644
--- a/make/DynamoRIOConfig.cmake.in
+++ b/make/DynamoRIOConfig.cmake.in
@@ -1,5 +1,5 @@
 # **********************************************************
-# Copyright (c) 2010-2021 Google, Inc.    All rights reserved.
+# Copyright (c) 2010-2025 Google, Inc.    All rights reserved.
 # Copyright (c) 2009-2010 VMware, Inc.    All rights reserved.
 # **********************************************************
 
@@ -1182,9 +1182,6 @@ endfunction (get_DynamoRIO_defines)
 set(DynamoRIO_EXT_drgui_NOLIB ON)
 set(DynamoRIO_EXT_droption_NOLIB ON)
 set(DynamoRIO_EXT_droption_INC ${DynamoRIO_cwd}/../ext/include)
-# Not really an extension, just for including drmemtrace.h
-# via use_DynamoRIO_extension(target, drmemtrace_static)
-set(DynamoRIO_EXT_drmemtrace_static_NOLIB ON)
 
 # DynamoRIO Extensions
 # Failure to call this in your client CMakeLists.txt when using an extension like
diff --git a/make/utils_exposed.cmake b/make/utils_exposed.cmake
index cc3ebcb7645..7c09e9c773a 100644
--- a/make/utils_exposed.cmake
+++ b/make/utils_exposed.cmake
@@ -1,5 +1,5 @@
 ## **********************************************************
-## Copyright (c) 2012-2021 Google, Inc.    All rights reserved.
+## Copyright (c) 2012-2025 Google, Inc.    All rights reserved.
 ## **********************************************************
 ##
 ## Redistribution and use in source and binary forms, with or without
@@ -290,7 +290,7 @@ function(DynamoRIO_force_static_link target lib)
     else ()
       set(incname "_dr_client_main")
     endif ()
-    append_property_string(TARGET ${target} LINK_FLAGS "/include:${incname}")
+    _DR_append_property_string(TARGET ${target} LINK_FLAGS "/include:${incname}")
   endif ()
 endfunction(DynamoRIO_force_static_link)
 


Test patch:
diff --git a/clients/drcachesim/tests/CMakeLists.txt b/clients/drcachesim/tests/CMakeLists.txt
index d68413bb0af..86bf232ba58 100644
--- a/clients/drcachesim/tests/CMakeLists.txt
+++ b/clients/drcachesim/tests/CMakeLists.txt
@@ -56,3 +56,11 @@ use_DynamoRIO_extension(analyzer_separate droption) # for droption.h
 use_DynamoRIO_drmemtrace(analyzer_separate) # for analysis framework headers
 target_link_libraries(analyzer_separate drmemtrace_analyzer drmemtrace_histogram
   drfrontendlib)
+
+# Test drmemtrace_static.
+if (UNIX) # XXX i#7560: Windows link errors remain but we don't have time to solve.
+  add_executable(burst_separate burst_static.cpp)
+  set_property(SOURCE burst_static.cpp APPEND PROPERTY COMPILE_DEFINITIONS "DEFINE_MAIN")
+  configure_DynamoRIO_static(burst_separate)
+  use_DynamoRIO_static_client(burst_separate drmemtrace_static)
+endif ()
diff --git a/clients/drcachesim/tests/burst_static.cpp b/clients/drcachesim/tests/burst_static.cpp
index 058beda71fa..e2aab9e77a1 100644
--- a/clients/drcachesim/tests/burst_static.cpp
+++ b/clients/drcachesim/tests/burst_static.cpp
@@ -138,3 +138,12 @@ dr_client_main(client_id_t id, int argc, const char *argv[])
 
 } // namespace drmemtrace
 } // namespace dynamorio
+
+// Used by our build-and-test to test external use (where there's no test_helpers).
+#ifdef DEFINE_MAIN
+int
+main(int argc, const char *argv[])
+{
+    return dynamorio::drmemtrace::test_main(argc, argv);
+}
+#endif