CMake "Cannot specify sources for target PROJECT_NAME which is not built by this project." - cmake

I am learning CMake but unfortunately most examples are either too simple, too complicated or the folder structure is different to what I'm designing.
I am getting an error but first I will explain the folder structure (please do critique):
MyProject
bin
build
src
ComponentA
ObjectA.cpp
CMakeLists.txt
ComponentB
ObjectB.cpp
CMakeLists.txt
CMakeLists.txt
main.cpp
CMakeLists.txt
I would like to be able to include some files using their absolute path, for example main.cpp might look like this:
#include <ComponentB/ObjectB.h>
int main()
{
ComponentB cb(1, 2, 3);
}
but within a source file I'd like to include it's header using the relative path:
#include <ComponentB.h>
ComponentB::ComponentB(int a, int b, int c) : _ca(a, b){}
(if this causes problems I can include using absolute paths)
My CMakeLists files look like:
MyProject/CMakeLists.txt:
cmake_minimum_required(VERSION 3.9.1)
project(MyProject)
add_subdirectory(src)
MyProject/src/CMakeLists.txt:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_ROOT_DIR}/bin)
add_executable(MyProject main.cpp)
add_subdirectory(ComponentA)
add_subdirectory(ComponentB)
MyProject/src/ComponentA/CMakeLists.txt:
target_sources(MyProject PUBLIC ComponentA.cpp)
MyProject/src/ComponentB/CMakeLists.txt:
target_sources(MyProject PUBLIC ComponentB.cpp)
target_include_directories(MyProject PUBLIC ComponentA)
However when I do:
cd build
cmake ..
I get this this error:
CMake Error at src/ComponentA/CMakeLists.txt:2 (target_sources):
Cannot specify sources for target "MyProject" which is not built by
this project.
CMake Error at src/ComponentB/CMakeLists.txt:2 (target_sources):
Cannot specify sources for target "MyProject" which is not built by
this project.
CMake Error at src/ComponentB/CMakeLists.txt:3 (target_include_directories):
Cannot specify include directories for target "MyProject" which is not
built by this project.

The ability for target_sources to add source files via relative path to a target in a different directory was added in CMake 3.13. Since you have specified a minimum version of 3.9.1, this will simply not work.
The policy in question is CMP0076, which is documented as follows:
New in version 3.13.
The target_sources() command converts relative paths to absolute.
In CMake 3.13 and above, the target_sources() command now converts relative source file paths to absolute paths in the following cases:
Source files are added to the target's INTERFACE_SOURCES property.
The target's SOURCE_DIR property differs from CMAKE_CURRENT_SOURCE_DIR.
It is the second bullet point that applies here.
You really ought to use a newer version of CMake. Anything more than a few versions behind the newest (3.23) is plain masochism.

Related

Using Cmake to add compiler options to existing cmake

