a. cmake_minimum_required
cmake_minimum_required(VERSION major[.minor[.patch[.tweak]]] [FATAL_ERROR])
cmake [选项] <源码路径>
cmake [选项] <现有构建路径>
因为source 目录在../
-G:指定构建系统,当前只想创建Linux/Unix系统标准Makefile。 所以指定为Unix Makefile.
具体支持何种构建系统:man cmake
可以看到类似入下内容:
Generators
The following generators are available on this platform:
这个CMakeLists.txt 内容中,构成可执行文件的文件个数很少,但如果源文件很多,则最好如Makefile中一样,指定一个源文件列表:
set (SRC_LIST main.cpp v4l2_util.cpp tran_data.cpp)
(注1)
1.2: 编译一个静态库,并使用这个静态库和main.cpp,最终再生成一个可执行程序:
即先生成libv4l2_utils.a.
main.cpp使用libv4l2_utils.a中的符号并最终生成V4L2_Utils.
CMakeLists.txt:
cmake_minimum_required (VERSION 2.6)
project (V4L2_Utils)
set (LIB_SRC_LIST
set (EXEC_SRC_LIST main.cpp)
add_library(V4L2_Utils STATIC
add_executable(Test_V4L2 ${EXEC_SRC_LIST})
target_link_libraries(Test_V4L2 V4L2_Utils)
说明:
创建一个名为 name 的库文件,STATIC, SHARED指定为静态或动态库。
库文件由源文件列表生成。
add_library(V4L2_Utils STATIC
生成一个静态库libV4l2_Utils.a 由v4l2_util.cpp tran_data.cpp生成
add_executable(Test_V4L2 ${EXEC_SRC_LIST})
可执行程序由哪些.o组成。
target_link_libraries(Test_V4L2 V4L2_Utils)
可执行程序Test_V4L2需要链接库V4L2_Utils
target_link_libraries( [item1 [item2 [...]]] [[debug|optimized|general] ] ...)
将给定的库链接到目标target上。
1.3: 编译一个动态库,并使用这个动态和main.cpp,最终再生成一个可执行程序:
cmake_minimum_required (VERSION 2.6)
project (V4L2_Utils)
set (LIB_SRC_LIST
set (EXEC_SRC_LIST main.cpp)
add_library(V4L2_Utils SHARED
add_executable(Test_V4L2 ${EXEC_SRC_LIST})
target_link_libraries(Test_V4L2 V4L2_Utils)
只变化了STATIC-->SHARED
1.4:
main.cpp中,需要include "v4l2_util.h"
但这个头文件并不在src目录内,而是在include目录
include, src为同级别目录。则main.cpp会找不到头文件。
所以,实际的CMakeLists.txt文件写法为:
cmake_minimum_required (VERSION 2.6)
project (V4L2_Utils)
set (LIB_SRC_LIST
set (EXEC_SRC_LIST main.cpp)
set (INCLUDE_DIRECTORIES ../include)
include_directories(${INCLUDE_DIRECTORIES})
add_library(V4L2_Utils SHARED
add_executable(Test_V4L2 ${EXEC_SRC_LIST})
target_link_libraries(Test_V4L2 V4L2_Utils)
将头文件目录添加进去。
1.5: 添加第三方库和库路径:
如果libV4L2.so是以第三方库形式出现。不需要编译,它放在resource目录下。则需要制定搜索库路径
cmake_minimum_required (VERSION 2.6)
project (V4L2_Utils)
set (EXEC_SRC_LIST main.cpp)
set (INCLUDE_DIRECTORIES ../include)
set (LINK_DIR ../../resource)
include_directories(${INCLUDE_DIRECTORIES})
link_directories(${LINK_DIR})
add_executable(Test_V4L2 ${EXEC_SRC_LIST})
target_link_libraries(Test_V4L2 V4L2_Utils)
说明:
link_directories 指定连接器查找库的路径。
1.6:创建Release和Debug版本:
#set (CMAKE_BUILD_TYPE Release)
set (CMAKE_BUILD_TYPE Debug)
分别指定为Release或者Debug模式。区别在于:
Release:
Debug:-g
也可以不加在txt内。在产生Makefile时才加入:
cmake -DCMAKE_BUILD_TYPE=Release
1.7: 增加编译和链接选项:
CMAKE_C_FLAGS
CMAKE_CXX_FLAGS
CMAKE_EXE_LINKER_FLAGS
分别相当于:CFLAGS, CXXFLAGS, LDFLAGS。
set (CMAKE_CXX_FLAGS
这种写法的好处是,不会覆盖CMAKE_CXX_FLAGS本来的信息。只是把需要添加的内容添加进去。
1.8: 多目录结构的cmake 使用:
V4L2_Utils实际的目录结构其实并不是所有源码都存放在src目录内。
它的目录结构是:
src: 存放生成库的源码。v4l2_util.cpp, tran_data.cpp
test:存放使用库的测试程序: main.cpp
include: 存放头文件: v4l2_util.h
resource: 存放第三方库
build:存放编译过程的文件
build/lib: 存放生成的libv4l2_utils.so
build/bin:存放main.cpp所产生的测试程序可执行文件。
此时,可以采用顶层目录和每个有源码的目录中均创建CMakeLists.txt的方式来处理(和Makefile处理方式类似)
顶层目录的CMakeLists.txt 内容如下:
cmake_minimum_required (VERSION 2.6)
project (V4L2_Utils)
add_subdirectory(src lib)
add_subdirectory(test bin)
说明:
add_subdirectory(source_dir [binary_dir]
构建添加一个子路径。source_dir选项指定了CMakeLists.txt源文件和代码文件的位置。如果source_dir是一个相对路径,那么source_dir选项会被解释为相对于当前的目录,但是它也可以是一个绝对路径。binary_dir选项指定了输出文件的路径。如果binary_dir是相对路径,它将会被解释为相对于当前输出路径。
请注意两个相对路径的不同。因为Sam是在Build目录内执行cmake ..
source_dir算相对路径时,是从CMakeLists.txt算起。
所以src指的是当前 CMakeLists.txt所在路径下的src. 而bin, lib 指的是当前输出路径下的bin,lib. 也就是build/bin build/lib
src CMakeLists.txt :
set (LIB_SRC_LIST
set (CMAKE_BUILD_TYPE Release)
include_directories(../include)
add_library(V4L2_Utils SHARED
test CMakeLists.txt :
set (EXEC_SRC_LIST main.cpp)
set (INCLUDE_DIRECTORIES ../include)
set (LINK_DIR ../../resource)
set (LINK_DIR "${LINK_DIR} ../../libs/")
set (CMAKE_BUILD_TYPE Release)
include_directories(${INCLUDE_DIRECTORIES})
link_directories(${LINK_DIR})
add_executable(Test_V4L2 ${EXEC_SRC_LIST})
target_link_libraries(Test_V4L2 V4L2_Utils)
这个做法一直不满意,其实有更好的做法
总结:
有了以下这些选项,写过Makefile的人可以很容易的使用CMake了。
生成可执行程序:
add_executable(Test_V4L2 ${EXEC_SRC_LIST})
生成静态库
add_library(V4L2_Utils STATIC
生成动态库:
add_library(V4L2_Utils SHARED
指定头文件路径: -I
include_directories(${INCLUDE_DIRECTORIES})
指定库文件路径: -L
link_directories(${LINK_DIR})
指定链接库: -l
target_link_libraries(Test_V4L2 V4L2_Utils)
CFLAGS,CXXFLAGS,LDFLAGS:
CMAKE_C_FLAGS,CMAKE_CXX_FLAGS,CMAKE_EXE_LINKER_FLAGS
注1:set 和message
set用来指定变量
如:
set (SRC_LIST main.cpp)
则变量SRC_LIST内容为main.cpp
${SRC_LIST} 则为取变量内容(与Bash类似)
message:用来显示变量
message (${SRC_LIST})
注2:
如何显示编译细节:
方法1:
在CMakeLists.txt中,
set(CMAKE_VERBOSE_MAKEFILE ON)
方法2:
有时不希望修改CMakeLists.txt文件,则可以在创建Makefile时加入:
cmake -DCMAKE_VERBOSE_MAKEFILE=ON
方法3:
有时连Makefile都不希望修改:
make VERBOSE=1
注2:相对路径问题:
set (LIBRARY_DIRECTORIES ../resource)
link_directories(${LIBRARY_DIRECTORIES})
这里会出警告:
This command specifies the relative path
可以做如下处理:
set (LIBRARY_DIRECTORIES ../resource)
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/${LIBRARY_DIRECTORIES})
注3:
https://cmake.org/
注4:
find_package()功能讲解:
例如:
find_package(Qt5Widgets)
可以被用来在系统中自动查找配置构建工程所需的程序库。在linux和unix类系统下这个命令尤其有用。CMake自带的模块文件里有大半是对各种常见开源库的find_package支持,支持库的种类非常多.
find_package( [version] [EXACT] [QUIET] [[REQUIRED|COMPONENTS] [components...]] [NO_POLICY_SCOPE])
查找并加载外来工程的设置。该命令会设置_FOUND变量,用来指示要找的包是否被找到了。如果这个包被找到了,与它相关的信息可以通过包自身记载的变量中得到。REQUIRED选项表示如果报没有找到的话,cmake的过程会终止,并输出警告信息
在REQUIRED选项之后,或者如果没有指定REQUIRED选项但是指定了COMPONENTS选项,在它们的后面可以列出一些与包相关的部件清单(components list)。
FIND_PACKAGE
就会有变量Qt5Widgets_FOUND,Qt5Widgets_INCLUDE_DIRS等相应的变量生效。
例如:
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs)
如果找到catkin package. 则catkin_FOUND 被设置为true. catkin_INCLUDE_DIRS, catkin_LIBRARIES 被设置。
如果没找到,因为有REQUIRED. 所以会抱错。