diff --git a/.github/install-dependency-packages.sh b/.github/install-dependency-packages.sh new file mode 100755 index 00000000..dc2ad19e --- /dev/null +++ b/.github/install-dependency-packages.sh @@ -0,0 +1,106 @@ +#!/bin/bash + +set -e + +############################## +# LINUX +############################## +GENERAL_PACKAGE_LIST_LINUX=( + python + gcc + make + cmake + tree + pkgconf + ninja + meson +) +IGUANA_PACKAGE_LIST_LINUX=( + fmt +) + +############################## +# MACOS +############################## +GENERAL_PACKAGE_LIST_MACOS=( + tree + ninja + meson +) +IGUANA_PACKAGE_LIST_MACOS=( + fmt +) + +############################################# + +if [ $# -ne 2 ]; then + echo "USAGE: $0 [runner] [latest/minver]" >&2 + exit 2 +fi +runner=$1 +verset=$2 +summary_file=pkg_summary.md +> $summary_file + +case $verset in + latest) echo "[+] Prefer latest version for iguana-specific dependencies" ;; + minver) echo "[+] Prefer minimum required version for iguana-specific dependencies" ;; + *) + echo "ERROR: unknown verset '$verset'" >&2 + exit 1 + ;; +esac + +############################################# + +info_pacman() { + echo "| \`$1\` | $(pacman -Qi $1 | grep -Po '^Version\s*: \K.+') |" >> $summary_file +} + +info_homebrew() { + echo "| \`$1\` | $(brew info $1 | head -n1) |" >> $summary_file +} + +############################################# + +case $runner in + + ubuntu*) + echo "[+] On Linux runner" + echo "[+] UPDATING" + pacman -Syu --noconfirm + ### install latest version of general packages + for pkg in ${GENERAL_PACKAGE_LIST_LINUX[@]}; do + echo "[+] INSTALLING PACKAGE $pkg" + pacman -S --noconfirm $pkg + info_pacman $pkg + done + ### install either the latest or minver version of iguana-specific packages + for pkg in ${IGUANA_PACKAGE_LIST_LINUX[@]}; do + echo "[+] INSTALLING PACKAGE $pkg" + case $verset in + latest) pacman -S --noconfirm $pkg ;; + minver) pacman -U --noconfirm $(meson/minimum-version.sh $pkg ALA) ;; + esac + info_pacman $pkg + done + ;; + + macos*) + [ "$verset" = "minver" ] && echo "ERROR: 'minver' not implemented for macOS" >&2 && exit 1 + echo "[+] On macOS runner" + export NO_COLOR=1 + ### install the latest version of all packages + for pkg in ${GENERAL_PACKAGE_LIST_MACOS[@]} ${IGUANA_PACKAGE_LIST_MACOS[@]}; do + echo "[+] INSTALLING PACKAGE $pkg" + brew install $pkg + info_homebrew $pkg + done + ;; + + *) + echo "ERROR: runner '$runner' is unknown to $0" >&2 + exit 1 + ;; + +esac diff --git a/.github/test-consumer-build.sh b/.github/test-consumer-build.sh index c62a07b3..9773bb83 100755 --- a/.github/test-consumer-build.sh +++ b/.github/test-consumer-build.sh @@ -25,9 +25,9 @@ exe() { # build and test case $tool in cmake) - exe cmake -S $source_dir -B $build_dir + exe cmake -S $source_dir -B $build_dir -G Ninja --install-prefix $install_dir exe cmake --build $build_dir - exe cmake --install $build_dir --prefix $install_dir + exe cmake --install $build_dir ;; make) pushd $source_dir diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d0a74c69..709d814e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,11 +7,16 @@ on: description: 'GitHub runner' required: true type: string - num_threads: - description: 'Number of threads or CPUs' + container: + description: 'Docker container' required: false type: string - default: 2 + default: '' + verset: + description: 'Dependency version set' + required: false + type: string + default: 'latest' defaults: run: @@ -19,7 +24,6 @@ defaults: env: hipo_version: 4.0.1 - fmt_version: 9.1.0 # for Linux runners, whereas macOS uses Homebrew version num_events: 10 jobs: @@ -30,7 +34,13 @@ jobs: build_hipo: name: Build HIPO runs-on: ${{ inputs.runner }} + container: + image: ${{ inputs.container }} steps: + - name: checkout iguana for dependency installation script + uses: actions/checkout@v4 + - name: install dependency packages + run: .github/install-dependency-packages.sh ${{ inputs.runner }} ${{ inputs.verset }} - name: checkout hipo uses: actions/checkout@v4 with: @@ -38,45 +48,16 @@ jobs: ref: ${{ env.hipo_version }} - name: build run: | - cmake -S . -B build -DCMAKE_INSTALL_PREFIX=hipo - cmake --build build -j${{ inputs.num_threads }} + cmake -S . -B build -G Ninja --install-prefix $(pwd)/hipo + cmake --build build cmake --install build tar czvf hipo{.tar.gz,} - - run: brew install tree - if: ${{ inputs.runner == 'macos-latest' }} - - run: tree hipo - uses: actions/upload-artifact@v4 with: name: build_deps_hipo retention-days: 1 path: hipo.tar.gz - build_fmt: - name: Build fmt - runs-on: ${{ inputs.runner }} - steps: - - name: checkout fmt - if: ${{ inputs.runner != 'macos-latest' }} # prefer Homebrew fmt installation on macOS (needed on every step, since we just want this job to succeed on macOS) - uses: actions/checkout@v4 - with: - repository: fmtlib/fmt - ref: ${{ env.fmt_version }} - - name: build - if: ${{ inputs.runner != 'macos-latest' }} - run: | - cmake -S . -B build -DCMAKE_INSTALL_PREFIX=fmt -DCMAKE_POSITION_INDEPENDENT_CODE=ON - cmake --build build -j${{ inputs.num_threads }} - cmake --install build - tar czvf fmt{.tar.gz,} - - run: tree fmt - if: ${{ inputs.runner != 'macos-latest' }} - - uses: actions/upload-artifact@v4 - if: ${{ inputs.runner != 'macos-latest' }} - with: - name: build_deps_fmt - retention-days: 1 - path: fmt.tar.gz - # build ######################################################### @@ -84,8 +65,9 @@ jobs: name: Build Iguana needs: - build_hipo - - build_fmt runs-on: ${{ inputs.runner }} + container: + image: ${{ inputs.container }} strategy: fail-fast: false matrix: @@ -100,44 +82,28 @@ jobs: clean: false fetch-tags: true fetch-depth: 0 - - name: setup meson - run: python -m pip install meson ninja ### dependencies - - name: get dependency build artifacts + - name: install dependency packages + run: .github/install-dependency-packages.sh ${{ inputs.runner }} ${{ inputs.verset }} + - name: get local dependencies uses: actions/download-artifact@v4 with: pattern: build_deps_* merge-multiple: true - - run: brew install fmt - if: ${{ inputs.runner == 'macos-latest' }} - - name: untar build + - name: untar local dependencies run: ls *.tar.gz | xargs -I{} tar xzvf {} + - name: tree local dependencies + run: tree hipo - name: summarize dependencies run: | echo '### Dependencies' >> $GITHUB_STEP_SUMMARY echo '| Dependency | Version |' >> $GITHUB_STEP_SUMMARY echo '| --- | --- |' >> $GITHUB_STEP_SUMMARY - for dep in python meson ninja ; do - echo "| \`$dep\` | $($dep --version) |" >> $GITHUB_STEP_SUMMARY - done - if [ "${{ inputs.runner }}" = "macos-latest" ]; then - echo "| \`fmt\` | $(brew info fmt | head -n1) |" >> $GITHUB_STEP_SUMMARY - else - echo "| \`fmt\` | ${{ env.fmt_version }} |" >> $GITHUB_STEP_SUMMARY - fi echo "| \`hipo\` | ${{ env.hipo_version }} |" >> $GITHUB_STEP_SUMMARY - ### tree - - run: brew install tree - if: ${{ inputs.runner == 'macos-latest' }} - - run: tree + cat pkg_summary.md >> $GITHUB_STEP_SUMMARY ### build iguana - - name: resolve dependencies - run: | - if [ ${{ inputs.runner }} = "macos-latest" ]; then - meson/resolve-dependencies.py --ini native.ini --hipo ./hipo # fmt is a system installation on macOS runners - else - meson/resolve-dependencies.py --ini native.ini --hipo ./hipo --fmt ./fmt # fmt is locally built on Linux runners - fi + - name: resolve local dependencies + run: meson/resolve-dependencies.py --ini native.ini --hipo ./hipo - name: meson setup run: meson setup --native-file=native.ini build-iguana - name: meson configure @@ -214,6 +180,8 @@ jobs: - download_validation_files - build_iguana runs-on: ${{ inputs.runner }} + container: + image: ${{ inputs.container }} strategy: fail-fast: false matrix: @@ -222,25 +190,18 @@ jobs: - { binding: cpp, extension: '' } - { binding: python, extension: '.py' } steps: - ### setup + ### dependencies and test data - uses: actions/checkout@v4 with: path: iguana_src # keep source code isolated - - name: install python binding runtime dependencies - if: ${{ matrix.binding == 'python' }} - run: | - python -m venv .venv - source .venv/bin/activate - echo PATH=$PATH >> $GITHUB_ENV - python -m pip install -r iguana_src/bind/python/requirements.txt - ### dependencies and test data + - name: install dependency packages + run: .github/install-dependency-packages.sh ${{ inputs.runner }} ${{ inputs.verset }} + working-directory: iguana_src - name: get dependency build artifacts uses: actions/download-artifact@v4 with: pattern: build_deps_* merge-multiple: true - - run: brew install fmt - if: ${{ inputs.runner == 'macos-latest' }} - name: get iguana build artifacts uses: actions/download-artifact@v4 with: @@ -253,11 +214,16 @@ jobs: run: | ls *.tar.gz | xargs -I{} tar xzvf {} rm -v *.tar.gz - ### tree - - run: brew install tree - if: ${{ inputs.runner == 'macos-latest' }} - name: tree artifacts run: tree + ### setup python virtaul environment (for python binding tests) + - name: install python binding runtime dependencies + if: ${{ matrix.binding == 'python' }} + run: | + python -m venv .venv + source .venv/bin/activate + echo PATH=$PATH >> $GITHUB_ENV + python -m pip install -r iguana_src/bind/python/requirements.txt ### set env vars - depends on runner and binding - name: source environment for Linux and python if: ${{ inputs.runner == 'ubuntu-latest' && matrix.binding == 'python' }} @@ -290,24 +256,22 @@ jobs: - download_validation_files - build_iguana runs-on: ${{ inputs.runner }} + container: + image: ${{ inputs.container }} strategy: fail-fast: false matrix: tool: [ cmake, make, meson ] steps: - ### setup - - uses: actions/checkout@v4 - - name: setup meson - if: ${{ matrix.tool == 'meson' }} - run: python -m pip install meson ninja ### dependencies and test data + - uses: actions/checkout@v4 + - name: install dependency packages + run: .github/install-dependency-packages.sh ${{ inputs.runner }} ${{ inputs.verset }} - name: get dependency build artifacts uses: actions/download-artifact@v4 with: pattern: build_deps_* merge-multiple: true - - run: brew install fmt - if: ${{ inputs.runner == 'macos-latest' }} - name: get iguana build artifacts uses: actions/download-artifact@v4 with: diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 7e0502ed..823d370d 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -11,8 +11,9 @@ concurrency: cancel-in-progress: true jobs: - Linux: + linux: + name: Linux (latest) uses: ./.github/workflows/ci.yml with: runner: ubuntu-latest - num_threads: 4 + container: archlinux/archlinux:latest diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 90f080fa..7ceedd0e 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -12,7 +12,7 @@ concurrency: jobs: macOS: + name: macOS (latest) uses: ./.github/workflows/ci.yml with: runner: macos-latest - num_threads: 3 diff --git a/.github/workflows/minver.yml b/.github/workflows/minver.yml new file mode 100644 index 00000000..312f43a5 --- /dev/null +++ b/.github/workflows/minver.yml @@ -0,0 +1,20 @@ +name: MinVer # minimum required-version of dependencies on Linux + +on: + pull_request: + push: + branches: [ main ] + tags: [ '*' ] + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + Linux: + name: Linux (minver) + uses: ./.github/workflows/ci.yml + with: + runner: ubuntu-latest + container: archlinux/archlinux:latest + verset: minver diff --git a/meson.build b/meson.build index 4404a9e8..9d0cb797 100644 --- a/meson.build +++ b/meson.build @@ -25,9 +25,18 @@ add_project_arguments( ) # resolve dependencies -fmt_dep = dependency('fmt', version: '>=9.1.0', method: 'pkg-config') -hipo_dep = dependency('hipo4', version: '>=4.0.1', method: 'pkg-config') +# NOTE: those that are typically installed by package managers should use `meson/minimum-version.sh` +fmt_dep = dependency( + 'fmt', + method: 'pkg-config', + version: run_command('meson' / 'minimum-version.sh', 'fmt', check: true).stdout().strip() +) yamlcpp_dep = dependency('yaml-cpp', version: '>=0.8.0', method: 'pkg-config') +hipo_dep = dependency( + 'hipo4', + method: 'pkg-config', + version: '>=4.0.1', +) # list of dependencies # FIXME: for users which use LD_LIBRARY_PATH, we should try to keep this list diff --git a/meson/minimum-version.sh b/meson/minimum-version.sh new file mode 100755 index 00000000..6361ab17 --- /dev/null +++ b/meson/minimum-version.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +if [ $# -eq 0 ]; then + echo """USAGE: $0 [package] [command(default=meson)] + + package: the package name; since this varies between package manager + repositories, we prefer to use the name from that used by the CI + + command: meson return a string for meson function \`dependency()\` + + ALA return a URL for the Arch Linux Archive (ALA), for CI + https://archive.archlinux.org/ + """ + exit 2 +fi +dep=$1 +[ $# -ge 2 ] && cmd=$2 || cmd=meson + +############################################# + +case $dep in + fmt) + result_meson='>=9.1.0' + result_ala='https://archive.archlinux.org/packages/f/fmt/fmt-9.1.0-4-x86_64.pkg.tar.zst' + ;; + *) + echo "ERROR: dependency '$dep' is unknown" >&2 + exit 1 + ;; +esac + +############################################# + +case $cmd in + meson) echo $result_meson ;; + ALA) echo $result_ala ;; + *) + echo "ERROR: command '$cmd' is unknown" >&2 + exit 1 + ;; +esac