Reputation: 616
I have code with one big directory of models which are going to be used in two binaries - the main program and tests. I want to put the models to the library which will compile once and then both main program and tests can use it without recompiling it again.
Here are my current directories:
root/
CMakeLists.cpp
src/
CMakeLists.txt
main.cpp
model/
/*a lot of cpp/hpp files*/
impl/
impl.cpp
impl.hpp (uses models)
test/
CMakeLists.txt
main.cpp
test.cpp (uses models and impl)
root/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(server)
set(CMAKE_CXX_STANDARD 14)
file(GLOB MODEL_SOURCES "src/model/*.cpp")
add_library(modelLibrary ${MODEL_SOURCES})
add_subdirectory(src)
add_subdirectory(test)
src/CMakeLists.txt
set(BINARY ${CMAKE_PROJECT_NAME})
file(GLOB_RECURSE SOURCES LIST_DIRECTORIES true *.h *.cpp)
set(SOURCES ${SOURCES})
add_executable(${BINARY} ${SOURCES})
include_directories(impl)
# can't see model files without this line
target_include_directories(${BINARY} PRIVATE ./model)
target_link_libraries(${BINARY} PUBLIC modelLibrary pistache pthread ssl crypto)
test/CMakeLists.txt
set(BINARY ${CMAKE_PROJECT_NAME}_test)
file(GLOB_RECURSE TEST_SOURCES LIST_DIRECTORIES false *.hpp *.cpp)
set(SOURCES ${TEST_SOURCES})
add_executable(${BINARY} ${TEST_SOURCES})
add_test(NAME ${BINARY} COMMAND ${BINARY})
# can't see model files without this line
target_include_directories(${BINARY} PRIVATE ../src/model)
target_link_libraries(${BINARY} modelLibrary gtest gtest_main pthread)
I have failed with using modelLibrary as only source. It still compiles the models two times. I'd like to achieve solution where models are compiled once and they are reachable from both - main program and test.
Upvotes: 0
Views: 697
Reputation: 356
I believe the reason you see the model files compiled twice is due to the recursive glob in src/CMakeLists.txt
.
file(GLOB_RECURSE SOURCES LIST_DIRECTORIES true *.h *.cpp)
This recursive glob will also walk into src/model
and grab the *.cpp
files there. So the model files are getting compiled as part of modelLibrary
as well as part of the server
executable.
One way to fix this would be to remove the recursive glob and create a separate CMakeLists.txt
in src/model
with the contents of:
# I wouldn't actually glob, see note below.
file(GLOB MODEL_SOURCES "*.cpp")
add_library(modelLibrary ${MODEL_SOURCES})
target_include_directories(modelLibrary PUBLIC ".")
One would need to make a call add_subdirectory()
for this new CMakeLists in either the root or the src/CMakeLists.txt
.
Notice the use of target_include_directories
in the possible solution. I put that there as I noticed it was being repeated in the test and executable. Using PUBLIC
on modelLibrary
means that consumers get the include directory just by using target_link_libraries
.
Note about globbing: from CMake docs on GLOB
Note We do not recommend using GLOB to collect a list of source files from your source tree. If no CMakeLists.txt file changes when a source is added or removed then the generated build system cannot know when to ask CMake to regenerate. The CONFIGURE_DEPENDS flag may not work reliably on all generators, or if a new generator is added in the future that cannot support it, projects using it will be stuck. Even if CONFIGURE_DEPENDS works reliably, there is still a cost to perform the check on every rebuild.
That note can be a bit hard to grok, but try to fully understand the consequences if you do decide to glob.
Upvotes: 3