使用 Conan 构建一个简单的 CMake 项目¶
让我们从一个示例开始:我们将创建一个使用最流行的 C++ 库之一:Zlib 的字符串压缩器应用程序。
在这种情况下,我们将使用 CMake 作为构建系统,但请记住,Conan **适用于任何构建系统**,并且不限于使用 CMake。您可以在阅读更多部分中查看更多其他构建系统的示例。
请首先克隆源代码以重新创建此项目,您可以在 GitHub 的 examples2 存储库中找到它们
$ git clone https://github.com/conan-io/examples2.git
$ cd examples2/tutorial/consuming_packages/simple_cmake_project
我们从一个非常简单的 C 语言项目开始,结构如下
.
├── CMakeLists.txt
└── src
└── main.c
此项目包含一个基本的 *CMakeLists.txt*,其中包含 **zlib** 依赖项,以及 *main.c* 中字符串压缩器程序的源代码。
让我们看看 *main.c* 文件
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <zlib.h>
int main(void) {
char buffer_in [256] = {"Conan is a MIT-licensed, Open Source package manager for C and C++ development "
"for C and C++ development, allowing development teams to easily and efficiently "
"manage their packages and dependencies across platforms and build systems."};
char buffer_out [256] = {0};
z_stream defstream;
defstream.zalloc = Z_NULL;
defstream.zfree = Z_NULL;
defstream.opaque = Z_NULL;
defstream.avail_in = (uInt) strlen(buffer_in);
defstream.next_in = (Bytef *) buffer_in;
defstream.avail_out = (uInt) sizeof(buffer_out);
defstream.next_out = (Bytef *) buffer_out;
deflateInit(&defstream, Z_BEST_COMPRESSION);
deflate(&defstream, Z_FINISH);
deflateEnd(&defstream);
printf("Uncompressed size is: %lu\n", strlen(buffer_in));
printf("Compressed size is: %lu\n", strlen(buffer_out));
printf("ZLIB VERSION: %s\n", zlibVersion());
return EXIT_SUCCESS;
}
此外,*CMakeLists.txt* 的内容是
cmake_minimum_required(VERSION 3.15)
project(compressor C)
find_package(ZLIB REQUIRED)
add_executable(${PROJECT_NAME} src/main.c)
target_link_libraries(${PROJECT_NAME} ZLIB::ZLIB)
我们的应用程序依赖于 **Zlib** 库。默认情况下,Conan 尝试从一个名为 ConanCenter 的远程服务器安装库。您可以在那里搜索库并检查可用版本。在我们的例子中,在检查了 Zlib 的可用版本后,我们选择使用最新的版本之一:**zlib/1.2.11**。
使用 Conan 安装 **Zlib** 库并从我们的项目中找到它的最简单方法是使用 *conanfile.txt* 文件。让我们创建一个包含以下内容的文件
[requires]
zlib/1.2.11
[generators]
CMakeDeps
CMakeToolchain
如您所见,我们在此文件中添加了两个部分,其语法类似于 *INI* 文件。
**[requires]** 部分是我们声明要在项目中使用的库的地方,在这种情况下是 **zlib/1.2.11**。
**[generators]** 部分告诉 Conan 生成编译器或构建系统将用来查找依赖项并构建项目的文件。在这种情况下,由于我们的项目基于 *CMake*,我们将使用 CMakeDeps 来生成有关 **Zlib** 库文件安装位置的信息,并使用 CMakeToolchain 通过 *CMake* 工具链文件将构建信息传递给 *CMake*。
除了 *conanfile.txt*,我们还需要一个 **Conan profile** 来构建我们的项目。Conan 配置文件允许用户为编译器、构建配置、架构、共享库或静态库等设置定义配置集。默认情况下,Conan 不会尝试自动检测配置文件,因此我们需要创建一个。为了让 Conan 尝试根据当前操作系统和安装的工具猜测配置文件,请运行
conan profile detect --force
这将根据环境检测操作系统、构建架构和编译器设置。它还将默认将构建配置设置为 *Release*。生成的配置文件将以名称 *default* 存储在 Conan 主文件夹中,并且默认情况下将在所有 Conan 命令中使用,除非通过命令行指定了另一个配置文件。此命令在 MacOS 上的输出示例将是
$ conan profile detect --force
Found apple-clang 14.0
apple-clang>=13, using the major as version
Detected profile:
[settings]
arch=x86_64
build_type=Release
compiler=apple-clang
compiler.cppstd=gnu17
compiler.libcxx=libc++
compiler.version=14
os=Macos
注意
关于 Conan 检测到的 C++ 标准的说明
Conan 将始终将默认 C++ 标准设置为检测到的编译器版本默认使用的标准,除非是使用 apple-clang 的 macOS。在这种情况下,对于 apple-clang>=11,它会设置 compiler.cppstd=gnu17
。如果您想使用不同的 C++ 标准,您可以直接编辑默认配置文件。首先,使用以下命令获取默认配置文件的位置
$ conan profile path default
/Users/user/.conan2/profiles/default
然后打开并编辑该文件,并将 compiler.cppstd
设置为您想要使用的 C++ 标准。
注意
使用自动检测到的编译器以外的编译器
如果您想更改 Conan 配置文件以使用与默认编译器不同的编译器,则需要更改 compiler
设置,并且还需要使用 tools.build:compiler_executables configuration 显式告知 Conan 在哪里找到它。
我们将使用 Conan 安装 **Zlib** 并生成 CMake 需要的文件,以找到该库并构建我们的项目。我们将在 *build* 文件夹中生成这些文件。为此,请运行
$ conan install . --output-folder=build --build=missing
您将获得类似于以下内容的命令输出
$ conan install . --output-folder=build --build=missing
...
-------- Computing dependency graph ----------
zlib/1.2.11: Not found in local cache, looking in remotes...
zlib/1.2.11: Checking remote: conancenter
zlib/1.2.11: Trying with 'conancenter'...
Downloading conanmanifest.txt
Downloading conanfile.py
Downloading conan_export.tgz
Decompressing conan_export.tgz
zlib/1.2.11: Downloaded recipe revision f1fadf0d3b196dc0332750354ad8ab7b
Graph root
conanfile.txt: /home/conan/examples2/tutorial/consuming_packages/simple_cmake_project/conanfile.txt
Requirements
zlib/1.2.11#f1fadf0d3b196dc0332750354ad8ab7b - Downloaded (conancenter)
-------- Computing necessary packages ----------
Requirements
zlib/1.2.11#f1fadf0d3b196dc0332750354ad8ab7b:cdc9a35e010a17fc90bb845108cf86cfcbce64bf#dd7bf2a1ab4eb5d1943598c09b616121 - Download (conancenter)
-------- Installing packages ----------
Installing (downloading, building) binaries...
zlib/1.2.11: Retrieving package cdc9a35e010a17fc90bb845108cf86cfcbce64bf from remote 'conancenter'
Downloading conanmanifest.txt
Downloading conaninfo.txt
Downloading conan_package.tgz
Decompressing conan_package.tgz
zlib/1.2.11: Package installed cdc9a35e010a17fc90bb845108cf86cfcbce64bf
zlib/1.2.11: Downloaded package revision dd7bf2a1ab4eb5d1943598c09b616121
-------- Finalizing install (deploy, generators) ----------
conanfile.txt: Generator 'CMakeToolchain' calling 'generate()'
conanfile.txt: Generator 'CMakeDeps' calling 'generate()'
conanfile.txt: Generating aggregated env files
如您在输出中所见,发生了一些事情
Conan 从远程服务器安装了 *Zlib* 库,如果该库可用,则默认情况下应该是 Conan Center 服务器。该服务器存储了 Conan 配方(这些配方是定义如何构建库的文件)和可以重用的二进制文件,因此我们不必每次都从源代码构建。
Conan 在 **build** 文件夹下生成了几个文件。这些文件是由我们在 **conanfile.txt** 中设置的
CMakeToolchain
和CMakeDeps
生成器生成的。CMakeDeps
生成文件,以便 CMake 找到我们刚刚下载的 Zlib 库。另一方面,CMakeToolchain
为 CMake 生成一个工具链文件,以便我们可以使用为我们的默认配置文件检测到的相同设置,使用 CMake 透明地构建我们的项目。
现在我们准备好构建和运行我们的 **compressor** 应用程序了
$ cd build
# assuming Visual Studio 15 2017 is your VS version and that it matches your default profile
$ cmake .. -G "Visual Studio 15 2017" -DCMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake"
$ cmake --build . --config Release
...
[100%] Built target compressor
$ Release\compressor.exe
Uncompressed size is: 233
Compressed size is: 147
ZLIB VERSION: 1.2.11
$ cd build
$ cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release
$ cmake --build .
...
[100%] Built target compressor
$ ./compressor
Uncompressed size is: 233
Compressed size is: 147
ZLIB VERSION: 1.2.11
请注意,CMakeToolchain
可能会生成 CMake **预设**文件,允许使用现代 CMake (>=3.23
) 的用户使用 cmake --preset
而不是传递工具链文件参数。请参阅使用 CMake 预设构建