ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CMAKE 基础学习篇1

2021-12-11 18:31:14  阅读:217  来源: 互联网

标签:cmake -- 基础 学习 headers build CMAKE hello examples


目录

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)

标签:cmake,--,基础,学习,headers,build,CMAKE,hello,examples
来源: https://www.cnblogs.com/tlam/p/15676672.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有