Przewodnik po Conan – menedżerze pakietów dla C/C++
Ten artykuł to szczegółowe opracowanie dotyczące Conan, zaawansowanego menedżera zależności dla projektów w językach C i C++. Omówione zostaną instalacja, tworzenie pakietów, zarządzanie zależnościami i zaawansowane scenariusze pracy na przykładach zgodnych z najlepszymi praktykami branżowymi.
1. Wprowadzenie do zarządzania pakietami w C/C++
Język C++ przez lata nie posiadał ustandaryzowanego systemu zarządzania pakietami, co zmuszało programistów do samodzielnego, manualnego zarządzania zależnościami. Powodowało to konflikty wersji, niezgodności systemów budowania i znaczne obciążenie utrzymaniem projektów. Conan powstał jako odpowiedź na te wyzwania, oferując międzyplatformowy, niezależny językowo menedżer pakietów przeznaczony do natywnego kodu.
Integruje się z licznymi systemami budowania, takimi jak CMake, MSBuild czy Make, gwarantując kompatybilność binarną dla różnych kompilatorów, architektur i systemów operacyjnych.
Kluczową innowacją Conana jest podejście zdecentralizowane. Zamiast wymuszać scentralizowane repozytoria, Conan pozwala organizacjom na uruchomienie własnych, prywatnych serwerów pakietów przy równoczesnej obsłudze publicznych repozytoriów jak Conan Center (ponad 1200 pakietów).
Każdy pakiet zawiera metadane definiujące kompatybilność pod względem wersji kompilatora, architektury i konfiguracji budowania, co umożliwia precyzyjne rozwiązywanie zależności.
2. Instalacja i konfiguracja
Conan wymaga Pythona w wersji 3.6 lub nowszej. Instalacja przy użyciu pip:
pip install conan
Po instalacji, sprawdź wersję:
conan --version
Dla systemów z ograniczonym środowiskiem Pythona (np. dystrybucje Linux zarządzające Pythonem centralnie), zalecane jest użycie pipx:
pipx install conan
pipx ensurepath
Po instalacji należy skonfigurować zdalne repozytoria:
conan remote add conancenter https://center.conan.io
conan remote add bincrafters https://bincrafters.jfrog.io/artifactory/api/conan/public-conan
Polecenie conan profile detect automatycznie ustawi domyślne parametry środowiska. Profile określają wersje kompilatora, typ budowania (Release/Debug), architekturę oraz inne ustawienia.
3. Kluczowe pojęcia i architektura
3.1 Przepisy (package recipes)
Każdy pakiet Conan opisany jest plikiem conanfile.py, który zawiera:
- Metadane – nazwa, wersja, autor, licencja;
- Opcje konfiguracyjne – biblioteka dynamiczna/statyczna, przełączniki funkcji;
- Metody budowania – logika dla różnych platform;
- Informacje o pakiecie – artefakty wyjściowe i wymagania zależności;
Przykładowy przepis:
from conan import ConanFile
class HelloConan(ConanFile):
name = "hello"
version = "1.0"
settings = "os", "compiler", "build_type", "arch"
def source(self):
self.run("git clone https://github.com/conan-io/hello.git")
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
def package(self):
self.copy("*.h", dst="include")
self.copy("*.lib", dst="lib", keep_path=False)
3.2 Zarządzanie binariami
Conan generuje unikalne identyfikatory pakietów (package ID) przy użyciu kryptograficznych skrótów na podstawie:
- ustawień (system operacyjny, kompilator, architektura),
- opcji pakietu (np. shared=True/False),
- wersji zależności,
- rewizji przepisu.
Zapewnia to kompatybilność binarną przez wymuszenie przebudowania, gdy zmienia się dowolna istotna cecha środowiska. Pakiety są przechowywane lokalnie (~/.conan2), z możliwością synchronizacji z repozytoriami zdalnymi.
4. Tworzenie i pakietowanie projektów
4.1 Inicjalizacja projektu
Wygeneruj szkielet projektu:
conan new cmake_lib -d name=myproject -d version=0.1
W efekcie otrzymasz:
├── CMakeLists.txt
├── conanfile.py
├── include
│ └── myproject.h
├── src
│ └── myproject.cpp
└── test_package
├── CMakeLists.txt
├── conanfile.py
└── src
└── example.cpp
4.2 Budowanie i testowanie
Stwórz pakiet poleceniem:
conan create . --build=missing
Co uruchomi kolejno:
source(): pobranie kodu źródłowego;build(): wywołanie CMake/make;package(): kopiowanie artefaktów do katalogu pakietu;test_package: walidacja integracji.
Katalog test_package zawiera aplikację konsumencką sprawdzającą poprawność linkowania i działania biblioteki.
5. Zarządzanie zależnościami
5.1 Konsumowanie pakietów
Tworzymy plik conanfile.txt z listą zależności:
[requires]
opencv/4.5.5
zlib/1.2.13
[generators]
CMakeDeps
CMakeToolchain
Instalacja zależności:
mkdir build && cd build
conan install .. --output-folder=.
5.2 Integracja z CMake
Dołącz generowane pliki do CMakeLists.txt:
include(${CMAKE_BINARY_DIR}/conan_toolchain.cmake)
project(MyApp)
find_package(OpenCV REQUIRED)
add_executable(app main.cpp)
target_link_libraries(app OpenCV::opencv)
Buduj projekt standardowym workflow dla CMake:
cmake --preset conan-release
cmake --build --preset conan-release
Generator CMakeToolchain zarządza propagacją zależności tranzytywnych oraz środowiskiem cross-kompilacji.
6. Zaawansowane scenariusze
6.1 Własne konfiguracje
Nadpisz domyślne opcje w profilu:
# myprofile
[settings]
os=Windows
compiler=msvc
compiler.version=193
build_type=Release
[options]
opencv:with_cuda=True
Użycie w instalacji:
conan install .. --profile=myprofile
6.2 Integracja CI/CD
Przykładowy workflow dla GitHub Actions:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Conan
run: pip install conan
- name: Build
run: |
conan profile detect
conan install . --output-folder=build
cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake
cmake --build .
6.3 Zarządzanie artefaktami
Wysyłanie pakietów do prywatnych repozytoriów:
conan remote add myremote http://my-artifactory.com
conan upload "myproject/0.1" --remote=myremote --all
Pobieranie pakietów w projektach konsumenckich:
conan install --requires=myproject/0.1 --remote=myremote
7. Zalecane praktyki
- Versionowanie semantyczne – stosuj
major.minor.patchz określeniem kompatybilności;
requires = "zlib/[~1.2]"
- Pakietowanie komponentowe – dziel rozbudowane biblioteki na komponenty;
def package_info(self):
self.cpp_info.components["core"].libs = ["mylib_core"]
self.cpp_info.components["extras"].libs = ["mylib_extras"]
- Kompatybilność binarna – wykorzystuj
package_id()do własnych reguł kompatybilności;
def package_id(self):
self.info.settings.compiler.version = "Any"
- Integracja z systemami kontroli wersji – odwołuj się bezpośrednio do repozytoriów;
def source(self):
self.run("git clone https://github.com/my/repo.git@v2.3")
Zakończenie
Conan rewolucjonizuje zarządzanie zależnościami w projektach C/C++ zapewniając stabilny, elastyczny ekosystem dystrybucji pakietów. Jego architektura rozwiązuje kluczowe problemy rozwoju natywnego:
- Reproduktywność binarna przez kryptograficzne identyfikatory pakietów,
- Spójność między-platformowa dzięki konfigurowalnym profilom,
- Niezależność od systemu budowania poprzez rozszerzalne generatory,
- Gotowość dla biznesu przez obsługę prywatnych repozytoriów.
Jak widać, Conan integruje się płynnie z nowoczesnymi toolchainami, obsługuje cross-kompilację i zależności wielojęzyczne. Rozwija się dynamicznie – wersja 2.x to m.in. ulepszone grafy zależności, lepsza integracja z CMake i uproszczona składnia poleceń.
Dalsza nauka:
- Oficjalna dokumentacja: docs.conan.io,
- Conan Center: conan.io/center,
- Zaawansowane przykłady: Conan Community Examples.
Kompleksowe podejście Conana zapewnia powtarzalne, łatwe do utrzymania buildy na każdym etapie tworzenia oprogramowania w C/C++, a według analiz branżowych redukuje czas integracji nawet o 60%.
