概要
ここではcondaビルド済みパッケージを作成する際に、躓いた点について備忘録的にまとめていく。
目次
-
rattler-build
とは - build環境とhost環境
-
run_exports
について -
stdlib("c")
の設定 - cmakeにおけるbuildスクリプトの書き方基本
- テスト時におけるソースコードの利用
- platform-specific
noarch
package
rattler-buid
とは
prefix.dev社が開発しているRust
を使って開発されている次世代のcondaパッケージ作成ツールである。conda-build
と同様なyaml形式のレシピ(meta.yaml
ではなく recipe.yaml
)を作成し、それに基づいてpypiにおけるwheel形式のような、conda用のビルド済み配布物(.conda
ファイル)の作成を行う。
詳しくはこちらのブログから: https://prefix.dev/blog/the_new_rattler_build
build環境とhost環境
condaビルドを行う際、build環境とhost環境がある。build環境はソースコードをビルドする環境、host環境はビルド済み配布物をインストールする環境である。そのため、host環境はtarget_platformとも呼ばれ、cross-compiling (例えば、linux-64からlinux-aarch64 (intelからARM)のコンパイルを行うこと)の際にも使用される。
また、それぞれの環境に必要なパッケージが異なり、build、host環境で必要となるパッケージはそれぞれ
- buildtimeに必要なパッケージ (
cmake
,gcc
,meson
,pkg-config
などのコンパイラー・ビルドツール) - コンパイラ時にリンクするパッケージ (
libboost
,glib
,hdf5
,python
などのsharedライブラリやpythonライブラリ)
である。
Python-C++ライブラリにおけるrecipe.yaml
のrequirementセクションの例として以下のように設定する。
requirements:
build:
- ${{ compiler("c") }}
- ${{ compiler("cxx") }}
- ${{ stdlib("c") }}
- git
- cmake
- ninja
- pkg-config
host:
- pip
- python
- numpy
- cython
- setuptools
- setuptools-scm
- scikit-build-core
- scikit-build
- libboost-devel
- hdf5
このとき、libboost-devel
パッケージをbuild
セクションに移動させると、build時に以下のようなエラーが表示される。
file Multiple conflicting paths found for libc++.1.dylib:
$BUILD_PREFIX/lib//libc++.1.dylib
$PREFIX/lib/libc++.1.dylib
これはコンパイル時のリンクで-Wl,-rpath,$BUILD_PREFIX/lib $BUILD_PREFIX/lib/libboost_filesystem.dylib
と-ldl $BUILD_PREFIX/lib/libboost_atomic.dylib
が追加されるため、conflictionが起きていると思われる。
参考: https://prefix-dev.github.io/rattler-build/latest/compilers/#cross-compilation
run_exports
について
ビルド時にリンクしたライブラリ(shared library等)はruntime環境でも必要になる。そのため、hostやbuildのrequirementで指定したパッケージをruntimeでのrequirementにも自動で追加させるためにrun_exports
が必要となる。
requirements:
run_exports: my-package
例えば、numpy
をhost環境のrequirementとして指定した場合、runtime環境でのrequirementに明示的に指定する必要はない。レシピ作成者がリンク時に利用したものと同じバージョンのnumpy
を自動的にruntime環境で指定してくれる。
参考: https://prefix-dev.github.io/rattler-build/latest/reference/recipe_file/#run-exports
stdlib("c")
の設定
build環境で${{ compiler("c") }}
を指定する場合、conda-forgeにおいてC言語のstandard libraryをstdlib("c")
として明示的に指定する必要がある。
参照: https://conda-forge.org/news/2024/03/24/stdlib-migration/
conda-forgeにおいてcompilerやstdlibは、conda_build_config.yamlにあるデフォル値によって決まるが、ローカルなPC環境でratller-buildを用いる場合、variants.yaml
を手動で作成する必要がある。LinuxとmacOSにおけるC言語のstdlibのみを設定する場合、以下のようになる。
c_stdlib:
- if: linux
then: sysroot
- if: osx
then: macosx_deployment_target
c_stdlib_version:
- if: linux
then: 2.17
- if: osx and x86_64
then: 10.13
- if: osx and arm64
then: 11.0
また、このファイルにpythonのバージョンを複数設定することで、github actionにおけるmatrixのような、複数ビルドも可能となる。(conda-forgeのconda_build_config.yamlのpythonセクションを参照)
cmakeにおけるbuildスクリプトの書き方基本
cmake
をbuild requirementに指定した場合、CMAKE_ARGS
など自動的に設定される。
また、cmakeにおけるPython_EXECUTABLE
を、Host環境上のpythonに指定する必要がある。
以下にcmake
とninja
を用いたビルド・コンパイルスクリプト(build.sh
)の例を示す。
#!/bin/bash
# CMake extra configuration:
extra_cmake_args=(
-G Ninja
-DCMAKE_INSTALL_LIBDIR=lib
-DBUILD_SHARED_LIBS=ON
# Python bindings
-DPython_EXECUTABLE="$PYTHON"
-DPython3_EXECUTABLE="$PYTHON"
)
cmake ${CMAKE_ARGS} "${extra_cmake_args[@]}" \
-DCMAKE_PREFIX_PATH=$PREFIX \
-DCMAKE_INSTALL_PREFIX=$PREFIX \
-B build -S $SRC_DIR
# Build and install
ninja
ninja install
ビルド時のデフォルト環境変数についてはこちらを参照
参考: https://conda-forge.org/docs/maintainer/knowledge_base/#using-cmake
テスト時におけるソースコードの利用
ビルド配布物を作成後、rattler-buildではテストが行われる。その際、ビルド環境は削除され、ソースコードへのパスである$SRC_DIR
も利用できない。
テスト環境へ、ソースコードにあるテストスクリプトや設定ファイルをコピーするためにはrecipe.yaml
のtestセクションを以下のように設定する。
tests:
- script:
- pytest
files:
source:
- python/tests/
- pyproject.toml
requirements:
run:
- pytest
ここではpytest
を用いたテストスクリプトを想定している。script:
におけるfile: sources:
にテスト時必要となるファイルをソースフォルダからコピーできる。
参考: https://prefix-dev.github.io/rattler-build/latest/reference/recipe_file/#extra-test-files
Platform-specific noarch
package
noarch
パッケージとはpure-PythonパッケージのようなCPU architectureやOSに依存しない(コンパイラされたバイナリーファイルを含まない)パッケージである。しかし、例えば、activationスクリプトを含める場合や、runtime依存にOS依存がある場合、プラットフォーム(OS)依存のnoarch
パッケージが必要となる。
このとき、conda-forgeでのビルドであればこれを達成できる。
方法
recipe.yaml
のrun requirementにてターゲットOSを示すvirtual packages: __linux
, __osx
, __win
, __unix
を加える。(__unix
はLinuxとMacOS両方を示す。)
build:
number: 0
noarch: python
requirements:
# ...
run:
- python >=${{ python_min }}
- numpy
- if: linux
then:
- __linux
- linux-only-dependency
- if: osx
then:
- __osx
- osx-only-dependency
- if: win
then:
- __win
- windows-only-dependency
conda-forgeにおいて、noarch
だとlinux_64
のCIランナーしかデフォルトで走らないが、複数のビルドplatformを走らせたい場合はconda-forge.yaml
のnoarch_platforms
に追加する。
noarch_platforms:
- linux_64
- osx_64
- win_64