Adding compiler "#define" flags in sub_directory CMakeLists.txt - cmake

My directory structure of project is build with multi CMakeLists.txts.
root
CMakeLists.txt
Src
main.c
CMSIS_lib
calculate.c
calculate.h
CMakeLists.txt
cmake
toolchain.cmake
build
In my CMSIS_lib I build separately my dependency source files calculate.c
and calculate.h with CMSIS_lib/CMakeList.txt:
set(util_source_files
calculate.c
calculate.h
)
add_library(util ${util_source_files})
target_include_directories(util calculate.h)
In my root CMakeLists.txt:
cmake_minimum_required(VERSION 3.4)
project(main_projct)
set(TOOLCHAIN_PREFIX /opt/gcc-arm-none-eabi)
set(CMAKE_TOOLCHAIN_FILE cmake/toolchain.cmake)
add_subdirectory(CMSIS_lib)
add_executable(main_projct main.c)
target_link_libraries(main_projct util)
Problem is that I must tell my compiler to add a #define GUCCI in my calculate.h (In MakeFile I know there is flag to tell a header define with -DGUCCI). I would like to add this flag to my compiler in my CMSIS_lib/CMakeList.txt, because when the first CMSIS_lib/CMakeList.txt is done building, he will skip everything under #ifndef GUCCI in my calculate.h, and when added in root CMakeLists.txt with target_link_libraries() I will not have all defines configuration correctly.
I am using cross-compiler and in my toolchain.cmake I use to define compiler flags with command SET_TARGET_PROPERTIES(${TARGET} PROPERTIES COMPILE_DEFINITIONS GUCCI}"), but this is to late because this only is seen by my root CMakeLists.txt and not by my sub director CMakeLists.txt.

