第一部分 入门
一、Hello world
文件目录
./_01
|
+- main.cpp
+- CMakeLists.txt
/
// main.cpp
#include <iostream>
int main()
{
std::cout << "Hello world!" << std::endl;
return 0;
}
# CMakeLists.txt
# 最低版本
cmake_minimum_required(VERSION 3.5)
# 项目名称
project(helloworld)
# 生成可执行文件
add_executable(helloworld main.cpp)
二、生成项目
// cmake [options] <path-to-source>
// cmake [options] <path-to-existing-build>
cmake .
2.1 编译 & 安装
Linux
make
make install
Windows
cmake --build . --config Release --target install
三、生成和使用库
文件目录
./_01
+- build/
+- math/
+- math.h
+- math.cpp
+- CMakeLists.txt
/
+- main.cpp
+- CMakeLists.txt
/
// main.cpp
#include <iostream>
#include "math/math.h"
int main()
{
auto max = z::max(4, 5);
std::cout << max << std::endl;
return 0;
}
# CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(helloworld)
set(SRC main.cpp)
add_subdirectory(math)
add_executable(${PROJECT_NAME} ${SRC})
target_link_libraries(${PROJECT_NAME} math)
// math/math.h
namespace z {
int max(int l, int r);
}
// math/math.cpp
#include "math.h"
namespace z{
int max(int l, int r)
{
return l > r ? l : r;
}
}
# math/CMakeLists.txt
set(SRC math.cpp)
add_library(math ${SRC})
构建&编译
cd build
cmake ..
# Linux
make
# Windows
cmake --build .
第二部分 进阶
一、常量 | 全局变量
Name | Value | set |
---|---|---|
PROJECT_NAME | 项目名称 | project(Alchemy VERSION 0.0.1) |
PROJECT_VERSION | 项目版本 | project(Alchemy VERSION 0.0.1) |
PROJECT_SOURCE_DIR | ||
EXECUTABLE_OUTPUT_PATH | 可执行文件输出目录 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) |
LIBRARY_OUTPUT_PATH | 生成库输出目录 | set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib) |
CMAKE_HOST_SYSTEM_NAME | ||
CMAKE_HOST_SYSTEM_VERSION | ||
CMAKE_HOST_SYSTEM_PROCESSOR | ||
CMAKE_VERSION | ||
CMAKE_GENERATOR | ||
CMAKE_BUILD_TOOL |
二、变量
CMake
只有一种数据类型:string,但是在很多命令中,可以被解释为其他类型,例如bool类型。
变量使用set()
和unset()
显示set或unset,其他命令也有修改变量值的语义。
变量拥有动态作用域,和当前声明的作用域绑定。
- 函数作用域(Function Scope)
- 文件夹作用域(Directory Scope)
- 持久缓存(Persistent Cache)
2.1 环境变量
环境变量是全局变量,永不cached。
$ENV{<variable>
可以用set/unset改变其值,但只是在当前camke进程中改变,不会改变系统环境值。
2.2 列表(Lists)
在确定的上下文中,变量可以被解释为列表。
string使用;
分隔为列表
set(srcs a.c b.c c.c) # sets "srcs" to "a.c;b.c;c.c"
set(x a "b;c") # sets "x" to "a;b;c", not "a;b\;c"
三、控制语句
3.1
if(<condition>)
<commands>
elseif(<condition>) # optional block, can be repeated
<commands>
else() # optional block
<commands>
endif()
3.2 循环
foreach(<loop_var> <items>)
<commands>
endforeach()
while(<condition>)
<commands>
endwhile()
break()
continue
四、函数和宏
4.1 宏
macro(<name> [<arg1> ...])
<commands>
endmacro()
4.2 函数
function(<name> [<arg1> ...])
<commands>
endfunction()
五、生成库
5.1 语法
add_library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
[source1] [source2 ...])
5.2 例子
add_library(math STATIC math.cpp)
六、使用第三方库
6.1 查找包
对camke支持的第三方库,可以使用find_package命令进行查找,然后链接,例如
find_package(OpenCV REQUIRED)
if(OpenCV_FOUND)
include_directories(${OpenCV_INCLUDE_DIRS})
list(APPEND LINK_LIBS ${OpenCV_LIBS})
endif()
通常,find_package会设置几个变量值
- XXX_FOUND : 是否查找到
- XXX_INCLUDE_DIRS :头文件位置
- XXX_LIBRARIES :库列表
- XXX_LIBRARYRARY_DIRS :库目录
6.2 编写查找包模块
对于不支持的第三发库,我们可以自行编写cmake模块
首先,在根目录下新建一个camke文件夹,然后将该模块添加到工程中
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/;${CMAKE_MODULE_PATH}")
然后编写模块,例如FindGlog.cmake
include(FindPackageHandleStandardArgs)
set(GLOG_ROOT_DIR "" CACHE PATH "Folder contains Google glog")
find_path(GLOG_INCLUDE_DIR glog/logging.h
HINTS ${GLOG_ROOT_DIR}
PATH_SUFFIXES include google-glog/include)
find_library(GLOG_LIBRARY glog
HINTS ${GLOG_ROOT_DIR}
PATH_SUFFIXES lib lib64)
find_package_handle_standard_args(Glog DEFAULT_MSG GLOG_INCLUDE_DIR GLOG_LIBRARY)
if(GLOG_FOUND)
set(GLOG_INCLUDE_DIRS ${GLOG_INCLUDE_DIR})
set(GLOG_LIBRARIES ${GLOG_LIBRARY})
message(STATUS "Found glog (include: ${GLOG_INCLUDE_DIR}, library: ${GLOG_LIBRARY})")
mark_as_advanced(GLOG_ROOT_DIR GLOG_LIBRARY_RELEASE GLOG_LIBRARY_DEBUG
GLOG_LIBRARY GLOG_INCLUDE_DIR)
endif()
七、添加编译选项
# 添加选项,默认ON
option (USE_MATH "Use math libs" ON)
# 根据选项
if (USE_MATH)
...
endif ()
八、设置编译参数
8.1 设置C++标准
最简单的设置
set(CMAKE_CXX_STANDARD 14)
更加完善的一些设置
# 检查编译器对C++标准的支持
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++14" COMPILER_SUPPORTS_CXX14)
CHECK_CXX_COMPILER_FLAG("-std=c++17" COMPILER_SUPPORTS_CXX17)
if(NOT COMPILER_SUPPORTS_CXX14)
message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} DO NOT SUPPORT C++14.")
endif()
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON) # 要求使用标准C++
set(CMAKE_CXX_EXTENSIONS OFF) # 关闭编译器对C++的扩展
8.2 编译参数
# windows
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4100")
# linux
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra")
九 、安装
十、测试
tricks
Windows平台 设置 执行的管理员权限
set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "/MANIFESTUAC:\"level='requireAdministrator' uiAccess='false'\"")
复制动态库到执行目录
function(copy_to_target_dir name)
add_custom_command(TARGET ${PROJECT_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${name} $<TARGET_FILE_DIR:${PROJECT_NAME}>)
endfunction()
file(GLOB_RECURSE DLL_FILES /path/to/*.dll)
foreach(dll ${DLL_FILES})
copy_to_target_dir(${dll})
endforeach()