How to add cmake project to another cmake project as library? - c++

I have been researching over hours but I still couldn't solve my problem.
This is Cmakelist of ProjectA. It perfectly works:
cmake_minimum_required(VERSION 3.5)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
project(ProjectA C CXX)
add_executable(ProjectA ${SOURCE_FILES_ProjectA})
target_link_libraries(ProjectA hts ${ZLIB} pthread)
target_compile_definitions(ProjectA PUBLIC -D_FILE_OFFSET_BITS=64 -DVERSION=\"${VERSION_STRING}\")
Now I want to add ProjectA to ProjectB as library but I got following error at first:
add_executable cannot create target "ProjectA" because another
target with the same name already exists. The existing target is a static
library created in source directory
Then, I changes cmakelist of projectB as below. Now makefile is created but it doesn't work. (I removed set(source_files) for simplicity)
ProjectB cmakelist:
include_directories(
${PROJECT_SOURCE_DIR}/lib
${PROJECT_SOURCE_DIR}/
${PROJECT_SOURCE_DIR}/lib/ProjectA)
add_library(ProjectA STATIC lib/ProjectA/src})
target_include_directories(ProjectA PUBLIC lib/ProjectA)
set_target_properties(ProjectA PROPERTIES LINKER_LANGUAGE CXX)
add_executable(ProjectB ${SOURCE_FILES})
target_link_libraries(ProjectB hts ${ZLIB} ProjectA pthread)
target_compile_definitions(ProjectB PUBLIC -D_FILE_OFFSET_BITS=64 -DVERSION=\"${VERSION_STRING}\")
Can you correct my cmakelist files, I am really lost in cmake syntax.

Related

CMake: Cannot link to a static library in a subdirectory

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)

Cannot build cmake project with including directories in cmake project

|---Engine
|----CMakeList.txt
|----Engine.cpp
|----Engine.h
|---Models
|----CMakeList.txt
|----Snake.cpp
|----Snake.hpp
|---Type
|----CMakeList.txt
|----Point.hpp
|---CMakeList.txt
|---main.cpp
I just can't tell the main sheet that I want to add a directory with files to it ...
Each time, errors of the following type appear:
CMake Error at CMakeLists.txt: 12 (target_include_directories):
Cannot specify include directories for target "Snake" which is not built by
this project.
CMake Error at CMakeLists.txt: 13 (target_link_directories):
Cannot specify link directories for target "Snake" which is not built by
this project.
CMake Error at Engine / CMakeLists.txt: 8 (target_include_directories):
Cannot specify include directories for target "Snake" which is not built by
this project.
CMake Error at CMakeLists.txt: 17 (target_link_libraries):
Cannot specify link libraries for target "Snake" which is not built by this
project.
- Configuring incomplete, errors occurred!
Which, for several hours of intensified attempts, are not corrected in any way. Can anyone help with this?
CMakeLists.txt from Engine folder:
set(HEADERS
Engine.h)
set(SOURCES
Engine.cpp)
add_library(Engine ${HEADERS} ${SOURCES})
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR})
Main CMakeList.txt:
cmake_minimum_required(VERSION 3.16.3)
project(Snake)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(PROJECT_SOURCES
main.cpp
)
target_include_directories(${PROJECT_NAME} PUBLIC Engine)
target_link_directories(${PROJECT_NAME} PUBLIC Engine)
add_subdirectory(Engine)
target_link_libraries(${PROJECT_NAME} Engine)
add_executable(${PROJECT_NAME}
${PROJECT_SOURCES}
)
find_package(SFML 2.5.1 COMPONENTS graphics audio REQUIRED)
include_directories(${SFML_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} sfml-graphics sfml-audio)
set(SFML_STATIC_LIBRARIES FALSE)
There are two errors. The first one is to call a PROJECT_NAME that hasn't been built yet. add_executable(${PROJECT_NAME} ...) and add_library(${PROJECT_NAME ...) should be used before the target_include_directories and target_link_directories that refers to it. Because, as #Stephen Newell noted, otherwise you will be using a PROJECT NAME that hasn't been declared/built yet.
The second error is that you are calling a PROJECT_NAME inside Engine/CMakeLists. Maybe you are missing a project(...) inside of it.
Maybe you should move set(SFML_STATIC_LIBRARIES FALSE) before linking it, as well.

Project Structure for unit testing (qtest) when using target_sources() command in sub directory

