My project structure is the following:
root
-CMakeLists.txt
----exec
-----CMakeLists.txt
-----src
------a.cpp
------a.h
----lib
-----CMakeLists.txt
-----src
------b.cpp
-----inc
------b.h
Exec target depends on lib target. My main CMakeLists.txt is just the following:
cmake_minimum_required(VERSION 2.8)
cmake_policy(SET CMP0048 NEW)
project(FOO CXX)
add_subdirectory(lib)
add_subdirectory(exec)
In the CMakeLists.txt of the library I use add_library() and I use add_executable() in the exec folder. The problem is that the executable can't find the library and I don't know how to say in the exec CMakeLists.txt that another target exist called lib which is a library to use. I think I'm missing something in the project configuration.
Lib CmakeLists.txt
cmake_minimum_required(VERSION 2.8)
cmake_policy(SET CMP0048 NEW)
project(BASIC CXX)
add_library(BASIC src/b.cpp)
set(HEADERS_FILE_DIRS inc)
include_directories(${HEADERS_FILE_DIRS})
#Linking
target_link_libraries(BASIC pthread)
Exec CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
cmake_policy(SET CMP0048 NEW)
project(EXEC CXX)
add_executable(EXEC src/a.cpp)
set(HEADERS_FILE_DIRS src ${CMAKE_CURRENT_SOURCE_DIR}/../lib/inc)
include_directories(${HEADERS_FILE_DIRS})
set_target_properties(EXEC PROPERTIES OUTPUT_NAME "EXEC")
find_library(BASIC_LIBRARY BASIC HINTS <ABS PATH HERE>/lib)
#Linking
target_link_libraries(EXEC pthread ${BASIC_LIBRARY})
As commented, you can simply link the BASIC CMake library target. Because it was created earlier in the same CMake invocation, CMake already know of its existence and will link it properly.
In addition, (if you can upgrade your CMake to at least 2.8.11) you can apply the lib/inc include directory directly to your BASIC library target using target_include_directories. Use the PUBLIC scoping argument here to propagate these include directories to consuming CMake targets. This way, you can avoid mentioning the lib/inc directory in your exec/CMakeLists.txt file altogether:
In lib/CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
cmake_policy(SET CMP0048 NEW)
project(BASIC CXX)
add_library(BASIC src/b.cpp)
set(HEADERS_FILE_DIRS inc)
# Assign this include directory to the target as a build AND usage requirement.
target_include_directories(BASIC PUBLIC ${HEADERS_FILE_DIRS})
# Linking
target_link_libraries(BASIC PUBLIC pthread)
In exec/CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
cmake_policy(SET CMP0048 NEW)
project(EXEC CXX)
add_executable(EXEC src/a.cpp)
set(HEADERS_FILE_DIRS src)
include_directories(${HEADERS_FILE_DIRS})
set_target_properties(EXEC PROPERTIES OUTPUT_NAME "EXEC")
# Linking BASIC to EXEC, which propagates the 'lib/inc' include directory
# and the 'pthread' library linkage to EXEC also.
target_link_libraries(EXEC PRIVATE BASIC)
Related
Here is my directory tree
I implemented accident component which have to be a standalone library. Here is CMakeLists.txt for it
set (ACCIDENT accident)
file (GLOB SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
file (GLOB HEADER_FILES "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp")
add_library (${ACCIDENT} STATIC ${HEADER_FILES} ${SOURCE_FILES})
target_include_directories (${ACCIDENT} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
add_subdirectory (test)
and that works fine. Now I am trying to use that library in note part which should be linked with accident. Especially the accident.hpp file should be visible in my IDE without doing things like this
#include "../../accident/include/accident.hpp"
and the code from accident.cpp should also be accessible. My attempts was similar to this one
set (MUSIC_NOTE music_note)
file (GLOB SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
file (GLOB HEADER_FILES "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp")
add_library (${MUSIC_NOTE} STATIC ${HEADER_FILES} ${SOURCE_FILES})
target_include_directories (${MUSIC_NOTE}
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include"
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../accident/include"
)
target_link_libraries (${MUSIC_NOTE} accident)
add_subdirectory (test)
unfortunately, it does not work - accident.hpp header is not found. Do you know where I am doing a mistake?
EDIT
In response to #Martin's question, here is my top level CMakeLists.txt
cmake_minimum_required (VERSION 3.5)
set (CMAKE_BUILD_TYPE Debug)
set (PROJECT_NAME scales)
project (${PROJECT_NAME} LANGUAGES CXX)
set (CMAKE_CXX_STANDARD 17)
set (CMAKE_CXX_STANDARD_REQUIRED ON)
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set (CMAKE_MODULE_PATH "${CMAKE_BINARY_DIR}" "${CMAKE_MODULE_PATH}")
set (CMAKE_PREFIX_PATH "${CMAKE_BINARY_DIR}" "${CMAKE_PREFIX_PATH}")
add_subdirectory (src)
add_subdirectory (external)
option (BUILD_TESTS "Build tests" ON)
enable_testing ()
if (BUILD_TESTS)
add_subdirectory (test)
endif ()
# Add google test
include (FetchContent)
FetchContent_Declare (
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG release-1.12.1
)
The note directory is in src, and src includes CMakeLists.txt with only one line
add_subdirectory (note)
In this note directory we have the stuff I pasted above Top level CMakeLists.txt in note directory contains
add_subdirectory (accident)
add_subdirectory (note)
EDIT 2
Problem resolved - see Ave Milia comment below. Thanks!
As we figured out in the comment section, the test executable was forgotten to be linked to the relevant static library.
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 want to build my C++ project with CMake and I want to include automatically every new file on "cmake ." my project structure is:
Application/ Graphics/ CMakeLists.txt CMakeLists.txt.user main.cpp
./Application:
CMakeLists.txt Logger/ Recovery/ application.cpp application.hpp firstclass.cpp firstclass.hpp singleton.hpp
./Application/Logger:
CMakeLists.txt logger.cpp logger.hpp
./Application/Recovery:
CMakeLists.txt recovery.cpp recovery.hpp
./Graphics:
CMakeLists.txt drawableobject.cpp drawableobject.hpp graphics.cpp graphics.hpp
Each folder has own CMakeLists.txt
I did so far this in master CMake:
cmake_minimum_required(VERSION 3.10)
# set the project name and version
project(Asteri VERSION 1.0)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
message("Source dir: ${SOURCE_DIR}")
#file(GLOB_RECURSE SRC_FILES ${SOURCE_DIR}/*.cpp)
#file(GLOB_RECURSE HEADER_FILES ${HEADER_DIR}/*.hpp)
set(PROJECT_NAME "Asteri")
macro(SUBDIRLIST result curdir)
file(GLOB children RELATIVE ${curdir} ${curdir}/*)
set(dirlist "")
foreach(child ${children})
if(IS_DIRECTORY ${curdir}/${child})
list(APPEND dirlist ${child})
endif()
endforeach()
set(${result} ${dirlist})
endmacro()
SUBDIRLIST(SUBDIRS ${CMAKE_CURRENT_SOURCE_DIR})
foreach(subdir ${SUBDIRS})
message("Subdirectory: ${subdir}")
add_subdirectory(${subdir})
endforeach()
add_executable(${Asteri} main.cpp)
The question is how to connect all pieces together?
What I need in other CMakeLists.txt?
How to communicate children -> parent or I misunderstood the concept of CMake?
No need for other CMakeLists.
I guess you want something like this in top CMakeLists:
cmake_minimum_required(VERSION 3.12)
project(Asteri VERSION 1.0)
file(GLOB_RECURSE ASTERI_SRC_FILES CONFIGURE_DEPENDS
"${PROJECT_SOURCE_DIR}/Application/*.cpp"
"${PROJECT_SOURCE_DIR}/Graphics/*.cpp"
)
add_executable(Asteri main.cpp ${ASTERI_SRC_FILES})
It's worth noting that GLOB/GLOB_RECURSE -even with CONFIGURE_DEPENDS- is bad practice: it's slow, specially on Windows from my experience, and may not work as expected depending on generator used.
I found out the answer to my problems.
set(SOURCES "${PROJECT_DIR}/main.cpp" CACHE INTERNAL STRINGS)
add_subdirectory(application)
FOREACH(it ${SOURCES})
message("source file: ${it}")
ENDFOREACH()
add_executable(Asteri ${SOURCES})
In this way I store main.cpp path into variable SOURCES
You can see your variables after 'make' in CMakeCache.txt.
After this is done, my variable SOURCES looks like:
/STRINGS
SOURCES:INTERNAL=/home/default/cpp_testing_project/cmake_project/source/main.cpp;
After that in application subdirectory I have CMakeLists.txt:
cmake_minimum_required(VERSION 3.7)
# Get source files
file(GLOB CPP_LIST "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/*.c")
set(SOURCES ${SOURCES} ${CPP_LIST} CACHE INTERNAL STRINGS)
And now SOURCES looks like:
SOURCES:INTERNAL=/home/default/cpp_testing_project/cmake_project/source/main.cpp;/home/default/cpp_testing_project/cmake_project/source/application/application.cpp;/home/default/cpp_testing_project/cmake_project/source/application/drawableobject.cpp;/home/default/cpp_testing_project/cmake_project/source/application/firstclass.cpp;/home/default/cpp_testing_project/cmake_project/source/application/graphics.cpp;/home/default/cpp_testing_project/cmake_project/source/application/application.hpp;/home/default/cpp_testing_project/cmake_project/source/application/drawableobject.hpp;/home/default/cpp_testing_project/cmake_project/source/application/firstclass.hpp;/home/default/cpp_testing_project/cmake_project/source/application/graphics.hpp;
I have the following directory structure:
main.cpp
CMakeLists.txt
src/
some_function.h
some_function.cpp
some_class.h
some_class.cpp
CMakeLists.txt
test/
catch.hpp
tests.cpp
CMakeLists.txt
CmakeLists.txt in the project root:
cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 11) # C++11
project(main)
add_subdirectory (src)
add_executable(main main.cpp)
target_link_libraries (main some_class)
CmakeLists.txt in the src/:
add_library (some_class some_class.h some_class.cpp some_function.h some_function.cpp)
The above works to build and run the main target.
Now I want to build and run tests. The file tests.cpp includes some_function.h and some_class.h. However, I am not sure how to add the src/ directory here.
This is what I have so far in test/ (results in a linking error for the function in some_function.h):
cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 11) # C++11
project(tests)
set(CATCH_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
add_library(Catch INTERFACE)
target_include_directories(Catch INTERFACE ${CATCH_INCLUDE_DIR})
add_executable(tests tests.cpp)
target_link_libraries(tests Catch)
Just link the some_class library target to the tests target, like you did with the main executable target.
CmakeLists.txt in the project root:
cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 11) # C++11
project(main)
add_subdirectory (src)
# Add the test sub-directory also.
add_subdirectory(test)
add_executable(main main.cpp)
target_link_libraries (main some_class)
CmakeLists.txt in the test directory:
project(tests)
set(CATCH_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
add_library(Catch INTERFACE)
target_include_directories(Catch INTERFACE ${CATCH_INCLUDE_DIR})
add_executable(tests tests.cpp)
# Link 'some_class' here also!
target_link_libraries(tests PRIVATE some_class Catch)
Normal targets created by add_library() or add_executable() have the scope of the project not the directory that's why their name must be unique within the project. So you can "target_link" some_class to your target tests even if target tests is not in a subdirectory of src/...
The <name> corresponds to the logical target name and must be globally unique within a project.
ref: https://cmake.org/cmake/help/latest/command/add_library.html#normal-libraries
This is not the case for imported targets.
The [imported] target name has scope in the directory in which it is created and below, but the GLOBAL option extends visibility. It may be referenced like any target built within the project.
ref: https://cmake.org/cmake/help/latest/command/add_library.html#imported-libraries
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.