I have a submodule with a CMakeLists.txt, which I would like to "amend" in a way to make it work for my specific purpose (I need to add compiler flags and a different output directory) The output is a static library. My current approach is as follows:
I have a CMakeLists.txt in the root directory, which adds the submodule CMakeLists.txt via add_subdirectory() like so:
set(CMAKE_CXX_FLAGS "-my_needed_flags "
add_subdirectory(SubmoduleLibrary)
set_target_properties(SubmoduleLibrary PROPERTIES ARCHIVE_OUTPUT_DIRECTORY output_folder)
add_custom_target(BuildLib)
add_dependencies(BuildLib SubmoduleLibrary)
Now this seems to work in some ways (the output directory is correctly chosen). But I get linker errors which I don't get when I compile the library adding the flags etc to the original CMakeLists.txt.
What is the correct way to build a library from an existing CMakeLists.txt with added parameters?

Providing include directory outside source folder for static library users

I am developing a simple static C library for learning purposes using cmake.
Some projects like GLFW provide an include folder on the root, so library users can copy it and use it as an include directory.
In my library, I want to have an include folder on the root, so when I use the library on other projects, I can just copy this folder and set it as an include directory.
Here is a simplified folder structure of my library:
include
+--mylib.h
src
+--myheader.h
+--mysource.c
+--CMakeLists.txt
CmakeLists.txt
The src folder has my headers and implementation files, and a CMakeLists.txt for building a static library out of mysource.c.
The CMakeLists on the root folder just sets the project and adds src as a subdirectory.
I want the mylib.h file to have a #include <myheader.h>.
Here's a detour to talk about how I want to use it when it's done.
The idea is that when using the lib on another project, I can have something like this:
deps
+--include
+--mylib.h
src
+--main.c
And in the main.c file, include mylib.h and use what's defined on myheader.h
Here the detour ends, and I'm talking about my actual lib project again.
How can I achieve this using cmake? As far as I know, the mylib.h file needs to know it's including files from the src diretory, but I see no way of setting that, as for exemple in GLFW this directory does not have a CMakeLists.txt.
I am gonna quess that this is a design issue since it would make sense to you if you would have installed the library to a system before you tried to use it. That is, not using add_subdirectory() but find_library() at usage.
First, if you are using a external library, but not installing it, you would include all files in you deps-folder. All files then include source-files and so on and will be compiled besides you main.c. This is done with add_subdirectory(deps/MyLib) and later also included in you main-project.
Example:
add_subdirectory(deps/MyLib EXCLUDE_FROM_ALL)
target_link_libraries(${PROJECT_NAME} PRIVATE MyLib)
target_include_directories(${PROJECT_NAME} PRIVATE MyLib)
If you do not want to compile it all the time, then you must instruct cmake where it can find headers and library-files. Preferred way is to use find_library() which does some magic for you. Since you do not mention any installation i will assume that it does not exist and your only option is then to use add_subdirectory().
"I can just copy this folder and set it as an include directory."
CMake wants to handle these things for you so you should never copy headers around. You should either use add_subdirectory() to include a project/headers or make use of the find_library() which make sure you find where the headers are in the system.
I suggest that you push yourself to learn howto install a library into a system and how to utilize it later, but only by using find_library(). Then the library will be global for all projects and also not duplicated.
Adding some kind of psudo-code in hope it all makes more sense. Although it is around add_subdirectory() since the code for installing is quite large unfortunately.
CMakeLists.txt for main.c
cmake_minimum_required(VERSION 3.8)
project(MyLibTest)
add_executable(${PROJECT_NAME}
src/main.c
)
add_subdirectory(external/MyLib EXCLUDE_FROM_ALL)
target_link_libraries(${PROJECT_NAME} PRIVATE MyLib)
target_include_directories(${PROJECT_NAME} PRIVATE MyLib)
CMakeLists.txt for library
cmake_minimum_required(VERSION 3.8)
project(MyLib)
add_library(${PROJECT_NAME} STATIC
src/MyLib.c
)
target_include_directories(${PROJECT_NAME}
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)
The structure for the project would then be:
/
external/MyLib
external/MyLib/src
MyLib.c
external/MyLib/include
MyLib.h
src
main.c
CMakeLists.txt

Making a CMake library accessible by other CMake packages automatically

I have one project that produces a library:
project (myCoolLibrary)
ADD_LIBRARY(my_cool_library SHARED ${mysources_SRC})
And another project that should be using this library:
find_package (myCoolLibrary REQUIRED)
INCLUDE_DIRECTORIES("${myCoolLibrary_INCLUDE_DIRS}" )
add_executable(myCoolExe ${my_sources_SRC} )
TARGET_LINK_LIBRARIES(myCoolExe ${myCoolLibrary_LIBRARIES} )
Is there a way that I can change the first file so that the second file works automatically? That by running CMake on the first file and then running make on the output, then running CMake on the second file, CMake is able to find the package?
An answer where I just give the address of where the first project is built to the second package is also acceptable.
Taking the code found in a blog post by #daniperez - Use CMake-enabled libraries in your CMake project (III) - I've come up with the following minimal solution:
myCoolLibrary/CMakeLists.txt
cmake_minimum_required(VERSION 3.3)
project(myCoolLibrary)
function(my_export_target _target _include_dir)
file(
WRITE "${CMAKE_CURRENT_BINARY_DIR}/${_target}Config.cmake"
"
include(\"\$\{CMAKE_CURRENT_LIST_DIR\}/${_target}Targets.cmake\")
set_property(
TARGET ${_target}
APPEND PROPERTY
INTERFACE_INCLUDE_DIRECTORIES \"${_include_dir}\"
)
"
)
export(TARGETS ${_target} FILE "${CMAKE_CURRENT_BINARY_DIR}/${_target}Targets.cmake")
# NOTE: The following call can pollute your PC's CMake package registry
# See comments/alternatives below
export(PACKAGE ${_target})
endfunction(my_export_target)
...
add_library(${PROJECT_NAME} SHARED ${mysources_SRC})
my_export_target(${PROJECT_NAME} "${CMAKE_CURRENT_SOURCE_DIR}")
myCoolExe/CMakeLists.txt
cmake_minimum_required(VERSION 3.3)
project(myCoolExe)
find_package(myCoolLibrary REQUIRED)
...
add_executable(${PROJECT_NAME} ${my_sources_SRC})
target_link_libraries(${PROJECT_NAME} myCoolLibrary)
To make it reusable I have packed everything into my_export_target(). And I'm friend of self-propagating properties like INTERFACE_INCLUDE_DIRECTORIES.
As commented by #ruslo, using export(PACKAGE ...) can pollute your package registry. So alternatively you can:
Write the target configuration files directly to some dedicated place specific for a certain toolchain
See e.g. How to install your custom CMake-Find module and 0003659: FIND_PACKAGE command improvements.
Set CMAKE_MODULE_PATH via the second project's CMake command line (injecting the search path(s) from the outside). If you are building the two projects anyway with a build script, then this is the most direct way to propagate the module search path(s).
Additional References
export()
CMake/Tutorials/Package Registry
Unable to find Eigen3 with CMake
How to instruct CMake to use the build architecture compiler

Writing a CMakeLists.txt for ROS

I am new to ROS (Indigo), and I want to write a C++ program to use the MoveIt! package.
However, I am confused as to what I need to have in my CMakeLists.txt file, such that the header and library files can be found.
For example, here is the file so far:
cmake_minimum_required(VERSION 2.8.1)
project(MicoMoveIt)
set(CMAKE_CXX_FLAGS "-std=c++11")
file(GLOB srcs *.cpp)
include_directories(/opt/ros/indigo/include)
link_directories(/opt/ros/indigo/lib)
add_executable(${PROJECT_NAME} ${srcs})
And my main.cpp file is:
#include <ros/ros.h>
#include <moveit/move_group_interface/move_group.h>
int main()
{
moveit::planning_interface::MoveGroup group("right_arm");
return 0;
}
But compiling this gives me the error:
/opt/ros/indigo/include/moveit/robot_model/joint_model.h:47: error: Eigen/Geometry: No such file or directory
#include <Eigen/Geometry>
^
So, I need to specify where to find these Eigen header files. But given that Eigen is a dependency of MoveIt!, then I shouldn't have to manually include all these header file directories.
How should I be writing the CMakeLists.txt file so that all header and library directories of dependencies are included?
Try with this changes:
cmake_minimum_required(VERSION 2.8.3)
project(<project_name>)
set(CMAKE_CXX_FLAGS "-std=c++11")
find_package(catkin REQUIRED COMPONENTS
<other_packages_you_need>
moveit_ros_planning_interface
)
catkin_package(CATKIN_DEPENDS)
include_directories(include ${catkin_INCLUDE_DIRS})
set(BINNAME <executable_name>)
set(SOURCES <cpp_source_files>)
add_executable (${BINNAME} ${SOURCES})
target_link_libraries(${BINNAME} ${catkin_LIBRARIES})
The key factor for your problem is the inclusion of package moveit_ros_planning_interface in the find_package() directive. Everytime you have to build some code, you have to add every package dependancies to your project (in this case you need the moveit interface package). Notice that the package.xml file plays a crucial role too.
Lastly you have to tell the linker to retrieve and link the libraries you are using in your project. To do so use target_link_libraries() and the useful catkin_LIBRARIES variable which almost does what you expected (you could manually add libraries, but it could be messy in big projects).
Have a look here and here for more info.
EDIT: in this case you do not need the link_directories() directive, which has to be used only when the linker has to know where to retrieve the external library.

CMake and dependencies

I have the following directory structure and library dependencies:
./lib-a
./lib-b (depending on lib-a)
Each directory contains a CMakeLists.txt file for generating its own library.
I am using an out-of-source building policy.
In order to say that lib-b depends on lib-a, I have put the command add_subdirectory(../lib-a lib-a) in ./lib-b/CMakeLists.txt, according to what is taught by the official CMake tutorial. This way I obtain that a subdirectory lib-a is created in ./lib-b/build dir.
This is not the behaviour I desire. What I would like to obtain is CMake making reference to lib-a in generating lib-b and, if lib-a has not been already generated, CMake should generate it inside ./lib-a/build by using the CMakeLists.txt of lib-a (in a behaviour similar to the one of the make tool when dealing with dependencies).
I would also like to add that I am not using a root CMakeLists.txt in my example, but what I would like to have is the lib-b/CMakeLists.txt declaring the dependency on lib-a, thus making lib-a to be compiled, if not already, by using its own lib-a/CMakeLists.txt.
Here is the dirs structure and their contents:
lib-a/
CMakeLists.txt (for compiling lib-a)
src/
test.cpp
include/
test.hpp
lib-b/
main.cpp
CMakeLists.txt (for compiling lib-b; here is the point where I would like to make reference to lib-a, that I need for the generation of lib-b)
lib-b/main.cpp contains also an include of test.hpp of lib-a, because it is using a function of lib-a. This should be taken into consideration in the specification of lib-b/CMakeLists.txt.
What should the content of the two lib-a/CMakeLists.txt and lib-b/CMakeLists.txt files be?
I think you misunderstand the tutorial. The thing that links the libraries together is target_link_library(lib_b lib_a). If the name of the dependency is a library that is part of the build, CMake will magically make the dependencies work. It has nothing to do with subdirectories. In fact, if I have the following directory structure:
./
./a.hpp
./a.cpp
./b.hpp
./b.cpp
./CMakeLists.txt
The following will set the dependencies just fine:
PROJECT(lib_a)
ADD_LIBRARY(lib_a a.hpp a.cpp)
PROJECT(lib_b)
ADD_LIBRARY(lib_b b.hpp b.cpp)
TARGET_LINK_LIBRARIES(lib_b lib_a)
This will work across subdirectory projects as well:
./
./CMakeLists.txt
./lib_a/CMakeLists.txt
./lib_a/a.hpp
./lib_a/a.cpp
./lib_b/CMakeLists.txt
./lib_b/b.hpp
./lib_b/b.cpp
And the list files:
# ./CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
ADD_SUBDIRECTORY(lib_a)
ADD_SUBDIRECTORY(lib_b)
# ./lib_a/CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(lib_a)
ADD_LIBRARY(lib_a a.hpp a.cpp)
# ./lib_b/CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(lib_b)
INCLUDE_DIRECTORIES(${lib_a_SOURCE_DIR})
ADD_LIBRARY(lib_b b.hpp b.cpp)
TARGET_LINK_LIBRARIES(lib_b lib_a)