ROS Group 产品服务
Product Service 开源代码库
Github 官网
Official website 技术交流
Technological exchanges 激光雷达
LIDAR ROS教程
ROS Tourials 深度学习
Deep Learning 机器视觉
Computer Vision
cmake的简单使用
-
在用别人写的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的官方文档。虽然我觉得那个并不是写出来给人看的。