CMake学习记录
<h1>CMake学习记录</h1><h2>宏</h2>
<pre><code class="language-cmake">macro (do_test arg1 arg2 result)
add_test (test_${arg1}_${arg2} Demo ${arg1} ${arg2})
set_tests_properties (test_${arg1}_${arg2}
PROPERTIES PASS_REGULAR_EXPRESSION ${result})
endmacro (do_test)
</code></pre>
<ul>
<li>描述:<code>macro(宏名 参数列表)</code>可以定义一个宏</li>
<li>第一个参数:宏名</li>
<li>其余参数:在宏当中使用的变量名</li>
<li>示例作用:定义一个宏简化测试代码的编写,<code>add_test</code>用于添加一个测试</li>
</ul>
<h2>条件语句</h2>
<h3>if语句</h3>
<pre><code class="language-cmake">if(condition)
Tab...
else()
Tab...
endif(condition)
</code></pre>
<h2>常用指令</h2>
<h3>add_definitions</h3>
<pre><code class="language-cmake">add_definitions(-DFOO -DBAR=123)
</code></pre>
<ul>
<li>描述:<code>add_definitions</code> 是 CMake 中用来 **批量向所有目标(可执行文件、库)添加编译宏定义(** <strong><code>-D</code></strong> <strong>选项)</strong>的命令。</li>
</ul>
<table>
<thead>
<tr>
<th>实际传给编译器</th>
<th>含义</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>-DFOO</code></td>
<td>定义宏 <code>FOO</code>(空值)</td>
</tr>
<tr>
<td><code>-DBAR=123</code></td>
<td>定义宏 <code>BAR</code> 为 <code>123</code></td>
</tr>
</tbody>
</table>
<p>相当于添加了:</p>
<pre><code class="language-Cpp">#define FOO
#define BAR 123
</code></pre>
<h3>add_library</h3>
<pre><code class="language-cmake">add_library(function STATIC
src/hello.cpp
)
</code></pre>
<ul>
<li>
<p>描述:使用一些源文件生成库</p>
</li>
<li>
<p>第一个参数:库名,实际生成的名字为<code>libfunction.xxx</code></p>
</li>
<li>
<p>第二个参数:决定生成的库是动态库还是静态库,没有则默认静态</p>
</li>
<li>
<p>第三个参数:生成库的源文件</p>
</li>
</ul>
<h3>add_excutable</h3>
<pre><code class="language-cmake">add_executable(Demo ${DIR_SRCS})
</code></pre>
<ul>
<li>描述:使用一些源文件编译并链接成一个可执行程序</li>
</ul>
<h3>add_subdirectory</h3>
<pre><code class="language-cmake">add_subdirectory(math)
</code></pre>
<ul>
<li>描述:将一个子目录添加到构建系统中</li>
<li>参数:子目录名称</li>
<li>示例代码作用:将math<strong>子目录中的CMakeLists.txt</strong>文件解析并加入到构建系统中</li>
</ul>
<h3>aux_source_directory</h3>
<pre><code class="language-cmake">aux_source_directory(<dir> <variable>)
</code></pre>
<ul>
<li>描述:自动获取指定目录中的所有源文件,并将这些文件存储到一个变量中</li>
</ul>
<h3>configure_file</h3>
<pre><code class="language-cmake">configure_file(
"${PROJECT_SOURCE_DIR}/config.h.in"
"${PROJECT_BINARY_DIR}/config.h"
)
</code></pre>
<ul>
<li>
<p>描述:将一个输入文件(通常是模板文件)配置为输出文件,它会根据CMake变量的值替换输入文件(模板文件)中的占位符,生成最终的配置文件</p>
</li>
<li>
<p>第一个参数:模板文件,通常以<code>.in</code>为后缀</p>
</li>
<li>
<p>第二个参数:输出的配置文件</p>
</li>
<li>
<p>注意点:</p>
<ul>
<li>模版文件后缀并非强制要求<code>in</code>,只是一种约定</li>
<li>模版文件需要我们自己预先定义好</li>
<li>生成的文件可以是源文件(如.h、.c、.cpp等),是也可以其他类型的文件(如配置文件等)</li>
</ul>
</li>
</ul>
<h3>execute_process</h3>
<pre><code class="language-Cpp">execute_process(
COMMAND git rev-parse HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE FULL_SHA
OUTPUT_STRIP_TRAILING_WHITESPACE
)
</code></pre>
<table>
<thead>
<tr>
<th>关键字 / 参数</th>
<th>含义</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>execute_process</code></td>
<td>CMake 提供的命令,用于 <strong>在配置阶段执行一条或多条外部命令</strong>。</td>
</tr>
<tr>
<td><code>COMMAND git rev-parse HEAD</code></td>
<td>要执行的命令:运行 <code>git rev-parse HEAD</code>,获取当前 Git 仓库的 <strong>完整 SHA 哈希值</strong>。</td>
</tr>
<tr>
<td><code>WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}</code></td>
<td>指定命令的运行目录为项目根目录<code>${CMAKE_SOURCE_DIR}</code>。</td>
</tr>
<tr>
<td><code>OUTPUT_VARIABLE FULL_SHA</code></td>
<td>把命令的标准输出(stdout)保存到 CMake 变量 <code>FULL_SHA</code>。</td>
</tr>
<tr>
<td><code>OUTPUT_STRIP_TRAILING_WHITESPACE</code></td>
<td>自动去掉<strong>输出</strong><code>FULL_SHA</code>末尾的换行符或空格,避免后面使用时出现 <code>\n</code>。</td>
</tr>
</tbody>
</table>
<h3>find_package</h3>
<pre><code class="language-cmake">find_package(<PackageName> )
</code></pre>
<ul>
<li>描述:<code>find_package</code> 是 CMake <strong>最重要、最常用</strong>的模块查找指令之一,用来在系统中“找到”某个第三方库或工具链,并自动为你设置头文件目录、库文件目录、库名称等变量,省去手动写 <code>include_directories()</code>、<code>target_link_libraries()</code> 的麻烦。</li>
</ul>
<table>
<thead>
<tr>
<th>参数</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code><PackageName></code></td>
<td>模块名,大小写不敏感,如 <code>OpenSSL</code>, <code>Boost</code>, <code>Threads</code></td>
</tr>
<tr>
<td><code></code></td>
<td>可指定最低版本,如 <code>3.1.0</code></td>
</tr>
<tr>
<td><code>REQUIRED</code></td>
<td>找不到就报错,构建停止</td>
</tr>
<tr>
<td><code>COMPONENTS</code></td>
<td>只找其中某些组件,如 <code>COMPONENTS system filesystem</code></td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th>模式</th>
<th>描述</th>
<th>文件来源</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Module 模式</strong></td>
<td>使用 CMake 自带的 <code>Find<PackageName>.cmake</code> 脚本</td>
<td><code><cmake prefix>/Modules/</code></td>
</tr>
<tr>
<td><strong>Config 模式</strong></td>
<td>使用库自己提供的 <code><PackageName>Config.cmake</code> 或 <code><PackageName>-config.cmake</code></td>
<td>库安装目录的 <code>lib/cmake/<PackageName>/</code></td>
</tr>
</tbody>
</table>
<ul>
<li>CMake 先尝试 Module,再尝试 Config。</li>
</ul>
<h4>成功后会生成哪些变量?</h4>
<p>以 <code>find_package(OpenSSL REQUIRED)</code> 为例:</p>
<table>
<thead>
<tr>
<th align="left">变量</th>
<th align="left">内容</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><code>OPENSSL_FOUND</code></td>
<td align="left"><code>TRUE</code></td>
</tr>
<tr>
<td align="left"><code>OPENSSL_INCLUDE_DIR</code></td>
<td align="left"><code>/usr/include/openssl</code></td>
</tr>
<tr>
<td align="left"><code>OPENSSL_LIBRARIES</code></td>
<td align="left"><code>/usr/lib/libssl.so;/usr/lib/libcrypto.so</code></td>
</tr>
<tr>
<td align="left"><code>OPENSSL_VERSION</code></td>
<td align="left"><code>1.1.1w</code></td>
</tr>
</tbody>
</table>
<p>你可以直接用:</p>
<pre><code class="language-cmake">target_include_directories(myapp PRIVATE ${OPENSSL_INCLUDE_DIR})
target_link_libraries(myapp PRIVATE ${OPENSSL_LIBRARIES})
</code></pre>
<h4>一个典型用法示例</h4>
<pre><code class="language-Cpp">find_package(PkgConfig REQUIRED)
pkg_check_modules(GIO REQUIRED gio-unix-2.0)
</code><p><code class="language-Cpp">target_include_directories(my_app PRIVATE ${GIO_INCLUDE_DIRS})<br>
target_link_libraries (my_app PRIVATE ${GIO_LIBRARIES})<br>
</code></p></pre><p></p>
<ol>
<li>
<p><code>find_package(PkgConfig REQUIRED)</code></p>
<ul>
<li><strong>作用</strong>:让 CMake 先找到 <code>pkg-config</code> 这个 <strong>系统小工具</strong>(Linux 下通常是 <code>/usr/bin/pkg-config</code>)。</li>
<li><code>REQUIRED</code>:如果系统没装 <code>pkg-config</code>,立即报错停止。</li>
<li>成功后,<code>PkgConfig</code> 模块会提供 <code>pkg_check_modules()</code> 命令。</li>
</ul>
</li>
<li>
<p><code>pkg_check_modules(GIO REQUIRED gio-unix-2.0)</code></p>
<ul>
<li>
<p><strong>作用</strong>:等价于在终端执行<code>pkg-config --cflags --libs gio-unix-2.0</code>。</p>
</li>
<li>
<p><strong>结果</strong>(自动生成以下变量):</p>
<table>
<thead>
<tr>
<th>变量名</th>
<th>内容示例(Linux)</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>GIO_FOUND</code></td>
<td><code>1</code></td>
</tr>
<tr>
<td><code>GIO_INCLUDE_DIRS</code></td>
<td><code>/usr/include/gio-unix-2.0;/usr/include/glib-2.0;...</code></td>
</tr>
<tr>
<td><code>GIO_LIBRARY_DIRS</code></td>
<td><code>/usr/lib/x86_64-linux-gnu</code></td>
</tr>
<tr>
<td><code>GIO_LIBRARIES</code></td>
<td><code>gio-2.0;gobject-2.0;glib-2.0</code></td>
</tr>
<tr>
<td><code>GIO_CFLAGS_OTHER</code></td>
<td><code>-DGLIB_VERSION_...</code> 等额外编译标志</td>
</tr>
</tbody>
</table>
</li>
</ul>
</li>
</ol>
<h3>install</h3>
<h4>安装可执行文件</h4>
<pre><code class="language-cmake">install(TARGETS <target> DESTINATION <dir>)
</code></pre>
<ul>
<li>描述:将编译出来的可执行文件target安装到目录dir中</li>
</ul>
<h4>安装文件</h4>
<pre><code class="language-cmake">install(FILES <file>... DESTINATION <dir>)
</code></pre>
<ul>
<li>将文件安装到目录中</li>
</ul>
<h4>安装目录</h4>
<pre><code class="language-cmake">install(DIRECTORY <dir> DESTINATION <dir>
)
</code></pre>
<ul>
<li>将整个目录安装到目标目录中,并【可选的】配置安装的目录文件访问权限</li>
<li>如果只想装 <code>.so</code>,加 <code>FILES_MATCHING PATTERN "*.so*"</code>。</li>
<li>目录末尾加 <code>/</code> 表示只装目录里的内容;不加会把目录本身也复制过去。</li>
</ul>
<h3>include_directories</h3>
<pre><code class="language-cmake">include_directories("${PROJECT_SOURCE_DIR}/math")
</code></pre>
<ul>
<li>描述:用于将指定的目录添加到编译器的<strong>头文件搜索路径</strong>中</li>
<li>参数:路径</li>
<li>示例代码作用:告诉编译器在编译时,将<code>${PROJECT_SOURCE_DIR}/math</code>目录中的头文件包含进来。</li>
</ul>
<h3>option</h3>
<pre><code class="language-cmake">option(USE_MYMATH "Use provided math implementation" ON)
</code></pre>
<ul>
<li>描述:定义一个布尔值配置选项</li>
<li>第一个参数:选项的名称,可以通过命令行来设置它的值</li>
<li>第二个参数:选项的描述信息</li>
<li>第三个参数:选项的默认值,<code>ON</code>表示默认启用,<code>OFF</code>表示禁用</li>
<li>补充说明:可以通过<code>ccmake</code>命令进入配置界面,按<code>c</code>可以配置相关选项,<code>option</code>定义的变量可以在此配置选项</li>
</ul>
<h3>set</h3>
<pre><code class="language-cmake">set(EXTRA_LIB ${EXTRA_LIBS} MathFunctions)
</code></pre>
<ul>
<li>
<p>描述:这种三参数写法是追加设置变量的值。</p>
<ul>
<li>它可以用来<strong>创建</strong>新变量,也可以<strong>修改</strong>现有变量的值。</li>
</ul>
</li>
<li>
<p>第一个参数:要设置的变量,如果没有则创建</p>
</li>
<li>
<p>第二个参数:引用要设置的变量,将给该变量赋值,若是该变量已有值,则追加赋值</p>
</li>
<li>
<p>第三个参数:要赋给变量的值</p>
</li>
</ul>
<pre><code class="language-cmake">set(variable value)
</code></pre>
<ul>
<li>
<p>描述:给变量赋值</p>
<ul>
<li>它可以用来<strong>创建</strong>新变量,也可以<strong>修改</strong>现有变量的值</li>
</ul>
</li>
</ul>
<h3>string</h3>
<pre><code class="language-Cpp">string(<SUBCOMMAND> <arg1> <arg2> ...)
</code></pre>
<ul>
<li>
<p>string是CMake的字符串处理命令,它有许多子命令,用来完成查找、替换、截取、正则、大小写转换等操作</p>
</li>
<li>
<p>子命令开头决定功能,<strong>倒数第二个变量是输出变量,倒数第一个变量是输入变量</strong></p>
</li>
<li>
<p><strong>子命令一览</strong></p>
</li>
</ul>
<table>
<thead>
<tr>
<th>子命令</th>
<th>作用</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>REGEX MATCH</strong></td>
<td>正则匹配一次</td>
<td><code>string(REGEX MATCH "pat" out "${str}")</code></td>
</tr>
<tr>
<td><strong>REGEX MATCHALL</strong></td>
<td>正则匹配所有</td>
<td><code>string(REGEX MATCHALL "pat" out "${str}")</code></td>
</tr>
<tr>
<td><strong>REGEX REPLACE</strong></td>
<td>正则替换</td>
<td><code>string(REGEX REPLACE "pat" "repl" out "${str}")</code></td>
</tr>
<tr>
<td><strong>REPLACE</strong></td>
<td>普通字符串替换</td>
<td><code>string(REPLACE "old" "new" out "${str}")</code></td>
</tr>
<tr>
<td><strong>SUBSTRING</strong></td>
<td>截取子串</td>
<td><code>string(SUBSTRING "${str}" 0 3 out)</code></td>
</tr>
<tr>
<td><strong>STRIP</strong></td>
<td>去掉首尾空格</td>
<td><code>string(STRIP "${str}" out)</code></td>
</tr>
<tr>
<td><strong>TOLOWER / TOUPPER</strong></td>
<td>大小写转换</td>
<td><code>string(TOLOWER "${str}" out)</code></td>
</tr>
<tr>
<td><strong>COMPARE EQUAL / LESS / GREATER</strong></td>
<td>字典序比较</td>
<td><code>string(COMPARE EQUAL "${a}" "${b}" result)</code></td>
</tr>
<tr>
<td><strong>LENGTH</strong></td>
<td>取字符串长度</td>
<td><code>string(LENGTH "${str}" len)</code></td>
</tr>
</tbody>
</table>
<h3>target_link_libraries</h3>
<pre><code class="language-cmake">target_link_libraries(<target>
<library1> )
</code></pre>
<ul>
<li>描述:将目标与所需的库进行链接</li>
</ul>
<h2>测试命令</h2>
<h3>add_test与set_tests_properties</h3>
<p><strong>要启用测试,需在测试用例代码前添加</strong><strong><code>enable_testing()</code></strong> <strong>启用测试功能。</strong></p>
<pre><code class="language-cmake">add_test(test_5_2 Demo 5 2)
set_tests_properties(test_5_2 PROPERTIES PASS_REGULAR_EXPRESSION
"is 25")
</code></pre>
<ul>
<li>
<p><code>add_test</code></p>
<ul>
<li>描述:add_test用于添加一个测试用例</li>
<li>第一个参数:测试用例名称</li>
<li>第二个参数:可执行文件名称</li>
<li>第三个参数:传递给第二个参数的参数列表</li>
</ul>
</li>
<li>
<p><code>set_tests_properties</code></p>
<ul>
<li>
<p>描述:用于设置测试用例的属性。它允许你为测试用例配置各种属性,例如预期输出、超时时间等。</p>
</li>
<li>
<p>第一个参数:测试用例名称,必须是已经被<code>add_test</code>定义的</p>
</li>
<li>
<p><strong><code>PROPERTIES</code></strong>关键字:表示接下来是属性的设置。</p>
</li>
<li>
<p><strong>常见属性</strong>:</p>
<ul>
<li><code>PASS_REGULAR_EXPRESSION</code>:测试通过时输出必须匹配的正则表达式。</li>
<li><code>FAIL_REGULAR_EXPRESSION</code>:测试失败时输出必须匹配的正则表达式。</li>
<li><code>TIMEOUT</code>:测试超时时间(秒)。</li>
<li><code>WILL_FAIL</code>:测试是否预期失败。</li>
<li><code>RUN_SERIAL</code>:测试是否需要串行运行。</li>
</ul>
</li>
<li>
<p>跟在属性后面的参数:类型为字符串或数字,表示属性的值</p>
</li>
</ul>
</li>
</ul>
<h2>内置变量</h2>
<pre><code class="language-cmake">my_project/
├── CMakeLists.txt
├── src/
│ ├── main.cpp
│ └── ...
├── include/
│ └── ...
└── ...
</code></pre>
<h3><strong><code>${PROJECT_SOURCE_DIR}</code></strong> </h3>
<ul>
<li>这个变量表示当前项目的源代码目录的路径。如上目录结构中, <strong><code>${PROJECT_SOURCE_DIR}</code></strong> 就是<code>my_project</code>的绝对地址</li>
<li>它是由 CMake 在解析 <code>CMakeLists.txt</code> 文件时自动设置的,不需要用户手动定义。</li>
<li>它的值是项目根目录的绝对路径,即包含顶级 <code>CMakeLists.txt</code> 文件的目录。</li>
</ul>
<h3><code>${PROJECT_BINARY_DIR}</code></h3>
<ul>
<li><code>${PROJECT_BINARY_DIR}</code>是CMake变量,表示项目的构建目录。</li>
<li>通常表示的是源文件编译输出的文件目录</li>
</ul>
<h3> <strong><code>${CMAKE_SOURCE_DIR}</code></strong> </h3>
<ul>
<li>与 <code>${PROJECT_SOURCE_DIR}</code> 类似,但更通用。它表示最顶层 <code>CMakeLists.txt</code> 文件所在的目录。</li>
<li>大多数时候,<code>${PROJECT_SOURCE_DIR}</code>与<code>${CMAKE_SOURCE_DIR}</code>表示相同的路径,如上所示目录结构中,两者就是等价的。</li>
</ul>
<h3><strong><code>${CMAKE_BINARY_DIR}</code></strong> </h3>
<ul>
<li>与 <code>${PROJECT_BINARY_DIR}</code> 类似,表示最顶层构建目录的路径。</li>
</ul>
<h3><code>$ENV{VAR_NAME}</code></h3>
<ul>
<li>描述:读取当前进程的系统环境变量<code>VAR_NAME</code>的值</li>
<li>单独的<code>$ENV</code>在CMAKE中是无意义的,带花括号的<code>$ENV{VAR_NAME}</code>用来读取环境变量的值</li>
<li>示例:<code>$ENV{HOME}</code>读取当前系统环境变量<code>HOME</code>的值,该值一般为用户主目录</li>
</ul>
<table>
<thead>
<tr>
<th>环境</th>
<th>Shell 写法</th>
<th>CMake 写法</th>
<th>典型值</th>
</tr>
</thead>
<tbody>
<tr>
<td>Linux/macOS</td>
<td><code>$HOME</code></td>
<td><code>$ENV{HOME}</code></td>
<td><code>/home/alice</code></td>
</tr>
<tr>
<td>Windows (PowerShell)</td>
<td><code>$env:USERPROFILE</code></td>
<td><code>$ENV{USERPROFILE}</code></td>
<td><code>C:\Users\alice</code></td>
</tr>
</tbody>
</table>
<h2>编译</h2>
<pre><code class="language-powershell">cmake <dir>
</code></pre>
<ul>
<li><code>dir</code>指包含<code>CMakeLists.txt</code>的目录,执行完会在当前目录(执行<code>cmake</code>命令时所在目录)生成<code>makefile</code>和一系列缓存文件</li>
<li>然后执行<code>make</code>命令,即可在当前目录下生成可执行文件</li>
</ul><br><br>
来源:https://www.cnblogs.com/kindledawn/p/19018798/cmakexue-xi-ji-lu-17b6xo
頁:
[1]