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)
Related
I have a large C++ library, and want to do some testing with GTest.
At the moment, the build is handled with CMake, in particular there is one CMakeLists.txt file in the root directory like the following
make_minimum_required(VERSION 3.13.0)
project(mylib)
find_package(PkgConfig REQUIRED)
set(CMAKE_BUILD_WITH_INSTALL_RPATH ON)
set(CMAKE_INSTALL_RPATH "${CMAKE_CURRENT_SOURCE_DIR}/lib/protobuf/src/.libs/")
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
SET(BASEPATH "${CMAKE_SOURCE_DIR}")
INCLUDE_DIRECTORIES("${BASEPATH}")
add_executable(mylib run.cpp)
add_subdirectory(src)
add_subdirectory(proto)
target_include_directories(mylib PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/lib/math
${CMAKE_CURRENT_SOURCE_DIR}/lib/protobuf/src
... some dirs ...
)
target_link_directories(mylib PRIVATE
... some libs ..
)
target_link_libraries(mylib
${CMAKE_CURRENT_SOURCE_DIR}/lib/math
${CMAKE_CURRENT_SOURCE_DIR}/lib/protobuf/src
.....
)
target_compile_options(mylib PUBLIC -D_REENTRANT -fPIC)
Then in the src directory and every sub-directory there is a CMakeLists.txt file, for example this is in src/
target_sources(mylib
PUBLIC
includes.hpp
)
add_subdirectory(algorithms)
add_subdirectory(collectors)
add_subdirectory(hierarchies)
add_subdirectory(mixings)
add_subdirectory(runtime)
add_subdirectory(utils)
My question here is the following: what is the least painful way to integrate GTest in the current project? I was thinking of having a test/ subdirectory, like I've seen here: Adding Googletest To Existing CMake Project
However this example requires that for each executable you manually list all the files it includes. Is there a quicker way to use the sources that are already added to 'mylib'?
You can split the current mylib executable target into two targets
mylib, a library target that is very much like the current mylib target, but without the run.cpp file
mylib_exe an executable target that compiles run.cpp and links to mylib
Now your test files can link to mylib.
I have a folder structure that is as follows:
|-CMakeLists.txt
|-main.cpp
|-network
---------- CMakeLists.txt
---------- network.h
---------- network.cpp
Where network is a folder containing the last 3 items.
I'm struggling to build this in CMake because the documentation is very strange to me. In my root CMakeLists.txt, it's as follows:
cmake_minimum_required(VERSION 3.11.0)
project(Test)
set(CMAKE_CXX_STANDARD 11)
include_directories ("${PROJECT_SOURCE_DIR}/network")
add_subdirectory (${PROJECT_SOURCE_DIR}/network)
add_executable(server main.cpp)
target_link_libraries (network)
find_package(Boost 1.67 REQUIRED COMPONENTS thread)
# Check for libray, if found print message, include dirs and link libraries.
if(Boost_FOUND)
message("Boost Found")
include_directories(${Boost_INCLUDE_DIRS})
target_link_libraries(server ${Boost_LIBRARIES})
target_link_libraries(server Boost::thread)
elseif(NOT Boost_FOUND)
error("Boost Not Found")
endif()
In the CMakeLists.txt in the network folder it's as follows:
cmake_minimum_required(VERSION 3.11.0)
project(Test)
set(CMAKE_CXX_STANDARD 11)
install(FILES ${MY_HEADER_FILES} DESTINATION ./)
add_executable(network network.cpp)
I made that by myself playing around to see if I can get CMake to add the files in that folder into the root project. Obviously, this is all just failing because I'm struggling to understand CMake from the documentation. My apologies. I get an error due to the implementation in "network.cpp" not being recognized:
main.cpp:(.text+0x409): undefined reference to `Socket::GetThis()'
I'm certain there's nothing wrong with the implementation because it's worked using another round about method but I want to build my project using the previous structure but I can't get my head around how to make the root CMakeLists and the network CMakeLists so that they work together.
How do I design the CMakeLists so that the network header and implementation are included in the root project. Also, the network library will be using Boost as well. Should I find the package in there too?
target_link_libraries (network)
You want to link "server" executable with "network" library. It's like this:
target_link_libraries(server PUBLIC network)
The PUBLIC can be omitted, but I like to specify it everywhere.
Also:
add_executable(network network.cpp)
should network.spp really be an executable? I guess there is no main in network.cpp`. You should:
add_library(network network.cpp)
And I guess the network include path is integral to the network library. So I would inside network/CMakeLists.txt do:
target_include_directories(network PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
Also note the target_compile_feature is preferred over set(CMAKE_CXX_STANDARD 11).
Also, there is no error() function. There is message(FATAL_ERROR).
All in all, I would write it like this:
# root/CMakeLists.txt
cmake_minimum_required(VERSION 3.11.0)
project(Test)
# this tells cmake that all c++ files that are in this file
# and all in add_subdirectory projects
# will compile with C++11 (by default)
set(CMAKE_CXX_STANDARD 11)
add_subdirectory(network)
add_executable(server main.cpp)
# tell cmake to link server with network library
# ie. server executable uses network library
target_link_libraries(server PUBLIC network)
find_package(Boost 1.67 REQUIRED COMPONENTS thread)
# Check for libray, if found print message, include dirs and link libraries.
if(Boost_FOUND)
message(STATUS "Boost Found")
target_include_directories(server PUBLIC ${Boost_INCLUDE_DIRS})
target_link_libraries(server PUBLIC ${Boost_LIBRARIES} Boost::thread)
elseif(NOT Boost_FOUND)
message(FATAL_ERROR "Boost Not Found")
endif()
and:
# network/CMakeLists.txt
add_libraries(network network.cpp)
# tell cmake, that all targets that link with network library
# will have include path added
target_include_directories(network PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
I link only server executable with boost. I have no idea if your network library needs to link with boost too, if so, move the boost info netowrk/CMakeLists.txt and target_link_libraries(network PUBLIC ${Boost_LIBRARIES})
I think you have to change line
add_executable(server main.cpp)
to
add_executable(server main.cpp network.cpp)
P.S I personally prefer to use this construction:
SET(PROJECT_NAME "MyProject")
...
file(GLOB SRC_FILES *.cpp)
...
add_executable("${PROJECT_NAME}" "${SRC_FILES}")
I would like to link projects that are added via add_subproject with one another. Suppose i have a project structure like this:
(root)
I--exec
I--"some source files"
I--CMakeLists.txt
I--lib
I--"some source files"
I--CMakeLists.txt
I--CMakeLists.txt
Is there some way i can have my root level CMakeLists.txt just sort-of as a workspace file? So it behaves like a .sln from Visual Studio?
I tried this, to give you an idea of what i mean:
cmake_minimum_required(VERSION 2.8)
project(test)
add_subdirectory(exec)
add_subdirectory(lib)
target_link_libraries(exec lib)
target_include_directories(exec lib/include)
Obviously, it threw a config error at the second last line, stating that i cannot do that because exec is not built by this file (the current CMakeLists.txt?). Is there some way to achive what i want to do?
For CMake >= 2.8.10, the usage of target_link_libraries and target_include_directories is incorrect.
They should specify the target SYSTEM|BEFORE|PUBLIC|INTERFACE|PRIVATE; prefixed by LINK_ on target_link_libraries.
As a side-note, just for clear dependency management (IMHO):
In your root CMakeLists.txt there should be no target_link_libraries nor target_include_directories, they should be in the subproject. So your root CMakeLists, for example, should be:
cmake_minimum_required(VERSION 2.8)
project(test)
add_subdirectory(lib)
add_subdirectory(exec)
In your exec/CMakeLists.txt:
add_executable (exec main.cpp)
target_link_libraries (exec LINK_PUBLIC lib)
target_include_directories (exec PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../lib)
In your lib/CMakeLists.txt:
add_library (lib libmain.cpp)
target_include_directories (lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
I'm not sure if it makes a difference, but I use the add_subdirectory for the library before the executable.
I'm trying to learn cmake and have started converting an old make project over to cmake. Here is a simplified version of the directory structure I now have:
CMakeLists.txt
src/
CMakeLists.txt
main.cpp
core/
CMakeLists.txt
/sourcecode, other cmakes, etc.
test/
CMakeLists.txt
someTest.cpp
Currently, in my root CMakeLists.txt file I simply have this:
cmake_minimum_required(VERSION 2.8)
project(all)
add_subdirectory(src)
add_subdirectory(test)
What I wanted to do, was have a library created by core/CMakeLists.txt that can be used by both src/CMakeLists.txt to build the main executable, but also loaded by test/CMakeLists to build the unit tests.
So my src/core/CMakeLists.txt file currently looks sort of like this:
cmake_minimum_required(VERSION 2.8)
project(core)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wpedantic -Wreorder -DBOOST_TEST_DYN_LINK -DBOOST_LOG_DYN_LINK ")
#some other directories in my core code:
add_subdirectory(display)
add_subdirectory(training)
add_subdirectory(utility)
#some packages I use...
find_package(Boost 1.55.0
COMPONENTS
log
program_options
serialization
thread
system
filesystem
REQUIRED)
find_package(GLUT REQUIRED)
find_package(OpenGL REQUIRED)
find_package(Eigen3 REQUIRED)
include_directories(
${PROJECT_SOURCE_DIR}
${EIGEN3_INCLUDE_DIR})
target_link_libraries(core
display
training
utility
${Boost_LIBRARIES}
${OPENGL_LIBRARIES}
${GLUT_LIBRARY}
${OpenMP_LIBRARIES})
So the idea is that I now have a core target I can simply link against to run my tests, and everything should work. However, when I try to build main, for example, I get:
Cannot specify link libraries for target "core" which is not built by this
project.
I thought this might be because core doesn't have a add_library command, but if I add add_library(core) I get this error:
You have called ADD_LIBRARY for library core without any source files. This typically indicates a problem with your CMakeLists.txt file
But I don't want to add any source files; I just want this target to link the targets in the core directory and produce a target I can link against from test.
Clearly I'm missing some core knowledge here, either with cmake or the toolchain itself. Help is appreciated :)
If you only want to create a core target without source files, you need to declare it like an INTERFACE target. So, try to add the following code to your src/core/CMakeLists.txt:
cmake_minimum_required(VERSION 3.0) # REQUIRED 3.x.x version
project(core)
...
# Here declare your core_interface target
add_library(core_interface INTERFACE)
target_link_libraries(core_interface INTERFACE
display
training
utility
${Boost_LIBRARIES}
${OPENGL_LIBRARIES}
${GLUT_LIBRARY}
${OpenMP_LIBRARIES})
As you can see, if you make this, you'll need to upgrade your CMake installed version.
Then, you'll build your tests or any executable, linking with this interface target directly:
add_executable(main main.cpp)
target_link_libraries(main core_interface)
I have a set of files that I want to make into a library and then use that library in another project. This it how it looks like right now
cmake_minimum_required(VERSION 2.8)
aux_source_directory(. SRC_LIST)
SET(CMAKE_CXX_FLAGS "-std=c++11 -fopenmp -fPIC")
add_library (helperlibs lib1.cpp lib2.cpp lib3.cpp lib4.cpp )
INSTALL(TARGETS helperlibs
DESTINATION "${HOME}/lib"
)
INSTALL(FILES lib1.h lib2.h lib3.h lib4.h helperheader.h
DESTINATION "${HOME}/include/helperlibs"
)
In this code Lib4 depends on Lib1-3 and Lib3 depends on Lib1-2 and Lib2 depends on Lib1. Each of these cpp files also depend on a helperheader.h file that contains some definitions and structs.
In my project I have the following CMake file
cmake_minimum_required(VERSION 2.8)
aux_source_directory(. SRC_LIST)
SET( CMAKE_CXX_FLAGS "-std=c++11 -fopenmp -fPIC")
SET(MYINCS ${HOME}/include/helperlibs)
SET(MYLIBDIR ${HOME}/lib)
SET(MYLIBS ${MYLIBDIR}/libhelperlibs.a )
include_directories(${MYINCS})
add_executable(main main.cpp)
target_link_libraries(main ${MYLIBS})
So what I am wondering if you want to create a static library and link to from a another project using cmake is this the way you should write?
Embed the search paths into the library target as properties and create an export.
This way executables in the same build tree will find the library and its include files without you having to specify paths (they become implicit).
I needed to read the cmake documentation carefully a few times before it dawned on me how it should work.
http://www.cmake.org/cmake/help/v3.0/manual/cmake-packages.7.html#creating-packages
http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html
excerpt from a live example:
add_library(trustportal-util ${CMAKE_CURRENT_LIST_FILE} ${_source_files} ${_disabled_source_files} )
target_link_libraries(trustportal-util ${Boost_LIBRARIES})
if(APPLE)
find_library(SECURITY_FRAMEWORK Security)
target_link_libraries(trustportal-util ${SECURITY_FRAMEWORK})
else()
find_library(LIB_SSL ssl)
find_library(LIB_CRYPTO crypto)
target_link_libraries(trustportal-util ${LIB_SSL} ${LIB_CRYPTO})
endif()
target_compile_definitions(trustportal-util PUBLIC BOOST_MOVE_USE_STANDARD_LIBRARY_MOVE)
target_include_directories(trustportal-util PUBLIC ${Boost_INCLUDE_DIRS})
target_include_directories(trustportal-util PRIVATE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
target_include_directories(trustportal-util SYSTEM PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
install(TARGETS trustportal-util
EXPORT trustportal-utilExport
DESTINATION lib
INCLUDES DESTINATION include
)
INSTALL(EXPORT trustportal-utilExport DESTINATION lib)
One option is to do what you are currently doing where you place the includes and libs in a common location, perhaps /usr/include and /usr/lib on linux, or ${HOME} on both Windows/Linux, up to you.
Another option is available if you use git. You can include the project inside another using submodules. Then use include_directory(${submodule}) and build and link directly for every project. The advantage of this approach is that dependencies are more localised. One problem with this method is if you recursively do this, you may end up with duplicates of some projects and cmake will complain that two libraries have the same name.