the build() method — conan 2.4.0 documentation (2024)

  • Tutorial
  • Creating packages
  • Build packages: the build() method
  • Edit on GitHub

We already used a Conan recipe that has a build() method and learned how to use thatto invoke a build system and build our packages. In this tutorial, we will modify thatmethod and explain how you can use it to do things like:

  • Building and running tests

  • Conditional patching of the source code

  • Select the build system you want to use conditionally

Please, first clone the sources to recreate this project. You can find them in theexamples2 repository on GitHub:

$ git clone https://github.com/conan-io/examples2.git$ cd examples2/tutorial/creating_packages/build_method

Build and run tests for your project

You will notice some changes in the conanfile.py file from the previous recipe.Let’s check the relevant parts:

Changes introduced in the recipe

conanfile.py

class helloRecipe(ConanFile): name = "hello" version = "1.0" ... def source(self): git = Git(self) git.clone(url="https://github.com/conan-io/libhello.git", target=".") # Please, be aware that using the head of the branch instead of an immutable tag # or commit is not a good practice in general git.checkout("with_tests") ... def requirements(self): if self.options.with_fmt: self.requires("fmt/8.1.1") self.test_requires("gtest/1.11.0") ... def generate(self): tc = CMakeToolchain(self) if self.options.with_fmt: tc.variables["WITH_FMT"] = True tc.generate() def build(self): cmake = CMake(self) cmake.configure() cmake.build() if not self.conf.get("tools.build:skip_test", default=False): test_folder = os.path.join("tests") if self.settings.os == "Windows": test_folder = os.path.join("tests", str(self.settings.build_type)) self.run(os.path.join(test_folder, "test_hello")) ...
  • We added the gtest/1.11.0 requirement to the recipe as a test_requires(). It’s atype of requirement intended for testing libraries like Catch2 or gtest.

  • We use the tools.build:skip_test configuration (False by default), to tell CMakewhether to build and run the tests or not. A couple of things to bear in mind:

    • If we set the tools.build:skip_test configuration to True Conan willautomatically inject the BUILD_TESTING variable to CMake set to OFF. You willsee in the next section that we are using this variable in our CMakeLists.txt todecide whether to build the tests or not.

    • We use the tools.build:skip_test configuration in the build() method,after building the package and tests, to decide if we want to run the tests or not.

    • In this case we are using gtest for testing and we have to check if thebuild method is to run the tests or not. This configuration also affects theexecution of CMake.test() if you are using CTest and Meson.test() for Meson.

Changes introduced in the library sources

First, please note that we are using another branch from the libhello library. Thisbranch has two novelties on the library side:

  • We added a new function called compose_message() to the library sources so we can addsome unit tests over this function. This function is just creating an output messagebased on the arguments passed.

  • As we mentioned in the previous section the CMakeLists.txt for the library uses theBUILD_TESTING CMake variable that conditionally adds the tests directory.

CMakeLists.txt

cmake_minimum_required(VERSION 3.15)project(hello CXX)...if (NOT BUILD_TESTING STREQUAL OFF) add_subdirectory(tests)endif()...

The BUILD_TESTING CMake variable is declared and set to OFFby Conan (if not already defined) whenever the tools.build:skip_test configuration isset to value True. This variable is typically declared by CMake when you use CTest butusing the tools.build:skip_test configuration you can use it in your CMakeLists.txteven if you are using another testing framework.

tests/CMakeLists.txt

cmake_minimum_required(VERSION 3.15)project(PackageTest CXX)find_package(GTest REQUIRED CONFIG)add_executable(test_hello test.cpp)target_link_libraries(test_hello GTest::gtest GTest::gtest_main hello)

With basic tests on the functionality of the compose_message() function:

tests/test.cpp

#include "../include/hello.h"#include "gtest/gtest.h"namespace { TEST(HelloTest, ComposeMessages) { EXPECT_EQ(std::string("hello/1.0: Hello World Release! (with color!)\n"), compose_message("Release", "with color!")); ... }}

Now that we have gone through all the changes in the code, let’s try them out:

