CMakeの研究と実践ノート

ブログを何日も書いていませんが、今日は「作成」を再開します。クロスプラットフォームのエンジニアリングビルドツールであるCMakeについて、後で簡単に確認できるようにスタディノートを作成します。

前書き

  • 背景
    CMakeは、いくつかのツールキット(VTK)を開発する過程で、キットウェア会社と一部のオープンソース開発者の派生物であり、最終的にシステムを形成し、独立したオープンソースプロジェクトになりました。プロジェクトは2001年に誕生し、公式Webサイトはhttps: //cmake。org/ヘルプドキュメントはhttps://cmake.org/documentation/です
  • 特徴
  1. BSDライセンスの下でリリースされたオープンソース
  2. クロスプラットフォームでは、Linux / Unixプラットフォームではネイティブのコンパイル構成ファイルを生成し、Makefileファイルを生成します。macOSプラットフォームではXcodeプロジェクトを生成し、WindowsプラットフォームではMSVCプロジェクトファイルを生成します。
  3. 大規模なプロジェクトを管理できます。例:KDE4
  4. コンパイルプロセスとコンパイルプロセスを簡素化し、cmake + makeのみが必要です
  5. 効率的
  6. 拡張可能、CMake専用の機能を備えたモジュールを記述し、CMake機能を拡張できます

CMake「helloworld」をビルドする

1.内部構造
  • ソースファイルを作成し、定義ファイルを作成します
#!/bin/bash
mkdir cmake_test1
cd cmake_test1
touch main.cpp 
touch CMakeLists.txt #创建CMake的构建定义文件,文件名大小写敏感
  • ソースコードを編集する
//main.cpp
#include <iostream>

int main() {
    
    
    std::cout << "hello world" << std::endl;
    return 0;
}
  • ビルド定義ファイルを編集します(コマンドは大文字と小文字を区別せず、パラメーターは関連しています)
#CMakeLists.txt
#指明对 CMake 最低版本的要求(对版本没有特殊要求可以省略)
cmake_minimum_required(VERSION 3.10.0)
#定义工程名称,并可指定工程支持的语言,支持的语言列表是可以忽略的,默认情况表示支持所有语言
project(HELLO)
#显式定义变量,如果有多个源文件,可以在 main.cpp 后面追加,可以用空格 " " 或分号隔开 ";"
set(SRC_LISTS main.cpp)
#定义了这个工程会生成一个文件名为 hello 的可执行文件,相关的源文件是 SRC_LISTS 中定义的源文件列表,在这里可以直接写成 add_executable(hello main.cpp)
#另外需要注意的是作为工程名的 HELLO 和生成的可执行文件 hello 是没有任何关系的
add_executable(hello ${SRC_LISTS})
  • 構築を開始します
#在当前目录构建对应平台的编译配置文件
cmake . 
#输出下面的信息    
-- The C compiler identification is AppleClang 12.0.0.12000032
-- The CXX compiler identification is AppleClang 12.0.0.12000032
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/liuwenlong/Downloads/code/cmake_proj/cmake_test1

CMakeCache.txtやMakefileなどの中間ファイルを生成します

  • コンパイル
#编译
make
#输出下面的信息   
Scanning dependencies of target hello
[ 50%] Building CXX object CMakeFiles/hello.dir/main.cpp.o
[100%] Linking CXX executable hello
[100%] Built target hello

実行可能ファイルhelloが生成されます

  • 注意
  1. projectname_BINARY_DIR(コンパイルパスを参照)およびprojectname_SOURCE_DIR(プロジェクトパスを参照)
cmake_minimum_required(VERSION 3.10.0)
#project 指令不仅定义工程名称,
#还隐式定义了两个 cmake 变量: <projectname>_BINARY_DIR(在这里就是HELLO_BINARY_DIR)和 <projectname>_SOURCE_DIR(在这里就是HELLO_SOURCE_DIR)
#CMake 系统也帮助我们预定义了 PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR 变量,他们的值分别跟 <projectname>_BINARY_DIR 与 <projectname>_SOURCE_DIR 一致
project(HELLO)
#message([SEND_ERROR | STATUS | FATAL_ERROR] "message to display" ...)指令用于向终端输出用户定义的信息,包含了三种类型:
#1.SEND_ERROR 产生错误,生成过程被跳过
#2.SATUS 输出前缀为“--”的信息
#3.FATAL_ERROR 立即终止所有 cmake 过程
message(STATUS "HELLO_BINARY_DIR: " ${HELLO_BINARY_DIR})
message(STATUS "HELLO_SOURCE_DIR: " ${HELLO_SOURCE_DIR})
message(STATUS "PROJECT_BINARY_DIR: " ${PROJECT_BINARY_DIR})
message(STATUS "PROJECT_SOURCE_DIR: " ${PROJECT_SOURCE_DIR})
  1. 参照変数
