First of all, I know there are very similar questions in this forum. However, none really answer my specific case. I have the following project structure:
|---Project_Root
|---CMakeLists.txt
|---build
|---src
| |---CMakeLists.txt
| |---many .cpp and .h files in multiple subfolders with a different CMakeLists.txt
|---tests
| |---CMakeLists.txt
| |---many .cpp files
In the Project_Root/CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
set(SRC_DIR src)
project(
Project
LANGUAGES CXX
)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(${PROJECT_NAME} "")
target_include_directories(${PROJECT_NAME} PRIVATE ${SRC_DIR})
add_subdirectory(${SRC_DIR})
In the src folder and subfolder CMakeLists.txt files:
cmake_minimum_required(VERSION 3.5)
set(SRC_FILES
Source1.cpp
)
set(HEADER_FILES
Source1.hpp
)
target_sources(${PROJECT_NAME}
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FILES}
${CMAKE_CURRENT_SOURCE_DIR}/${HEADER_FILES}
)
Now in the tests subfolder:
project(Test LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
enable_testing()
add_executable(Test tst_test.cpp)
add_test(NAME Test COMMAND Test)
target_link_libraries(Test PRIVATE Qt5::Test)
In the above CMakeLists.txt I want to include the main project as a static library. I can, for example, add a new library target (say Project_Lib
) in the root CMakeLists.txt and use once again the command:
target_sources(Project_Lib
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FILES}
${CMAKE_CURRENT_SOURCE_DIR}/${HEADER_FILES}
)
in all the subfolders.
But is there a more elegant way of doing it without having to modify all the CMakeLists.txt in the subfolders? For example, is there way to extract the source files from the Project
target, so that it can be reused to make the Project_Lib
target?
As you described, you can make a new static library target Project_Lib
. Take advantage of the fact that you parameterized the target name by using the project name (${PROJECT_NAME}
), so you actually don't have to change all of the CMakeLists.txt files in the subfolders. Just change the project name.
As I commented, simply exclude the main.cpp
file from the static library, and add it to a separate executable target instead.
In Project_Root/CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
set(SRC_DIR src)
# Change the project name, as now the static library is the primary target.
project(
Project_Lib
LANGUAGES CXX
)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Create the static library target, whose sources are populated in subdirectories.
add_library(${PROJECT_NAME} STATIC)
target_include_directories(${PROJECT_NAME} PRIVATE ${SRC_DIR})
# The only modification necessary in the subdirectories is to *exclude* the
# main.cpp file from the target_sources for the static library.
add_subdirectory(${SRC_DIR})
# Add *only* the main.cpp file to the executable target.
add_executable(Project_Exe src/main.cpp)
# Link the static library target to the executable.
target_link_libraries(Project_Exe PRIVATE ${PROJECT_NAME})
In tests/CMakeLists.txt:
...
# Link the static library to your Test executable also.
target_link_libraries(Test PRIVATE Project_Lib Qt5::Test)