I want to use modern CMake project structure convention in my new project to follow good practices and to be consistent with many other projects, but I'm facing problem with include path.
My directories structure looks as follows:
.
├── build
├── CMakeLists.txt
├── extern
│ └── CMakeLists.txt
└── src
├── CMakeLists.txt
└── main.cpp
I want to use FetchContent_Declare instead of git submodules to manage the third-party libraries.
The root CMakeLists.txt:
cmake_minimum_required(VERSION 3.16 FATAL_ERROR)
set(ProjectName "MyApp")
project(${ProjectName})
add_subdirectory(extern)
add_subdirectory(src)
The extern CMakeLists.txt:
cmake_minimum_required(VERSION 3.16 FATAL_ERROR)
include(FetchContent)
FetchContent_Declare(
extern_spdlog
GIT_REPOSITORY https://github.com/gabime/spdlog.git
GIT_TAG v1.8.2)
FetchContent_GetProperties(extern_spdlog)
if(NOT extern_spdlog_POPULATED)
FetchContent_Populate(extern_spdlog)
add_subdirectory(
${extern_spdlog_SOURCE_DIR}
${extern_spdlog_BINARY_DIR}
)
endif()
The src CMakeLists.txt:
cmake_minimum_required(VERSION 3.16)
set(BINARY ${CMAKE_PROJECT_NAME})
file(GLOB_RECURSE SOURCES LIST_DIRECTORIES true *.h *.cpp)
set(SOURCES ${SOURCES})
add_executable(${BINARY}_run ${SOURCES})
add_library(${BINARY}_lib STATIC ${SOURCES})
target_link_libraries(${BINARY}_run extern_spdlog)
And the main.cpp:
#include <spdlog/spdlog.h>
int main(int argc, char* argv[]) {
spdlog::info("Welcome to spdlog!");
return 0;
}
CMake executes and the spdlog library is cloned properly and can be found in the build directory at: build/_deps/extern_spdlog-src.
If I call make in the build directory then I get fatal error: spdlog/spdlog.h: No such file or directory.
How to add include directories for the external libraries used in the application?
I was initially confused about this as well. It doesn't help that the names of the FetchContent targets often match the names of the imported targets. What worked for me was similar (though not identical) to what the first comment states. I used target_link_libraries(target spdlog::spdlog) (if you want to use the pre-compiled library or spdlog::spdlog_header_only if you want to use the header source only version.
Related
A bit of background on what I am trying to achieve: I already have a project that I have developed in CMake (it is collection of CMake projects: basically a state machine with a few helper libraries). Now, I want to develop a GUI in Qt that this state machine can control (and make it do stuff). However, for the life of me, I cannot figure out how to properly export the library which has the Qt classes and functions to another CMake package's executable. I am on Windows, and using the Mingw-w64 compiler and make program.
I was experimenting with 2 simple CMake projects, one which has a simple Qt form (which I just copied from and modified this repository and the corresponding youtube video given in the README), and the other which has the executable. I was trying to link the first project with the second project, however, whenever I build the autogenerated makefile, it fails in the end, saying that symbols are undefined (For example undefined reference to run_stuff::run_stuff()'). I apologize if the files are dirty, I have been trying out various stuff to no avail.
Things I have tried:
I have followed the answer here very carefully.
I have tried setting CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS to ON, as suggested by many sites (like this one) for running DLLs
I have tried making the library static (hence doing away with the need for DLLs)
I have tried setting the target_include_dirs from private to public and also commenting out that line. (not sure what that does, but okay)
However, no matter what I do, I always end with linking errors in the end, and my executable in the second project is not able to access any functions from the Qt project. Any suggestions on what I should try next? Would be really helpful if you could point out errors I am making in my CMakeLists.txt files (once again apologies for the messy code and CMakeLists)
My project CMake file looks like this:
cmake_minimum_required(VERSION 3.14)
# if (WIN32)
# set(CMAKE_SHARED_LIBRARY_PREFIX "")
# endif ()
set(CMAKE_MAKE_PROGRAM $ENV{MAKE})
set(CMAKE_CONFIGURATION_TYPES "Release;RelWithDebInfo" CACHE STRING "" FORCE)
set(CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS ON)
set(WINDOWS_EXPORT_ALL_SYMBOLS ON)
add_subdirectory(QT6CMake)
add_subdirectory(Exec)
The library CMake file:
cmake_minimum_required(VERSION 3.14)
if (WIN32)
project(MY_PROJECT LANGUAGES CXX)
elseif(UNIX)
project(MY_PROJECT)
endif()
set(CMAKE_CONFIGURATION_TYPES "Release;RelWithDebInfo" CACHE STRING "" FORCE)
#======================= INCLUSION OF Qt =======================#
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_PREFIX_PATH $ENV{QTDIR})
find_package(Qt6Core REQUIRED)
find_package(Qt6Widgets REQUIRED)
#=================== INCLUSION OF Project Files ====================#
set(FORMS_DIR "${CMAKE_SOURCE_DIR}/forms")
set(INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include")
set(SOURCE_DIR "${CMAKE_SOURCE_DIR}/src")
include_directories(${FORMS_DIR})
include_directories(${INCLUDE_DIR})
include_directories(${SOURCE_DIR})
file(GLOB_RECURSE SOURCES
"${FORMS_DIR}/*.ui"
"${FORMS_DIR}/*.qrc"
"${INCLUDE_DIR}/*.h"
"${SOURCE_DIR}/*.cpp"
)
#=================== SETUP EXECTUABLE ====================#
# Enable debug logging on RELWITHDEBINFO configuration
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS
$<$<CONFIG:RELWITHDEBINFO>:QT_MESSAGELOGCONTEXT>
)
# Add the forms directory to the AUTOUIC search paths
set(CMAKE_AUTOUIC_SEARCH_PATHS ${CMAKE_AUTOUIC_SEARCH_PATHS} ${FORMS_DIR})
# Add the executable
if (WIN32)
add_executable(MY_PROJECT WIN32 ${SOURCES})
elseif(UNIX)
add_executable(MY_PROJECT ${SOURCES})
endif()
# Add the target includes for MY_PROJECT
target_include_directories(MY_PROJECT PRIVATE ${FORMS_DIR})
target_include_directories(MY_PROJECT PRIVATE ${INCLUDE_DIR})
target_include_directories(MY_PROJECT PRIVATE ${SOURCE_DIR})
#===================== LINKING LIBRARIES =======================#
target_link_libraries(MY_PROJECT Qt6::Widgets)
The Exec CMake file:
cmake_minimum_required(VERSION 3.14)
project(somexec)
add_definitions(${MY_PROJECT_DEFINITIONS})
include_directories(${MY_PROJECT_INCLUDE_DIRS})
if (WIN32)
add_executable(${PROJECT_NAME} WIN32 main.cpp)
elseif(UNIX)
add_executable(${PROJECT_NAME} main.cpp)
endif()
target_link_libraries(${PROJECT_NAME} MY_PROJECT)
Here is the codebase.
EDIT:
Finally the code seems to be working, courtesy of Guillaume Racicot's multiple edits and fixes. I am going to leave this repository public in case anyone wants to see the codebase. Also, right now, I don't understand all the CMake commands that he has used, will try to understand those as well
The CMake code from the tutorial uses very old fashioned and outdated CMake practices. It works when creating a simple project, but won't work when doing libraries. To share files between projects, you need to export the CMake targets. You can do that by creating this file first:
cmake/yourlibrary-config.cmake
include(CMakeFindDependencyMacro)
# write it like you find_package of your cmake scripts
find_dependency(Qt6 COMPONENTS Core Widgets REQUIRED)
include("${CMAKE_CURRENT_LIST_DIR}/yourlibrary-targets.cmake")
Then, add this to your main project cmake files. You should have a CMake file that looks like this:
cmake_minimum_required(VERSION 3.21)
project(yourlibrary CXX)
# First, create your library. List all the files one by one. Don't use globs
add_library(yourlibrary src/mainwindow.cpp)
# Then add an alias of your library to enable target syntax
add_library(yourlibrary::yourlibrary ALIAS yourlibrary)
# Automatically generate Qt ui and moc
set_target_properties(yourlibrary PROPERTIES
AUTOUIC ON
AUTOMOC ON
AUTOUIC_SEARCH_PATHS forms
)
# Then, include gnuinstalldir to get the platform's standard directories:
include(GNUInstallDirs)
# Then, carefully add your include directories. All of your `target_include_directories` must look like this
target_include_directories(yourlibrary PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> # include directory in your build tree
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> # include directory when installed
)
# Then, include Qt and link qt
find_package(Qt6 COMPONENTS Core Widgets REQUIRED)
target_link_libraries(yourlibrary PUBLIC Qt6::Core Qt6::Widgets)
# Now, create the install script. We install all header files under `include/yourlibrary` to install them in `<prefix>/include/yourlibrary`:
install(
DIRECTORY include/yourlibrary
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN "*.hpp" PATTERN "*.h"
)
# We add `yourlibrary` target into the export set.
# The export set will contain all targets to be imported by the other project.
# It also installs the library to the install script so they are installed:
install(TARGETS yourlibrary EXPORT yourlibrary-targets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
# Now, we install the export set. This will generate a CMake file exporting all the target for other projects to use:
install(EXPORT yourlibrary-targets
DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/yourlibrary"
NAMESPACE yourlibrary::
)
# Now, we also export the current buildtree. Other project will be able to import the project directly from a build dir:
configure_file(cmake/yourlibrary-config.cmake yourlibrary-config.cmake COPYONLY)
export(
EXPORT yourlibrary-targets
NAMESPACE yourlibrary::
FILE "${PROJECT_BINARY_DIR}/yourlibrary-targets.cmake"
)
# The file we created earlier:
install(
FILES cmake/yourlibrary-config.cmake
DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/yourlibrary"
)
I omitted the installation of the generated headers since they are usually considered private for the project.
For the library, have a source tree looking like this:
yourlibrary
├── cmake
│ └── yourlibrary-config.cmake
├── forms
│ └── mainwindow.ui
├── include
│ └── yourlibrary
│ └── mainwindow.h
├── src
│ └── mainwindow.cpp
└── CMakeLists.txt
To use the library, you have two choices.
Either you embed it in your project using add_subdirectory(yourlibrary)
Either you build it separately and use find_package(yourlibrary REQUIRED)
You can't do both.
I usually prefer using find_package, but it require a package manager to avoid manually building all dependencies.
If you use add_subdirectory
Then remove find_package(yourlibrary REQUIRED) from your project. Simply add the directory and have your main project file look like this:
cmake_minimum_required(VERSION 3.21)
project(exec LANGUAGES CXX)
# Embed the project
add_subdirectory(yourlibrary)
add_executable(myexec main.cpp)
target_link_libraries(myexec PUBLIC yourlibrary::yourlibrary)
I assume a project tree like this:
SampleProject
├── yourlibrary
│ └── ...
├── CMakeLists.txt
└── main.cpp
If you build yourlibrary separately
First, build the library and (optionally) install it in a known location.
Now, you can build your library that uses Qt. You will need a CMakeLists.txt that looks like this:
cmake_minimum_required(VERSION 3.21)
project(myexec LANGUAGES CXX)
# also finds Qt and all
find_package(yourlibrary REQUIRED)
add_executable(myexec main.cpp)
target_link_libraries(myexec PUBLIC yourlibrary::yourlibrary)
If you install the yourlibrary library, it will simply work. If you want to use it from its build tree, simply run the CMake command with -DCMAKE_PREFIX_PATH=/path/to/yourlibrary/build. It should point to the build directory of the library, or the installation prefix if you installed it in a custom location.
I'm trying to build two projects using cmake at same-time.
My folder structure is as follows:
project
├── CMakeLists.txt
├── build
├── out
├── lib
├── yanthra_engine
│ ├── CMakeLists.txt
│ └── ...
└───sandbox
├── CMakeLists.txt
└── ...
main CmakeLists.txt
cmake_minimum_required(VERSION 3.4.1)
project(yanthra_console VERSION 0.1 DESCRIPTION "A 3d Game Engine.")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -fexceptions")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release;Debug" CACHE STRING "Build type selections" FORCE)
add_subdirectory(yanthra_engine)
add_subdirectory(sandbox)
yanthra_engine/CMakeLists.txt
set(THIRD_PARTY_DIR "../../../third-party")
set(MAIN_SOURCE_DIR "../../main/src")
include_directories(${THIRD_PARTY_DIR}/SDL/include)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../lib )
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../lib)
file(GLOB_RECURSE CPP_HEADERS ${MAIN_SOURCE_DIR}/*.hpp)
file(GLOB_RECURSE CPP_SOURCES ${MAIN_SOURCE_DIR}/*.cpp)
add_library(
yanthra
SHARED
${CPP_HEADERS}
${CPP_SOURCES}
)
set (CMAKE_SHARED_LINKER_FLAGS "-F../yanthra_engine/Frameworks -framework SDL2 -framework OpenGL")
sandbox/CMakeLists.txt
set(THIRD_PARTY_DIR "../../main")
set(MAIN_SOURCE_DIR "./src")
include_directories(${THIRD_PARTY_DIR}/include)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../out)
file(GLOB_RECURSE CPP_HEADERS ${MAIN_SOURCE_DIR}/includes/*.h)
file(GLOB_RECURSE CPP_SOURCES ${MAIN_SOURCE_DIR}/*.cpp)
file(GLOB_RECURSE LIB ${MAIN_SOURCE_DIR}/../lib/*.dylib)
add_executable(
yanthra_sandbox
${CPP_HEADERS}
${CPP_SOURCES}
)
set_target_properties(
yanthra_sandbox
PROPERTIES
LINK_FLAGS
"-F../yanthra_engine/Frameworks -framework SDL2 -framework OpenGL"
)
target_link_libraries(yanthra_sandbox PRIVATE ${LIB})
I would like to know if I'm generating library file in each build mode, how will I link it with it's corresponding executable, given the fact that each mode builds its output to to its own folder i.e for library its lib/Debug (for debug mode) and for executable its out/Debug.
You don't seem to link the link the yanthra target. You should do this though, since this will automatically choose the library compiled with the current configuration.
sandbox/CMakeLists.txt
...
target_link_libraries(yanthra_sandbox PRIVATE yanthra ${LIB})
...
As for importing the other libs: It would be preferrable to use find_library. This should automatically set the link options and make adding them for yanthra_sandbox unnecessary.
yanthra_engine/CMakeLists.txt
...
list(APPEND CMAKE_FRAMEWORK_PATH "${CMAKE_CURRENT_SOURCE_DIR}/Frameworks")
find_library(SDL2_LIB SDL2 REQUIRED)
find_library(OPEN_GL_LIB OpenGL REQUIRED)
target_link_library(yanthra PUBLIC "${SDL2_LIB}" "${OPEN_GL_LIB}")
This should allow you to remove the compiler flags from both targets. If there are no dependencies in the lib directory you could also remove the search for the libraries on the file system/
I'm struggling with an project that includes CMake (version 3.11) and subdirectories. It includes ITK as an external library.
I want to create library that I can use in the different subdirectories like MyApp to build multiple applications that are based on MyLib and every change in MyLib is updated in the other applications. The MyLib is a header-only templated library. In addition this kind of libraries do not get a own project in VisualStudio.
My questions are:
What is the correct way of using CMake in this scenario? I have searched and tried some example but was not successful. Ideally I can build applications depending on the MyLib independently. The top CMakeLists.txt may not pull in the includes from the library. This should be done by the applications.
What would change if the MyLib becomes a non-header-only library? In the future I may add non templated classes.
Bonus question:
How can I add the header-only library to VisualStudio? This is more a question for convencience.
Any help is appreciated and I can provide more details if necessary.
The source environment looks like this:
ProjectDirectory
- CMakeLists.txt
-- MyLib
- CMakeLists.txt
-- include
- File1.h (template header)
- File1.hxx (template body)
-- src
- (empty for now)
-- MyApp
- CMakeLists.txt
- AppFile1.cxx (File containing main function)
This is an out-of-source-build project. Ideally the compiled libraries and application are put in a directory like this (on Windows):
└── bin
├── Debug
│ ├── MyApp.exe
│ └── MyLib.lib
└── Release
├── MyApp.exe
└── MyLib.lib
ProjectDirectory CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(project_name)
# Setup build locations.
if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
endif()
if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
endif()
if(NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
endif()
add_subdirectory(MyLib)
add_subdirectory(MyApp)
MyLib CMakeLists.txt:
find_package(ITK REQUIRED
COMPONENTS RTK ITKImageIO)
include(${ITK_USE_FILE})
set(HDRS
${CMAKE_CURRENT_SOURCE_DIR}/include/File1.h
${CMAKE_CURRENT_SOURCE_DIR}/include/File1.hxx
)
add_library(MyLib ${HDRS})
target_include_directories(MyLib
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
PRIVATE
src)
target_link_libraries(MyLib
PUBLIC ${ITK_LIBRARIES})
export(TARGETS MyLib FILE MyLibConfig.cmake)
MyApp CMakeLists.txt
find_package(ITK REQUIRED
COMPONENTS RTK ITKRegistrationMethodsv4 ITKTransformIO ITKImageIO)
include(${ITK_USE_FILE})
set(SRCS
AppFile1.cxx)
add_executable(MyApp ${SRCS})
include_directories(${CMAKE_SOURCE_DIR}/MyLib/include)
target_link_libraries(MyApp
${ITK_LIBRARIES}
MyLib)
Edit1: Remove the project(X) from MyLib and MyApp CMakeLists.txt and change target to MyLib.
You can have an empty project, just create a custom target:
add_custom_target(MyLib SOURCES ${CMAKE_MYLIB_SRC} ${CMAKE_MYLIB_HDR})
As your code is header only, any depend target will see the changes in the files and would be recompiled. There is nothing to do on top of this. You don't have to create the target, although for your third question, that's the answer.
But if ITK is only your dependency, now that you have a target, you can add PUBLIC properties on it, like dependent libraries that need to be linked against it because of your library.
In that case, the code for them needs to add:
target_link_library(${NEWTARGET} PRIVATE MyLib) # PUBLIC/PRIVATE has to be tailored
That's the answer for question 1.
If your library becomes non-header only, just change the add_custom_target call.
What is the proper way to install bundled interface dependencies in Modern CMake?
I have a library MyLib that has an interface dependency on libDep (MyLib.hpp contains #include <libDep.h>). Anything that depends on MyLib also transitively depends on libDep.
libDep is a single header taken from a gist so I have included it part of the source-tree of MyLib
$ tree
.
├── CMake
│ ├── MyLibConfig.cmake.in
│ └── modules
│ └── FindlibDep.cmake
├── CMakeLists.txt
├── include
│ └── MyLib
│ └── MyLib.hpp
├── src
│ └── MyLib.cpp
└── third_party
└── libDep
└── libDep.h
I would like to install libDep with myLib, in with a path like include/MyLib/third_party/libDep.
Here is the CMakeLists for MyLib
cmake_minimum_required(VERSION 3.3.0)
Project(MyLib
DESCRIPTION "Library with bundled interface dependency"
LANGUAGES CXX)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMake/modules)
# Find LibDep dependency
find_package(libDep REQUIRED)
# MyLib library
add_library(MyLib STATIC
${CMAKE_SOURCE_DIR}/src/MyLib.cpp)
target_include_directories(MyLib
PUBLIC $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include/MyLib>
PUBLIC $<INSTALL_INTERFACE:include/MyLib>)
target_link_libraries(MyLib
INTERFACE libDep)
MyLib locates libDep with FindlibDep.cmake located in CMAKE_MODULE_PATH
find_path(LibDep_INCLUDE_DIR
NAMES LibDep.hpp
PATHS third_party/libDep)
PATH_SUFFIXES Mylib/third_party/libDep)
mark_as_advanced(LibDep_FOUND LibDep_INCLUDE_DIR)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LibDep
REQUIRED_VARS
LibDep_INCLUDE_DIR
)
if(LibDep_FOUND)
set(LibDep_INCLUDE_DIRS ${LibDep_INCLUDE_DIR})
endif()
if(LibDep_FOUND AND NOT TARGET MyLib::LibDep)
add_library(MyLib::LibDep INTERFACE IMPORTED)
set_target_properties(MyLib::LibDep PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES ${LibDep_INCLUDE_DIR})
endif()
I install MyLib like
install(TARGETS MyLib
EXPORT MyLibTargets
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
RUNTIME DESTINATION bin
INCLUDES DESTINATION include)
include(CMakePackageConfigHelpers)
write_basic_package_version_file(MyLibConfigVersion.cmake)
install(EXPORT MyLibTargets
FILE MyLibTargets.cmake
NAMESPACE MyLib::
DESTINATION lib/cmake/MyLib)
configure_file(CMake/MyLibConfig.cmake.in MyLibConfig.cmake #ONLY)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/MyLibConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/MyLibConfigVersion.cmake"
DESTINATION lib/cmake/MyLib)
install(DIRECTORY ${MyLib_PUBLIC_INCLUDE_DIR}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
# Package with CPack
include(InstallRequiredSystemLibraries)
include(CPack)
MyLibConfig.cmake.in declares a dependency on libDep
include(CMakeFindDependencyMacro)
# Dependencies
add_library(libDep REQUIRED)
# Add the targets file
include("${CMAKE_CURRENT_LIST_DIR}/MyLibTargets.cmake")
libDep is installed into MyLib's tree with
install(DIRECTORY ${libDep_INCLUDE_DIRS}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/MyLib/third_party)
and I copy the find module with
install(FILES
${CMAKE_MODULE_PATH}/FindlibDep.cmake
DESTINATION lib/cmake/MyLib)
Unfortunately users of MyLib don't see FindlibDep.cmake by default
$ cmake ..
CMake Error at /usr/share/cmake-3.10/Modules/CMakeFindDependencyMacro.cmake:48 (find_package):
By not providing "FindlibDep.cmake" in CMAKE_MODULE_PATH this project has
asked CMake to find a package configuration file provided by "libDep", but
CMake did not find one.
Could not find a package configuration file provided by "libDep" with any
of the following names:
libDepConfig.cmake
libDep-config.cmake
Add the installation prefix of "libDep" to CMAKE_PREFIX_PATH or set
"libDep_DIR" to a directory containing one of the above files. If "libDep"
provides a separate development package or SDK, be sure it has been
installed.
Call Stack (most recent call first):
/usr/local/lib/cmake/MyLib/MyLibConfig.cmake:5 (find_dependency)
CMakeLists.txt:9 (find_package)
-- Configuring incomplete, errors occurred!
The user can manually locate FindlibDep.cmake and add it to their CMAKE_MODULE_PATH but that shouldn't be required.
A reproduction of this issue is available on GitHub.
You need to use the PROJECT_ variable for the source dir instead of the CMAKE_ variable:
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMake/modules)
PROJECT_SOURCE_DIR gets the source dir from the most recently executed project() directive (in this case, your library).
You should also be adding your current CMAKE_MODULE_PATH to the new path, as shown above.
I have a framework wich depends on multiple third party libraries. I would like to share my framework easily. For example the user needs only my includes and add my lib to use my framework, and not all the dependencies.
I use CMake to create my libs, but I am still trying to understand how it works.
The hierarchy of the project
test
├── CMakeLists.txt
├── libA
│ ├── CMakeLists.txt
│ ├── libA.cpp
│ ├── libA.hpp
├── libB
│ ├── CMakeLists.txt
│ ├── libB.cpp
│ ├── libB.hpp
└── test
├── CMakeLists.txt
└── main.cpp
The libB depends on the libA, and I would like to add only the libB to make the project works.
The content of the main CMakeLists.txt located in test/:
cmake_minimum_required (VERSION 2.8.11)
project (C CXX)
include(CheckCXXCompilerFlag)
add_subdirectory("libA")
add_subdirectory("libB")
add_subdirectory("test")
The content of the main CMakeLists.txt located in test/libA:
cmake_minimum_required (VERSION 2.8.11)
project (A CXX)
include(CheckCXXCompilerFlag)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++14")
file(GLOB SOURCES "*.cpp")
add_library(A STATIC ${SOURCES})
The content of the main CMakeLists.txt located in test/libB:
cmake_minimum_required (VERSION 2.8.11)
project (B CXX)
include(CheckCXXCompilerFlag)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++14")
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} "-static")
include_directories("../libA")
link_directories("../libA")
file(GLOB SOURCES "*.cpp")
add_library(B STATIC ${SOURCES})
target_link_libraries(B A)
The content of the main CMakeLists.txt located in test/test:
cmake_minimum_required (VERSION 2.8.11)
project (C CXX)
include(CheckCXXCompilerFlag)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++14")
include_directories(../libA)
include_directories(../libB)
link_directories(../build/libB)
link_directories(../build/libA)
add_executable(C main.cpp)
target_link_libraries(C B)
If I run the main CMake all works fine, the standalone is well generated.
But if I want to create only the exe by going into test/test and running "cmake . && make", I have an undefined reference to addL(int, int). To make it works I have to add target_link_libraries(C A) at the end of the CMakeLists. Is it normal ? Is it possible to add only the main library without its dependencies ?
Command invocation
target_link_libraries(C B)
have different meanings in your use-cases.
In "all" use-case 'B' is (previously) defined as a CMake target, so CMake knows location of the library (link_directories is not used in that case), and automatically propagates all dependencies of library 'B' to executable 'C'.
In "test-only" use case there is no CMake target named 'B', so it is just transformed to linker option -lB. Linker searches appropriate library file under link directories (link_directories is needed in that case). But information about 'B' dependencies is lost, so automatic linking with A isn't performed.
Your project may provide a standalone CMake script which can be included by a user of your library. The script should define all needed dependencies. Common "types" of such scripts are FindXXX.cmake and XXXConfig.cmake, which can be included via find_package(XXX) command.