# CMake package guidelines (简体中文)

From ArchWiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
翻译状态：本文是 CMake package guidelines 的翻译。上次翻译日期：2020-07-19。如果英文版本有所更改，则您可以帮助同步翻译。

本文档涵盖为使用 CMake 的软件编写 PKGBUILD 的标准和准则。

## 简介

从 CMake 网站：

  CMake is an open-source, cross-platform family of tools designed to build, test and package software. CMake is used to control the software compilation process using simple platform and compiler independent configuration files, and generate native makefiles and workspaces that can be used in the compiler environment of your choice.

### 典型用法

典型用法是运行 `cmake` 命令，然后执行构建命令。该 `cmake` 命令通常会设置一些参数，检查所需的依赖关系并创建构建文件，从而使该软件可以通过诸如 `make` 和 `ninja` 的其他工具进行构建。

## CMake 的不良行为

由于其自身的生成生成文件的内部特性，有时 CMake 可能会以不良方式运行。这样，在为基于 CMake 的软件编写 PKGBUILD 时，应注意一些步骤。

### CMake 可以自动覆盖默认的编译器优化标志

使用 `-DCMAKE_BUILD_TYPE=Release` 选项运行 CMake 是很常见的。一些上游项目甚至无意中在其构建指令中包含此选项，但这会产生不希望的行为。

每个构建类型都会导致 CMake 自动将一组标志附加到 `CFLAGS` 和 `CXXFLAGS`。当使用通用 `Release` build 类型时，它会自动附加`-O3`[1] 编译器优化标志，这将覆盖当前为 `-O2` （在 makepkg 配置文件中定义）的默认 Arch Linux 标志。这是不希望的，因为它偏离了 Arch Linux 的目标优化级别。

#### 关于 `-O3` 的注意事项

使用 `-O3` 不能保证软件的性能会更好，有时甚至会减慢程序的速度。在某些情况下，它也会破坏软件。有一个很好的理由说明为什么 Linux 开发人员选择 `-O2` 作为目标优化级别，我们应该坚持使用它。除非您确切知道自己在做什么，或者如果上游明确告诉或暗示需要 `-O3` ，否则我们应该避免在包中使用它。

#### 修复自动优化标志覆盖

由于 CMake 的灵活性，以 100% 有保证的方式解决这个问题不是一个简单的问题。请注意，没有标准的解决方案可适用于所有情况。本节将讨论可能的解决方案和应遵守的一些要点。

默认的 CMake 构建类型是 `None` ，默认情况下它不会向 `CFLAGS` 和 `CXXFLAGS` 附加任何标志，因此只要省略 `CMAKE_BUILD_TYPE` 选项的使用，就可以像默认为 `None`一样工作。但请注意，忽略此选项并不能保证解决问题，因为如果命令行中未设置 `CMAKE_BUILD_TYPE` ，则许多软件项目会自动将 CMake 文件中的生成类型设置为`Release` （或其他类型）。

由于默认的 `None` build 类型在默认情况下不会向 `CFLAGS` 和 `CXXFLAGS` 追加任何标志，因此使用 `-DCMAKE_BUILD_TYPE=None` 选项也可以工作。一般来说，使用 `-DCMAKE_BUILD_TYPE=None` 选项比省略使用 `CMAKE_BUILD_TYPE` 要好。当上游自动将生成类型设置为 `Release` 时，它将覆盖以下情况：省略 `CMAKE_BUILD_TYPE` 时，它默认不会附加任何标志，并且很少看到软件为 `None` 构建类型设置不需要的标志。

但不幸的是，事情并没有那么简单，比如只使用 `-DCMAKE_BUILD_TYPE=None` t来解决这个问题。当使用 `None` 构建类型修复 `-O3` 问题时，可能会遇到另一个问题。对于许多软件项目来说，在 CMake文 件中为版本生成类型定义一些必需的编译器标志是一种常见的做法（例如，设置 `CMAKE_C_FLAGS_RELEASE` and `CMAKE_CXX_FLAGS_RELEASE` 变量）。如果使用 `None` 构建类型，在没有这些上游定义标志的情况下编译时，此类软件可能会中断或出现错误行为。为了确定是否缺少某些标志，您需要查看 CMake 文件，或者可以比较 `make VERBOSE=1` 对于 `None` `Release` 构建类型的输出。如果 `None` 构建类型导致某些上游定义的标志丢失，该怎么办？在这种情况下，您可能正处于两种有问题的情况的中间，因为如果使用 `Release` 构建类型，您将丢失一些必需的上游定义的标志。解决这种情况没有标准的办法，应该逐案分析。如果上游为 `Release` 构建类型定义了 `-O2` ，则可以使用 `-DCMAKE_BUILD_TYPE=Release` （参见下文）。否则，修补C Make 文件可能是一个解决方案。

