I need to make library test and use it in other projects by #include <libraryname>
In project test:
CmakeLists.txt
...
add_library(libtest STATIC lib.h lib.cpp)
set_target_properties(libtest PROPERTIES PUBLIC_HEADER lib.h)
install(TARGETS libtest
PUBLIC_HEADER DESTINATION include
RUNTIME DESTINATION bin
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib)
...
In project testUseLibrary:
CmakeLists.txt
...
add_executable(project main.cpp)
target_link_libraries(project PUBLIC libtest)
...
main.cpp
#include <libtest> // error
int main() {
return 0;
}
In project testUseLibrary #include<libtest> doesn't see library.
You need to use target_include_directories to specify the include directories for your target. In this case, the directory where libtest resides.
Related
I am building a lib that is wrapping a third party lib. Both the third party lib and the wrapper lib are build using cmake with the add_library function with the STATIC keyword. However when I try to build a executable that uses this wrapper lib, I get undefined references to the third party lib. Here is the code:
Third party lib spdlog.cmake:
include(FetchContent)
FetchContent_Declare(
spdlog
GIT_REPOSITORY https://github.com/gabime/spdlog.git
GIT_TAG v1.11.0
)
FetchContent_MakeAvailable(spdlog)
This lib can be build in different ways, but I have checked that we use the line add_library(spdlog STATIC ${SPDLOG_SRCS} ${SPDLOG_ALL_HEADERS})
Then the wrapper lib utils.cmake:
cmake_minimum_required (VERSION 3.1)
project (Utils)
# set C++20
set (CMAKE_CXX_STANDARD 20)
include(cmake/spdlog.cmake)
file(GLOB SRCS src/*.cpp)
file(GLOB HDRS include/*.h)
add_library(Utils STATIC ${SRCS} ${HDRS})
target_include_directories(Utils PUBLIC include)
target_link_libraries(Utils PRIVATE spdlog)
I link here using PRIVATE since we do not expose spdlog in the headers of this lib.
Then the executable cmake. Actually the wrapper lib is a separate project and the (static) lib that is created and its header files are is copied to a folder (Libs/Utils/lib and Libs/Utils/include) of the executable project.
cmake_minimum_required (VERSION 3.1)
project (Foo)
# Find Utils
set(UTILS_DIR "${PROJECT_SOURCE_DIR}/Libs/Utils")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${UTILS_DIR}/cmake/")
find_package(UTILS REQUIRED)
file(GLOB SRCS src/*.cpp)
add_executable(Foo ${SRCS})
target_include_directories(Foo PUBLIC ${UTILS_INCLUDE_DIRS})
target_link_libraries(Foo ${UTILS_LIBRARIES})
Finally the find script for the Utils lib:
SET(UTILS_DEFINITIONS ${UTILS_DEFINITIONS})
IF (UTILS_INCLUDE_DIR)
# Already in cache, be silent
SET(UTILS_FIND_QUIETLY TRUE)
ENDIF (UTILS_INCLUDE_DIR)
set(UTILS_INCLUDE_DIR
${UTILS_DIR}/include
)
set(UTILS_STATIC_LIBRARY
${UTILS_DIR}/lib/libUtils.a
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(UTILS DEFAULT_MSG
UTILS_INCLUDE_DIR UTILS_STATIC_LIBRARY)
mark_as_advanced(UTILS_INCLUDE_DIR UTILS_STATIC_LIBRARY)
set(UTILS_LIBRARIES ${UTILS_STATIC_LIBRARY})
set(UTILS_INCLUDE_DIRS ${UTILS_INCLUDE_DIR})
The Utils lib builds fine, but when I build Foo, I get a lot of linker errors (the Logger.cpp is a file in Utils lib:
Logger.cpp:(.text+0x90): undefined reference to `spdlog::logger::sinks()
If I also copy the (static) lib of spdlog to libs folder and set UTILS_STATIC_LIBRARY to include this lib, it links. However since the spdlog is build statically I would assume that linking to the Utils lib would be enough.
Can somebody tell me what I am doing wrong?
I am making a custom library that I want to be installable for users. However, when I try to use my own library in a cmake executable, I get a build error saying that the library headers were not found.
The library CMakeLists.txt:
cmake_minimum_required(VERSION 3.16)
project(mylibrary)
include(GNUInstallDirs)
set(CMAKE_CXX_STANDARD 14)
# Register a library - This will created lib[xxx].so
add_library(mylibrary SHARED src/library.cpp)
configure_file(mylibrary.pc.in mylibrary.pc #ONLY)
# List the /include directory
target_include_directories(mylibrary PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
install(TARGETS mylibrary
EXPORT mylibraryConfig
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
export(TARGETS mylibrary
FILE "${CMAKE_CURRENT_BINARY_DIR}/mylibraryConfig.cmake")
install(EXPORT mylibraryConfig
DESTINATION "${CMAKE_INSTALL_LIBDIR}/mylibrary/cmake"
NAMESPACE mylibraryConfig::)
install(
DIRECTORY include
DESTINATION ${CMAKE_INSTALL_PREFIX})
install(FILES ${CMAKE_BINARY_DIR}/mylibrary.pc
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig)
Which I successfully build and install with:
$ cmake .. -DCMAKE_INSTALL_PREFIX=~/libraries/local # Use non-standard destination
$ make && make install
The executableCMakeLists.txt:
cmake_minimum_required(VERSION 3.16)
project(myexecutable)
set(CMAKE_CXX_STANDARD 14)
find_package(mylibrary REQUIRED)
add_executable(myexecutable src/main.cpp)
target_link_libraries(myexecutable PUBLIC mylibrary)
target_include_directories(myexecutable PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
I can prepare cmake for this project:
$ cmake .. -DCMAKE_PREFIX_PATH=~/libraries/local # Use non-standard location
However, building it fails:
$ make
fatal error: mylibrary/library.h: No such file or directory
2 | #include <mylibrary/library.h>
To my understanding the location of the library (binaries and headers) is embedded in the installed package. And through find_package() that information retrieved, so why isn't it working here?
Similar questions:
I largely based my library cmake on: How to create a shared library with cmake?
Same problem but I am already using target_include_directories: Cmake Linking Shared Library: "No such file or directory" when include a header file from library
When a shared library target is namespaced in the config file you need to reference it with the full name in the downstream packages when using find_package, i.e. you need to use
target_link_libraries(myexecutable PUBLIC mylibraryConfig::mylibrary)
Alternatively, remove the namespace from the install by replacing
install(EXPORT mylibraryConfig
DESTINATION "${CMAKE_INSTALL_LIBDIR}/mylibrary/cmake"
NAMESPACE mylibraryConfig::)
...with:
install(EXPORT mylibraryConfig
DESTINATION "${CMAKE_INSTALL_LIBDIR}/mylibrary/cmake")
I am confused on how to statically include the source code of SDL2. I am trying to do this to make a library I am working on more portable.
Currently, when I try to include my library in another project it says "Cannot open include file: 'SDL2/SDL.h': No such file or directory".
My Filesystem:
include
--Header Files
src
--Source Files
extern
--SDL2
build
Here is an example of the file causing the error:
#include <iostream>
#include <SDL2/SDL.h> //Error
using namespace std;
/* The code */
Here is an example of my main CMakeLists.txt:
cmake_minimum_required(VERSION 3.7)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
project(MyProject VERSION 1.0.0)
set(SDL2_SOURCE_DIR “${CMAKE_SOURCE_DIR}/extern/SDL2”)
add_subdirectory(extern/SDL2)
add_subdirectory(src)
Here is an example of my src CMakeLists.txt:
set(PROJECT_NAME MyProject)
file(GLOB HEADER_FILES "${CMAKE_SOURCE_DIR}/include/*.h")
file(GLOB SOURCES "*.cpp")
add_library(${PROJECT_NAME} ${SOURCES} ${HEADER_FILES})
target_include_directories(${PROJECT_NAME} PUBLIC "${CMAKE_SOURCE_DIR}/include")
target_link_libraries(${PROJECT_NAME} PRIVATE SDL2main SDL2-static)
set_target_properties( ${PROJECT_NAME}
PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin"
)
add_subdirectory() will process the subdirectory as a cmake porject (process the provided CMakeLists.txt for SDL). If you read that CMakeLists.txt, you'd see that it add the include directories relative to SDL2_SOURCE_DIR, which is empty by default.
What I would try is to set SDL2_SOURCE_DIR to ${CMAKE_CURRENT_SOURCE_DIR}/extern/SDL2 to make the path absolute. Like that SDL include dirs will be valid everywhere in your project.
You can also manually add the correct includes by using the include_directories() directive.
I am trying to learn CMake and for that purpose I am working with an example project of the structure shown below. I am trying to configure all the CMakeLists.txt files such that after make install I can copy the resulting build directory and copy-paste it around freely such that other people are able run the executable.
Problem: after running make install (maxOS 10.14.6 (Darwin 18.7.0)) everything works if I run the executable inside build BUT if I move the build directory from its original location - for example to Desktop - the executable is unable to find the shared libraries. It seems that the reason for this is that the paths to the shared libraries are defined as absolute paths instead of relative paths with respect to the build directory.
Question: How can I build the project such that the executable finds the shared libs?
Project structure:
myapp
|
CMakeLists.txt (top-level)
- build
- app
| CMakeLists.txt (app)
| - inc
| - app
| app.h
| - src
| app.cpp
| main.cpp
|
- external
|
- mylib
CMakeLists.txt (mylib)
- inc
- mylib
mylib.h
- src
mylib.cpp
CMakeLists:
CMakeLists.txt (top-level)
cmake_minimum_required(VERSION 3.0)
project(myapp)
add_subdirectory(external/mylib)
add_subdirectory(app)
CMakeLists.txt (app)
# myapp program
cmake_minimum_required(VERSION 3.0)
project(myapp_prog)
set(SOURCES ./src/)
set(HEADERS ./inc/app/)
set(SOURCE_FILES
${SOURCES}/app.cpp)
set(HEADER_FILES
${HEADERS}/app.h)
# All sources that need to be tested in unit test go into a static library
add_library(myapp_lib SHARED ${HEADER_FILES} ${SOURCE_FILES})
target_include_directories(myapp_lib PUBLIC ${HEADERS})
# The main program
add_executable(prog ./src/main.cpp)
target_include_directories(prog PUBLIC ./inc/)
# Link the libraries
target_link_libraries(prog PRIVATE myapp_lib mylib)
install(TARGETS myapp_lib DESTINATION ${CMAKE_BINARY_DIR}/lib)
CMakeLists.txt (mylib)
# mylib
cmake_minimum_required(VERSION 3.0)
project(mylib)
set(SOURCES src/)
set(HEADERS inc/mylib/)
set(SOURCE_FILES
${SOURCES}/mylib.cpp)
set(HEADER_FILES
${HEADERS}/mylib.h)
add_library(mylib SHARED ${HEADER_FILES} ${SOURCE_FILES})
target_include_directories(mylib PUBLIC inc/)
install(TARGETS mylib DESTINATION ${CMAKE_BINARY_DIR}/lib)
C++ code:
mylib.h
void mylib_print_hello();
mylib.cpp
#include "library.h"
#include <iostream>
void mylib_print_hello() {
std::cout << "Hello from mylib!" << std::endl;
}
app.h
void myapp_hello();
app.cpp
#include <iostream>
#include "app.h"
void myapp_hello()
{
std::cout << "Hello from myapp!" << std::endl;
}
main.cpp
#include <iostream>
#include "app/app.h"
#include "mylib/mylib.h"
int main()
{
myapp_hello();
mylib_print_hello();
}
I think the issue is that you might be confusing the build step with the install step. By using ${CMAKE_BINARY_DIR}, you are passing an absolute path to your binary directory (build), which may interfere with the moving of the build afterwards. If you would like to ouput your libraries to a folder after the build, you may set the target of the library with:
set_target_property(<library-name> PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
This will affect only the build stage of your project. As far as installs go, you are better off using only relative paths in the install directives. These paths will be relative to your ${CMAKE_INSTALL_PREFIX} variable. For example, you would use:
install(TARGETS mylib DESTINATION lib)
To install the library under the ${CMAKE_INSTALL_PREFIX}/lib folder. Best practice states that you should NEVER manipulate this variable directly in your CMakeLists.txt files, as it could break a build somewhere down the line. Starting with CMake 3.15, it is possible to use cmake --install to install a project. This command allows setting an installation prefix, such as:
cmake --install . --prefix desired/install/path
With this, all your link path should stay valid.
Please add a macos tag to this question.
I think that you are looking for a relative RPATH. CMake builds the executable with an absolute RPATH, so if you move or rename the build directory the program stop working. In your example, you only need to modify the main program CMakeLists.txt, to change the value of the RPATHs that CMake inserts in your executable.
# The main program
add_executable(prog ./src/main.cpp)
target_include_directories(prog PUBLIC ./inc/)
set_target_properties(prog PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE INSTALL_RPATH "#executable_path/;#executable_path/../external/mylib")
You can verify the values of the LC_RPATHs with this command from your build directory:
$ otool -l app/prog
For dependencies between libraries, it may also be useful "#loader_path" instead of #executable_path. And for other Unix operating systems, use "$ORIGIN". More information here.
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.