编译与链接

编译器

通过环境变量指定编译器:

$ CC=clang CXX=clang++ cmake ..

通过参数指定编译器:

$ cmake -D CMAKE_C_COMPILER=clang -D CMAKE_CXX_COMPILER=clang++ ..

也可以在 cmake 脚本中指定:

set(CMAKE_C_COMPILER clang)
set(CMAKE_CXX_COMPILER clang++)

环境检查

  • CheckCCompilerFlags
  • CheckCSourceCompiles
  • CheckCSourceRuns
  • CheckCXXCopmilerFlags
  • CheckCXXSourceCompiles
  • CheckCXXSourceRuns

以下示例用于检查当前 linux 系统中是否有 sendfile() 系统调用.

include(CheckCSourceRuns)
check_c_source_runs(
    "
#include <sys/sendfile.h>
#include <errno.h>

int main(void) {
  int s = 0;
  int fd = 1;
  ssize_t n;
  off_t off = 0;
  n = sendfile(s, fd, &off, 1);
  if (n == -1 && errno == ENOSYS) {
    return 1;
  } else {
    return 0;
  }
}
    "
    HAS_SENDFILE
)

if (HAS_SENDFILE)
  message("Has sendfile")
endif ()

# 从缓存变量中移除 HAS_SENDFILE.
unset(HAS_SENDFILE CACHE)

编译选项

对当前目录作用域及子目录作用域中的所有目标(targets) 都有效:

add_compile_options(-Wall -Wextra -Werror -Wpedantic --pedantic-errors)
target_add_compile_options(Foo -Wall -Wextra -Werror -Wpedantic --pedantic-errors)

编译器特性

比如, 我们要求使用 c++17 的标准来编译目标 Foo.

target_compile_features(Foo PRIVATE cxx_std_17)

CMake 是如何处理这些编译选项的呢? 首先 cmake 命令在生成配置文件时, 会打印这样的信息:

-- Detecting CXX compile features
-- Detecting CXX compile features - done

这里, 运持的是 cmake 自己提供的一些编译器特性检查模块. 并会生成一个基于当前 编译器版本号对应的所有 C++ 版本. 如果对某个版本是完全支持的, 就会有类似 CMAKE_CXX17_STANDARD__HAS_FULL_SUPPORT 这样的临时属性. 如果不是完整支持的, 就会进行一些临时的编译任务, 编译一些 c++ 代码片段, 以检测当前编译器对某个特性 是否支持.

静态编译可执行文件

只需要修改一下链接时的选项即可:

target_link_libraries(Foo -static)

生成静态库

默认情况下, 如果不指定库类型时, 默认编译出的是动态库.

add_library(Foo ${FOO_SRC_FILES})

此时, 可以修改选项 BUILD_SHARE_LIBS:

cmake -DBUILD_SHARE_LIBS=OFF ....