项目链接:
cmake-examples
01 Basic
A Hello CMake
目标:
- CMake 基本框架
- 使用Visual Studio 打开构建的项目
CMakeList.txt
# 设置最小的CMake版本
# 可以通过命令查询环境中 cmake 的版本 cmake --version
cmake_minimum_required(VERSION 3.0)
# 设置项目名称
project(hello_cmake)
# 添加一个可执行程序
add_executable(hello_cmake "main.cpp")
编译
- 创建 Build 目录 并进入Build目录
- 执行
cmake ..
- 使用使用visual studio 打开 .sln文件,并编译。
B 添加头文件
目标:
- 使用 cmake 导入头文件。
文件目录:
.
├── CMakeLists.txt
├── include
│ └── Hello.h
└── src
├── Hello.cpp
└── main.cpp
在main.cpp 中引用 Hello.h
如果不在CMake中导入头文件,就会报错提示找不到 Hello.h 的头文件
CMake 地址相关的宏
Variable | Info |
---|---|
CMAKE_SOURCE_DIR | The root source directory |
CMAKE_CURRENT_SOURCE_DIR | The current source directory if using sub-projects and directories. |
PROJECT_SOURCE_DIR | The source directory of the current cmake project. |
CMAKE_BINARY_DIR | The root binary / build directory. This is the directory where you ran the cmake command. |
CMAKE_CURRENT_BINARY_DIR | The build directory you are currently in. |
PROJECT_BINARY_DIR | The build directory for the current project. |
假如项目的路径是: D:\workSpace\cmake-examples\01-basic\B-hello-headers
Variable | Info |
---|---|
CMAKE_SOURCE_DIR | D:/workSpace/cmake-examples/01-basic/B-hello-headers |
CMAKE_CURRENT_SOURCE_DIR | D:/workSpace/cmake-examples/01-basic/B-hello-headers |
PROJECT_SOURCE_DIR | D:/workSpace/cmake-examples/01-basic/B-hello-headers |
CMAKE_BINARY_DIR | D:/workSpace/cmake-examples/01-basic/B-hello-headers/build |
CMAKE_CURRENT_BINARY_DIR | D:/workSpace/cmake-examples/01-basic/B-hello-headers/build |
PROJECT_BINARY_DIR | D:/workSpace/cmake-examples/01-basic/B-hello-headers/build |
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(HelloHeaders)
message("This is a message with a pipe symbol: ||")
message(====================================================================)
message("|CMAKE_SOURCE_DIR |" ${
CMAKE_SOURCE_DIR} "|")
message("|CMAKE_CURRENT_SOURCE_DIR |" ${
CMAKE_CURRENT_SOURCE_DIR} "|")
message("|PROJECT_SOURCE_DIR |" ${
PROJECT_SOURCE_DIR} "|")
message("|CMAKE_BINARY_DIR |" ${
CMAKE_BINARY_DIR} "|")
message("|CMAKE_CURRENT_BINARY_DIR |" ${
CMAKE_CURRENT_BINARY_DIR} "|")
message("|PROJECT_BINARY_DIR |" ${
PROJECT_BINARY_DIR} "|")
message(====================================================================)
set(SOURCE
src/Hello.cpp
src/main.cpp
)
add_executable(HelloHeaders ${
SOURCE})
# 添加头文件
# PRIVATE 表示只为当前的目标添加头文件目录,不会影响其他目标
target_include_directories(HelloHeaders
PRIVATE
${
PROJECT_SOURCE_DIR}/include
)
C 静态库
目标: 使用CMake打包静态库。在windows 下,将某一个模块,打包成静态库。将会生成:
- xxx.lib 文件
- xxx.h 头文件
在其他代码里就可以导入头文件,链接.lib文件来调用模块中的功能。
文件目录:
├── CMakeLists.txt
├── include
│ └── static
│ └── Hello.h
└── src
├── Hello.cpp
└── main.cpp
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(hello_library)
############################################################
# 创建静态库
############################################################
add_library(hello_library_lib STATIC src/Hello.cpp)
# 导入include 头文件目录
target_include_directories(hello_library_lib
PUBLIC
${
PROJECT_SOURCE_DIR}/include)
############################################################
# 创建可执行文件
############################################################
add_executable(hello_library_exe
src/main.cpp)
# 链接静态库
target_link_libraries(hello_library_exe
PRIVATE
hello_library_lib)
添加一个静态库
add_library(hello_library_lib STATIC src/Hello.cpp)
- STATIC 表示打包静态库
导入头文件
# 导入include 头文件目录
target_include_directories(hello_library_lib
PUBLIC
${
PROJECT_SOURCE_DIR}/include)
在这里使用了 PUBLIC 的作用域,这将使得include目录在如下场景被使用:
- 编译静态库时
- 当编译以及链接目标库时
作用域的含义:
- PRIVATE 目录被加在当前目标的 include路径
- INTERFACE 目录将被加在任意链接这个库的 include 路径
- PUBLIC 和上面一样, 目录将被加在任意链接这个库的 include 路径
TIPS:
- 对于 public 头文件,通常最好将您的include文件夹,使用子目录进行"命名空间"化。
- target_include_directories接收的目录将成为您的包含(include)目录树的根目录,您的C++文件应该包含从根目录到您的头文件的路径。
- 在这个例子里面,你可以这样导入:
#include "static/Hello.h"
- 使用这种方法意味着在您的项目中使用多个库时,头文件名称冲突的可能性较小。带上了库的名字,不然容易导致有重复的名字的库,带来很多意外的结果。
链接库
add_executable(hello_binary
src/main.cpp
)
target_link_libraries( hello_binary
PRIVATE
hello_library
)
动态库
动态库,在Windows下会生成:
- xx.dll
- xx.lib
- xx.h
在CMake上只有一点不同就是:
# 生成动态库
add_library(hello_libary_dll
SHARED
src/Hello.cpp)
在到处动态库时,在windows平台下,需要在要到处的类前面加上一个宏 __declspec, 如果不加,将不会生成 .lib文件,在windows平台下会导入出错的。
#ifndef __HELLO_H__
#define __HELLO_H__
class __declspec( dllexport ) Hello
{
public:
void print();
};
#endif
安装
目的: 在编译后,我们希望我们编译的目标, 头文件或者配置文件等移动到相关的目录下,这时候在CMake中就有了 Installing 的概念。基础的安装位置是由变量 **CMAKE_INSTALL_PREFIX ** 控制的。我们在使用 cmake 编译时可以加上这个参数:
cmake .. -DCMAKE_INSTALL_PREFIX=/install/location
比如我这里默认的安装路径为:
CMAKE_INSTALL_PREFIX | C:/Program Files (x86)/HelloHeaders |
---|
# - Install 二进制文件
install (TARGETS cmake_examples_inst_bin DESTINATION bin)
# - Install Library
install (TARGETS cmake_examples_inst LIBRARY DESTINATION lib)
# -install Header files
# - copy include directory to CMAKE_INSTALL_PREFIX/include
install(DIRECTORY ${
PROJECT_SOURCE_DIR}/include/ DESTINATION include)
# - Config
# - Copy config file to CMAKE_INSTALL_PREFIX/etc
install (FILES cmake-examples.conf DESTINATION etc)
Windows install 编译结果
1>-- Install configuration: "Debug"
1>-- Installing: D:/workSpace/cmake-examples/01-basic/E-installing/install_dir/bin/cmake_examples_inst_bin.exe
1>-- Installing: D:/workSpace/cmake-examples/01-basic/E-installing/install_dir/lib/cmake_examples_inst.lib
1>-- Installing: D:/workSpace/cmake-examples/01-basic/E-installing/install_dir/bin/cmake_examples_inst.dll
1>-- Installing: D:/workSpace/cmake-examples/01-basic/E-installing/install_dir/include
1>-- Installing: D:/workSpace/cmake-examples/01-basic/E-installing/install_dir/include/installing
1>-- Installing: D:/workSpace/cmake-examples/01-basic/E-installing/install_dir/include/installing/Hello.h
1>-- Installing: D:/workSpace/cmake-examples/01-basic/E-installing/install_dir/etc/cmake-examples.conf
Note: 如果安装目录在C盘,并且没有用管理员权限,不会运行成功。!!!!
设置编译类型
CMake 提供了内置的编译类型:
- Release - Adds the -O3 -DNDEBUG flags to the compiler
- Debug - Adds the -g flag
- MinSizeRel - Adds -Os -DNDEBUG
- RelWithDebInfo - Adds -O2 -g -DNDEBUG flags
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message("Setting build type to 'RelWithDebInfo' as none was specified.")
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
"MinSizeRel" "RelWithDebInfo")
endif()
编译选项
CMake 支持设置编译选项,并且提供如下方式:
- 使用 ** target_compile_definitions()** 函数。 在现代CMake中设置C++标志的推荐方法是使用每个目标(target)的标志,可以通过target_compile_definitions()函数传递给其他目标。这将为库填充INTERFACE_COMPILE_DEFINITIONS,并根据作用域将定义传递给链接的目标。
target_compile_definitions(cmake_examples_compile_flags
PRIVATE EX3
)
- 使用 CMAKE_C_FLAGS and CMAKE_CXX_FLAGS 变量
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEX2" CACHE STRING "Set C++ Compiler Flags" FORCE)
- 在编译命令中设置
cmake .. -DCMAKE_CXX_FLAGS="-DEX3"
导入第三方库
以导入Boost 库为例:
find_package(Boost 1.46.1 REQUIRED COMPONENTS filesystem system)
- find_package 函数将搜索 CMake 模块,这些模块通常是 Findxxx.cmake 的文件,文件通常在 CMAKE_MODULE_PATH 下面。 例如,我的默认模块文件在:C:/Program Files/CMake/share/cmake-3.26/Modules/ 下。
- Boost 库的名字,通常会去找 FindBoost.cmake这个模块文件
- 1.46.1 三方库的版本必须大于这个版本
- REQUIRED 如果找不到会编译失败
- COMPONENTS 查找的库的组件。
检查是否已经找到库了
许多的包都会包含一个变量 XXX_FOUND ,用来表示这个包是否在系统中是可用的。
比如:
if(Boost_FOUND)
message ("boost found")
include_directories(${
Boost_INCLUDE_DIRS})
else()
message (FATAL_ERROR "Cannot find Boost")
endif()