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)
Related
I have the following folder structure:
- lib/
-libA/
-include/
- libA.h
-src/
- libA.cpp
-CMakeLists.txt (1)
-libB/
-headerB1.h
-headerB2.h
-headerBx.h
-CMakeLists.txt (2)
- src/
-main.cpp
- CMakeLists.txt (3)
in libA.h I try to include one of the header files from libB. In this case that would be headerB1.h by doing
#include <headerB1.h>
But unfortunately, I get the following error in cmake:
fatal error C1083: cannot open include file: 'headerB1.h': No such file or directory from the libA.h file.
I have the following CMake contents:
/CMakeLists.txt (3)
cmake_minimum_required(VERSION 3.10)
project(project)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(SOURCES
src/main.cpp
)
add_executable(${PROJECT_NAME} ${SOURCES})
add_subdirectory("lib/libA")
add_subdirectory("lib/libB")
target_link_libraries(${PROJECT_NAME} PUBLIC libA)
target_link_libraries(${PROJECT_NAME} PUBLIC libB)
lib/libA/CMakeLists.txt (1)
add_library(libA STATIC)
target_sources(libA PRIVATE src/libA.cpp)
target_include_directories(libA
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src
)
lib/libB/CMakeLists.txt (2)
add_library(libB INTERFACE)
target_include_directories(libB INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
library B (libB) is a header only library in my view (correct me if I'm using the incorrect terms).
So libA actually 'uses' libB but somehow, adding or creating libB is not executed as I thought it would. What are my misconceptions here and how can I solve it?
main.cpp:
#include <libA.h> //This works!
int main(void) {
//do something with libA class / functions
}
libA.h:
#include <headerB1.h> //This causes the cmake (mingw32-make.exe) error
I use:
cmake
vscode
mingw32-make
I actually did take a look at: CMake include library in another library
But making my CMakeLists (1) like the following code did not work for me unfortunately. Or, again, I have misunderstood the solution.
add_library(libA SHARED)
target_sources(libA PRIVATE src/libA.cpp)
target_include_directories(libA
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src
)
target_link_libraries(libA PRIVATE libB)
target_include_directories(libA PUBLIC ${CMAKE_ROOT}/lib/libB)
Ok, this was actually pretty straightforward for a solution but it does make sense that libB would have to be compiled first because libA makes use of it.
So, in CMakeLists.txt (3) I have switched the two following lines:
add_subdirectory("lib/libA")
add_subdirectory("lib/libB")
to
add_subdirectory("lib/libB")
add_subdirectory("lib/libA")
And I also made sure to have added the following code snippet like suggested in the other stackoverflow question, to the libA CMakeLists.txt (1). CMake include library in another library
target_link_libraries(libA PRIVATE libB)
target_include_directories(libA PUBLIC ${CMAKE_ROOT}/lib/libB)
Now, all compiles as expected without errors.
I have the following folder structure in my c++ project
*--build
|---(building cmake here)
|
*--main.cpp
|
*--CMakeLists.txt (root)
|
*--modules
|---application
|------app.h
|------app.cpp
|------CMakeLists.txt
And the code below for both CMakeLists.txt files:
CMakeLists.txt (module)
cmake_minimum_required(VERSION 3.15.2)
file(GLOB APPLICATION_HEADERS *.h *.hpp)
file(GLOB APPLICATION_SRC *.c *.cpp)
add_library(app_lib STATIC
${APPLICATION_HEADERS}
${APPLICATION_SRC})
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR})
CMakeLists.txt (root)
cmake_minimum_required(VERSION 3.15.2)
project(main)
enable_language(C CXX)
#set directories
set(CMAKE_BINARY_DIR build)
set(CMAKE_CONFIGURATION_TYPES UNIX)
set(CMAKE_MODULES_DIR ${SOURCE_DIR}/cmake)
add_executable(${PROJECT_NAME} main.cpp)
# Build sub-modules
include_directories(modules/application)
add_subdirectory(modules/application)
find_library(MY_APP_LIB app_lib REQUIRED)
target_link_libraries(${PROJECT_NAME} PUBLIC ${MY_APP_LIB})
However, when I do cmake .. in my build directory, it seems like my app library just doesn't build and it doesn't link to it. I end up with the following error:
CMake Error at CMakeLists.txt:80 (find_library):
Could not find MY_APP_LIB using the following names: app_lib
I tried looking at other stackoverflow questions but it seems like I'm missing something. Any help is appreciated!
Thanks!
You don't need to use find_* to locate the library. In fact you cannot locate the library this way, since find_library searches the file system for the library during configuration, i.e. before anything gets compiled.
There's good news though: If the targets are created in the same cmake project, you can simply use the name of the cmake target as parameter for target_link_libraries:
...
add_library(app_lib STATIC
${APPLICATION_HEADERS}
${APPLICATION_SRC})
# note: this should be a property of the library, not of the target created in the parent dir
target_include_directories(app_lib PUBLIC .)
...
add_subdirectory(modules/application)
target_link_libraries(${PROJECT_NAME} PUBLIC app_lib)
You don't need to do find_library for your own targets, just link directly to app_lib:
target_link_libraries(${PROJECT_NAME} PUBLIC app_lib)
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)
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
CMake Project Structure: How do I properly merge libraries together and include them in multiple executables
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.
Here is a minimal example using object libraries to manage sharing object files between static (or shared!) libraries and how to link to them.
In level1/CMakeLists.txt:
add_library(level1_obj OBJECT level1.cpp level1.h)
target_include_directories(level1_obj PUBLIC "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>")
add_library(level1)
target_link_libraries(level1 PUBLIC level1_obj)
In level2/CMakeLists.txt
add_subdirectory(level1)
add_library(level2_obj OBJECT level2.cpp level2.h)
target_include_directories(level2_obj PUBLIC "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>")
add_library(level2)
target_link_libraries(level2 PUBLIC level1_obj level2_obj)
Notice that level2 is linked to level1_obj, not level1.
In main/CMakeLists.txt:
cmake_minimum_required(VERSION 3.21)
project(TestProject)
add_subdirectory(level2)
add_executable(app Main.cpp)
target_link_libraries(app PRIVATE level2)
One bug to be aware of is that Xcode does not like libraries without any real source files. If that's a concern, you can add an empty source file to your static library targets.
Please be sure to read the documentation on object libraries:
https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#object-libraries
https://cmake.org/cmake/help/latest/command/target_link_libraries.html#linking-object-libraries
https://cmake.org/cmake/help/latest/command/add_library.html#object-libraries
Also worth noting is that unless you have some need to distribute your level2 library independently from level1, it would be better to keep their objects separate and require linking to both. Normal target linking in CMake handles this automatically via the transitive linking mechanism.
File Structure:
CMakeLists.txt
src/
evolution.cpp
evolution.h
main.cpp
helpers/
disposable.h
engine/
game.h
game.cpp
CMakeLists.txt:
cmake_minimum_required(VERSION 3.17)
project(evolution)
add_library(helpers
src/helpers/disposable.h)
set_target_properties(helpers PROPERTIES LINKER_LANGUAGE CXX)
add_library(engine
src/engine/game.h
src/engine/game.cpp)
add_executable(evolution src/main.cpp)
target_link_libraries(evolution engine helpers)
The Game class (game.h) inherits from Diposable (disposable.h), but I am unable to build the project with a simple #include "disposable.h" in the game.h file.
How do I configure CMake so that the engine library can see the helpers library?
CMake error:
[ 20%] Building CXX object CMakeFiles/engine.dir/src/engine/game.cpp.o
In file included from /home/shane/projects/evolution/src/engine/game.cpp:1:
/home/shane/projects/evolution/src/engine/game.h:4:10: fatal error: disposable.h: No such file or directory
4 | #include "disposable.h"
| ^~~~~~~~~~~~~~
compilation terminated.
Adding headers to a project really only helps IDEs find the headers. It doesn't change the build instructions. Instead you need to use target_include_directories() with a INTERFACE or PUBLIC section to get any libraries that link to this to add the include directories to itself.
Your helpers library is more of an interface for now. To get this minimum example working do this:
cmake_minimum_required(VERSION 3.17)
project(evolution)
add_library(helpers INTERFACE) # INTERFACE is good for header-only libraries
target_include_directories(helpers INTERFACE src/helpers)
add_library(engine
src/engine/game.h
src/engine/game.cpp)
add_executable(evolution src/main.cpp)
target_link_libraries(evolution engine helpers)
Now include with angular brackets: #include <disposable.h>
If your library becomes more complicated (more than just header files), then replace INTERFACE in add_library with your sources. To make include directories available to the helpers library and any library that links to it, change INTERFACE to PUBLIC in target_include_directories.
cmake_minimum_required(VERSION 3.17)
project(evolution)
add_library(helpers src/helpers/helper.cpp)
target_include_directories(helpers PUBLIC src/helpers)
add_library(engine
src/engine/game.h
src/engine/game.cpp)
add_executable(evolution src/main.cpp)
target_link_libraries(evolution engine helpers)