$ conan create . --build=missing -tf=""...[ 25%] Building CXX object CMakeFiles/hello.dir/src/hello.cpp.o[ 50%] Linking CXX static library libhello.a[ 50%] Built target hello[ 75%] Building CXX object tests/CMakeFiles/test_hello.dir/test.cpp.o[100%] Linking CXX executable test_hello[100%] Built target test_hellohello/1.0: RUN: ./tests/test_helloCapturing current environment in /Users/user/.conan2/p/tmp/c51d80ef47661865/b/build/generators/deactivate_conanbuildenv-release-x86_64.shConfiguring environment variablesRunning main() from /Users/user/.conan2/p/tmp/3ad4c6873a47059c/b/googletest/src/gtest_main.cc[==========] Running 1 test from 1 test suite.[----------] Global test environment set-up.[----------] 1 test from HelloTest[ RUN ] HelloTest.ComposeMessages[ OK ] HelloTest.ComposeMessages (0 ms)[----------] 1 test from HelloTest (0 ms total)[----------] Global test environment tear-down[==========] 1 test from 1 test suite ran. (0 ms total)[ PASSED ] 1 test.hello/1.0: Package '82b6c0c858e739929f74f59c25c187b927d514f3' built...

As you can see, the tests were built and run. Let’s use now the tools.build:skip_testconfiguration in the command line to skip the test building and running:

$ conan create . -c tools.build:skip_test=True -tf="""...[ 50%] Building CXX object CMakeFiles/hello.dir/src/hello.cpp.o[100%] Linking CXX static library libhello.a[100%] Built target hellohello/1.0: Package '82b6c0c858e739929f74f59c25c187b927d514f3' built...

You can see now that only the library target was built and that no tests were built orrun.

Conditionally patching the source code

If you need to patch the source code the recommended approach is to do that in thesource() method. Sometimes, if that patch depends on settings or options, you haveto use the build() method to apply patches to the source code before launching thebuild. There are several ways to do this in Conan.One of them would be using the replace_in_filetool:

import osfrom conan import ConanFilefrom conan.tools.files import replace_in_fileclass helloRecipe(ConanFile): name = "hello" version = "1.0" # Binary configuration settings = "os", "compiler", "build_type", "arch" options = {"shared": [True, False], "fPIC": [True, False]} default_options = {"shared": False, "fPIC": True} def build(self): replace_in_file(self, os.path.join(self.source_folder, "src", "hello.cpp"), "Hello World", "Hello {} Friends".format("Shared" if self.options.shared else "Static"))

Please, note that patching in build() should be avoided if possible and only be done forvery particular cases as it will make more difficult to develop your packages locally (wewill explain more about this in the local development flow section later)

Conditionally select your build system

It’s not uncommon that some packages need one build system or another depending on theplatform we are building on. For example, the hello library could build in Windows usingCMake and in Linux and MacOS using Autotools. This can be easily handled in thebuild() method like this:

...class helloRecipe(ConanFile): name = "hello" version = "1.0" # Binary configuration settings = "os", "compiler", "build_type", "arch" options = {"shared": [True, False], "fPIC": [True, False]} default_options = {"shared": False, "fPIC": True} ... def generate(self): if self.settings.os == "Windows": tc = CMakeToolchain(self) tc.generate() deps = CMakeDeps(self) deps.generate() else: tc = AutotoolsToolchain(self) tc.generate() deps = PkgConfigDeps(self) deps.generate() ... def build(self): if self.settings.os == "Windows": cmake = CMake(self) cmake.configure() cmake.build() else: autotools = Autotools(self) autotools.autoreconf() autotools.configure() autotools.make() ...

See also

  • Patching sources

the build() method — conan 2.4.0 documentation (2024)
Top Articles
Latest Posts
Article information

Author: Annamae Dooley

Last Updated:

Views: 5806

Rating: 4.4 / 5 (65 voted)

Reviews: 88% of readers found this page helpful

Author information

Name: Annamae Dooley

Birthday: 2001-07-26

Address: 9687 Tambra Meadow, Bradleyhaven, TN 53219

Phone: +9316045904039

Job: Future Coordinator

Hobby: Archery, Couponing, Poi, Kite flying, Knitting, Rappelling, Baseball

Introduction: My name is Annamae Dooley, I am a witty, quaint, lovely, clever, rich, sparkling, powerful person who loves writing and wants to share my knowledge and understanding with you.