I use CMake to build a project that consists of multiple nested static libraries .A similar but simple structure is shown in the figure below:
TestProject:
|-CMakeLists.txt
|-Main.cpp
|-level2
| | - level2.cpp
| | - level2.h
| | - CMakeLists.txt
| | - level1
| | |-level1.cpp
| | |-level1.h
| | |-CMakeLists.txt
Now, I use CMake to build static libraries for each level separately. According to my test, the static library of each layer only contains the .cpp and .h files of that layer. However, I want to combine it with the library referenced by the previous layer when the static library of each layer is generated. For example, I build the static lib of level 1 first.Then, in the CMakeLists.txt of level 2, I create the static library of level 2 depend on the static library of level 1 ( target_link_libraries(${PROJECT_NAME} LEVEL1) ), and then, I wanted to merge the libraries of level 2 and level 1 together to a new static lib file named as level1_2.lib.
Here is my CMakeLists.txt in Level1:
cmake_minimum_required(VERSION 3.5)
#projcet name
project(LEVEL1 LANGUAGES CXX)
add_library( ${PROJECT_NAME} add.cpp)
# Add the include directories of user-written sources.
target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR})
And this is the CMakelists.txt of level2.
cmake_minimum_required(VERSION 3.5)
project(LEVEL2 LANGUAGES CXX)
add_subdirectory(level1)
add_library( ${PROJECT_NAME} addplus.cpp)
target_link_libraries(${PROJECT_NAME} LEVEL1)
target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR})
find_program(MSVC_LIB_TOOL lib.exe)
set(LIBNAME "level1_2.lib")
add_custom_command(
TARGET examplelib POST_BUILD
COMMAND ${MSVC_LIB_TOOL} /OUT:${LIBNAME} $<TARGET_FILE:LEVEL2> $<TARGET_FILE:LEVEL1>
DEPENDS LEVEL1 LEVEL2
COMMENT "Combining libs..."
)
add_custom_target(combinedLib
ALL
DEPENDS ${LIBNAME}
)
I use the add_custom_command and add_custom_target method trying to generate the mixed lib, referenced to several website below:
CMake linking libraries into one single library
But they can't really solve my needs.Only level1.lib and level2.lib is generated.
Any help would be appreciated.
UPDATE in 08-21 =======================================================
Thanks for everyone's reply.Now I used object library(reference from Alex's answer), and get the merged static library.Here's my new code:
#CMakeLists.txt in level1
cmake_minimum_required(VERSION 3.5)
#projcet name
project(LEVEL1 LANGUAGES CXX)
# Generate lib
add_library( LEVEL1obj OBJECT add.cpp)
# Add the include directories of user-written sources.
target_include_directories(LEVEL1obj PUBLIC ${PROJECT_SOURCE_DIR})
add_library(${PROJECT_NAME})
target_link_libraries(${PROJECT_NAME} PUBLIC LEVEL1obj)
And this is the CMakelists.txt of level2.
#CMakeLists.txt in level2
cmake_minimum_required(VERSION 3.5)
#projcet name
project(LEVEL2 LANGUAGES CXX)
add_subdirectory(level1)
add_library( LEVEL2obj OBJECT addplus.cpp addplus.h)
# Add the include directories of user-written sources.
target_include_directories(LEVEL2obj PUBLIC ${PROJECT_SOURCE_DIR})
target_link_libraries(LEVEL2obj LEVEL1obj)
add_library( ${PROJECT_NAME})
target_link_libraries(${PROJECT_NAME} PUBLIC LEVEL1obj LEVEL2obj)
This is the top level CMakeLists.txt in test project
cmake_minimum_required(VERSION 3.5)
project(TestCppLib)
file(GLOB SRC "${PROJECT_SOURCE_DIR}/*.cpp")
add_subdirectory(level2)
add_executable(${PROJECT_NAME} ${SRC})
target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR})
target_link_libraries(${PROJECT_NAME} PRIVATE LEVEL2)
The slightly different from Alex's answer is : because my level2 library depends on the level1 library, I added a library dependency to it by target_link_libraries(LEVEL2obj LEVEL1obj)
. The slightly different answer from Alex's is that because my level2 library depends on the level1 library generation, I added a library dependency to it through the following code. At least for now, it works well.
add_custom_command
? (And useexampleLib
target which is never created, which should give a configuration error.) Instead, use common generating variant of that command:add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${LIBNAME} COMMAND ...)
. – NeurotomyI wanted to merge the libraries of level 2 and level 1 together to a new static lib
But what for? Just link librarylevel1
with librarylevel2
, and the dependencies are transitive. Or do you want to specifically distributelevel1_2.lib
to the clients? If so, I would suggest instead making one library from the start in cmake. – Halimafile(GLOB SRC "${PROJECT_SOURCE_DIR}/*.cpp")
-- please do not glob withoutCONFIGURE_DEPENDS
(put it afterSRC
) – Wageworkertarget_link_libraries
with a visibility specifier (one of PRIVATE, PUBLIC, or INTERFACE). There is not an implied default; instead, forgetting to put one triggers legacy behavior with strange edge cases that can bite you later as your code evolves. – Wageworkerbecause my level2 library depends on the level1 library generation
- depending on the type of dependency, consider usingadd_dependencies
instead oftarget_link_libraries
. – Wageworkercmake --version
and put that in yourcmake_minimum_required
– Wageworker