CMAKE 基础学习篇1

目录

01 基础

A 认识CMAKE

本篇文件结构:

A-hello-cmake$ tree
.
├── CMakeLists.txt
├── main.cpp
  • CMakeLists.txt : 包含想要运行的CMake命令
  • main.cpp : 源文件

入门概念

  • CMakeLists.txt : 运行cmake命令时,会在当前文件夹下搜索该文件并运行其中的命令,如果不存在该文件则cmake命令会报错。
  • 最低CMake版本要求:
cmake_minimum_required(VERSION 3.5)
  • Project : 项目名称可以方便多项目结构的变量使用
project (hello_cmake)
  • 创建可执行文件:该命令需要指明(生成的可执行文件名称,源文件名称序列)
add_executable(hello_cmake main.cpp)
  • 某些命令会创建一些全局环境变量:
cmake_minimum_required(VERSION 2.6)
project (hello_cmake)
add_executable(${PROJECT_NAME} main.cpp)

该例子中project()会创建一个变量${PROJECT_NAME},方便后续使用。

二进制文件目录

CMAKE_BINARY_DIR : 用户运行cmake命令生成二进制文件的根目录。CMake支持两种方式来生成二进制文件目录:in-place原地生成 和 out-of-souce 隔绝源代码的另一目录下生成。

  • in-place build :源文件目录下运行cmake命令,和源文件混杂在一起
A-hello-cmake$ cmake .
-- The C compiler identification is GNU 4.8.4
-- The CXX compiler identification is GNU 4.8.4
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/matrim/workspace/cmake-examples/01-basic/A-hello-cmake

A-hello-cmake$ tree
.
├── CMakeCache.txt
├── CMakeFiles
│   ├── 2.8.12.2
│   │   ├── CMakeCCompiler.cmake
│   │   ├── CMakeCXXCompiler.cmake
│   │   ├── CMakeDetermineCompilerABI_C.bin
│   │   ├── CMakeDetermineCompilerABI_CXX.bin
│   │   ├── CMakeSystem.cmake
│   │   ├── CompilerIdC
│   │   │   ├── a.out
│   │   │   └── CMakeCCompilerId.c
│   │   └── CompilerIdCXX
│   │       ├── a.out
│   │       └── CMakeCXXCompilerId.cpp
│   ├── cmake.check_cache
│   ├── CMakeDirectoryInformation.cmake
│   ├── CMakeOutput.log
│   ├── CMakeTmp
│   ├── hello_cmake.dir
│   │   ├── build.make
│   │   ├── cmake_clean.cmake
│   │   ├── DependInfo.cmake
│   │   ├── depend.make
│   │   ├── flags.make
│   │   ├── link.txt
│   │   └── progress.make
│   ├── Makefile2
│   ├── Makefile.cmake
│   ├── progress.marks
│   └── TargetDirectories.txt
├── cmake_install.cmake
├── CMakeLists.txt
├── main.cpp
├── Makefile
  • out-of-space build :额外创建了build目录,cmake ..进行生成。
A-hello-cmake$ mkdir build

A-hello-cmake$ cd build/

matrim@freyr:~/workspace/cmake-examples/01-basic/A-hello-cmake/build$ cmake ..
-- The C compiler identification is GNU 4.8.4
-- The CXX compiler identification is GNU 4.8.4
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/matrim/workspace/cmake-examples/01-basic/A-hello-cmake/build

A-hello-cmake/build$ cd ..

A-hello-cmake$ tree
.
├── build
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   │   ├── 2.8.12.2
│   │   │   ├── CMakeCCompiler.cmake
│   │   │   ├── CMakeCXXCompiler.cmake
│   │   │   ├── CMakeDetermineCompilerABI_C.bin
│   │   │   ├── CMakeDetermineCompilerABI_CXX.bin
│   │   │   ├── CMakeSystem.cmake
│   │   │   ├── CompilerIdC
│   │   │   │   ├── a.out
│   │   │   │   └── CMakeCCompilerId.c
│   │   │   └── CompilerIdCXX
│   │   │       ├── a.out
│   │   │       └── CMakeCXXCompilerId.cpp
│   │   ├── cmake.check_cache
│   │   ├── CMakeDirectoryInformation.cmake
│   │   ├── CMakeOutput.log
│   │   ├── CMakeTmp
│   │   ├── hello_cmake.dir
│   │   │   ├── build.make
│   │   │   ├── cmake_clean.cmake
│   │   │   ├── DependInfo.cmake
│   │   │   ├── depend.make
│   │   │   ├── flags.make
│   │   │   ├── link.txt
│   │   │   └── progress.make
│   │   ├── Makefile2
│   │   ├── Makefile.cmake
│   │   ├── progress.marks
│   │   └── TargetDirectories.txt
│   ├── cmake_install.cmake
│   └── Makefile
├── CMakeLists.txt
├── main.cpp

