CMake 学习

CMake 是一个开源、跨平台的工具系列,旨在构建、测试和打包软件。

📕CMake 基本语法

输出信息

message("hello cmake")

变量

set(name "pomin")
message("My name is ${name}!")

操作符

这些操作符一般使用大写

  • 逻辑运算
# 逻辑真:ON , 1, YES, TRUE, Y
# 逻辑假:OFF, 0, NO, FALSE, N, NOTFOUND, IGNORER

# 直接判断,非空值,0,FALSE,OFF 或者 NOTFOUND即为 true
if (var)

# 逻辑非
if (NOT var)

# 逻辑与
if (var1 AND var2)

# 逻辑或
if (var1 OR var2)
  • 前置运算符
# 当 cmd_name 是可调用的命令时为 true
if (COMMAND cmd_name)

# 当 var 已经被设置了值时为 true
if (DEFINED var)

# 当指定的文件或者目录存在时为 true
if (EXISTS file_or_dir_name)

# 当 name 是目录或者是绝对路径时为 true
if (IS_DIRECTORY name)
if (IS_ABSOLUTE name)
  • 比较运算
# 大于
if (var1 GREATER var2)

# 等于
if (var1 EQUAL var2)

# 小于
if (var1 LESS var2)

# 字符串比较
# STRLESS, STREQUAL 和 STRGREATER

# 版本比较
# VERSION_LESS, VERSION_EQUAL 和 VERSION_GREATER

# 当 file_1 文件的修改时间比 file_2 文件的修改时间要新时为 true
if (file_1 IS_NEWER_THAN file_2)

# 正则表达式支持,当给定的内容与给定的正则表达式相匹配时为 true
if (str MATCHES regex)

次序: () > 前置运算符 > 比较运算 > NOT > AND / OR

if

set(str "x86")
if(str MATCHES "x86")
    message("str is x86")
else()
    message("str is arm")
endif()

while

set(num "1")
while(${num} LESS "5")
    message("num : ${num}")
    math(EXPR num "${num} + 1")
endwhile()

foreach

foreach(i RANGE 1 5)
    message("i : ${i}")
endforeach()

宏,其中声明的变量为全局变量,宏外可以使用

macro(print str)
    message(${str})
endmacro()

print("hello macro")

函数

函数,其中声明的变量为局部变量,函数外不可使用

function(printf str)
    message(${str})
endfunction()

printf("hello function")

🧨CMake 环境配置命令

文件类型

CMakeLists.txt 文件有两种:工程文件和脚本文件

  • 工程文件:放在工程根目录的 CMakeLists.txt,使用 project() 指定工程信息的

  • 脚本文件:放在工程的子目录,编译工程所需的链接库等,可以使用 -P 命令使用直译模式。

cmake版本

cmake_minimum_required(VERSION 3.0.0)

工程配置

  • 工程名
project(hello)
  • 添加工程子目录

子目录中也含有 CMakeLists.txt 脚本

add_subdirectory(lib)

添加文件

  • 添加头文件路径
include_directories(inc)
  • 添加源文件路径
# 查找当前目录下的所有源文件并将名称保存到 CUR_DIR_SRCS 变量中
aux_source_directory(. ROOT_DIR_SRCS)

# 查找src目录下的所有源文件并将名称保存到 SRC_DIR_SRCS 变量中
aux_source_directory(src SRC_DIR_SRCS)

可以用 CMAKE_MODULE_PATH 来指定外部的包含目录

set (CMAKE_MODULE_PATH /usr/include)
find_path (MODULE_INCLUDE_DIR header.h path1 path2)
find_library (MODULE_LIBRARY library path1 path2)
find_package (MODULE_PACKAGE ....)

编译配置

  • 库文件输出
# 从一组源文件中编译出一个库文件并命名
# 静态库
add_library(out_name ${DIR_SRCS})
# 动态库
add_library(out_name SHARED ${DIR_SRCS})
  • 可执行文件输出
# 从 SRC_DIR_SRCS 与 ROOT_DIR_SRCS 中编译出可执行文件 hello
add_executable(hello
              ${SRC_DIR_SRCS}
              ${ROOT_DIR_SRCS}
            )
  • 添加链接库
# 放在 add_executable(...) 之后
target_link_libraries(hello hello_lib)

组合变量

  • PROJECT_SOURCE_DIR 工程根目录
  • CMAKE_BUILD_TYPE
    • None: 编译器默认值
    • Debug: 产生除错信息
    • Release: 进行最佳化
    • RelWithDebInfo: 进行最佳化,但仍然会启用 DEBUG flag
    • MinSizeRel: 进行程式码最小化
  • CMAKE_C_FLAGS C 编译器的编译选项
  • CMAKE_CXX_FLAGS C++ 编译器的编译选项

🔅常用命令行

cmake -P CMakeLists.txt
# 直译模式
cmake -Da=99 -Db=99
# 指定变量值
cmake -DCMAKE_BUILD_TYPE=Debug
# 设置开发模式为 Debug 模式
cmake --help-command-list
# 查看所有cmake命令
cmake --help-command message
# 查看具体某个命令说明

💨示例工程

目录结构

.
├── CMakeLists.txt
├── inc
│   └── hello.h
├── lib
│   ├── CMakeLists.txt
│   ├── hello_lib.c
│   └── hello_lib.h
├── main.c
└── src
    └── hello.c
  • 工程根目录 CMakeLists.txt
# cmake版本要求
cmake_minimum_required(VERSION 3.0.0)

# 工程名字
project(hello)

# 添加头文件路径
include_directories(inc)

# 查找当前目录下的所有源文件并将名称保存到 CUR_DIR_SRCS 变量中
aux_source_directory(. ROOT_DIR_SRCS)

# 查找src目录下的所有源文件并将名称保存到 SRC_DIR_SRCS 变量中
aux_source_directory(src SRC_DIR_SRCS)

# 添加库路径
add_subdirectory(lib)

# 从 SRC_DIR_SRCS 与 ROOT_DIR_SRCS 中编译出可执行文件 hello
add_executable(hello
    ${SRC_DIR_SRCS}
    ${ROOT_DIR_SRCS}
)
# 添加链接库
target_link_libraries(hello hello_lib)
  • 工程根目录 main.c
#include "./inc/hello.h"
#include "./lib/hello_lib.h"

int main(int argc, char const* argv[]) {
    hello();
    hello_lib();
    return 0;
}
  • inc 目录 hello.h 与 src 目录 hello.c
#ifndef _HELLO_H
#define _HELLO_H

#include <stdio.h>

int hello(void);

#endif	// _HELLO_H
#include "hello.h"

int hello(void) {
    printf("Hello\n");
    return 0;
}
  • lib 目录 CMakeLists.txt
# 查找lib目录下的所有源文件并将名称保存到 LIB_DIR_SRCS 变量中
aux_source_directory(. LIB_DIR_SRCS)
# 编译lib目录为静态库
# add_library(hello_lib ${LIB_DIR_SRCS})
# 动态库
add_library(hello_lib SHARED ${LIB_DIR_SRCS})
  • lib 目录 hello_lib.h 与 hello_lib.c
#ifndef _HELLO_LIB_H
#define _HELLO_LIB_H
#include <stdio.h>

int hello_lib(void);

#endif	// _HELLO_H
#include "hello_lib.h"

int hello_lib(void) {
    printf("Hello lib\n");
    return 0;
}

编译结果

-

⚡⚡⚡ OVER ⚡⚡⚡