包开发流程

本节介绍 Conan 本地开发流程,该流程允许您在本地项目目录中处理包,而无需首先将包的内容导出到 Conan 缓存。

这种本地工作流程鼓励用户在其配方相关的本地子目录中执行试错,就像开发人员通常使用其他构建工具测试构建项目一样。 策略是在此阶段单独测试 conanfile.py 方法。

让我们将此流程用于我们在 上一节 中创建的 hello 包。

请克隆源代码以重新创建此项目。 您可以在 GitHub 上的 examples2.0 仓库中找到它们

$ git clone https://github.com/conan-io/examples2.git
$ cd examples2/tutorial/developing_packages/local_package_development_flow

您可以检查文件夹的内容

.
├── conanfile.py
└── test_package
    ├── CMakeLists.txt
    ├── conanfile.py
    └── src
        └── example.cpp

conan source

您通常会希望从 conan source 命令开始。 这里的策略是您正在隔离测试您的 source 方法,并将文件下载到相对于 conanfile.py 的临时子文件夹。 此相对文件夹由 layout() 方法中的 self.folders.source 属性定义。 在这种情况下,由于我们使用预定义的 cmake_layout,我们使用 src_folder 参数设置该值。

注意

在此示例中,我们正在打包来自远程仓库的第三方库。 如果您的源代码与您的配方在同一仓库中,则在大多数情况下,运行 conan source 不是必需的。

让我们看一下配方的 source()layout() 方法

...

def source(self):
    # Please be aware that using the head of the branch instead of an immutable tag
    # or commit is not a good practice in general.
    get(self, "https://github.com/conan-io/libhello/archive/refs/heads/main.zip",
        strip_root=True)

def layout(self):
    cmake_layout(self, src_folder="src")

...

现在运行 conan source 命令并检查结果

$ conan source .
conanfile.py (hello/1.0): Calling source() in /Users/.../local_package_development_flow/src
Downloading main.zip
conanfile.py (hello/1.0): Unzipping 3.7KB
Unzipping 100%

您可以看到出现了一个新的 src 文件夹,其中包含所有 hello 库源代码。

.
├── conanfile.py
├── src
│   ├── CMakeLists.txt
│   ├── LICENSE
│   ├── README.md
│   ├── include
│   │   └── hello.h
│   └── src
│       └── hello.cpp
└── test_package
    ├── CMakeLists.txt
    ├── conanfile.py
    └── src
        └── example.cpp

现在可以轻松检查源代码并验证它们。 一旦您的 source 方法正确并且包含您期望的文件,您就可以继续测试与下载依赖项相关的各种属性和方法。

conan install

运行 conan source 命令后,您可以运行 conan install 命令。 此命令将根据需要安装所有配方要求,并通过运行 generate() 方法准备构建所需的所有文件。

我们可以检查配方中参与此步骤的所有部分

...

class helloRecipe(ConanFile):

    ...

    generators = "CMakeDeps"

    ...

    def layout(self):
        cmake_layout(self, src_folder="src")

    def generate(self):
        tc = CMakeToolchain(self)
        tc.generate()

    ...

现在运行 conan install 命令并检查结果

$ conan install .
...
-------- Finalizing install (deploy, generators) --------
conanfile.py (hello/1.0): Writing generators to ...
conanfile.py (hello/1.0): Generator 'CMakeDeps' calling 'generate()'
conanfile.py (hello/1.0): Calling generate()
...
conanfile.py (hello/1.0): Generating aggregated env files

您可以看到出现了一个新的 build 文件夹,其中包含 Conan 构建库所需的所有文件,例如 CMake 的工具链和几个环境配置文件。