构建可执行文件

其实CMake在build目录下生成了Makefile文件,在该目录下运行make真正构建项目的可执行文件。

$ mkdir build

$ cd build

$ cmake ..
-- The C compiler identification is GNU 4.8.4
-- The CXX compiler identification is GNU 4.8.4
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /workspace/cmake-examples/01-basic/hello_cmake/build

$ make
Scanning dependencies of target hello_cmake
[100%] Building CXX object CMakeFiles/hello_cmake.dir/hello_cmake.cpp.o
Linking CXX executable hello_cmake
[100%] Built target hello_cmake

$ ./hello_cmake
Hello CMake!

B 头文件 hello-headers

本篇文件结构:

B-hello-headers$ tree
.
├── CMakeLists.txt
├── include
│   └── Hello.h
└── src
    ├── Hello.cpp
    └── main.cpp

目录相关的路径变量

CMake声明了一些变量:

Variable Info
CMAKE_SOURCE_DIR The root source directory (环境变量)
CMAKE_CURRENT_SOURCE_DIR The current source directory if using sub-projects and directories. 当前CMakeList.txt所在目录
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. 当前编译target所在目录
PROJECT_BINARY_DIR The build directory for the current project. 运行cmake命令的目录
PROJECT_SOURCE_DIR The source directory of the current cmake project. 工程根目录

https://www.jianshu.com/p/9d246e4071d4

创建变量例子

  • 创建一个源文件变量:
# Create a sources variable with a link to all cpp files to compile
set(SOURCES
    src/Hello.cpp
    src/main.cpp
)

add_executable(${PROJECT_NAME} ${SOURCES})
  • GLOB命令查找匹配文件:
file(GLOB SOURCES "src/*.cpp")

现代CMake不提倡这种方式来关联源文件名称,而是建议通过一些类似add_XXX的方法来声明变量。

头文件路径设置

target_include_directories(target
    PRIVATE
        ${PROJECT_SOURCE_DIR}/include
)
  • 该方法相当于在编译时使用-I指定了头文件搜索路径。
  • PRIVATE标识符的意义建议查看CMake官方文档了解。

使用Verbose

之前的例子中,使用make命令,只会简单打印build了哪些文件。

使用make VERBOSE=1可以把一些make的细致过程打印出来:

$ make clean