First of all, I know there are very similar questions in this forum. However, none really answer my specific case.
I have the following project structure:
|---Project_Root
|---CMakeLists.txt
|---build
|---src
| |---CMakeLists.txt
| |---many .cpp and .h files in multiple subfolders with a different CMakeLists.txt
|---tests
| |---CMakeLists.txt
| |---many .cpp files
In the Project_Root/CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
set(SRC_DIR src)
project(
Project
LANGUAGES CXX
)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(${PROJECT_NAME} "")
target_include_directories(${PROJECT_NAME} PRIVATE ${SRC_DIR})
add_subdirectory(${SRC_DIR})
In the src folder and subfolder CMakeLists.txt files:
cmake_minimum_required(VERSION 3.5)
set(SRC_FILES
Source1.cpp
)
set(HEADER_FILES
Source1.hpp
)
target_sources(${PROJECT_NAME}
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FILES}
${CMAKE_CURRENT_SOURCE_DIR}/${HEADER_FILES}
)
Now in the tests subfolder:
project(Test LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
enable_testing()
add_executable(Test tst_test.cpp)
add_test(NAME Test COMMAND Test)
target_link_libraries(Test PRIVATE Qt5::Test)
In the above CMakeLists.txt I want to include the main project as a static library. I can, for example, add a new library target (say Project_Lib) in the root CMakeLists.txt and use once again the command:
target_sources(Project_Lib
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FILES}
${CMAKE_CURRENT_SOURCE_DIR}/${HEADER_FILES}
)
in all the subfolders.
But is there a more elegant way of doing it without having to modify all the CMakeLists.txt in the subfolders? For example, is there way to extract the source files from the Project target, so that it can be reused to make the Project_Lib target?
As you described, you can make a new static library target Project_Lib. Take advantage of the fact that you parameterized the target name by using the project name (${PROJECT_NAME}), so you actually don't have to change all of the CMakeLists.txt files in the subfolders. Just change the project name.
As I commented, simply exclude the main.cpp file from the static library, and add it to a separate executable target instead.
In Project_Root/CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
set(SRC_DIR src)
# Change the project name, as now the static library is the primary target.
project(
Project_Lib
LANGUAGES CXX
)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Create the static library target, whose sources are populated in subdirectories.
add_library(${PROJECT_NAME} STATIC)
target_include_directories(${PROJECT_NAME} PRIVATE ${SRC_DIR})
# The only modification necessary in the subdirectories is to *exclude* the
# main.cpp file from the target_sources for the static library.
add_subdirectory(${SRC_DIR})
# Add *only* the main.cpp file to the executable target.
add_executable(Project_Exe src/main.cpp)
# Link the static library target to the executable.
target_link_libraries(Project_Exe PRIVATE ${PROJECT_NAME})
In tests/CMakeLists.txt:
...
# Link the static library to your Test executable also.
target_link_libraries(Test PRIVATE Project_Lib Qt5::Test)

How do I link a library using CMake?

I'm trying to add a new library to a project built using CMake and am having trouble. I'm trying to follow this. I've made a test project that looks like this:
cmake_test/
test.cpp
CMakeLists.txt
liblsl/
include/
lsl_cpp.h
CMakeLists.txt
liblsl64.dll
liblsl64.so
build/
the CMakeLists.txt in cmake_test looks like this:
cmake_minimum_required(VERSION 3.10)
# set the project name and version
project(Tutorial VERSION 1.0)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
add_executable(Tutorial test.cpp)
add_subdirectory(liblsl)
target_link_libraries(Tutorial PUBLIC ${LSL_LIBRARY})
and the CMakeLists.txt in liblsl looks like this:
find_path(LSL_INCLUDE_DIR lsl_cpp.h)
find_library(LSL_LIBRARY liblsl64)
include_directories(${LSL_INCLUDE_DIR})
But I keep getting the error No rule to make target '.../liblsl64.lib', needed by 'Tutorial.exe'. Stop.
Any idea what I'm doing wrong?
I'm on Windows 10 using mingw-w64 v5.4.0 if that makes any difference.
CMakeLists.txt in cmake_test:
cmake_minimum_required(VERSION 3.10)
project(Tutorial VERSION 1.0)
add_subdirectory(liblsl)
add_executable(Tutorial test.cpp)
target_compile_features(Tutorial PUBLIC cxx_std_11)
target_link_libraries(Tutorial PUBLIC liblsl)
CMakeLists.txt in liblsl:
add_library(liblsl SHARED IMPORTED GLOBAL)
set_target_properties(liblsl PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/include")
set_target_properties(liblsl PROPERTIES IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/liblsl64.so")
For Windows use:
set_target_properties(liblsl PROPERTIES IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/liblsl64.dll")
set_target_properties(liblsl PROPERTIES IMPORTED_IMPLIB "${CMAKE_CURRENT_SOURCE_DIR}/liblsl64.lib")
In add_library, you say SHARED because your library is a shared one (so/dll), you say IMPORTED because you don't want to build the library, and you say GLOBAL because you want it to be visible outside liblsl.

CMake: linking against a library linked to Qt5

I have a library which uses Qt5. I build it with this CMakeLists.txt file:
cmake_minimum_required (VERSION 3.0)
project (testLib LANGUAGES CXX)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
find_package(Qt5 REQUIRED Widgets)
add_library(testLib SHARED
src/TestClass.cpp
src/TestClass.h
)
target_include_directories(testLib PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
target_link_libraries(testLib PUBLIC Qt5::Widgets)
export(TARGETS testLib FILE testLib-exports.cmake)
Now I try to link an executable against this library in the build path. This is what I've tried so far:
cmake_minimum_required (VERSION 3.0)
project(TestProject)
add_executable(myexec src/main.cpp )
include(/path/to/testLib-exports.cmake)
target_link_libraries(myexec testLib)
I am getting this error:
Target "myexec" links to target "Qt5::Widgets" but the target was not
found. Perhaps a find_package() call is missing for an IMPORTED
target, or an ALIAS target is missing?
I don't want to explicitly use find_package() in myexec's cmake file, but want it to be transitive. How should I link against testLib then? If the answer is not in the build path it is fine.
EDIT: I changed the export line to:
export(TARGETS testLib FILE testLib-exports.cmake EXPORT_LINK_INTERFACE_LIBRARIES)
This seems to be exactly what I need, but the generated files with and without EXPORT_LINK_INTERFACE_LIBRARIES are identical. Both if them say
This file does not depend on other imported targets which have
been exported from the same project but in a separate export set.
As far as I understand, it should use testLib's target LINK_INTERFACE_LIBRARIES property, but I noticed that it is NOTFOUND. maybe this is the problem? However, INTERFACE_LINK_LIBRARIES has Qt5::Widgets.