在用别人写的c或者c++程序的时候。最经常见到的就是cmakelist.txt这个文件了。通常想要编译程序的时候需要执行
cmake
make
make install
这里cmake就是根据cmakelist.txt文件生成编译时使用的makefile文件
一个程序的编译过程需要经过两个主要的过程。一个是把各个文件编译成机械码,另一个是把编译出的各个文件的机械码链接成一个文件。而cmakelist.txt的作用就是告诉编译软件头文件和链接库在什么地方,以及添加一些编译的特殊参数。下面就简单介绍一下cmakelist.txt应该怎么写。这里只介绍基本的功能,目的是快速上手,所以算是一个 cmakelist.txt quick start guide.
以下面这个文件为例
cmake_minimum_required(VERSION 2.8.3)
project(orb_slam2)
find_package(catkin REQUIRED COMPONENTS
roscpp
sensor_msgs
image_transport
message_filters
cv_bridge
cmake_modules)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O3 -march=native ")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O3 -march=native")
# Check C++11 or C++0x support
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
add_definitions(-DCOMPILEDWITHC11)
message(STATUS "Using flag -std=c++11.")
elseif(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
add_definitions(-DCOMPILEDWITHC0X)
message(STATUS "Using flag -std=c++0x.")
else()
message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()
LIST(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../../../cmake_modules)
find_package(OpenCV 2.4.3 REQUIRED)
find_package(Eigen3 3.1.0 REQUIRED)
find_package(Pangolin REQUIRED)
find_package(libmongocxx REQUIRED)
find_package(libbsoncxx REQUIRED)
catkin_package()
include_directories(
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/../../../
${PROJECT_SOURCE_DIR}/../../../include
${Pangolin_INCLUDE_DIRS}
${LIBMONGOCXX_INCLUDE_DIRS}
${LIBBSONCXX_INCLUDE_DIRS}
)
set(LIBS
${catkin_LIBRARIES}
${OpenCV_LIBS}
${EIGEN3_LIBS}
${Pangolin_LIBRARIES}
${PROJECT_SOURCE_DIR}/../../../Thirdparty/DBoW2/lib/libDBoW2.so
${PROJECT_SOURCE_DIR}/../../../Thirdparty/g2o/lib/libg2o.so
${PROJECT_SOURCE_DIR}/../../../lib/libORB_SLAM2.so
${LIBMONGOCXX_LIBRARY_DIRS}/libmongocxx.so
${LIBBSONCXX_LIBRARY_DIRS}/libbsoncxx.so
)
# Node for monocular camera
add_executable(mono
src/ros_mono.cc
)
target_link_libraries(mono
${LIBS}
)
# Node for RGB-D camera
add_executable(rgbd
src/ros_rgbd.cc
)
target_link_libraries(rgbd
${LIBS}
)
# Node for stereo camera
add_executable(stereo
src/ros_stereo.cc
)
target_link_libraries(stereo
${LIBS}
)
首先是指定cmake的版本
然后是工程的名字
然后是find_package. 软件一般都是有依赖关系的,如果你依赖别的软件,就可以通过find_package来载入依赖的软件的相关信息,比如软件的头文件,软件的链接库位置。find_package会在特定的目录里去找对应的软件config文件。在cmake的安装路径下里面有各种已安装的软件包的cmake文件。find_package实际上就是在找这些文件,然后执行一遍。有时自己依赖的软件包并不提供这样的文件,这时候就要自己去写。
上图的libbsoncxx-config.cmake就是libbsoncxx这个软件包的cmake文件。在cmake文件中的CMAKE_MODULE_PATH变量就是find_package找的路径。可以在里面添加上自定义的路径。find_package还可以添加上 REQUIRED标记,表明这个软件包是必须的。如果find_package没有找到这个软件包,那么cmake就出报出没有找到这个软件包的错误。
Set 可以用来设置环境变量的。
然后在cmake文件里面是有简单的判断分支结构可以用的,简单的语法就是
If(xxxx)
elseif(xxxx)
endif(xxxx)
需要注意的是elseif里面并不是另一种条件,这里要和if里面写的一样。表示当if的条件未被满足时应该执行的语句。如果想要实现更加复杂的判断,就需要嵌套的if语句。
最后就是 include_directories和 target_link_libraries。这两个的意义很明确,就是设置头文件的地址和链接库的位置。还有就是生成可执行程序的命令 add_executable, 第一个变量是生成的文件名字,之后是对应的源文件。如果不想生成可执行文件,只是想生成一个链接库供别人使用,那么可以用add_library这个命令。使用方法和 add_executable基本一致。下面是一个例子
add_library(${PROJECT_NAME} SHARED
src/System.cc
src/Tracking.cc
src/LocalMapping.cc
src/LoopClosing.cc
src/ORBextractor.cc
src/ORBmatcher.cc
src/FrameDrawer.cc
src/Converter.cc
src/MapPoint.cc
src/KeyFrame.cc
src/Map.cc
src/MapDrawer.cc
src/Optimizer.cc
src/PnPsolver.cc
src/Frame.cc
src/KeyFrameDatabase.cc
src/Sim3Solver.cc
src/Initializer.cc
src/Viewer.cc
)
SHARED是这个库的类型。动态链接库还是静态链接库。
到这里基本上简单的cmakelist文件已经可以自己写了。下面说说软件库的cmake文件怎么写。就是find_package那个命令会用到的那个文件。
我们还是以一个例子来做说明。
# - Find MongoDB
# Find the MongoDB includes and client library
# This module defines
# MongoDB_INCLUDE_DIR, where to find mongo/client/dbclient.h
# MongoDB_LIBRARIES, the libraries needed to use MongoDB.
# MongoDB_FOUND, If false, do not try to use MongoDB.
if(MongoDB_INCLUDE_DIR AND MongoDB_LIBRARIES)
set(MongoDB_FOUND TRUE)
else(MongoDB_INCLUDE_DIR AND MongoDB_LIBRARIES)
find_path(MongoDB_INCLUDE_DIR bsoncxx/builder/basic/document.hpp
/usr/local/include/mongocxx/v_noabi
/usr/local/include/libbson-1.0
/usr/local/include/libmongoc-1.0
/usr/local/include/bsoncxx/v_noabi
)
if(WIN32)
find_library(MongoDB_LIBRARIES NAMES mongoclient
PATHS
$ENV{ProgramFiles}/Mongo/*/lib
$ENV{SystemDrive}/Mongo/*/lib
)
else(WIN32)
find_library(MongoDB_LIBRARIES NAMES mongocxx bsoncxx
PATHS
/usr/lib
/usr/lib64
/usr/lib/mongo
/usr/lib64/mongo
/usr/local/lib
/usr/local/lib64
/usr/local/lib/mongo
/usr/local/lib64/mongo
/opt/mongo/lib
/opt/mongo/lib64
)
endif(WIN32)
if(MongoDB_INCLUDE_DIR AND MongoDB_LIBRARIES)
set(MongoDB_FOUND TRUE)
message(STATUS "Found MongoDB: ${MongoDB_INCLUDE_DIR}, ${MongoDB_LIBRARIES}")
else(MongoDB_INCLUDE_DIR AND MongoDB_LIBRARIES)
set(MongoDB_FOUND FALSE)
if (MongoDB_FIND_REQUIRED)
message(FATAL_ERROR "MongoDB not found.")
else (MongoDB_FIND_REQUIRED)
message(STATUS "MongoDB not found.")
endif (MongoDB_FIND_REQUIRED)
endif(MongoDB_INCLUDE_DIR AND MongoDB_LIBRARIES)
mark_as_advanced(MongoDB_INCLUDE_DIR MongoDB_LIBRARIES)
endif(MongoDB_INCLUDE_DIR AND MongoDB_LIBRARIES)
这是一个叫做MongoDB的软件包的cmake文件。
这个文件会通过设置MongoDB_FOUND变量来告诉cmake这个库有没有找到。这里需要注意的就是find_path这个指令。这个就是用来判断软件是否存在的关键指令。find_path的第一个参数接的是变量名字,之后是文件的名字。后面接一系列这个文件可能存在的路径。也就是软件的可能安装路径。如果在以下路径成功找到这个文件。第一个变量就会被赋值。反之如果找不到,那么这个变量就会被设成False。之后可以用if来判断不同条件下需要执行的语句。大致上就是如此。
这里只是一些简单的介绍,如果想要更全面的更准确的了解cmake那么可以去看看cmake的官方文档。虽然我觉得那个并不是写出来给人看的。