$ make VERBOSE=1
/usr/bin/cmake -H/home/matrim/workspace/cmake-examples/01-basic/hello_headers -B/home/matrim/workspace/cmake-examples/01-basic/hello_headers/build --check-build-system CMakeFiles/Makefile.cmake 0
/usr/bin/cmake -E cmake_progress_start /home/matrim/workspace/cmake-examples/01-basic/hello_headers/build/CMakeFiles /home/matrim/workspace/cmake-examples/01-basic/hello_headers/build/CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: Entering directory `/home/matrim/workspace/cmake-examples/01-basic/hello_headers/build'
make -f CMakeFiles/hello_headers.dir/build.make CMakeFiles/hello_headers.dir/depend
make[2]: Entering directory `/home/matrim/workspace/cmake-examples/01-basic/hello_headers/build'
cd /home/matrim/workspace/cmake-examples/01-basic/hello_headers/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /home/matrim/workspace/cmake-examples/01-basic/hello_headers /home/matrim/workspace/cmake-examples/01-basic/hello_headers /home/matrim/workspace/cmake-examples/01-basic/hello_headers/build /home/matrim/workspace/cmake-examples/01-basic/hello_headers/build /home/matrim/workspace/cmake-examples/01-basic/hello_headers/build/CMakeFiles/hello_headers.dir/DependInfo.cmake --color=
make[2]: Leaving directory `/home/matrim/workspace/cmake-examples/01-basic/hello_headers/build'
make -f CMakeFiles/hello_headers.dir/build.make CMakeFiles/hello_headers.dir/build
make[2]: Entering directory `/home/matrim/workspace/cmake-examples/01-basic/hello_headers/build'
/usr/bin/cmake -E cmake_progress_report /home/matrim/workspace/cmake-examples/01-basic/hello_headers/build/CMakeFiles 1
[ 50%] Building CXX object CMakeFiles/hello_headers.dir/src/Hello.cpp.o
/usr/bin/c++    -I/home/matrim/workspace/cmake-examples/01-basic/hello_headers/include    -o CMakeFiles/hello_headers.dir/src/Hello.cpp.o -c /home/matrim/workspace/cmake-examples/01-basic/hello_headers/src/Hello.cpp
/usr/bin/cmake -E cmake_progress_report /home/matrim/workspace/cmake-examples/01-basic/hello_headers/build/CMakeFiles 2
[100%] Building CXX object CMakeFiles/hello_headers.dir/src/main.cpp.o
/usr/bin/c++    -I/home/matrim/workspace/cmake-examples/01-basic/hello_headers/include    -o CMakeFiles/hello_headers.dir/src/main.cpp.o -c /home/matrim/workspace/cmake-examples/01-basic/hello_headers/src/main.cpp
Linking CXX executable hello_headers
/usr/bin/cmake -E cmake_link_script CMakeFiles/hello_headers.dir/link.txt --verbose=1
/usr/bin/c++       CMakeFiles/hello_headers.dir/src/Hello.cpp.o CMakeFiles/hello_headers.dir/src/main.cpp.o  -o hello_headers -rdynamic
make[2]: Leaving directory `/home/matrim/workspace/cmake-examples/01-basic/hello_headers/build'
/usr/bin/cmake -E cmake_progress_report /home/matrim/workspace/cmake-examples/01-basic/hello_headers/build/CMakeFiles  1 2
[100%] Built target hello_headers
make[1]: Leaving directory `/home/matrim/workspace/cmake-examples/01-basic/hello_headers/build'
/usr/bin/cmake -E cmake_progress_start /home/matrim/workspace/cmake-examples/01-basic/hello_headers/build/CMakeFiles 0

C 链接静态库 static-library

本篇学习创建并链接一个静态库的简单例子。

该篇文件结构:

$ tree
.
├── CMakeLists.txt
├── include
│   └── static
│       └── Hello.h
└── src
    ├── Hello.cpp
    └── main.cpp

创建静态库

add_library(hello_library STATIC
    src/Hello.cpp
)

该方法将会使用Hello.cpp创建一个静态库libhello_library.a

静态库的头文件关联

target_include_directories(hello_library
    PUBLIC
        ${PROJECT_SOURCE_DIR}/include
)

在以下两种情况时,编译命令会包含该指定的头文件路径:

  • 编译库
  • 任意链接该静态库的可执行文件

范围限定声明符号:

  • PRIVATE:该目录添加到target的include directories
  • INTERFACE:该目录添加到链接该库的target的include directories
  • PUBLIC:同时包含上述两种。

上述方式的头文件路径添加相当于:

#include "static/Hello.h"

链接静态库

add_executable(hello_binary
    src/main.cpp
)

target_link_libraries( hello_binary
    PRIVATE
        hello_library
)

类似于:

/usr/bin/c++ CMakeFiles/hello_binary.dir/src/main.cpp.o -o hello_binary -rdynamic libhello_library.a

D 链接动态库 shared-library

创建动态库

add_library(hello_library SHARED
    src/Hello.cpp
)

为库添加别名

add_library(hello::library ALIAS hello_library)

通过为库添加别名,后续链接相关库时可以直接使用其别名。

链接共享库

add_executable(hello_binary
    src/main.cpp
)

target_link_libraries(hello_binary
    PRIVATE
        hello::library
)

上述cmake命令等价于:

/usr/bin/c++ CMakeFiles/hello_binary.dir/src/main.cpp.o -o hello_binary -rdynamic libhello_library.so -Wl,-rpath,/home/matrim/workspace/cmake-examples/01-basic/D-shared-library/build

E 安装 installing

本篇展示如何生成make install命令,帮助将项目的一些头文件和可执行文件安装到系统上。

本篇文件结构:

$ tree
.
├── cmake-examples.conf
├── CMakeLists.txt
├── include
│   └── installing
│       └── Hello.h
├── README.adoc
└── src
    ├── Hello.cpp
    └── main.cpp
  • cmake-examples.conf : 示例配置文件