.
├── build
│   └── Release
│       └── generators
│           ├── CMakePresets.json
│           ├── cmakedeps_macros.cmake
│           ├── conan_toolchain.cmake
│           ├── conanbuild.sh
│           ├── conanbuildenv-release-x86_64.sh
│           ├── conanrun.sh
│           ├── conanrunenv-release-x86_64.sh
│           ├── deactivate_conanbuild.sh
│           └── deactivate_conanrun.sh
├── conanfile.py
├── src
│   ├── CMakeLists.txt
│   ├── CMakeUserPresets.json
│   ├── LICENSE
│   ├── README.md
│   ├── include
│   │   └── hello.h
│   └── src
│       └── hello.cpp
└── test_package
    ├── CMakeLists.txt
    ├── conanfile.py
    └── src
        └── example.cpp

现在生成了构建所需的所有文件,您可以继续测试 build() 方法。

conan build

运行 conan build 命令将调用 build() 方法

...

class helloRecipe(ConanFile):

    ...

    def build(self):
        cmake = CMake(self)
        cmake.configure()
        cmake.build()

    ...

让我们运行 conan build

$ conan build .
...
-- Conan toolchain: C++ Standard 11 with extensions ON
-- Conan toolchain: Setting BUILD_SHARED_LIBS = OFF
-- Configuring done
-- Generating done
-- Build files have been ...
conanfile.py (hello/1.0): CMake command: cmake --build ...
conanfile.py (hello/1.0): RUN: cmake --build ...
[100%] Built target hello

对于大多数配方,build() 方法应该非常简单,您也可以直接调用构建系统,而无需调用 Conan,因为您拥有构建所需的所有必要文件。 如果您检查 src 文件夹的内容,您会找到一个 CMakeUserPresets.json 文件,您可以使用它来配置和构建 conan-release 预设。 让我们试试看

$ cd src
$ cmake --preset conan-release
...
-- Configuring done
-- Generating done

$ cmake --build --preset conan-release
...
[100%] Built target hello

您可以检查直接调用 CMake 的结果与我们使用 conan build 命令得到的结果相同。

注意

在此示例中,我们使用 CMake 预设。 这需要 CMake >= 3.23,因为从 CMakeUserPresets.jsonCMakePresets.json 的“include”仅自该版本起受支持。 如果您不想使用预设,可以使用类似这样的方法

cmake <path> -G <CMake generator> -DCMAKE_TOOLCHAIN_FILE=<path to
conan_toolchain.cmake> -DCMAKE_BUILD_TYPE=Release

如果您无法使用预设功能,Conan 将在您每次运行 conan install 时显示确切的 CMake 命令。

conan export-pkg

现在我们在本地构建了包二进制文件,我们也可以使用 conan export-pkg 命令将这些工件打包到 Conan 本地缓存中。 请注意,此命令将在 Conan 缓存中创建包,并在之后运行 test_package 对其进行测试。

$ conan export-pkg .
conanfile.py (hello/1.0) package(): Packaged 1 '.h' file: hello.h
conanfile.py (hello/1.0) package(): Packaged 1 '.a' file: libhello.a
conanfile.py (hello/1.0): Package 'b1d267f77ddd5d10d06d2ecf5a6bc433fbb7eeed' created
conanfile.py (hello/1.0): Created package revision f09ef573c22f3919ba26ee91ae444eaa
...
conanfile.py (hello/1.0): Package folder /Users/...
conanfile.py (hello/1.0): Exported package binary
...
[ 50%] Building CXX object CMakeFiles/example.dir/src/example.cpp.o
[100%] Linking CXX executable example
[100%] Built target example

-------- Testing the package: Running test() --------
hello/1.0 (test package): Running test()
hello/1.0 (test package): RUN: ./example
hello/1.0: Hello World Release!
hello/1.0: __x86_64__ defined
hello/1.0: __cplusplus201103
hello/1.0: __GNUC__4
hello/1.0: __GNUC_MINOR__2
hello/1.0: __clang_major__14
hello/1.0: __apple_build_version__14000029

现在您可以列出本地缓存中的包,并检查是否已创建 hello/1.0 包。

$ conan list hello/1.0
Local Cache
  hello
    hello/1.0

另请参阅