|
3 | 3 | build_id()
|
4 | 4 | ==========
|
5 | 5 |
|
6 |
| -The ``build_id()`` method allows to re-use the same build to create different binary packages in the cache, |
7 |
| -potentially saving build time as it can avoid some unnecessary re-builds. It is therefore an optimization method. |
| 6 | +The ``build_id()`` method allows you to **reuse a single build** to create multiple binary packages in the Conan cache, |
| 7 | +saving time by avoiding unnecessary rebuilds. |
8 | 8 |
|
9 |
| -In the general case, there is one build folder for each binary package, with the exact same ``package_id`` of the package. However this behavior |
10 |
| -can be changed, there are a couple of scenarios that this might be useful: |
| 9 | +It is primarily an optimization tool for situations where **building each configuration separately isn't feasible**. |
11 | 10 |
|
12 |
| -- The package build scripts generate several different configurations at once (like both debug and release artifacts) in the same run, without the possibility of building each configuration separately. |
13 |
| -- The package build scripts generate one binary configuration, but different artifacts that can be packaged separately. For example if there are some test executables, you might want to create two packages: one just containing the library for general usage, and another one also containing the tests (for compliance, later reproducibility, debugging, etc). |
| 11 | +There are a couple of scenarios where this could be useful, for example, when a package build: |
14 | 12 |
|
15 |
| -In the first case, we could for example write: |
| 13 | +* **Generates multiple configurations in a single build run**: |
| 14 | + Some build scripts always produce both Debug and Release artifacts together, without a way to build them separately. |
16 | 15 |
|
17 |
| -.. code-block:: python |
| 16 | + |
| 17 | +* **Produces one configuration but different sets of artifacts**: |
| 18 | + The build could generate the main library plus some test executables, and you want to create: |
| 19 | + |
| 20 | + * one package with just the library (for general use), and |
| 21 | + * another package that includes both the library and the test binaries (for compliance, debugging, or reproducibility). |
| 22 | + |
| 23 | +In these scenarios, **reusing the same build folder avoids recompiling the same sources multiple times** just because you need slightly different packaging. |
| 24 | + |
| 25 | +How does the build folder relate to the package ID and the build ID? |
| 26 | +-------------------------------------------------------------------- |
| 27 | + |
| 28 | +By default, Conan creates **one build folder per unique package ID**, where: |
| 29 | + |
| 30 | +* Generally, the **package ID** depends on the combination of `settings`, `options`, and dependencies. |
| 31 | +* Each different **package ID** triggers a separate ``build()`` execution and generates a separate build folder. |
| 32 | + |
| 33 | +When you define the ``build_id()`` method, you can **force different package IDs to share the same build folder** by customizing `self.info_build`: |
| 34 | + |
| 35 | +* ``self.info_build`` is like ``self.info``, but it only affects the computation of the **build ID**, not the final package ID. |
| 36 | +* Any package IDs with the same build ID will reuse the same build folder and the same build step. |
| 37 | + |
| 38 | + |
| 39 | +Example: sharing the build for Debug and Release |
| 40 | +++++++++++++++++++++++++++++++++++++++++++++++++ |
| 41 | + |
| 42 | +.. code-block:: python |
18 | 43 |
|
19 | 44 | settings = "os", "compiler", "arch", "build_type"
|
20 | 45 |
|
21 | 46 | def build_id(self):
|
22 | 47 | self.info_build.settings.build_type = "Any"
|
23 | 48 |
|
24 |
| -This recipe will generate a final different package with a different ``package_id`` for debug and release configurations. But as the ``build_id()`` will generate the |
25 |
| -same ``build_id`` for any ``build_type``, then just one folder and one ``build()`` will be done, building both debug and release artifacts, |
26 |
| -and then the ``package()`` method will be called for each configuration, and it should package the artifacts conditionally to the ``self.settings.build_type`` value. Different builds will still be |
27 |
| -executed if using different compilers or architectures. |
| 49 | +* With this recipe, Debug and Release will each produce their own package IDs (and thus their own binary packages), |
| 50 | + but they will **share the same build folder**, because the build ID ignores the ``build_type`` setting. |
| 51 | +* **However, you still need to run one** :command:`conan create` **command per configuration** (e.g., once for Debug, once for Release). |
| 52 | + Conan will check if the build folder already exists (based on the shared build ID) and skip the actual compilation |
| 53 | + if it's already been built, only executing `package()` to create the corresponding package. |
28 | 54 |
|
29 |
| -Other information like custom package options can also be changed: |
| 55 | +Example workflow: |
30 | 56 |
|
31 |
| -.. code-block:: python |
| 57 | +.. code-block:: bash |
32 | 58 |
|
33 |
| - def build_id(self): |
34 |
| - self.info_build.options.myoption = 'MyValue' # any value possible |
35 |
| - self.info_build.options.fullsource = 'Always' |
| 59 | + # First build: creates the build folder + packages the Debug package |
| 60 | + $ conan create . -s build_type=Debug |
| 61 | +
|
| 62 | + # Second build: reuses the previous build folder + packages the Release package without rebuilding |
| 63 | + $ conan create . -s build_type=Release |
| 64 | +
|
| 65 | +This way, although we called :command:`conan create` twice (once per package ID), the actual build will only happen once. |
| 66 | + |
| 67 | +.. note:: |
| 68 | + |
| 69 | + You can also customize ``build_id()`` based on options: |
| 70 | + |
| 71 | + .. code-block:: python |
| 72 | +
|
| 73 | + def build_id(self): |
| 74 | + self.info_build.options.myoption = "MyValue" |
| 75 | + self.info_build.options.fullsource = "Always" |
| 76 | +
|
| 77 | +Conditional usage of the build ID |
| 78 | +--------------------------------- |
36 | 79 |
|
37 |
| -If the ``build_id()`` method does not modify the ``info_build`` data, and it still produces a different id than |
38 |
| -the ``package_id``, then the standard behavior will be applied. Consider the following: |
| 80 | +If the ``build_id()`` method does not modify the ``self.info_build`` data, and produces the same build ID as the package ID, |
| 81 | +then the standard behavior will be applied. For example: |
39 | 82 |
|
40 |
| -.. code-block:: python |
| 83 | +.. code-block:: python |
41 | 84 |
|
42 | 85 | settings = "os", "compiler", "arch", "build_type"
|
43 | 86 |
|
44 | 87 | def build_id(self):
|
45 | 88 | if self.settings.os == "Windows":
|
46 | 89 | self.info_build.settings.build_type = "Any"
|
47 | 90 |
|
48 |
| -This will only produce a different ``build_id`` if the package is for Windows, thus running ``build()`` just |
49 |
| -once for all ``build_type`` values. The behavior |
50 |
| -in any other OS will be the standard one, as if the ``build_id()`` method was not defined, running |
51 |
| -one different ``build()`` for each ``build_type``. |
| 91 | +This will only produce a different **build ID** if the package is for Windows, so it will only run the ``build()`` method once |
| 92 | +for all the ``build_type`` values. |
52 | 93 |
|
| 94 | +For any other OS, Conan will behave as usual (as if the ``build_id()`` method was not defined), running the ``build()`` method |
| 95 | +for every ``build_type`` configuration. |
53 | 96 |
|
54 | 97 | .. note::
|
55 | 98 |
|
56 | 99 | **Best practices**
|
57 | 100 |
|
58 |
| - Conan strongly recommends to use one package binary with its own ``package_id`` for each different configuration. The goal of the ``build_id()`` method is to deal with legacy build scripts that cannot easily be changed to do the build of one configuration each time. |
| 101 | + The goal of the ``build_id()`` method is to deal with legacy build scripts that cannot easily be changed |
| 102 | + to compile one configuration at a time. We strongly recommend to just package **one package binary per package ID** |
| 103 | + for each different configuration. |
0 commit comments