I have a project with the below structure. Basically, there are two static libraries: lib_a and lib_b. lib_a uses classes and functions defined in lib_b. There is the main executable, which depends on lib_a (and indirectly on lib_b), and unit tests for lib_a, which also indirectly depend on lib_b.
project
|--CMakeLists.txt
|--static_lib_a
| |--CMakeLists.txt
| |--include
| | \--header_a.h
| \--src
| |--file_a.h
| \--file_a.cpp
|--static_lib_b
| |--CMakeLists.txt
| |--include
| | \--header_b.h
| \--src
| |--file_b.h
| \--file_b.cpp
|--main_exe
| |--CMakeLists.txt
| \--main.cpp
\--unit_test
|--CMakeLists.txt
|--main.cpp
\--test_lib_a.cpp
Since static libraries generally do not link with each other, both main_exe and unit_test need to link lib_a and lib_b. Is there a way to tell CMake that anything that links lib_a also needs to link with lib_b, without specifying this explicitly in main_exe and unit_test? That is, can I express this dependency in static_lib_a/CMakeLists.txt file?
What should be the content of each of the CMakeLists.txt file?
So far I have the following, which produces linking errors (that is, lib_b does not get linked to unit_test):
project/CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(project)
enable_testing()
add_subdirectory(static_lib_a)
add_subdirectory(static_lib_b)
add_subdirectory(main_exe)
add_subdirectory(unit_test)
project/static_lib_a/CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
add_library(lib_a STATIC)
target_sources(lib_a PRIVATE
src/file_a.cpp)
target_include_directories(lib_a
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
target_link_libraries(lib_a lib_b)
project/static_lib_b/CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
add_library(lib_b STATIC)
target_sources(lib_b PRIVATE
src/file_b.cpp)
target_include_directories(lib_b
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
main_exe/CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
add_executable(main_exe)
target_sources(main_exe PRIVATE main.cpp)
target_link_libraries(main_exe PRIVATE lib_a)
unit_test/CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
include(CTest)
add_executable(unit_test)
target_sources(unit_test PRIVATE
main.cpp
test_lib_a.cpp)
target_link_libraries(unit_test PRIVATE lib_a)
add_test(NAME unit_test COMMAND unit_test)
add_custom_target(run_unit_test ALL
COMMAND ${CMAKE_CTEST_COMMAND} -C debug --output-on-failure
DEPENDS unit_test)
Related
I have the following code structure:
--src
|--common--include--common---datatype--a_h_file.hpp
| |
| --src
|
|--main_lib
| |--------include-----one---one.hpp
| |
| |---src--------one----one.cpp
| CMakeLists.txt
|---main.cpp
CMakeLists.txt
main.cpp uses one.hpp without problem.
My CMakeLists.txt files are like this
Upper level
cmake_minimum_required(VERSION 3.0.0)
project(MyProject VERSION 1.0.0)
add_subdirectory(main_lib)
add_executable(myproj main.cpp)
target_link_libraries(myproj PUBLIC mainpub)
and the other
add_library(mainpub
src/one/one.cpp)
target_include_directories(mainpub PUBLIC include)
With this I can use one.hpp
My problem is that by design it has been decided that one.hpp should include a_h_file.hpp like this
(one.hpp)
#pragma once
float addition(float,float);
#include "common/data_type/a_h_file.hpp" //<---THIS!
class whatever{
public:
int number=1;
};
So, my question is how do I modify the CMake files to include the path /src/common/include to the paths that are going to be considered in order to be able to use a_h_file.hpp?
EDIT: I tried
cmake_minimum_required(VERSION 3.0.0)
project(MyProject VERSION 1.0.0)
add_library(Common INTERFACE)
target_include_directories(Common INTERFACE common/include)
add_subdirectory(main_lib)
add_executable(myproj main.cpp)
target_link_libraries(myproj PUBLIC mainpub)
and in the other
add_library(mainpub
src/one/one.cpp)
#target_include_directories(mainpub PUBLIC include ../common/include)
#target_include_directories(mainpub PUBLIC Common)
#target_include_directories(mainpub PUBLIC include)
target_include_directories(mainpub PUBLIC Common include)
but it did not work :(
fatal error: common/data_type/a_h_file.hpp: No such file or directory
#include "common/data_type/a_h_file.hpp"
^~~~~~~~~~~~~~~~~~~~~~~~~~~
EDIT2:
Modified the second Cmake file to
add_library(mainpub
src/one/one.cpp)
target_link_libraries(mainpub PUBLIC Common)
target_include_directories(mainpub PUBLIC include)
It did not work either.
First, define an INTERFACE target for your common directory in the top-level CMakeLists.txt:
add_library(Common INTERFACE)
target_include_directories(Common INTERFACE common/include)
Then just link against it in your targets, which will propagate the include directories:
target_link_libraries(mainpub PUBLIC Common)
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
| | |-third_party.lib-------(When I build level1.lib, I need to add dependence of this library.)
I use CMake to build static libraries for each level separately.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 level1 first, which depend on the existed third_party.lib.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 and third_party.lib together to a new static lib file named as level1_2.lib.
According to another similar question but different at the third_partyl.lib(CMake linking static libraries in different subdirectories into one single static library), I used object library, and get the merged static library.Here's my code:
#CMakeLists.txt in level1
cmake_minimum_required(VERSION 3.20.3)
#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})
add_dependencies(${PROJECT_NAME} LEVEL1obj)
target_link_libraries(${PROJECT_NAME} PUBLIC LEVEL1obj)
And this is the CMakelists.txt of level2.
#CMakeLists.txt in level2
cmake_minimum_required(VERSION 3.20.3)
#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 PUBLIC LEVEL1obj)
add_library( ${PROJECT_NAME})
add_dependencies(${PROJECT_NAME} LEVEL1obj LEVEL2obj)
target_link_libraries(${PROJECT_NAME} PUBLIC LEVEL1obj LEVEL2obj)
This is the top level CMakeLists.txt in test project
cmake_minimum_required(VERSION 3.20.3)
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})
add_dependencies(${PROJECT_NAME} LEVEL2)
target_link_libraries(${PROJECT_NAME} PRIVATE LEVEL2)
Now, I completed the compilation of level1-level2 projects with help. However, one problem is overlooked:I don't know how to deal with third-party libraries in level1.I don't know how to use the Object Library method to merge the third-party library with level1.lib.. I cannot use the method of building the object library first and then merging them. Because as far as I know, CMake may not have a method to convert a static library into an OBJECT library.
So, when I merge libraries, how should I deal with this third-party library problem?
Any help would be appreciated.
There are numerous similar questions on Stack Overflow, but none come near to answering my question.
I have a C++ library built using CMake:
mylib
| - CMakeLists.txt
| - src/
| | - m.h
| | - m.cpp
| - include/
| | - mylib/
| | | - a.h
| | | - something/
| | | | - some.h
| - cmake/
| - mylibConfig.cmake.in
| - mylibConfigVersion.cmake.in
I then create another library or executable which includes the aforementioned library:
myapp
| - CMakeLists.txt
| - src/
| | - main.cpp
| - include/
| | - myapp/
| | | - b.h
| - libs
| | - mylib
And would like to use mylib within myapp like so. Please take notice how mylib headers are included in a directory like format:
#include <mylib/a.h>
#include <mylib/something/some.h>
mylib should be built when building myapp so that the following works without any other build steps:
$ cd myapp/build
$ cmake ..
$ make
Here is a list of some of the Stack Overflow posts I have reviewed. I have attempted each, and they simply do not work:
CMake: How to build external projects and include their targets
CMake ExternalProject_Add() and FindPackage()
Assuming in the project described, only header files in the mylib/include directory are to be considered public:
The top-level CMakeLists.txt for mylib needs to contain:
cmake_minimum_required(VERSION 3.13 FATAL_ERROR)
project(mylib VERSION 0.1 LANGUAGES CXX)
add_library(${MyLibName} ${MyLib_SOURCES})
target_include_directories(${MyLibName}
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src
)
This ensures that projects including mylib will only have access to files in the include/ directory. Files in include/ can be used like #include <myfile.h> and files in include/mylib (the general convention) can be used like #include <mylib/myfile.h>.
The top-level CMakeLists.txt for myapp should include:
cmake_minimum_required(VERSION 3.13 FATAL_ERROR)
project(myapp VERSION 0.1 LANGUAGES CXX)
add_subdirectory(libs/mylib)
add_executable(${MyAppName} ${MyApp_SOURCES})
target_link_libraries(${MyAppName} ${MyLibName}
The use of add_subdirectory ensures that mylib will be built before myapp and target_link_libraries adds mylib to the executable.
As mentioned by Tzalumen, make sure you take a look at the CMake tutorials and prefer the use of cmake --build . instead of make.
So, I actually do this in one of my projects.
First, the library needs to be built with ADD_LIBRARY(), but I'm assuming you do that. Something like
ADD_LIBRARY (${MyLibName} ${SOURCES}) in the library's CMakeLists.txt
That adds the library into cmake's list of libraries.
Second, you add the library to your project with
target_link_libraries (${PROJECT_NAME} ${MyLibName}) in the executable's CMakeLists.txt, the same one where you have your add_executable (${PROJECT_NAME} ${SOURCES})
That will set up the dependency chain to force MyLibName to explicitly build before PROJECT_NAME.
Having problems setting up a project to keep directory structure with cmake.
Project structure I want to keep:
Project
|-libA
| |-fileA.h
| |-fileA.cpp
| |-CMakeLists.txt
|-include
| |-fileI.h
|-program1
| |-main.cpp
| |-CMakeLists.txt
|-CMakeLists.txt
source code include example:
#include "libA/fileA.h"
This doesn't work. Cmake can't find "libA/fileA.h", it will only work if I create a following directory structure:
Project
|-libA
| |-libA (directory)
| |-fileA.h
| |-fileA.cpp
| |-CMakeLists.txt
|-include
| |-fileI.h
|-program1
| |-main.cpp
| |-CMakeLists.txt
|-CMakeLists.txt
What can I do to keep the project structure as shown in the first example and to keep directory name in source files? (eg #include "libA/fileA.h")
Project cmake:
cmake_minimum_required(VERSION 3.8)
project(A)
include_directories( ${PROJECT_SOURCE_DIR}/include )
add_subdirectory(libA)
add_subdirectory(program1)
libA cmake:
set(LIBA_SRC libA/fileA.cpp)
add_library(libA SHARED ${LIBA_SRC})
Program1 cmake:
set (PROGRAM1_SRC main.cpp)
add_executable (program1 ${PROGRAM_SRC})
target_link_libraries (program1 libA)
target_include_directories (program1 PUBLIC ${PROJECT_SOURCE_DIR}/libA)
If you change the include directory in program1 to
target_include_directories (program1 PUBLIC ${PROJECT_SOURCE_DIR})
it will search from your source directory, so "libA/fileA.h" will find it's target.
I've got a question on cmake project configuration.
The following is my project structure.
trunk
|
|---- mylib
| |
| ---- mylib.h
| ---- mylib.c
| ---- *MYLIB_CMakeList.txt*
|
|---- alib
| |
| ---- alib.h
| ---- alibName.lib
| ---- *ALIB_CMakeList.txt*
|
|
|---- main
| |
| ---- main.cpp
| ---- *MAIN_CMakeList.txt*
|
---- *TOP_CMakeList.txt*
mylib subfolder contains the source code (c) to create my own static library. This code depends on alib.
The main subfolder contains the example code (C++) which uses mylib.
Here is how I've written my CMakeList files:
**TOP_CMakeList.txt**
cmake_minimum_required(VERSION 3.4)
add_subdirectory(mylib)
add_subdirectory(alib)
add_subdirectory(main)
------------------------------------------------------------------------------------------------------------
**MYLIB_CMakeList.txt**
cmake_minimum_required(VERSION 3.4)
project(MyLib C)
if (WIN32)
set(CMAKE_SHARED_LIBRARY_PREFIX "")
endif ()
include_directories(${alib_INCLUDE_DIRS})
add_library(${PROJECT_NAME} STATIC mylib.c)
target_link_libraries(${PROJECT_NAME} alib)
set(${PROJECT_NAME}_DEFINITIONS CACHE INTERNAL "${PROJECT_NAME}: Definitions" FORCE)
set(${PROJECT_NAME}_INCLUDE_DIRS ${PROJECT_SOURCE_DIR} CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE)
------------------------------------------------------------------------------------------------------------
**ALIB_CMakeList.txt**
cmake_minimum_required(VERSION 3.4)
project(ALib)
set(${PROJECT_NAME}_DEFINITIONS CACHE INTERNAL "${PROJECT_NAME}: Definitions" FORCE)
set(${PROJECT_NAME}_INCLUDE_DIRS ${PROJECT_SOURCE_DIR} CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE)
------------------------------------------------------------------------------------------------------------
**MAIN_CMakeList**
make_minimum_required(VERSION 3.4)
project(Executable CPP)
file(GLOB CPP_FILES *.cpp)
add_definitions(${MyLib_DEFINITIONS})
include_directories(${MyLib_INCLUDE_DIRS})
add_executable(${PROJECT_NAME} ${CPP_FILES})
target_link_libraries(${PROJECT_NAME} MyLib)
With such configuration it doesn't recognize the alib dependency of mylib. In particular (I'm developing under Windows) I get this error:
/usr/lib/gcc/x86_64-pc-cygwin/4.9.3/../../../../x86_64-pc-cygwin/bin/ld:
cannot find -lalibName.lib
I can't figure out how to correctly do it. Any suggestions?
Seems that the alib project does not specify any kind of library targets the same way as mylib does:
Try adding this to alibs' CMake file
add_library(${PROJECT_NAME} STATIC <<< alib SOURCES HERE >>>)
Static libraries can't have dependencies(well, they can but they don't drag them with themselves) so there is no point in providing alib in target_link_libraries(...) for another static library. You should provide alib to the add_execuable command directly.
Alternatively, you can build a big static library from both mylib and alib but it will be less elegant and platfrom dependant. For gcc you should look at ar tool.
Remove the add_subdirectory(alib) command, then remove CMake file from the alib subfolder — you don't need it. Then in the cmake file where you have your add_executable command put the following(after the line);
link_directories(../alib)
target_link_libraries(${PROJECT_NAME} alibName.lib)