Your CMSIS_lib/CMakeLists.txt should look like this:
set(util_source_files
calculate.c
calculate.h
)
add_library(util ${util_source_files})
target_include_directories(util ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(util PUBLIC GUCCI)
Note target_compile_definitions line, with PUBLIC parameter: it instructs cmake to use -DGUCCI compiler option while compiling util, and all targets that are linked against util.
Also note change in target_include_directories. You placed header file as parameter, but you should place directory instead.

Related

Cmake - Add files from other sub-projects

Let's say I have two sub-projects: A and B
This is my root CMakeLists.txt
cmake_minimum_required (VERSION 3.8)
project ("Project")
add_subdirectory ("A")
add_subdirectory ("B")
In /B I have file test.h
How can I include /B/test.h in A ?
I have tried to add target_include_directories(B) in /A/CMakeLists.txt but it does not seem to work
When you write add_subdirectory(B) (quotes are not necessary), you must have a CMakeLists.txt in the directory B.
This CMakeLists.txt may have the following content:
add_library(targetB INTERFACE)
target_include_directories(targetB INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
These 2 lines create a CMake target called targetB with the INTERFACE property. This is very handy for header only library. All cmake target that links with targetB will then include the CMAKE_CURRENT_SOURCE_DIR with is the directory A where your test.h is.
Then, you have add_subdirectory(A) with a CMakeLists.txt that may look like this (assuming you have a main in this dir A):
add_executable(foo ${CMAKE_CURRENT_SOURCE_DIR}/main.c)
target_link_libraries(foo PRIVATE targetB)
Then second line create the relation between the target foo and the target targetB and, when compiling, the path to your test.h will be set in the command line.

Using constant folder with cmake

I have a constant MYPROJECT in my ~/.bashrc file:
export MYPROJECT = /home/loom/my_project
I can see the constant is defined in the terminal:
loom#loom$ ls -ld $MYPROJECT
drwxr-xr-x 25 loom loom 4096 Jul 21 22:12 /home/loom/my_project
I tried to use the constant in my CMakeLists.txt:
add_executable(booo src/main.cpp ${MYPROJECT}/foo/trunk/bar/File.h)
However, it produces an error:
CMake Error at CMakeLists.txt:17 (add_executable):
Cannot find source file:
/foo/trunk/bar/File.h
Tried extensions .c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp
.hxx .in .txx
CMake Error: CMake can not determine linker language for target: booo
CMake Error: Cannot determine link language for target "booo".
It is processed without errors if I have used explicit path without $MYPROJECT:
add_executable(booo src/main.cpp /home/loom/my_project/foo/trunk/bar/File.h)
How to use path defined in .bashrc in cmake?
Instead of
add_executable(booo src/main.cpp ${MYPROJECT}/foo/trunk/bar/File.h)
use
add_executable(booo src/main.cpp $ENV{MYPROJECT}/foo/trunk/bar/File.h)
The CMake documentation states:
Use the syntax $ENV{VAR} to read environment variable VAR. See also
the set() command to set ENV{VAR}.
https://cmake.org/cmake/help/v3.4/variable/ENV.html
Turning my comment into an answer
There are a lot of ways you could do this in CMake. Out of bad experiences with using environment variables directly inside CMake projects (they have to be valid not only during the first call to CMake configuration/generation but also later during all consecutive builds), I would recommend to transfer your constant into a cached CMake variable.
I'm using one of the following ways in my projects:
Injecting MYPROJECT CMake via its -D option, e.g.
cmake -DMYPROJECT:PATH=$MYPROJECT ..
Then CMake would cache this value in its own MYPROJECT internal variable.
When you get values from the "outside" you should think about what to do if no value is provided or it's not a valid directory. Throwing a fatal error and/or retry with a default value?
The following example shows only transformation steps and sanity checks (no default value retry):
if (NOT DEFINED MYPROJECT OR NOT IS_DIRECTORY MYPROJECT)
file(TO_CMAKE_PATH "$ENV{MYPROJECT}" _ENV_MYPROJECT_REL)
get_filename_component(_ENV_MYPROJECT "${_ENV_MYPROJECT_REL}" ABSOLUTE)
if (NOT _ENV_MYPROJECT)
message(FATAL_ERROR "Environment variable MYPROJECT not provided.")
else()
set(MYPROJECT "${_ENV_MYPROJECT}" CACHE INTERNAL "")
endif()
endif()
Using find_path(), which will also cache its result:
find_path(
MYPROJECT_INCLUDE_DIR
NAMES File.h
PATHS ENV MYPROJECT
/home/loom/my_project
PATH_SUFFIXES foo/trunk/bar
)
if (NOT MYPROJECT_INCLUDE_DIR)
...
Or - assuming your external project does not only consists of header files but also libraries like foo.a - following CMake's A Sample Find Module and extending the find_path() code from above by:
find_library(
MYPROJECT_LIBRARY
NAMES foo
PATHS ENV MYPROJECT
PATH_SUFFIXES foo/lib
)
if(MYPROJECT_INCLUDE_DIR AND MYPROJECT_LIBRARY AND NOT TARGET MyProject::MyProject)
add_library(MyProject::MyProject UNKNOWN IMPORTED)
set_target_properties(
MyProject::MyProject
PROPERTIES
IMPORTED_LOCATION "${MYPROJECT_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${MYPROJECT_INCLUDE_DIR}"
)
endif()
Now you can use it directly as any other CMake target with
add_executable(booo src/main.cpp)
target_link_libraries(booo MyProject::MyProject)
More References
What's the CMake syntax to set and use variables?
preferred cmake project structure

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.

Getting a CMake Error: Cannot specify link libraries for target which is not built by the project

I am implementing CMake in my code but I'm getting the error
"Cannot specify link libraries for target "Qt5::Widgets" which is not built by the project".
Below are the contents of the CMakeLists.txt:
#Specify the version being used aswell as the language
cmake_minimum_required(VERSION 2.6)
#Name your project here
project(eCAD)
#Sends the -std=c++11 flag to the gcc compiler
ADD_DEFINITIONS(-std=c++11)
#This tells CMake to main.cpp and name it eCAD
add_executable(eCAD main.cpp)
#include the subdirectory containing our libs
add_subdirectory (gui)
include_directories(gui)
#include Qt directories
find_package(Qt5Widgets)
find_package(Qt5Core)
find_package(Qt5Designer)
SET(QT_USE_QTDESIGNER ON)
#link_libraries
target_link_libraries(Qt5::Widgets Qt5::Core)
In addition to the accepted answer: An important detail is to place target_link_libraries after the add_executable and find_package lines, so all linked components are known.
The first argument of target_link_libraries is the target name:
target_link_libraries(eCAD Qt5::Widgets Qt5::Core)
Also, do not confuse target name with the project name:
a command project specifies a project name, but
a target is the one created with add_executable, add_library or add_custom_target.
The error message is about the target.
Set you_lib_name before setting target_link_libraries
set(you_lib_name libname)
target_link_libraries(you_lib_name Qt5::Widgets Qt5::Core)

CMake: Linking to an imported library with dependencies fails

I have a subdirectory with a CMakeLists.txt which should compile a library using make and export the result as an imported library to the parent directory:
set(static_lib ${CMAKE_CURRENT_BINARY_DIR}/lib/mylib.a)
add_custom_command(
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT ${static_lib}
COMMAND make
COMMAND make install PREFIX=${CMAKE_CURRENT_BINARY_DIR}
)
add_custom_target(compile_mylib DEPENDS ${static_lib})
add_library(mylib STATIC IMPORTED)
set_property(TARGET mylib PROPERTY IMPORTED_LOCATION ${static_lib})
add_dependencies(mylib compile_mylib)
The CMakeLists.txt in the parent directory looks like this:
add_subdirectory(deps/mylib)
add_executable(mybin source.c)
target_link_libraries(mybin mylib)
On OSX this works just fine - but if I compile the same on Ubuntu it seems to ignore the subdirectory's CMakeLists and complains:
/usr/bin/ld.bfd.real: cannot find -lmylib
I'm using Clang for compilation.
The solution is to add GLOBAL to your add_library call so that it is visible to the parent CMakeLists.txt
you can try this:
find_library(MYLIB mylib.a ${CMAKE_CURRENT_BINARY_DIR}/lib)
then set your link libraries:
target_link_libraries(mybin ${MYLIB})
should be work.