cmake 使用 “${
    
    }” 引用(应用)变量,但是在 “IF” 控制语句,变量是直接使用变量名引用,而不需要 “${
    
    }” ;如果使用了 “${
    
    }” 引用变量,“IF” 会去判断名为 “${
    
    }” 所代表的变量的值,那是不存在的
  • クリーンアッププロジェクト
#可以对构建结果进行清理,但是无法对产生的中间文件进行清理,因为 CMakeLists.txt 可以执行脚本并通过脚本生成一些临时文件,但是却没有办法来跟踪这些临时文件到底是哪些,所以推荐使用外部构建
make clean 
2.外部構造
  • 内部ビルドは自動的にクリーンアップできない中間ファイルを生成するため、元のディレクトリが乱雑に見えるため、プロジェクトのビルドには通常、外部ビルド方法が使用されます
cd cmake_test1
#在之前的工程目录下创建用于放置中间文件和最终生成的文件目录(build)
mkdir build
#".."利用上一层目录的CMakeLists.txt文件构建构成
cmake ..
#构建过程中的中间文件和最终生成的文件都在一个子目录中了,不会对原始目录产生任何影响了
make

より標準的なCMake「helloworld」

次に、より標準化されたCMake「helloworld」プロジェクトを構築します

  • srcサブディレクトリをプロジェクトディレクトリに追加して、ソースファイルを保存します
  • ビルドプロセスによって生成された中間ファイルとバイナリ出力ファイルは、ビルドディレクトリの下のbinファイルに配置されます。
  • run.shによって生成されたバイナリ実行可能ファイルをプロジェクトディレクトリに作成します
#!/bin/bash
mkdir cmake_test2
cd cmake_test2
mkdir src
mkdir build
touch run.sh
touch CMakeLists.txt
cd src
touch main.cpp
touch CMakeLists.txt
cd ../build
  • プロジェクトディレクトリのビルド定義ファイルを編集します
#cmake_test2/CMakeLists.txt
cmake_minimum_required(VERSION 3.10.0)
project(HELLO)
#add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL]),该指令用于添加存放源文件的子目录( source_dir ),并可以指定中间二进制和目标二进制存放的位置( [binary_dir] 可选),EXCLUDE_FROM_ALL 参数的含义是将这个目录从编译过程中排除,如工程有 example,可能就需要工程构建完成后,再进入 example 目录单独进行构建
#下面的命令将src子目录加入工程,并指定编译输出(包含编译中间结果)路径为 bin 目录;如果不进行 bin 目录的指定,那么编译结果(包括中间结果)都将存放在 build/src 目录(这个目录跟原有的 src 目录对应),指定 bin 目录后,相当于在编译时将 src 重命名为 bin,所有的中间结果和目标二进制都将存放在 bin 目录
add_subdirectory(src bin)
  • srcサブディレクトリのビルド定義ファイルを編集します(プロジェクトに複数のディレクトリがある場合は、管理する各ディレクトリにCMakeLists.txtがあることを確認する必要があります)
set(SRC_LISTS main.cpp)
add_executable(hello ${SRC_LISTS})
  • EXECUTABLE_OUTPUT_PATH和LIBRARY_OUTPUT_PATH
#不论 add_subdirectory 是否指定编译输出目录,我们都可以通过 set 指令重新定义 EXECUTABLE_OUTPUT_PATH 和 LIBRARY_OUTPUT_PATH 变量来指定最终的目标二进制的位置(指最终生成的 hello 或者最终的共享库,不包含编译生成的中间文件)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
#添加上面命令的原则是:在哪里 add_executable 或 add_library,如果需要改变目标存放路径,就在哪里加入上述的定义
#将上面的命令加在 cmake_test2/src/CMakeLists.txt 文件中
set(SRC_LISTS main.cpp)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
add_executable(hello ${SRC_LISTS})
  • 実行スクリプトの編集
#!/bin/bash
cd build/bin/
./hello

静的および動的ライブラリを構築する

  • ソースファイルを作成し、定義ファイルを作成します
#!/bin/bash
mkdir cmake_test3
cd cmake_test3
touch CMakeLists.txt
mkdir lib
cd lib
touch hello.h
touch hello.cpp
touch CMakeLists.txt
mkdir -p ../build
  • ソースファイルを編集する
//hello.h
#ifndef __HELLO__
#define __HELLO__
#include <iostream>
void printFunc();
#endif //__HELLO__
//hello.cpp
#include "hello.h"
void printFunc() {
    
    
    std::cout << "hello world" << std::endl;
}
  • ビルド定義ファイルを編集する
#/cmake_test3/CMakeLists.txt
cmake_minimum_required(VERSION 3.10.0)
project(HELLOLIB)
add_subdirectory(lib)
#/cmake_test3/lib/CMakeLists.txt

