|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +comments: false |
| 4 | +title: "Introducing the Local-Recipes-Index: A New Repository Type in Conan" |
| 5 | +meta_title: "Understanding Conan's Local-Recipes-Index to improve package management for C/C++ - Conan Blog" |
| 6 | +description: "Explore the capabilities of Conan's local-recipes-index feature and how it enhances dependency management for C and C++ libraries." |
| 7 | +--- |
| 8 | + |
| 9 | +ConanCenter, the central open-source repository for C and C++ libraries, is a success |
| 10 | +story, containing a vast collection of C and C++ open-source packages. It processes hundreds |
| 11 | +of thousands of download requests daily, building its packages [from a central GitHub |
| 12 | +repository](https://github.com/conan-io/conan-center-index), which is organized in a |
| 13 | +specific folder layout and received nearly 6,000 pull requests from contributors in |
| 14 | +2023 alone. |
| 15 | + |
| 16 | +However, ConanCenter does not fit all use cases. For instance, it cannot include |
| 17 | +closed-source libraries or tools that might still be beneficial to the community. |
| 18 | +Additionally, some organizations, particularly large enterprises, prefer not to use |
| 19 | +binaries downloaded from the internet. Instead, they build their own binaries in-house |
| 20 | +using the `conan-center-index` recipes. These organizations often need to customize these |
| 21 | +recipes to meet unique requirements that are not applicable to the broader community, |
| 22 | +making such contributions unsuitable for the upstream repository. The Conan documentation |
| 23 | +[acknowledges this |
| 24 | +practice](https://docs.conan.io/2/devops/conancenter/hosting_binaries.html), recommending |
| 25 | +working from a fork of `conan-center-index` for such needs. |
| 26 | + |
| 27 | +For all those reasons in version 2.2.0, Conan introduced a new repository type called |
| 28 | +`local-recipes-index`, designed to offer more flexibility by allowing a Conan remote to |
| 29 | +point to a local copy of Conan recipes with a specific layout. |
| 30 | + |
| 31 | +The `local-recipes-index` allows users to maintain a local folder with the same structure |
| 32 | +as the `conan-center-index` GitHub repository, using it as a source for package recipes. |
| 33 | +This new type of repository is recipes-only, necessitating the construction of package |
| 34 | +binaries from source on each machine where the package is used. For sharing binaries |
| 35 | +across teams, we continue to recommend [using a Conan remote server like |
| 36 | +Artifactory](https://docs.conan.io/2/tutorial/conan_repositories/setting_up_conan_remotes/artifactory/artifactory_ce_cpp.html) |
| 37 | +for production purposes. |
| 38 | + |
| 39 | +<p class="centered"> |
| 40 | + <img src="{{ site.baseurl }}/assets/post_images/2024-04-23/general-flow-diagram.png" style="display: block; margin-left: auto; margin-right: auto;" alt="Diagram of the general workflow"/> |
| 41 | +</p> |
| 42 | + |
| 43 | +In this post, we will explore how this feature facilitates the following: |
| 44 | + |
| 45 | +- This feature enables contributors to share package recipes with the community for |
| 46 | + libraries that might not be suitable for ConanCenter due to various reasons, such as |
| 47 | + licensing constraints or binary distribution policies. An example of this could be CUDA |
| 48 | + or other proprietary libraries, which are distributed as precompiled closed-source |
| 49 | + binaries. |
| 50 | + |
| 51 | +- It simplifies the adoption of best practices outlined [in the Conan |
| 52 | + documentation](https://docs.conan.io/2/devops/conancenter/hosting_binaries.html) for |
| 53 | + organizations requiring custom-built binaries or modified ConanCenter recipes to meet |
| 54 | + unique requirements. This approach grants users complete control over their third-party |
| 55 | + dependencies, ensuring they are both robust and fully customizable. |
| 56 | + |
| 57 | +Next, we'll delve into practical examples to demonstrate these two use cases of the |
| 58 | +`local-recipes-index` repository. |
| 59 | + |
| 60 | +## Using a local-recipes-index repository with your own recipes |
| 61 | + |
| 62 | +In this section, we will illustrate how to use the `local-recipes-index` feature for |
| 63 | +scenarios where certain libraries or tools, due to licensing restrictions or proprietary |
| 64 | +nature, are not suitable for ConanCenter. |
| 65 | + |
| 66 | +For demonstration purposes, let's create a `local-recipes-index` repository for a hypothetical |
| 67 | +`hello` closed-source library using the `local_recipes_index` template for the `conan new` |
| 68 | +command: |
| 69 | + |
| 70 | + $ mkdir repo && cd repo |
| 71 | + $ conan new local_recipes_index -d name=hello -d version=0.1 \ |
| 72 | + -d url=https://github.com/conan-io/libhello/archive/refs/tags/0.0.1.zip \ |
| 73 | + -d sha256=1dfb66cfd1e2fb7640c88cc4798fe25853a51b628ed9372ffc0ca285fe5be16b |
| 74 | + $ cd .. |
| 75 | + |
| 76 | +The `conan new local_recipes_index` command creates a template that assumes CMake as the |
| 77 | +build system alongside other heavy assumptions. In practice, it will require customizing |
| 78 | +it, but for this demo, it works as-is. It will create a folder layout equal to the |
| 79 | +`conan-center-index` GitHub repository: |
| 80 | + |
| 81 | + . |
| 82 | + └── repo |
| 83 | + └── recipes |
| 84 | + └── hello |
| 85 | + ├── all |
| 86 | + │ ├── conandata.yml |
| 87 | + │ ├── conanfile.py |
| 88 | + │ └── test_package |
| 89 | + │ ├── CMakeLists.txt |
| 90 | + │ ├── conanfile.py |
| 91 | + │ └── src |
| 92 | + │ └── example.cpp |
| 93 | + └── config.yml |
| 94 | + |
| 95 | +After setting up the repository, we add it as a local remote to Conan: |
| 96 | + |
| 97 | + $ conan remote add mylocalrepo ./repo --allowed-packages="hello/*" |
| 98 | + |
| 99 | +Please pay special attention to the `--allowed-packages` argument. This argument ensures |
| 100 | +that all packages other than `hello` are discarded by Conan. This can be used to minimize |
| 101 | +the surface area for a potential supply chain attack. |
| 102 | + |
| 103 | +Now you can list and install packages from this new repository: |
| 104 | + |
| 105 | + $ conan list "*" -r=mylocalrepo |
| 106 | + $ conan install --requires=hello/0.1 -r=mylocalrepo --build=missing |
| 107 | + |
| 108 | +At this point, you could push this repository to your GitHub account and share it with the |
| 109 | +community. Please be aware that, as we commented earlier, this feature is specifically |
| 110 | +tailored for scenarios where certain libraries are not suitable for ConanCenter. Remember, |
| 111 | +a "local-recipes-index" repository has limitations: it is not fully reproducible as it |
| 112 | +models only versions and not revisions, and it does not provide binaries. Therefore, |
| 113 | +outside of these cases, it is advised to use a remote package server such as Artifactory. |
| 114 | + |
| 115 | +Now, users simply need to clone the GitHub repository and add the cloned folder as a local |
| 116 | +repository themselves. |
| 117 | + |
| 118 | +## Building Binaries from a private `conan-center-index` fork |
| 119 | + |
| 120 | +As outlined in [the Conan DevOps |
| 121 | +Guide](https://docs.conan.io/2/devops/using_conancenter.html), there are many cases where |
| 122 | +organizations need to operate independently of ConanCenter by building their own binaries. |
| 123 | +Being decoupled from the public upstream ConanCenter server and building your own binaries |
| 124 | +from a fork of ``conan-center-index`` as suggested in the linked documentation page can have |
| 125 | +many advantages, including absolute control and possibility to customize recipes, giving |
| 126 | +us the ability for the repository to act as a snapshot of versions, be completely robust |
| 127 | +against possible continuous changes and new releases in upstream ConanCenter, etc. |
| 128 | + |
| 129 | +The `local-recipes-index` repository allows you to easily build binaries from a fork of |
| 130 | +`conan-center-index`, and then hosting them on a Conan remote repository like Artifactory. |
| 131 | +The main difference with the process explained [in the Conan DevOps |
| 132 | +guide](https://docs.conan.io/2/devops/conancenter/hosting_binaries.html) is the ability |
| 133 | +to immediately test multiple local changes without the need to export each time a recipe |
| 134 | +is modified. |
| 135 | + |
| 136 | +Note that in this case, mixing binaries from ConanCenter with locally built binaries is |
| 137 | +not recommended for several reasons: |
| 138 | + |
| 139 | +- Binary compatibility: There may be small differences in setup between the ConanCenter CI |
| 140 | +and the user's CI. Maintaining a consistent setup for all binaries can mitigate some issues. |
| 141 | + |
| 142 | +- Full control over builds: Building all binaries yourself ensures you have complete control |
| 143 | +over the compilation environment and dependency versions. |
| 144 | + |
| 145 | +Instead, it's recommended to build all your direct and transitive dependencies from the fork. |
| 146 | +To begin, remove the upstream ConanCenter as it will not be used, everything will come |
| 147 | +from our own fork: |
| 148 | + |
| 149 | + $ conan remote remove conancenter |
| 150 | + |
| 151 | +Then we will clone our fork (in this case, we are cloning directly the upstream for demo |
| 152 | +purposes, but you would be cloning your fork instead): |
| 153 | + |
| 154 | + $ git clone https://github.com/conan-io/conan-center-index |
| 155 | + |
| 156 | +Add this as our `mycenter` remote: |
| 157 | + |
| 158 | + # Add the mycenter remote pointing to the local folder |
| 159 | + $ conan remote add mycenter ./conan-center-index |
| 160 | + |
| 161 | +And that’s all! Now you're set to list and use packages from your `conan-center-index` local folder: |
| 162 | + |
| 163 | + $ conan list "zlib/*" -r=mycenter |
| 164 | + mycenter |
| 165 | + zlib |
| 166 | + zlib/1.2.11 |
| 167 | + zlib/1.2.12 |
| 168 | + zlib/1.2.13 |
| 169 | + zlib/1.3 |
| 170 | + zlib/1.3.1 |
| 171 | + |
| 172 | +We can also install packages from this repo, for example we can do: |
| 173 | + |
| 174 | + $ conan install --requires=zlib/1.3 |
| 175 | + ... |
| 176 | + ======== Computing dependency graph ======== |
| 177 | + zlib/1.3: Not found in local cache, looking in remotes... |
| 178 | + zlib/1.3: Checking remote: mycenter |
| 179 | + zlib/1.3: Downloaded recipe revision 5c0f3a1a222eebb6bff34980bcd3e024 |
| 180 | + Graph root |
| 181 | + cli |
| 182 | + Requirements |
| 183 | + zlib/1.3#5c0f3a1a222eebb6bff34980bcd3e024 - Downloaded (mycenter) |
| 184 | + |
| 185 | + ======== Computing necessary packages ======== |
| 186 | + Requirements |
| 187 | + zlib/1.3#5c0f3a1a222eebb6bff34980bcd3e024:72c852c5f0ae27ca0b1741e5fd7c8b8be91a590a - Missing |
| 188 | + ERROR: Missing binary: zlib/1.3:72c852c5f0ae27ca0b1741e5fd7c8b8be91a590a |
| 189 | + |
| 190 | +As we can see, Conan managed to get the recipe for ``zlib/1.3`` from ``mycenter``, but |
| 191 | +then it failed because there is no binary. This is expected, **the repository only contains |
| 192 | +the recipes, but not the binaries**. We can build the binary from source with |
| 193 | +``--build=missing`` argument: |
| 194 | + |
| 195 | + $ conan install --requires=zlib/1.3 --build=missing |
| 196 | + ... |
| 197 | + zlib/1.3: package(): Packaged 2 '.h' files: zconf.h, zlib.h |
| 198 | + zlib/1.3: package(): Packaged 1 file: LICENSE |
| 199 | + zlib/1.3: package(): Packaged 1 '.a' file: libz.a |
| 200 | + zlib/1.3: Created package revision 0466b3475bcac5c2ce37bb5deda835c3 |
| 201 | + zlib/1.3: Package '72c852c5f0ae27ca0b1741e5fd7c8b8be91a590a' created |
| 202 | + zlib/1.3: Full package reference: zlib/1.3#5c0f3a1a222eebb6bff34980bcd3e024:72c852c5f0ae27ca0b1741e5fd7c8b8be91a590a#0466b3475bcac5c2ce37bb5deda835c3 |
| 203 | + zlib/1.3: Package folder /home/conan/.conan2/p/b/zlib1ed9fe13537a2/p |
| 204 | + WARN: deprecated: Usage of deprecated Conan 1.X features that will be removed in Conan 2.X: |
| 205 | + WARN: deprecated: 'cpp_info.names' used in: zlib/1.3 |
| 206 | + |
| 207 | + ======== Finalizing install (deploy, generators) ======== |
| 208 | + cli: Generating aggregated env files |
| 209 | + cli: Generated aggregated env files: ['conanbuild.sh', 'conanrun.sh'] |
| 210 | + Install finished successfully |
| 211 | + |
| 212 | +We can see now the binary package in our local cache: |
| 213 | + |
| 214 | + $ conan list zlib:* |
| 215 | + Local Cache |
| 216 | + zlib |
| 217 | + zlib/1.3 |
| 218 | + revisions |
| 219 | + 5c0f3a1a222eebb6bff34980bcd3e024 (2024-04-10 11:50:34 UTC) |
| 220 | + packages |
| 221 | + 72c852c5f0ae27ca0b1741e5fd7c8b8be91a590a |
| 222 | + info |
| 223 | + settings |
| 224 | + arch: x86_64 |
| 225 | + build_type: Release |
| 226 | + compiler: gcc |
| 227 | + compiler.version: 9 |
| 228 | + os: Linux |
| 229 | + options |
| 230 | + fPIC: True |
| 231 | + shared: False |
| 232 | + |
| 233 | +Finally, upload the binary package to our Artifactory repository to make it available for |
| 234 | +our organization, users and CI jobs: |
| 235 | + |
| 236 | + $ conan remote add myartifactoryrepo <artifactory_url> |
| 237 | + $ conan upload zlib* -r=myartifactoryrepo -c |
| 238 | + |
| 239 | +This way, consumers of the packages will not only enjoy the pre-compiled binaries and |
| 240 | +avoid having to always re-build from source all dependencies, but that will also provide |
| 241 | +stronger guarantees that the dependencies build and work correctly, that all dependencies |
| 242 | +and transitive dependencies play well together, etc. Decoupling the binary creation |
| 243 | +process from the binary consumption process is the way to achieve faster and more reliable |
| 244 | +usage of dependencies. |
| 245 | + |
| 246 | +Remember, in a production setting, the `conan upload` command should be executed by CI, |
| 247 | +not developers, following the [Conan |
| 248 | +guidelines](https://docs.conan.io/2/knowledge/guidelines.html). This approach ensures that |
| 249 | +package consumers enjoy pre-compiled binaries and consistency across dependencies. |
| 250 | + |
| 251 | +### Modifying the local-recipes-index repository files |
| 252 | + |
| 253 | +One of the advantages of this approach is that all the changes that we do in every single |
| 254 | +recipe are automatically available for the Conan client. For example, changes to the |
| 255 | +`recipes/zlib/config.yml` file are immediately recognized by the Conan client. If you |
| 256 | +edit that file and remove all versions but the latest and then we `list` the recipes: |
| 257 | + |
| 258 | + $ conan list "zlib/*" -r=mycenter |
| 259 | + mycenter |
| 260 | + zlib |
| 261 | + zlib/1.3.1 |
| 262 | + |
| 263 | +When some of the recipes change, then note that the current Conan home already contains a |
| 264 | +cached copy of the package, so it will not update it unless we explicitly use the |
| 265 | +``--update``, as any other Conan remote. |
| 266 | + |
| 267 | +So if we do a change in the ``zlib`` recipe in ``recipes/zlib/all/conanfile.py`` and |
| 268 | +repeat: |
| 269 | + |
| 270 | + $ conan install --requires=zlib/1.3.1 -r=mycenter --update --build=missing |
| 271 | + |
| 272 | +We will immediately have the new package binary locally built from source from the new |
| 273 | +modified recipe in our Conan home. |
| 274 | + |
| 275 | +### Using local-recipes-index Repositories in Production |
| 276 | + |
| 277 | +Several important points should be considered when using this new feature: |
| 278 | + |
| 279 | +- It is designed for **third-party packages**, where recipes in one repository are creating |
| 280 | + packages with sources located elsewhere. To package your own code, the standard practice |
| 281 | + of adding `conanfile.py` recipes along with the source code and using the standard |
| 282 | + `conan create` flow is recommended. |
| 283 | + |
| 284 | +- The `local-recipes-index` repositories point to **local folders in the filesystem**. |
| 285 | + While users may choose to sync that folder with a git repository or other version |
| 286 | + control mechanisms, Conan is agnostic to this, as it is only aware of the folder in the |
| 287 | + filesystem that points to the (current) state of the repository. Users may choose to run |
| 288 | + git commands directly to switch branches/commit/tags and Conan will automatically |
| 289 | + recognise the changes |
| 290 | + |
| 291 | +- This approach operates at the source level and does not generate package binaries. For |
| 292 | + deployment for development and production environments, the use of a remote package |
| 293 | + server such as Artifactory is crucial. It's important to note that this feature is not a |
| 294 | + replacement for Conan's remote package servers, which play a vital role in hosting |
| 295 | + packages for regular use. |
| 296 | + |
| 297 | +- Also, note that a server remote can retain a history of changes storing multiple recipe |
| 298 | + revisions. In contrast, a `local-recipes-index` remote can only represent a single |
| 299 | + snapshot at any given time. |
| 300 | + |
| 301 | +Furthermore, this feature does not support placing server URLs directly in recipes; remote |
| 302 | +repositories must be explicitly added with `conan remote add`. Decoupling abstract package |
| 303 | +requirements, such as "zlib/1.3.1", from their specific origins is crucial to resolving |
| 304 | +dependencies correctly and leveraging Conan's graph capabilities, including version |
| 305 | +conflict detection and resolution, version-ranges resolution, [opting into |
| 306 | +pre-releases](https://docs.conan.io/2/devops/versioning/resolve_prereleases.html), |
| 307 | +[platform_requires](https://docs.conan.io/2/reference/config_files/profiles.html#platform-requires), |
| 308 | +[replace_requires](https://docs.conan.io/2/reference/config_files/profiles.html#replace-requires), |
| 309 | +etc. This separation also facilitates the implementation of modern DevOps practices, such |
| 310 | +as package immutability, full relocatability and package promotions. |
| 311 | + |
| 312 | +## Conclusions |
| 313 | + |
| 314 | +The `local-recipes-index` repository type introduces a new tool that enables workflows |
| 315 | +previously not possible with Conan 1.X: |
| 316 | + |
| 317 | +- It allows the easy creation of packages from forks of the `conan-center-index` GitHub |
| 318 | + repository. Many enterprises require this due to policies necessitating private |
| 319 | + customizations in recipes that are unsuitable for merging into the upstream repository. |
| 320 | + |
| 321 | +- It provides a solution for packaging closed-source libraries and tools within the C/C++ |
| 322 | + ecosystem that cannot be included in ConanCenter, enabling their recipes to be shared |
| 323 | + and conveniently used within the Conan community. |
0 commit comments