基础知识与命令
1.一些指令
#添加头文件搜索目录,对于纯头文件组成的eigen就可以使用了
- target_link_directories(${PROJECT_NAME} PUBLIC /usr/include/eigen3)
#添加要链接的库 - target_link_libraries(myapp PUBLIC hellolib)
#添加一个宏定义 - target_add_definitions(myapp PUBLIC MY_MACRO=1)
- target_add_definitions(myapp PUBLIC -DMY_MACRO=1) # 与 MY_MACRO=1 等价
#添加编译器命令行选项 - arget_compile_options(myapp PUBLIC -fopenmp)
#添加要编译的源文件 - target_sources(myapp PUBLIC hello.cpp other.cpp)
以及可以通过下列指令(不推荐使用),把选项加到所有接下来的目标去: - include_directories(/opt/cuda/include) # 添加头文件搜索目录
- link_directories(/opt/cuda) # 添加库文件的搜索路径
- add_definitions(MY_MACRO=1) # 添加一个宏定义
- add_compile_options(-fopenmp) # 添加编译器命令行选项
例如,windows中,在文件头部加入add_definitions(-DNOMINMAX),以屏蔽<windows.h>中min
2.通常一个库一个模块(对应主CMakeLists.txt中的add_subdirectory),即子模块
在子模块的CMakeLists.txt中
add_library(xxxlib STATIC xxx.cpp)
#.是指这个CMakeLists.txt所在的目录,PUBILC修饰符使得目标可执行文件在链接link这个xxxlib将得到这个xxlib的头文件目录.
target_inlcude_directories(xxxlib PUBLIC .)
3.除了像eigen这种纯头文件的,有以源文件的方式加入工程,比如ORB-SLAM2中的DBOW2
cmake_minimum_required(VERSION 2.8)
project(DBoW2)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O3 -march=native ")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O3 -march=native")
#定义一些变量
set(HDRS_DBOW2
DBoW2/BowVector.h
...)
set(SRCS_DBOW2
DBoW2/BowVector.cpp
...)
set(HDRS_DUTILS
DUtils/Random.h
...)
find_package(OpenCV 3.0 QUIET)
if(NOT OpenCV_FOUND)
find_package(OpenCV 2.4.3 QUIET)
if(NOT OpenCV_FOUND)
message(FATAL_ERROR "OpenCV > 2.4.3 not found.")
endif()
endif()
#设置lib输出目录
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
#添加头文件搜索目录
include_directories(${OpenCV_INCLUDE_DIRS})
#用源文件来编译库
add_library(DBoW2 SHARED ${SRCS_DBOW2} ${SRCS_DUTILS})
#为目标链接库
target_link_libraries(DBoW2 ${OpenCV_LIBS})
4还有一些要提前安装的库
需要用,如 find_package(fmt REQUIRED)
找到现代 CMake 认为一个包 (package) 可以提供多个库,又称组件 (components),比如 target_link_libraries(myexec PUBLIC fmt::fmt)
,为避免冲突,每个包都享有一个独立的名字空间,以 :: 分割。你可以指定要用哪几个组件:
find_package(TBB REQUIRED COMPONENTS tbb tbbmalloc REQUIRED)
target_link_libraries(myexec PUBLIC TBB::tbb TBB::tbbmalloc)
5.例子
以cmake-examples-02为例
#basic/CMakeLists.txt
cmake_minimum_required (VERSION 3.5)
project(subprojects)
#CMakeLists.txt文件可以包含和调用包含CMakeLists.txt文件的子目录
# Add sub directories
add_subdirectory(sublibrary1)
add_subdirectory(sublibrary2)
add_subdirectory(subbinary)
/sublibrary1 源码编译了一个库文件
#生成静态库的CMakeLists.txt
# Set the project name
project (sublibrary1)
# Add a library with the above sources
#此处${PROJECT_NAME}是当前project的名字,sublibrary1
add_library(${PROJECT_NAME} src/sublib1.cpp)
add_library(sub::lib1 ALIAS ${PROJECT_NAME})
#将头文件移至每个项目include目录下的子文件夹,而将目标include保留为根include文件夹。 这是防止文件名冲突的一个好主意,因为您必须包括以下文件:#include "sublib1/sublib1.h"
target_include_directories( ${PROJECT_NAME}
PUBLIC ${PROJECT_SOURCE_DIR}/include
)
\sublibrary2
#生成仅有头文件的库的CMakeLists.txt
# Set the project name
project (sublibrary2)
#如果您有一个库被创建为仅头文件的库,则cmake支持INTERFACE目标,以允许创建没有任何构建输出的目标
add_library(${PROJECT_NAME} INTERFACE)
add_library(sub::lib2 ALIAS ${PROJECT_NAME})
#此处INTERFACE的作用是:使用INTERFACE范围包含该目标的目录。 INTERFACE范围用于制定在链接此目标的任何库中使用的目标需求,但在目标本身的编译中不使用
target_include_directories(${PROJECT_NAME}
INTERFACE
${PROJECT_SOURCE_DIR}/include
)
\subbianry
project(subbinary)
# Create the executable
add_executable(${PROJECT_NAME} main.cpp)
#使用别名sub :: lib1从subproject1链接静态库
#使用别名sub :: lib2从subproject2链接仅标头的库
#这将导致该目标的包含目录添加到该项目中即lib1,lib2中的target_include_directories()语句
target_link_libraries(${PROJECT_NAME}
sub::lib1
sub::lib2
)