一些软件项目在其 CMake 文件中为 `Release` 构建类型硬编码为 `-O2`，因此，如果您确定 `-O2` 是正在使用的优化级别，那么在这种情况下可以安全地设置 `-DCMAKE_BUILD_TYPE=Release`。

警告：

- 使用 `None` 类型时，某些软件可能会崩溃。当使用 `None` 构建类型检查软件是否会中断或丢失功能时，请测试软件。
- 某些软件可能只适用于 `Release` 构建类型。你需要实验和测试软件。

### 验证修复

通过启用生成工具的详细模式，可以验证CMake是否正确使用了修复程序。例如，当使用 `make` （这是CMake的默认值）时，可以通过将 `VERBOSE=1` 添加到 `make` 中（比如 `make VERBOSE=1`)来完成。这将使 `make` 能够输出正在执行的编译器命令。然后，您可以运行 makepkg 并检查输出，看看编译器是否使用了 `-D_FORTIFY_SOURCE=2` 和 `-O2` 标志。如果在每个命令行中显示多个优化标志，则该行中的最后一个标志将是编译器使用的标志（这意味着 `-O2` 需要是最后一个优化标志才能生效）。

## 前缀和库安装目录

标准 Arch Linux `/usr` 前缀可以由 `-DCMAKE_INSTALL_PREFIX=/usr` CMake 选项指定。通常需要这样做，因为许多软件默认将文件安装到 `/usr/local` 前缀中。

一些上游项目将 CMake 文件设置为将库安装到 `/usr/lib64` 目录中。如果是这种情况，可以使用 `-DCMAKE_INSTALL_LIBDIR=lib` CMake选项将库安装目录正确设置为 `/usr/lib`。

## 提示和技巧

### 指定目录

自从CMake 3.13版本以来，有一个 `-B` 选项可以自动创建构建目录。这样可以避免使用单独的mkdir（或install）命令创建生成目录。`-S` 选项指定源目录（搜索 `CMakeLists.txt` 文件的位置），并避免在执行 `cmake` 之前将 `cd` 插入源树。这两个选项结合在一起，是指定生成目录和源目录的方便方法。例如，对于构建名为 foo 的程序：

    PKGBUILD

    build() {
        cmake -B build -S "foo-${pkgver}" [other_cmake_options]
        make -C build
    }

### 减少可能不需要的输出

`-Wno-dev` 选项将抑制某些警告的输出，这些警告仅适用于编写 `CMakeLists.txt` 文件的上游项目开发人员。删除这些警告将使 CMake 输出更好，并减少检查它的负担。一般来说，这些警告通常可以被打包程序安全地忽略。

### 从二进制文件中删除不安全的 `RPATH` 引用

有时生成的二进制文件可能在 `RPATH`中包含不安全的引用。这可以通过在构建的包上运行 Namcap 来验证，并且包含一个应该修复的安全问题。使用 `CMAKE_SKIP_INSTALL_RPATH=YES` 或 `CMAKE_SKIP_RPATH=YES` CMake 选项很有可能解决此问题。您需要同时使用这两个选项进行实验，并查看在所讨论的软件中什么可以工作（不需要同时使用这两个选项）。

### 获取所有可用的 CMake 选项

要获取软件项目可用的所有“可见”CMake选项，请在源树（主 `CMakeLists.txt` 文件所在）中执行 `cmake -LAH`。

如果要保存输出以供以后参考，可以将其重定向到文件：

    $ cmake -LAH >options.txt 2>&1

## 模板

下面是 `build()` 函数的通用模板，它是基于 CMake 的包的起点。假设包被命名为 foo，它是基于 C 和 C++ 的，并且它不为 CMake 文件中的 `Release` 构建类型定义任何必需的编译器标志：

    PKGBUILD

    build() {
        cmake -B build -S "foo-${pkgver}" \
            -DCMAKE_BUILD_TYPE='None' \
            -DCMAKE_INSTALL_PREFIX='/usr' \
            -Wno-dev
        make -C build
    }

不要忘记将 cmake 放在 makedepends。

## 范例包

- i2pd
- libmysofa

## 另请参见

- CMake 文档
- 最新版本的文档参考
- Wikipedia 文章
- cmake(1)

Category:

- Arch package guidelines (简体中文)