I've compiled a c++ dynamic library using cmake and I want to add to my iOS app. But the header file directory of this .framework is empty, I refer to the CMakeFiles written in the cmake documentation. I don't know where the problem is?
Any help would be greatly appreciated.
Here is my CMake script
cmake_minimum_required(VERSION 3.2)
project(Xml C CXX)
set(CMAKE_SYSTEM_NAME Darwin)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(HEADERS
./include
)
include_directories(
${HEADERS}
)
aux_source_directory(. DIR_SRCS)
add_library(Xml SHARED
${DIR_SRCS}
${HEADERS}
)
set_target_properties(Xml PROPERTIES
FRAMEWORK TRUE
FRAMEWORK_VERSION CXX
PUBLIC_HEADER ${HEADERS}
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer"
)
Compilation progress
Scanning dependencies of target Xml
[ 10%] Building CXX object CMakeFiles/Xml.dir/ILock.cpp.o
[ 20%] Building CXX object CMakeFiles/Xml.dir/ParamSet.cpp.o
[ 30%] Building CXX object CMakeFiles/Xml.dir/StringConvert.cpp.o
[ 40%] Building CXX object CMakeFiles/Xml.dir/XmlFile.cpp.o
[ 50%] Building CXX object CMakeFiles/Xml.dir/XmlInterface.cpp.o
[ 60%] Building CXX object CMakeFiles/Xml.dir/tinystr.cpp.o
[ 70%] Building CXX object CMakeFiles/Xml.dir/tinyxml.cpp.o
[ 80%] Building CXX object CMakeFiles/Xml.dir/tinyxmlerror.cpp.o
[ 90%] Building CXX object CMakeFiles/Xml.dir/tinyxmlparser.cpp.o
[100%] Linking CXX shared library Xml.framework/Xml
Copying OS X content Xml.framework/Versions/CXX/Headers/include
[100%] Built target Xml
Compiled dynamic library
The issue is solved. CMake can't get all header files with the ./include syntax. The following is a modified CMake script.
set(HEADERS
./include/a.h
./include/b.h
./include/c.h
)
include_directories(
./include
)
aux_source_directory(. DIR_SRCS)
add_library(Xml SHARED
${DIR_SRCS}
${HEADERS}
)
set_target_properties(Xml PROPERTIES
FRAMEWORK TRUE
PUBLIC_HEADER "${HEADERS}"
)
Related
Hello and thanks in advance for the help,
I have a linking issue with my cmake that I don't get. I'm trying to include a shared lib(modbuspp) in submodule which require another shared lib(libmodbus) on my computer. It seem simple but during exec linking it give me undefined reference to my computer lib (libmodbus) when I did add the includes. Does anyone has an idea why ? Here is my Cmake:
cmake_minimum_required(VERSION 3.10)
set(CMAKE_BUILD_TYPE Release)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(This test)
project(${This} VERSION "0.1.0")
configure_file("${PROJECT_SOURCE_DIR}/src/config.h.in" "${PROJECT_SOURCE_DIR}/src/config.h")
#enable_testing()
#add_subdirectory(googletest)
#add_subdirectory(test)
file(GLOB Sources
"src/*.hpp"
"src/*.cpp"
)
add_executable(${This} ${Sources})
find_package(nlohmann_json 3.2.0 REQUIRED)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
find_package(Modbus REQUIRED)
message(TROLOLO:${MODBUS_INCLUDE_DIRS})
include_directories(${MODBUS_INCLUDE_DIRS})
#target_include_directories(${This} PRIVATE ${MODBUS_INCLUDE_DIRS})
#work on libmodbuspp exemple "-shared -fPIC -pthread -I/usr/local/include -I/usr/include/modbus -L/usr/local/lib -lmodbuspp -lmodbus"
#Configure: cmake -DMODBUSPP_USE_EXTERNAL_JSON=ON -DMODBUSPP_WITH_STATIC=1 -DINSTALL_LIB_DIR=libs -DMODBUSPP_UNIT_TESTS=0 -S . -B build
add_subdirectory(external/libmodbuspp)
include_directories(external/libmodbuspp/include)
#target_include_directories(${This} PRIVATE external/libmodbuspp/include)
link_directories(${This} PRIVATE ${PROJECT_BINARY_DIR}/external/libmodbuspp/lib)
target_link_libraries(${This} PRIVATE ${MODBUS_LIBRARIES} modbuspp-shared)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
target_link_libraries(${This} PUBLIC Threads::Threads)
And here are the compile error:
Scanning dependencies of target objlib
[ 4%] Building CXX object external/libmodbuspp/lib/CMakeFiles/objlib.dir/__/src/bufferedslave.cpp.o
[ 9%] Building CXX object external/libmodbuspp/lib/CMakeFiles/objlib.dir/__/src/device.cpp.o
[ 14%] Building CXX object external/libmodbuspp/lib/CMakeFiles/objlib.dir/__/src/master.cpp.o
[ 19%] Building CXX object external/libmodbuspp/lib/CMakeFiles/objlib.dir/__/src/message.cpp.o
[ 23%] Building CXX object external/libmodbuspp/lib/CMakeFiles/objlib.dir/__/src/netlayer.cpp.o
[ 28%] Building CXX object external/libmodbuspp/lib/CMakeFiles/objlib.dir/__/src/request.cpp.o
[ 33%] Building CXX object external/libmodbuspp/lib/CMakeFiles/objlib.dir/__/src/response.cpp.o
[ 38%] Building CXX object external/libmodbuspp/lib/CMakeFiles/objlib.dir/__/src/router.cpp.o
[ 42%] Building CXX object external/libmodbuspp/lib/CMakeFiles/objlib.dir/__/src/rtulayer.cpp.o
[ 47%] Building CXX object external/libmodbuspp/lib/CMakeFiles/objlib.dir/__/src/server.cpp.o
/home/aurelia/git/test/external/libmodbuspp/src/server.cpp: In static member function ‘static void* Modbus::Server::Private::loop(std::future<void>, Modbus::Server::Private*)’:
/home/aurelia/git/test/external/libmodbuspp/src/server.cpp:434:3: warning: no return statement in function returning non-void [-Wreturn-type]
434 | }
| ^
[ 52%] Building CXX object external/libmodbuspp/lib/CMakeFiles/objlib.dir/__/src/slave.cpp.o
[ 57%] Building CXX object external/libmodbuspp/lib/CMakeFiles/objlib.dir/__/src/tcplayer.cpp.o
[ 61%] Building CXX object external/libmodbuspp/lib/CMakeFiles/objlib.dir/__/src/timeout.cpp.o
[ 61%] Built target objlib
Scanning dependencies of target modbuspp-shared
[ 66%] Linking CXX shared library libmodbuspp.so
[ 66%] Built target modbuspp-shared
Scanning dependencies of target test
[ 71%] Building CXX object CMakeFiles/test.dir/src/StaticDI.cpp.o
[ 76%] Building CXX object CMakeFiles/test.dir/src/StaticDO.cpp.o
[ 80%] Building CXX object CMakeFiles/test.dir/src/conf.cpp.o
[ 85%] Building CXX object CMakeFiles/test.dir/src/main.cpp.o
[ 90%] Building CXX object CMakeFiles/test.dir/src/modbusServer.cpp.o
[ 95%] Linking CXX executable test
/usr/bin/ld: external/libmodbuspp/lib/libmodbuspp.so.1.0.0: undefined reference to `modbus_rtu_set_rts_delay'
/usr/bin/ld: external/libmodbuspp/lib/libmodbuspp.so.1.0.0: undefined reference to `modbus_get_byte_timeout'
/usr/bin/ld: external/libmodbuspp/lib/libmodbuspp.so.1.0.0: undefined reference to `modbus_rtu_get_rts'
/usr/bin/ld: external/libmodbuspp/lib/libmodbuspp.so.1.0.0: undefined reference to `modbus_close'
/usr/bin/ld: external/libmodbuspp/lib/libmodbuspp.so.1.0.0: undefined reference to `modbus_mapping_free'
/usr/bin/ld: external/libmodbuspp/lib/libmodbuspp.so.1.0.0: undefined reference to `modbus_set_indication_time
But all those reference can be found in the include that was linked with include_directories :
/usr/include/modbus$ grep rtu_set_rts_delay ./*
./modbus-rtu.h:MODBUS_API int modbus_rtu_set_rts_delay(modbus_t *ctx, int us);
Let's take a real example - I have two native android lib modules (CMake). First module name is - libtetdecoder (further here - A) and another one is - libtetplayer(further here - B). So, lib A use opencv and lib B use lib A. Then, opencv is shared lib and it means that in order to make it work in lib A I need to include headers as well as .so files.
I do it in CMakeList.txt this way
...
include_directories(${pathToOpenCv}/sdk/native/jni/include)
add_library(lib_opencv SHARED IMPORTED)
set_target_properties(lib_opencv PROPERTIES IMPORTED_LOCATION
${pathToOpenCv}/sdk/native/libs/${CMAKE_ANDROID_ARCH_ABI}/libopencv_java3.so)
...
As I told above lib B use lib A (but not opencv), so chain looks like this B -> A -> opencv(shared). Question is - if I need in this case include opencv configuration(CMake) in lib B? Because as far as I understood if lib B is going to use lib A, so it means that lib B should implement all the dependencies the same as lib A.
Why I ask, because today I have this implementation in lib A and B, if I try to clean up lib B CMakeList.txt and remove opencv config line it doesn't work.
So, question is - if I really need to include this opencv dependency in all derivative libs?
If you are linking it all via target_link_libraries and link them PUBLICly, dependencies should be transitive, look here.
Directory structure:
- src
-- CMakeLists.txt
-- ecu.cpp
-- engine_ecu.cpp
-- ...
- test
-- CMakeLists.txt
-- integration_test.cpp
src/CMakeLists.txt:
project(EngineController)
add_library(Lib1 SHARED
ecu.cpp
)
add_library(Lib2 SHARED
engine_ecu.cpp
load_detector.cpp
math_helper.cpp
temperature_sensor.cpp
)
target_link_libraries(Lib1
PUBLIC
EngineControllerApi
)
target_link_libraries(Lib2
PUBLIC
EngineControllerApi
Lib1
)
test/CMakeLists.txt:
project(EngineControllerTest)
add_executable(${PROJECT_NAME}
integration_test.cpp
)
target_link_libraries(${PROJECT_NAME}
PUBLIC
Lib2
)
yields the following:
-- Build files have been written to: /diaggen/example/engine_controller/build
[ 11%] Building CXX object src/CMakeFiles/Lib1.dir/ecu.cpp.o
[ 22%] Linking CXX shared library libLib1.so
[ 22%] Built target Lib1
[ 33%] Building CXX object src/CMakeFiles/Lib2.dir/engine_ecu.cpp.o
[ 44%] Building CXX object src/CMakeFiles/Lib2.dir/load_detector.cpp.o
[ 55%] Building CXX object src/CMakeFiles/Lib2.dir/math_helper.cpp.o
[ 66%] Building CXX object src/CMakeFiles/Lib2.dir/temperature_sensor.cpp.o
[ 77%] Linking CXX shared library libLib2.so
[ 77%] Built target Lib2
[ 88%] Building CXX object test/CMakeFiles/EngineControllerTest.dir/integration_test.cpp.o
[100%] Linking CXX executable EngineControllerTest
[100%] Built target EngineControllerTest
I believe CMake should figure it out. First of all, make sure that you call find_package prior to referencing OpenCV at all. I believe that you could stick to target_link_libraries without having to alter PROPERTIES the way you do. Under the hood, I believe that target_link_libraries also modifies some PROPERTIES, but I believe it's much clearer this way.
I've been writing a compiler using LLVM as the backend. The CMake files I've written so far have worked on Linux, but I haven't had any luck on Windows. The project is split into a library and "driver" executable with their own CMakeLists.txt in separate subdirectories.
The top level CMakeLists.txt looks like this:
cmake_minimum_required (VERSION 3.7.0)
project (compiler)
set (CMAKE_CXX_STANDARD 14)
set (CMAKE_CXX_STANDARD_REQUIRED ON)
set (CMAKE_CXX_EXTENSIONS OFF)
find_package (LLVM REQUIRED CONFIG)
message (STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message (STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
include_directories (${LLVM_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS})
add_subdirectory (Compiler_Lib)
add_subdirectory (Compiler_exe)
The CMakeLists.txt for the library:
cmake_minimum_required (VERSION 3.7.0)
add_library (compiler_lib
AST.cpp
AST.h
parser.cpp
parser.h
scanner.cpp
scanner.h
token.cpp
token.h
visualizer.cpp
visualizer.h
codegen.cpp
codegen.h)
target_include_directories (compiler_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(compiler_lib LLVM)
And the CMakeLists.txt for the executable (which is where linking to the libraries fails):
cmake_minimum_required (VERSION 3.7.0)
project (compiler_exe)
add_executable (compiler_exe Compiler_exe.cpp getopt.h getopt.cpp)
target_link_libraries (compiler_exe LINK_PUBLIC LLVM compiler_lib)
I run the command "c:\Program Files\CMake\bin\cmake.exe" .. -G"MinGW Makefiles" -DCMAKE_PREFIX_PATH=C:\Users\James\llvm+clang-7.0.0-win64-msvc-release where C:\Users\James\llvm+clang-7.0.0-win64-msvc-release is the path to prebuilt LLVM libraries. However, running mingw32-make afterwards fails with the output
Scanning dependencies of target compiler_lib
[ 10%] Building CXX object Compiler_Lib/CMakeFiles/compiler_lib.dir/AST.cpp.obj
[ 20%] Building CXX object Compiler_Lib/CMakeFiles/compiler_lib.dir/parser.cpp.obj
[ 30%] Building CXX object Compiler_Lib/CMakeFiles/compiler_lib.dir/scanner.cpp.obj
[ 40%] Building CXX object Compiler_Lib/CMakeFiles/compiler_lib.dir/token.cpp.obj
[ 50%] Building CXX object Compiler_Lib/CMakeFiles/compiler_lib.dir/visualizer.cpp.obj
[ 60%] Building CXX object Compiler_Lib/CMakeFiles/compiler_lib.dir/codegen.cpp.obj
[ 70%] Linking CXX static library libcompiler_lib.a
[ 70%] Built target compiler_lib
Scanning dependencies of target compiler_exe
[ 80%] Building CXX object Compiler_exe/CMakeFiles/compiler_exe.dir/Compiler_exe.cpp.obj
[ 90%] Building CXX object Compiler_exe/CMakeFiles/compiler_exe.dir/getopt.cpp.obj
[100%] Linking CXX executable compiler_exe.exe
c:/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../../mingw32/bin/ld.exe: cannot find -lLLVM
collect2.exe: error: ld returned 1 exit status
Compiler_exe\CMakeFiles\compiler_exe.dir\build.make:102: recipe for target 'Compiler_exe/compiler_exe.exe' failed
mingw32-make[2]: *** [Compiler_exe/compiler_exe.exe] Error 1
CMakeFiles\Makefile2:176: recipe for target 'Compiler_exe/CMakeFiles/compiler_exe.dir/all' failed
mingw32-make[1]: *** [Compiler_exe/CMakeFiles/compiler_exe.dir/all] Error 2
Makefile:82: recipe for target 'all' failed
mingw32-make: *** [all] Error 2
This is the first time I've used CMake so I could have missed something obvious, but as I say it seems to work on Linux.
For the linking to succeed two things need to be true:
1) the file libLLVM.a needs to exist
2) that file has to be in a directory in the library search path
There should be a way to get cmake to tell you the list of places it searches for libraries, and you need to find a way to get wherever libLLVM.a exists into that list of dirs.
Apologies for the partial answer, but that's the troubleshooting path...
I am trying to use / learn CMake to embed Python into a C++ application that uses Qt.
I am using FIND_PACKAGE in an attempt to get a non-system package installation (Anaconda Python 2.7.9) in. I can not get the compiler to see any version other than the system installation (version 2.7.5).
My CMakeLists.txt is:
#Minimum CMAKE version
CMAKE_MINIMUM_REQUIRED(VERSION 3.0)
#Name the project
PROJECT(embedpython)
#Set the version number
SET(embedpython_VERSION_MAJOR 0)
SET(embedpython_VERSION_MINOR 1)
SET(CMAKE_AUTOMOC ON)
SET(CMAKE_INCLUDE_CURRENT_DIR ON)
FIND_PACKAGE(Qt4 4.8.6 REQUIRED QtGui QtCore)
QT4_WRAP_CPP(embedpython_HEADERS_MOC ${embedpython_HEADERS})
message(status "QT FOUND: ${Qt4_FOUND}")
FIND_PACKAGE(PythonLibs 2.7.9 REQUIRED)
message(status "libs found: ${PYTHONLIBS_FOUND}")
MESSAGE(STATUS "PYTHON_LIBRARIES: ${PYTHON_LIBRARIES}")
MESSAGE(STATUS "PYTHON_INCLUDE_PATH: ${PYTHON_INCLUDE_PATH}")
MESSAGE(STATUS "PYTHONLIBS_VERSION: ${PYTHONLIBS_VERSION_STRING}")
MESSAGE(STATUS "PYTHON_INCLUDE_DIRS: ${PYTHON_INCLUDE_DIRS}")
INCLUDE(${QT_USE_FILE})
ADD_DEFINITIONS(${QT_DEFINITIONS})
INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
SET(embedpython_SOURCES
main.cpp
mainwindow.cpp
pythonutilsimpl.cpp
ipcepythonrunner.cpp)
SET(embedpython_HEADERS
mainwindow.h
pythonutilsimpl.h
ipcepythonutils.h
ipcepythonrunner.h)
ADD_EXECUTABLE(embedpython ${embedpython_SOURCES} ${embedpython_HEADERS_MOC})
TARGET_LINK_LIBRARIES(embedpython ${QT_LIBRARIES} ${PYTHON_LIBRARIES})
Which outputs:
cmpt:build user$ /Applications/CMake.app/Contents/bin/cmake .. && make
statusQT FOUND: TRUE
statuslibs found: TRUE
-- PYTHON_LIBRARIES: /home/me/anaconda/lib/libpython2.7.dylib
-- PYTHON_INCLUDE_PATH: /home/me/anaconda/include/python2.7
-- PYTHONLIBS_VERSION: 2.7.9
-- PYTHON_INCLUDE_DIRS: /home/me/anaconda/include/python2.7
-- Configuring done
-- Generating done
-- Build files have been written to: /home/me/Desktop/EmbedPython/build
Scanning dependencies of target embedpython_automoc
[ 16%] Automatic moc for target embedpython
Generating moc_mainwindow.cpp
[ 16%] Built target embedpython_automoc
Scanning dependencies of target embedpython
[ 33%] Building CXX object CMakeFiles/embedpython.dir/main.cpp.o
[ 50%] Building CXX object CMakeFiles/embedpython.dir/mainwindow.cpp.o
[ 66%] Building CXX object CMakeFiles/embedpython.dir/pythonutilsimpl.cpp.o
[ 83%] Building CXX object CMakeFiles/embedpython.dir/ipcepythonrunner.cpp.o
[100%] Building CXX object CMakeFiles/embedpython.dir/embedpython_automoc.cpp.o
Linking CXX executable embedpython
[100%] Built target embed python
Using ccmake, I have set PYTHON_INCLUDE_DIR and PYTHON_LIBRARY so that FIND_PACKAGE succeeds in finding Python 2.7.9.
Within the C++ I have a debug to print the python version and path. Without fail, this returns Python 2.7.5. What is required in the CMake file to get the version of Python at the PATH I am aiming for?
I'm currently using CMake to build my project and CppUnit to Test it. In my CMake file i create two executables. sample is the compiled source itself. And with sample_test I run the tests. If i r
Here a part of my CMakeLists.txt
SET(SAMPLE_ROOT_PATH ${PROJECT_BINARY_DIR})
SET(SAMPLE_SOURCE_PATH ${SAMPLE_ROOT_PATH}/src)
SET(SAMPLE_TEST_SOURCE_PATH ${SAMPLE_ROOT_PATH}/test)
SET(SAMPLE_BIN_PATH ${SAMPLE_ROOT_PATH}/bin)
SET(SAMPLE_EXEC_NAME sample)
SET(SAMPLE_TEST_EXEC_NAME sample_test)
SET(EXECUTABLE_OUTPUT_PATH ${SAMPLE_BIN_PATH})
FILE(GLOB_RECURSE SAMPLE_SOURCE_FILES ${SAMPLE_SOURCE_PATH}/*.cpp)
FILE(GLOB_RECURSE SAMPLE_TEST_SOURCE_FILES ${SAMPLE_TEST_SOURCE_PATH}/*.cpp)
SET(SAMPLE_TEST_SOURCE_FILES ${SAMPLE_TEST_SOURCE_FILES} ${SAMPLE_SOURCE_FILES}
)
LIST(REMOVE_ITEM SAMPLE_TEST_SOURCE_FILES ${SAMPLE_SOURCE_PATH}/main.cpp)
SET(CMAKE_CXX_FLAGS "-g -Wall")
ADD_EXECUTABLE(${SAMPLE_EXEC_NAME} ${SAMPLE_SOURCE_FILES})
ADD_EXECUTABLE(${SAMPLE_TEST_EXEC_NAME} ${SAMPLE_TEST_SOURCE_FILES})
this is the output of make
[ 8%] Building CXX object CMakeFiles/sample.dir/src/KeyBuffer.cpp.obj
[ 12%] Building CXX object CMakeFiles/sample.dir/src/main.cpp.obj
[ 20%] Building CXX object CMakeFiles/sample.dir/src/Object.cpp.obj
[ 45%] Building CXX object CMakeFiles/sample.dir/src/World.cpp.obj
Linking CXX executable bin/sample.exe
[ 45%] Built target sample
[ 50%] Building CXX object CMakeFiles/sample_test.dir/test/KeyBufferTest.cpp.obj
[ 54%] Building CXX object CMakeFiles/sample_test.dir/test/ObjectTest.cpp.obj
[ 66%] Building CXX object CMakeFiles/sample_test.dir/src/KeyBuffer.cpp.obj
[ 75%] Building CXX object CMakeFiles/sample_test.dir/src/Object.cpp.obj
[100%] Building CXX object CMakeFiles/sample_test.dir/src/World.cpp.obj
Linking CXX executable bin/sample_test.exe
As you can see Object.cpp, World.cpp and KeyBuffer.cpp get compiled twice! How can i prevent it? Or is there a better way to handle the CppUnit tests using CMake?
Each target may have different compiler flags configured, so if you add one source files to two targets, separate object files need to be produced from this one source file for both targets.
The usual solution is to compile the shared source files into a static library which is then linked into both application targets.
add_library(base STATIC ${shared_SOURCES}) # except e.g. foo_main.cpp
add_executable(foo ${foo_only_SOURCES})
target_link_libraries(foo base)
add_executable(bar ${bar_only_SOURCES})
target_link_libraries(bar base)
Conceptually CMake treats each target (i.e., executable or library) as a separate build unit. The generated build system will produce an object file for each source file belonging to the target. By default CMake does not avoid redundant compilations of source files that are used in multiple targets, even if the compilation settings (compilation flags, preprocessor definitions ...) are exactly the same.
CMake 2.8.8 introduced a new feature called OBJECT_LIBRARY target to address the problem of avoiding redundant compilations:
To generate an object library use add_library:
FILE(GLOB_RECURSE SAMPLE_SOURCE_FILES ${SAMPLE_SOURCE_PATH}/*.cpp)
ADD_LIBRARY(sample_objects OBJECT EXCLUDE_FROM_ALL ${SAMPLE_SOURCE_FILES})
Other targets created by add_library or add_executable may reference the objects using an expression of the form $<TARGET_OBJECTS:objlib>:
ADD_EXECUTABLE(${SAMPLE_EXEC_NAME} $<TARGET_OBJECTS:sample_objects>)
FILE(GLOB_RECURSE SAMPLE_TEST_SOURCE_FILES ${SAMPLE_TEST_SOURCE_PATH}/*.cpp)
ADD_EXECUTABLE(${SAMPLE_TEST_EXEC_NAME} $<TARGET_OBJECTS:sample_objects> ${SAMPLE_TEST_SOURCE_FILES})
Compared with using a regular static library to avoid redundant compilation, an object library has the advantage that it does not need to be linked. On top of that it cannot be imported, exported or installed.