I am developing a set of practices to facilitate commonality in our projects. One of them, to facilitate unit tests, is that for a given executable, all the sources except for “main” should be in a “library” (OBJECT library is fine). This makes it easier to write unit tests in a sub-directory without awkward cross-directory references.
The basic construct looks like this:
set(myTarget foo) # for the "foo" executable
set(myDepend ${myTarget}Lib) # testable sources
add_library( ${myDepend} OBJECT ... )
add_executable( ${myTarget} ... )
target_link_libraries( ${myTarget} ${myDepend} ...)
To facilitate this pattern, I’ve created a macro in the top-level CMakeLists.txt:
macro( DeclProg target )
set( myTarget ${target} )
set( myDepend ${myTarget}Lib )
add_library( ${myDepend} OBJECT )
add_executable( ${myTarget} )
target_link_libraries( ${myTarget} PRIVATE {$myDepend} )
endmacro()
Then, in the “foo/CMakeLists.txt”, I just do
DeclProg( foo )
target_sources( ${myDepend} PUBLIC foo1.cc )
target_sources( ${myTarget} PRIVATE main.cc )
# as needed
target_link_libraries( ${myDepend} PUBLIC
#any libraries needed
)
Unfortunately, this is causing linker errors with multiple definitions of code. Running make VERBOSE=1
I can see this link line (line breaks added for readability):
c++ -g "CMakeFiles/foo.dir/main.cpp.o"
"CMakeFiles/foo.dir/foo1.cpp.o"
"CMakeFiles/foo.dir/foo1.cpp.o"
CMakeFiles/foo.dir/cmake_device_link.o
-o foo
-L/usr/local/cuda/targets/x86_64-linux/lib <elided various libraries>
Why is foo1.cpp.o
being listed twice on the link line?
CMake: 3.26.1
RHEL 9
gcc 12.2.1
CUDA 12.1.0 (the cuda code is in static libraries, which triggers the cmake_device_link.o
file)