安装Installing

CMake提供make install在目标系统上安装可执行文件、库等,这些安装位置通过变量CMAKE_INSTALL_PREFIX来控制。通过cmake命令可以修改该变量:

cmake .. -DCMAKE_INSTALL_PREFIX=/install/location

通过install方法,决定哪些文件会被安装:

install (TARGETS cmake_examples_inst_bin
    DESTINATION bin)

该例子为安装该可执行文件到destionation ${CMAKE_INSTALL_PREFIX}/bin

# 安装库
install (TARGETS cmake_examples_inst
    LIBRARY DESTINATION lib)
# 安装头文件目录    
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/
    DESTINATION include)
# 安装配置文件    
install (FILES cmake-examples.conf
    DESTINATION etc)
  • 当运行make install后,CMake会生成install_manifest.txt文件,记录所有被安装的文件名称。
  • 如果在root下运行make install命令后,上述这个记录文件则会被root持有。

重载默认安装位置

上述的例子中的默认安装位置来源环境变量CMAKE_INSTALL_PREFIX,即/usr/local/

if( CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT )
  message(STATUS "Setting default CMAKE_INSTALL_PREFIX path to ${CMAKE_BINARY_DIR}/install")
  set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE STRING "The path to use for make install" FORCE)
endif()

这个cmake命令例子会把默认安装位置改为build目录下。

临时暂存安装目录

如果需要暂存安装,来确认所有必要文件已经被安装。可以使用make install命令并带上 DESTDIR 路径参数。

make install DESTDIR=/tmp/stage

该命令会创建一个安装路径:${DESTDIR}/${CMAKE_INSTALL_PREFIX},上述例子安装后路径如下:

$ tree /tmp/stage
/tmp/stage
└── usr
    └── local
        ├── bin
        │   └── cmake_examples_inst_bin
        ├── etc
        │   └── cmake-examples.conf
        └── lib
            └── libcmake_examples_inst.so

卸载

CMake并没有添加make uninstall来支持卸载功能,有需要可以具体再查阅资料,一个例子如下:

sudo xargs rm < install_manifest.txt

F 构建类型 build-type

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

设置编译类型

cmake .. -DCMAKE_BUILD_TYPE=Release

修改默认编译类型和自定义细节

set(CMAKE_BUILD_TYPE "Release")
set(CMAKE_C_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -rdynamic -g -ggdb")
set(CMAKE_C_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
if (NOT CMAKE_BUILD_TYPE)
	set (CMAKE_BUILD_TYPE Release)
endif()

G 编译参数 compile-flags

CMake主要提供了两种方式来设置编译参数选项:

  • 方法target_compile_definitions()
  • 变量CMAKE_C_FLAGSCMAKE_CXX_FLAGS

为每一个target都设置编译参数

target_compile_definitions(cmake_examples_compile_flags
    PRIVATE EX3
)

该命令会使得编译target时,带上编译选项-DEX3。并且此处如果使用PUBLIC限定,使得链接了该target的编译也会带上该编译参数。

设置默认C++编译参数

一般默认情况下,编译参数变量CMAKE_CXX_FLAGSCMAKE_C_FLAGS为空或者为适当选项。

set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEX2" CACHE STRING "Set C++ Compiler Flags" FORCE) # 设置CPP编译选项

同理可得:

  • CMAKE_C_FLAGS用于设置C编译参数
  • CMAKE_LINKER_FLAGS用于设置链接参数

还有一种传递参数的方式

cmake .. -DCMAKE_CXX_FLAGS="-DEX3"

H 三方库使用 third-party-library

几乎所有比较重要的项目都需要诸如第三方库、外部头文件等依赖项。CMake支持使用find_package()函数来支持查找这些依赖。FindXXX.cake文件中的依赖会去CMAKE_MODULE_PATH路径中查找。Linux上默认搜索依赖路径为/usr/share/cmake/Modules

本篇示例将需要boost库安装到本机中。

查找包 Finding a Package

https://zhuanlan.zhihu.com/p/97369704?utm_source=wechat_session

find_package() 函数将从CMAKE_MODULE_PATH中的文件夹列表中搜索“FindXXX.cmake”中的 CMake 模块。

find_package(Boost 1.46.1 REQUIRED COMPONENTS filesystem system)
上一篇:Java中判断是否为空的方法


下一篇:TurtleBot3-OpenCR软件设置