#构建动态库
set(SRC_LISTS hello.cpp)
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/shared)
#add_library(libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL] source1 source2 ... sourceN) 
#libname 不需要写全 libhello.so,只需要填写 hello 即可,cmake 系统会自动为你生成 libhello.X
#类型有三种:
#SHARED,动态库
#STATIC,静态库
#MODULE,在使用 dyld 的系统有效,如果不支持 dyld,则被当作 SHARED 对待。
#EXCLUDE_FROM_ALL 参数的意思是这个库不会被默认构建,除非有其他的组件依赖或者手工构建
add_library(hello SHARED ${SRC_LISTS})

#构建静态库
set(SRC_LISTS hello.cpp)
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/static)
add_library(hello STATIC ${SRC_LISTS})

#动态库和静态库同时构建
set(SRC_LISTS hello.cpp)
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/library)
#因为如果库的名字相同会创建失败,这里先创建两个不同名字的库
add_library(hello_static STATIC ${SRC_LISTS})
add_library(hello_shared SHARED ${SRC_LISTS})
#set_target_properties(target1 target2 ... PROPERTIES prop1 value1 prop2 value2 ...) 指令设置 target 属性
#可以用来设置输出的名称,对于动态库,还可以用来指定动态库版本和 API 版本
set_target_properties(hello_static PROPERTIES OUTPUT_NAME "hello")
set_target_properties(hello_shared PROPERTIES OUTPUT_NAME "hello")
  • ビルドとコンパイル
cmake ..
make

外部共有ライブラリとヘッダーファイルを参照する

  • ソースファイルを作成し、定義ファイルを作成します
#!/bin/bash
mkdir cmake_test4
cd cmake_test4
touch CMakeLists.txt
mkdir build
mkdir lib
mkdir src
cd src
touch main.cpp
touch CMakeLists.txt
  • 動的ライブラリと静的ライブラリ、およびcmake_test3で生成された対応するヘッダーファイルをlibディレクトリにコピーします
  • ソースファイルを編集する
//main.cpp
#include "hello.h"
int main() {
    
    
    printFunc();
    return 0;
}
  • ビルド定義ファイルを編集する
#cmake_test4/CMakeLists.txt
cmake_minimum_required(VERSION 3.10.0)
project(LINKLIB)
add_subdirectory(src)
#cmake_test4/src/CMakeLists.txt

#默认链接动态库
set(SRC_LISTS main.cpp)
#include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 ...) 用来向工程添加多个特定的头文件搜索路径,路径之间用空格分割,如果路径中包含了空格,可以使用双引号将它括起来,默认的行为是追加到当前的头文件搜索路径的后面
#可以通过两种方式来进行控制搜索路径添加的方式:
#1.CMAKE_INCLUDE_DIRECTORIES_BEFORE,通过 set 使这个 cmake 变量为 on,可以将添加的头文件搜索路径放在已有路径的前面
#2.通过 AFTER 或者 BEFORE 参数,也可以控制是追加还是置前
include_directories(../lib)
#link_directories(directory1 directory2 ...) 添加非标准的共享库搜索路径
link_directories(../lib)
add_executable(main ${SRC_LISTS})
#target_link_libraries(target library1 <debug | optimized> library2 ...) 可以用来为 target 添加需要链接的共享库
#直接写共享库的名字默认链接的使动态库
target_link_libraries(main hello)

#查看编译依赖情况
ldd main
	linux-vdso.so.1 (0x00007ffe09558000)
	libhello.so => /home/vim/longlong/cmake_test4/src/../lib/libhello.so (0x00007fa94f17a000)
	libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fa94edf1000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa94ea00000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fa94e662000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fa94f57e000)
	libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fa94e44a000)

#指定要链接的动态库
set(SRC_LISTS main.cpp)
include_directories(../lib)
link_directories(../lib)
add_executable(main ${SRC_LISTS})
#指定要链接的动态库
target_link_libraries(main libhello.so)

#Linux下查看编译依赖情况(macOS下:otool -L main)
ldd main
	linux-vdso.so.1 (0x00007ffd644fc000)
	libhello.so => /home/vim/longlong/cmake_test4/src/../lib/libhello.so (0x00007f7735891000)
	libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f7735508000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f7735117000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f7734d79000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f7735c95000)
	libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f7734b61000)

#指定要链接的静态库
set(SRC_LISTS main.cpp)
include_directories(../lib)
link_directories(../lib)
add_executable(main ${SRC_LISTS})
#指定要链接的静态库
target_link_libraries(main libhello.a)

#查看编译依赖情况
ldd main
	linux-vdso.so.1 (0x00007ffd5d197000)
	libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f6fbb7e0000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6fbb3ef000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f6fbb051000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f6fbbd6b000)
	libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f6fbae39000)
  • ビルドコンパイル
cmake ..
make

参考記事:
[1]。「Cmakeの練習」

侵害がある場合は、連絡して削除してください。エラーがある場合は、訂正してください。ありがとうございます。

おすすめ

転載: blog.csdn.net/xiao_ma_nong_last/article/details/109687728