CMAKE 基础学习篇1
作者:互联网
- 01 基础
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_FLAGS
和CMAKE_CXX_FLAGS
为每一个target都设置编译参数
target_compile_definitions(cmake_examples_compile_flags
PRIVATE EX3
)
该命令会使得编译target时,带上编译选项-DEX3
。并且此处如果使用PUBLIC限定,使得链接了该target的编译也会带上该编译参数。
设置默认C++编译参数
一般默认情况下,编译参数变量CMAKE_CXX_FLAGS
和CMAKE_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)
标签:cmake,--,基础,学习,headers,build,CMAKE,hello,examples 来源: https://www.cnblogs.com/tlam/p/15676672.html