Introduction to CMakeLists<span>CMakeLists.txt</span>
file is the input file for the CMake build system used to build software packages. Any package that conforms to the CMake specification contains one or more <span>CMakeLists.txt</span>
files that describe how to build the code and where to install it. The <span>CMakeLists.txt</span>
file used for catkin projects is a standard CMakeLists.txt file but with some additional constraints.
Your <span>CMakeLists.txt</span>
file must follow this format; otherwise, your package will not build correctly. The order of configuration is important.
- Required CMake version (
<span>cmake_minimum_required</span>
) - Package name (
<span>project()</span>
) - Find additional CMake/Catkin packages required for building (
<span>find_package()</span>
) - Enable Python module support (
<span>catkin_python_setup()</span>
) - Message / Service / Action generators (
<span>add_message_files()</span>
,<span>add_service_files()</span>
,<span>add_action_files()</span>
) - Call message / service / action generation (
<span>generate_messages()</span>
) - Specify package build information export (
<span>catkin_package()</span>
) - Libraries / Executables to build (
<span>add_library()</span>
/<span>add_executable()</span>
/<span>target_link_libraries()</span>
) - Tests to build (
<span>catkin_add_gtest()</span>
) - Installation rules (
<span>install()</span>
)
Below is an example of the CMakeLists for fast_lio
cmake_minimum_required(VERSION 2.8.3)
project(fast_lio)
# Specify the minimum CMake version and project name
SET(CMAKE_BUILD_TYPE "Debug")
# Compilation type, also can be release for more optimization
ADD_COMPILE_OPTIONS(-std=c++14 )
ADD_COMPILE_OPTIONS(-std=c++14 )
set( CMAKE_CXX_FLAGS "-std=c++14 -O3" )
add_definitions(-DROOT_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/\")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fexceptions" )
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -pthread -std=c++0x -std=c++14 -fexceptions")
message("Current CPU architecture: ${CMAKE_SYSTEM_PROCESSOR}")
if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)" )
include(ProcessorCount)
ProcessorCount(N)
message("Processor number: ${N}")
if(N GREATER 4)
add_definitions(-DMP_EN)
add_definitions(-DMP_PROC_NUM=3)
message("core for MP: 3")
elseif(N GREATER 3)
add_definitions(-DMP_EN)
add_definitions(-DMP_PROC_NUM=2)
message("core for MP: 2")
else()
add_definitions(-DMP_PROC_NUM=1)
endif()
else()
add_definitions(-DMP_PROC_NUM=1)
endif()
find_package(OpenMP QUIET)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
#find_package(PythonLibs REQUIRED)
find_path(MATPLOTLIB_CPP_INCLUDE_DIRS "matplotlibcpp.h")
If your project depends on other "wet" packages (packages that need to be compiled), at the CMake level, they automatically become components of catkin. Instead of using find_package for these packages individually, it is more convenient to specify them as components. For example, if you use the
geometry_msgs package:
find_package(catkin REQUIRED COMPONENTS geometry_msgs nav_msgs sensor_msgs roscpp rospy std_msgs pcl_ros tf livox_ros_driver2 message_generation eigen_conversions)
find_package(Eigen3 REQUIRED)
find_package(PCL 1.8 REQUIRED)
message(Eigen: ${EIGEN3_INCLUDE_DIR})
include_directories( ${catkin_INCLUDE_DIRS} ${EIGEN3_INCLUDE_DIR} ${PCL_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS} include)
add_message_files( FILES Pose6D.msg)
generate_messages( DEPENDENCIES geometry_msgs)
catkin_package( CATKIN_DEPENDS geometry_msgs nav_msgs roscpp rospy std_msgs message_runtime DEPENDS EIGEN3 PCL INCLUDE_DIRS)
add_executable(fastlio_mapping src/laserMapping.cpp include/ikd-Tree/ikd_Tree.cpp src/preprocess.cpp)target_link_libraries(fastlio_mapping ${catkin_LIBRARIES} ${PCL_LIBRARIES} ${PYTHON_LIBRARIES})target_include_directories(fastlio_mapping PRIVATE ${PYTHON_INCLUDE_DIRS})
If CMake finds a package through <span>find_package</span>
, it creates several CMake environment variables that provide information about the found package. These environment variables can be used in subsequent CMake scripts. They describe the location of the exported header files, source files, libraries that the package depends on, and the paths to these libraries. The variable names always follow the convention <span><package_name>_<property></span>
:
<span><name>_FOUND</span>
: Set to<span>true</span>
if the library is found, otherwise<span>false</span>
.<span><name>_INCLUDE_DIRS</span>
or<span><name>_INCLUDES</span>
: The include paths exported by the package.<span><name>_LIBRARIES</span>
or<span><name>_LIBS</span>
: The libraries exported by the package.<span><name>_DEFINITIONS</span>
: Definition information.
Why should Catkin packages be specified as components?
Catkin packages are not actually components of catkin. Instead, they utilize CMake’s component functionality in the design of catkin to save you a lot of input time.
For Catkin packages, if you use them as components of catkin with <span>find_package</span>
, the benefit is that a set of environment variables prefixed with <span>catkin_</span>
will be created. For example, suppose you use the <span>nodelet</span>
package in your code. The recommended way to find the package is
find_package(catkin REQUIRED COMPONENTS nodelet)
This means that the exported include paths, libraries, etc., of <span>nodelet</span>
will also be appended to the <span>catkin_</span>
variables. For example, <span>catkin_INCLUDE_DIRS</span>
will not only include the include paths of catkin but also those of <span>nodelet</span>
! This will be very useful later.
We can also use <span>find_package</span>
separately to find <span>nodelet</span>
This means that the paths, libraries, etc., of <span>nodelet</span>
will not be added to the <span>catkin_</span>
variables.
This will produce variables like <span>nodelet_INCLUDE_DIRS</span>
, <span>nodelet_LIBRARIES</span>
, etc. Using the following method will also create the same variables
find_package(catkin REQUIRED COMPONENTS nodelet)
<span>catkin_package()</span>
is a CMake macro provided by catkin. This is necessary to specify catkin-specific information to the build system, which in turn is used to generate pkg-config and CMake files.
This function must be called before declaring any targets using <span>add_library()</span>
or <span>add_executable()</span>
. This function has 5 optional parameters:
- INCLUDE_DIRS: The include paths exported by the package (i.e., compilation flags).
- LIBRARIES: The libraries exported by the project.
- CATKIN_DEPENDS: Other catkin projects that this project depends on.
- DEPENDS: Non-catkin CMake projects that this project depends on. For better understanding, please refer to this explanation.
- CFG_EXTRAS: Additional configuration options
catkin_package( INCLUDE_DIRS include LIBRARIES ${PROJECT_NAME} CATKIN_DEPENDS roscpp nodelet DEPENDS eigen opencv)
This indicates that the <span>include</span>
folder within the package folder is where the exported header files are located. The value of the CMake environment variable <span>${PROJECT_NAME}</span>
is the content you previously passed to the <span>project()</span>
function, which in this case is <span>robot_brain</span>
.<span>roscpp</span>
and <span>nodelet</span>
are the packages required to build/run this package, while <span>eigen</span>
and <span>opencv</span>
are the system dependencies required to build/run this package.
Include paths and library paths
Before specifying targets, you need to specify where to find the resources required for these targets, especially header files and libraries:
- Include paths: Where the code being built (most commonly in C/C++) can find header files.
- Library paths: Where the libraries that the executable targets depend on are located.
include_directories(<directory 1>, <directory 2>, ..., <directory N>)
link_directories(<directory 1>, <directory 2>, ..., <directory N>)
To specify the executable targets that must be built, we must use CMake’s <span>add_executable()</span><span> function</span>
add_executable(myProgram src/main.cpp src/some_file.cpp src/another_file.cpp)
This will build an executable target named <span>myProgram</span>
that is built from 3 source files:<span>src/main.cpp</span>
, <span>src/some_file.cpp</span>
, and <span>src/another_file.cpp</span>
.
<span>target_link_libraries</span>
Use the <span>target_link_libraries()</span>
function to specify the libraries that the executable target should link against. This is usually done after calling <span>add_executable()</span>
. If ROS is not found, add <span>${catkin_LIBRARIES}</span>
Messages (<span>.msg</span>
), services (<span>.srv</span>
), and actions (<span>.action</span>
) in ROS require a special preprocessing build step before they can be built and used by ROS packages. These macros generate language-specific files so that users can use messages, services, and actions in their chosen programming language. The build system will use all available generators (e.g., <span>gencpp</span>
, <span>genpy</span>
, <span>genlisp</span>
, etc.) to generate bindings.
Three macros are provided to handle messages, services, and actions:
<span>add_message_files</span>
<span>add_service_files</span>
<span>add_action_files</span>
Then a macro must be called to trigger the generation process:generate_messages()For detailed information, see
https://wiki.ros.org/catkin/CMakeLists.txt
—
<span>CMAKE_PREFIX_PATH</span>
is an important environment variable in CMake that plays a key role when CMake searches for resources such as dependent libraries, header files, and executables. Here is a detailed introduction:
1. Basic Concept
<span>CMAKE_PREFIX_PATH</span>
is a list of multiple paths, separated by colons <span>:</span>
in Unix/Linux systems and semicolons <span>;</span>
in Windows systems. When CMake performs search operations, it refers to the paths specified by this variable to locate the required resources.
2. Working Mechanism
When you use search commands like <span>find_package</span>
, <span>find_library</span>
, <span>find_path</span>
, <span>find_file</span>
, etc., in the CMakeLists.txt file, CMake utilizes <span>CMAKE_PREFIX_PATH</span>
in the following steps:
- Traverse the path list: CMake checks each path in
<span>CMAKE_PREFIX_PATH</span>
sequentially. - Search for resources: For each path, CMake searches for the required resources in its specific subdirectories. For example, for library files, it typically looks in the
<span>lib</span>
subdirectory; for header files, it looks in the<span>include</span>
subdirectory; for CMake configuration files, it looks in the<span>lib/cmake</span>
or<span>share/cmake</span>
subdirectory.
3. Specific Functions
3.1 Custom Library and Package Search
In actual development, you may use some custom libraries or third-party libraries that are not installed in the system’s default standard paths. In this case, you can add the installation paths of these libraries to <span>CMAKE_PREFIX_PATH</span>
, so that CMake can find the required libraries and header files in these paths. For example, if you compiled a library named <span>my_library</span>
and installed it in the <span>/path/to/my_library</span>
directory, you can set <span>CMAKE_PREFIX_PATH</span>
as follows:
export CMAKE_PREFIX_PATH=/path/to/my_library:$CMAKE_PREFIX_PATH
Then use <span>find_package</span>
or <span>find_library</span>
in the CMakeLists.txt to find this library
find_library(MY_LIBRARY my_library HINTS /path/to/my_library/lib)
if(MY_LIBRARY) message(STATUS "Found my_library: ${MY_LIBRARY}")endif()
There may be multiple versions of the same library in the system, and by setting <span>CMAKE_PREFIX_PATH</span>
, you can specify CMake to use a specific version of the library. Add the installation path of the library you want to use to the front of <span>CMAKE_PREFIX_PATH</span>
, and CMake will prioritize searching for the required resources in that path.For example, if you have an old version of a library installed in <span>/path/to/old_library</span>
and a new version installed in <span>/path/to/new_library</span>
, if you want to use the new version of the library, you can set it as follows:
export CMAKE_PREFIX_PATH=/path/to/new_library:$CMAKE_PREFIX_PATH
All of the above are temporary settings; you can write them to bashrc for permanent handling.