diff --git a/.ci/check-debian-packaging.sh b/.ci/check-debian-packaging.sh new file mode 100755 index 0000000..4d27539 --- /dev/null +++ b/.ci/check-debian-packaging.sh @@ -0,0 +1,175 @@ +#!/bin/sh +# Static validation of the debian/ packaging metadata in this repository. +# +# A real package build compiles all of OpenModelica and takes hours, so the +# nightly Jenkins job is the only place the packaging is exercised end to end. +# This script checks what can be checked in seconds: that the control files +# parse, that debhelper accepts the declared compatibility level on this +# distribution, that debian/rules only calls helpers that still exist and only +# passes options that still exist at that compat level, and that every +# debian/. file belongs to a binary package we build. +# +# It does NOT catch a .install glob that stopped matching because upstream moved +# a file; only a real build does that. +# +# Run it from the top of the repository, inside a distribution we ship for: +# +# docker run --rm -v "$PWD:/src" -w /src ubuntu:24.04 sh -c \ +# 'apt-get update -qq && apt-get install -qy --no-install-recommends \ +# debhelper dpkg-dev && .ci/check-debian-packaging.sh' + +set -eu + +# Keep in sync with the compat level declared in the control files. +EXPECTED_COMPAT=13 + +TREES="debian OMPlot/debian OMOptim/debian OpenModelica-doc/debian" + +# debhelper config files named debian/.. A typo in the +# package part makes debhelper ignore the file without a word, and the package +# then ships empty, so the package name has to exist in debian/control. +PKG_SUFFIXES="install docs dirs links examples manpages menu menu-method info + init service tmpfiles sharedmimeinfo lintian-overrides preinst postinst prerm + postrm triggers README.Debian NEWS" + +# Command/option combinations debhelper has removed. The compat level each was +# dropped in is listed in debhelper-compat-upgrade-checklist(7); add a line here +# when a helper we call loses an option we pass. +# Fields: helper:option:compat level that removed it:what to use instead +removed_usage() { + cat <<'REMOVED' +dh_install:--list-missing:12:dh_missing --list-missing +dh_install:--fail-missing:12:dh_missing --fail-missing +dh_clean:-k:12:dh_prep +dh_installinit:--no-restart-on-upgrade:12:--no-stop-on-upgrade +REMOVED +} + +status=0 +fail() { echo " FAIL: $*" >&2; status=1; } +ok() { echo " ok: $*"; } + +command -v dh_assistant >/dev/null 2>&1 || { + echo "dh_assistant not found; this script needs debhelper >= 13.5" >&2 + exit 2 +} + +scratch=$(mktemp -d) +trap 'rm -rf "$scratch"' EXIT + +echo "debhelper $(dpkg-query -f '${Version}' -W debhelper) on $(. /etc/os-release; echo "$PRETTY_NAME")" + +for tree in $TREES; do + echo "== $tree" + work="$scratch/$(echo "$tree" | tr / _)" + mkdir -p "$work" + cp -a "$tree" "$work/debian" + + # debian/changelog is a template. The source-package job fills it in the same + # way (see update-source-repo.py and make-packages.py in the apt-build repo). + sed -i -e 's/@REV@/1.0.0~dev-0-g0000000/' -e 's/@DISTS@/unstable/' \ + -e "s/@TIME@/$(date -R)/" "$work/debian/changelog" + + if [ -e "$work/debian/compat" ]; then + fail "debian/compat still exists; the compat level belongs in Build-Depends: debhelper-compat" + else + ok "no stale debian/compat" + fi + + if ! ( + cd "$work" || exit 1 + + if ! changelog=$(dpkg-parsechangelog 2>&1); then + printf '%s\n' "$changelog" >&2 + echo " FAIL: debian/changelog does not parse" >&2 + exit 1 + fi + echo " ok: changelog parses ($(printf '%s\n' "$changelog" | sed -n 's/^Source: //p')" \ + "$(printf '%s\n' "$changelog" | sed -n 's/^Version: //p'))" + + if ! perl -MDpkg::Control::Info -e ' + my $c = Dpkg::Control::Info->new("debian/control"); + print $_->{Package}, "\n" for $c->get_packages(); + ' > packages.txt 2> control.err; then + cat control.err >&2 + echo " FAIL: debian/control does not parse" >&2 + exit 1 + fi + if ! [ -s packages.txt ]; then + echo " FAIL: debian/control declares no binary packages" >&2 + exit 1 + fi + echo " ok: control parses ($(wc -l < packages.txt | tr -d ' ') binary packages)" + + # The check that catches a mis-declared compat level: debhelper accepts only + # "debhelper-compat (= N)", and errors out if this distribution's debhelper + # does not support N. + if ! compat=$(dh_assistant active-compat-level 2>&1); then + printf '%s\n' "$compat" >&2 + echo " FAIL: debhelper rejects the declared compatibility level" >&2 + exit 1 + fi + compat=$(printf '%s\n' "$compat" | sed -n 's/.*"active-compat-level":\([0-9]*\).*/\1/p') + if [ "$compat" != "$EXPECTED_COMPAT" ]; then + echo " FAIL: active compat level is '$compat', expected $EXPECTED_COMPAT" >&2 + exit 1 + fi + echo " ok: compat level $compat" + ); then + status=1 + continue + fi + + packages="$work/packages.txt" + + # Every helper debian/rules calls has to still ship in this debhelper. + sed -e 's/#.*//' "$tree/rules" > "$work/rules.uncommented" + missing="" + for helper in $(grep -o 'dh_[a-z0-9_]*' "$work/rules.uncommented" | sort -u); do + command -v "$helper" >/dev/null 2>&1 || missing="$missing $helper" + done + if [ -n "$missing" ]; then + fail "debian/rules calls helpers that no longer exist:$missing" + else + ok "every dh_* helper called by debian/rules exists" + fi + + # ... and must not pass options removed at or below our compat level. + removed="" + removed_usage > "$work/removed-usage" + while IFS=: read -r cmd opt gone use; do + [ -n "$cmd" ] || continue + [ "$EXPECTED_COMPAT" -ge "$gone" ] || continue + if grep -q -- "$cmd[^&|;]*[[:space:]]$opt\\b" "$work/rules.uncommented"; then + removed="$removed + $cmd $opt (gone in compat $gone; use: $use)" + fi + done < "$work/removed-usage" + if [ -n "$removed" ]; then + fail "debian/rules uses debhelper options removed at compat $EXPECTED_COMPAT:$removed" + else + ok "no debhelper options removed at compat $EXPECTED_COMPAT" + fi + + orphans="" + for f in "$tree"/*; do + [ -f "$f" ] || continue + base=${f##*/} + for suffix in $PKG_SUFFIXES; do + case "$base" in + *".$suffix") + pkg=${base%".$suffix"} + grep -qx "$pkg" "$packages" || orphans="$orphans $base" + ;; + esac + done + done + if [ -n "$orphans" ]; then + fail "config files naming a package that is not in debian/control:$orphans" + else + ok "every debian/. file matches a binary package" + fi +done + +[ $status -eq 0 ] && echo "all checks passed" +exit $status diff --git a/.ci/check-rpm-spec.sh b/.ci/check-rpm-spec.sh new file mode 100755 index 0000000..3af633f --- /dev/null +++ b/.ci/check-rpm-spec.sh @@ -0,0 +1,78 @@ +#!/bin/sh +# Static validation of rpm/SPECS/openmodelica.spec.tpl. +# +# The template is not a valid spec file on its own: the RPM job in the apt-build +# repository substitutes a set of upper-case placeholders into it before calling +# rpmbuild (see the rpmInfo map in apt-build's Jenkinsfile). This script does +# the same substitution with representative values and then asks rpm itself to +# parse the result, which catches the syntax mistakes that have broken nightly +# RPM builds before: a missing %, an empty %define, a stray comment. +# +# It does not build anything, so it says nothing about BuildRequires being +# installable or the %files list matching what the build produces. +# +# Run it from the top of the repository, inside a distribution we ship for: +# +# docker run --rm -v "$PWD:/src" -w /src fedora:43 sh -c \ +# 'dnf install -y rpm-build >/dev/null && .ci/check-rpm-spec.sh' + +set -eu + +TEMPLATE=rpm/SPECS/openmodelica.spec.tpl + +# Representative values, in the order the Jenkins job applies them. They only +# have to be shaped like the real thing; the point is to parse the spec. +NAME=openmodelica-nightly +DEBVERSION=1.28.0~dev-489-gda9d1ce +RPMVERSION=1.28.0~dev~489~gda9d1ce +CONFIGUREFLAGS= +DOCUMENTATIONVERSION=latest +PATCHCMDS= +PATCHES= +PRIORITY=1018000 +PRIVATELIBS='lib.*Modelica.*|lib[oO][mM][^n].*[.]so.*|libklu[.]so.*|libsundials.*' +RELEASENUM=1 +BRANCH=nightly +DATE=$(LC_ALL=C date "+%a %b %d %Y") + +command -v rpmspec >/dev/null 2>&1 || { + echo "rpmspec not found; install rpm-build" >&2 + exit 2 +} + +scratch=$(mktemp -d) +trap 'rm -rf "$scratch"' EXIT +spec="$scratch/openmodelica.spec" + +# '%' is safe as the sed delimiter: none of the values above contain one. +sed -e "s%NAME%$NAME%g" \ + -e "s%DEBVERSION%$DEBVERSION%g" \ + -e "s%RPMVERSION%$RPMVERSION%g" \ + -e "s%CONFIGUREFLAGS%$CONFIGUREFLAGS%g" \ + -e "s%DOCUMENTATIONVERSION%$DOCUMENTATIONVERSION%g" \ + -e "s%PATCHCMDS%$PATCHCMDS%g" \ + -e "s%PATCHES%$PATCHES%g" \ + -e "s%PRIORITY%$PRIORITY%g" \ + -e "s%PRIVATELIBS%$PRIVATELIBS%g" \ + -e "s%RELEASENUM%$RELEASENUM%g" \ + -e "s%BRANCH%$BRANCH%g" \ + -e "s%DATE%$DATE%g" \ + "$TEMPLATE" > "$spec" + +echo "rpm $(rpm --version | awk '{print $3}') on $(. /etc/os-release; echo "$PRETTY_NAME")" + +if ! out=$(rpmspec -P "$spec" 2>&1 >/dev/null); then + printf '%s\n' "$out" >&2 + echo " FAIL: $TEMPLATE does not parse" >&2 + exit 1 +fi +[ -z "$out" ] || printf '%s\n' "$out" +echo " ok: template parses" + +nevr=$(rpmspec -q --srpm --qf '%{name} %{version}-%{release}\n' "$spec" 2>/dev/null) +echo " ok: source package would be $nevr" + +subpkgs=$(rpmspec -q --qf '%{name}\n' "$spec" 2>/dev/null | sort -u | tr '\n' ' ') +echo " ok: binary packages: $subpkgs" + +echo "all checks passed" diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..b7c2df9 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,17 @@ +# Keep the actions used by the workflows in .github/workflows up to date. +# +# They are pinned to commit SHAs, so without this they silently stay on whatever +# was current when the workflow was written. Quarterly is often enough for a +# repository whose CI is three files, and the group means it arrives as one pull +# request rather than one per action. +version: 2 +updates: + - package-ecosystem: github-actions + # For github-actions this means .github/workflows, not a subdirectory. + directory: / + schedule: + interval: quarterly + groups: + actions: + patterns: + - "*" diff --git a/.github/workflows/build-deb.yml b/.github/workflows/build-deb.yml new file mode 100644 index 0000000..1b6b73c --- /dev/null +++ b/.github/workflows/build-deb.yml @@ -0,0 +1,110 @@ +# Full build of OpenModelica plus the Debian packages, the way the nightly +# Jenkins job does it: configure/make (autoconf) from a git checkout, then +# dpkg-buildpackage using the debian/ directory of this repository. +# +# This is the only job that can catch a .install glob that stopped matching +# because upstream moved or dropped a file -- the failure that breaks the +# nightly build. It compiles all of OpenModelica, so it takes hours. The fast +# metadata-only checks live in packaging.yml. +# +# Uses the Autoconf + Makefile build; to be switched to the CMake build later. +name: full deb build + +on: + workflow_dispatch: + inputs: + openmodelica-ref: + description: OpenModelica git ref to build + default: master + pull_request: + paths: + - 'debian/**' + - '.github/workflows/build-deb.yml' + +permissions: + contents: read + +jobs: + build: + # Only ubuntu-latest: Jenkins covers the rest of the distribution matrix. + runs-on: ubuntu-latest + timeout-minutes: 360 + + steps: + - name: Check out the build scripts + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + path: buildscripts + + - name: Check out OpenModelica + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: OpenModelica/OpenModelica + ref: ${{ inputs.openmodelica-ref || 'master' }} + submodules: recursive + # The package version comes from git describe, so the tags and the + # history behind them have to be there. + fetch-depth: 0 + path: openmodelica + + - name: Free up disk space + run: | + # A full OpenModelica build does not fit next to the preinstalled + # toolchains on a hosted runner. + sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \ + /usr/local/share/boost "$AGENT_TOOLSDIRECTORY" || true + df -h / + + - name: Install build dependencies + run: | + sudo apt-get update -qq + sudo DEBIAN_FRONTEND=noninteractive apt-get install -qy \ + --no-install-recommends build-essential devscripts equivs fakeroot + # Same approach as the build-deps images (Dockerfile.deb.template in + # the apt-build repository): install exactly what debian/control asks + # for, so a missing or renamed build dependency fails here. + sudo mk-build-deps --install --remove \ + --tool 'apt-get -y --no-install-recommends' \ + buildscripts/debian/control + + - name: Assemble the source tree + working-directory: openmodelica + run: | + # Version string exactly as update-source-repo.py builds it: + # v1.28.0-dev-489-gda9d1ce -> 1.28.0~dev-489-gda9d1ce + version=$(git describe --abbrev=7 --tags --match='v*.*.*' 2>/dev/null | + sed -e 's/^v//' -e 's/-/~/') || true + if [ -z "$version" ]; then + version="0.0.0~ci-$(git rev-parse --short HEAD)" + echo "git describe found no tag; using $version" + fi + echo "Building openmodelica $version" + + rm -rf debian + cp -a ../buildscripts/debian debian + sed -i -e "s/@REV@/$version/" -e "s/@TIME@/$(date -R)/" debian/changelog + head -1 debian/changelog + + - name: Build the packages + working-directory: openmodelica + run: dpkg-buildpackage -rfakeroot -b -us -uc -j"$(nproc)" + + - name: Show what was built + if: always() + run: | + ls -la *.deb || true + for deb in *.deb; do + [ -e "$deb" ] || continue + echo "=== $deb" + dpkg-deb -I "$deb" | sed -n 's/^ //p' | grep -E '^(Package|Version|Architecture|Depends):' || true + dpkg-deb -c "$deb" | wc -l | xargs echo " files:" + done + + - name: Upload packages + if: always() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: debs + path: '*.deb' + if-no-files-found: warn + retention-days: 7 diff --git a/.github/workflows/packaging.yml b/.github/workflows/packaging.yml new file mode 100644 index 0000000..88c2422 --- /dev/null +++ b/.github/workflows/packaging.yml @@ -0,0 +1,59 @@ +# Fast sanity checks on the packaging metadata in this repository. +# +# The nightly Jenkins job in the apt-build repository is the only place a +# package is actually built, and it takes hours, so nothing here builds +# anything. These jobs only check that the metadata is well formed and that +# every distribution we ship for still accepts it -- which is what breaks when +# a helper, a compat level or a spec macro is retired under us. +# +# The image lists mirror current-linux-os-releases.json in the apt-build repo; +# update them when a distribution is added or goes EOL. +name: packaging + +on: + push: + branches: [master] + pull_request: + workflow_dispatch: + +jobs: + debian: + name: debian (${{ matrix.image }}) + runs-on: ubuntu-latest + container: ${{ matrix.image }} + strategy: + fail-fast: false + matrix: + image: + - ubuntu:jammy + - ubuntu:noble + - ubuntu:resolute + - debian:trixie + steps: + - name: Install debhelper + run: | + apt-get update -qq + DEBIAN_FRONTEND=noninteractive apt-get install -qy --no-install-recommends \ + debhelper dpkg-dev + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - run: .ci/check-debian-packaging.sh + + rpm: + name: rpm (${{ matrix.image }}) + runs-on: ubuntu-latest + container: ${{ matrix.image }} + strategy: + fail-fast: false + matrix: + image: + - almalinux:8 + - almalinux:9 + - almalinux:10 + - fedora:43 + - fedora:44 + steps: + - name: Install rpm-build + run: | + (command -v dnf >/dev/null && dnf install -y rpm-build) || yum install -y rpm-build + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - run: .ci/check-rpm-spec.sh diff --git a/OMOptim/debian/compat b/OMOptim/debian/compat deleted file mode 100644 index ec63514..0000000 --- a/OMOptim/debian/compat +++ /dev/null @@ -1 +0,0 @@ -9 diff --git a/OMOptim/debian/control b/OMOptim/debian/control index 66e6d85..7764919 100644 --- a/OMOptim/debian/control +++ b/OMOptim/debian/control @@ -2,7 +2,7 @@ Source: omoptim Section: math Priority: optional Maintainer: OpenModelica Build System -Build-Depends: debhelper (>= 9.0.0), +Build-Depends: debhelper-compat (= 13), libqt4-dev (>= 4.4.3), omniidl:native (>= 4.0.0) | omniidl4:native | omniidl (>= 4.0.0) | omniidl4, libomniorb4-dev, diff --git a/OMPlot/debian/compat b/OMPlot/debian/compat deleted file mode 100644 index ec63514..0000000 --- a/OMPlot/debian/compat +++ /dev/null @@ -1 +0,0 @@ -9 diff --git a/OMPlot/debian/control b/OMPlot/debian/control index 533f43a..4773904 100644 --- a/OMPlot/debian/control +++ b/OMPlot/debian/control @@ -2,7 +2,7 @@ Source: omplot Section: math Priority: optional Maintainer: OpenModelica Build System -Build-Depends: debhelper (>= 9.0.0), +Build-Depends: debhelper-compat (= 13), libqt4-dev (>= 4.4.3), autoconf, omc-common diff --git a/OpenModelica-doc/debian/compat b/OpenModelica-doc/debian/compat deleted file mode 100644 index ec63514..0000000 --- a/OpenModelica-doc/debian/compat +++ /dev/null @@ -1 +0,0 @@ -9 diff --git a/OpenModelica-doc/debian/control b/OpenModelica-doc/debian/control index c0748a5..a3a01af 100644 --- a/OpenModelica-doc/debian/control +++ b/OpenModelica-doc/debian/control @@ -2,7 +2,7 @@ Source: openmodelica-doc Section: math Priority: optional Maintainer: OpenModelica Build System -Build-Depends: debhelper (>= 9.0.0) +Build-Depends: debhelper-compat (= 13) Standards-Version: 3.9.6 Package: omc-doc diff --git a/README.md b/README.md index ec829a5..04f1c2f 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,177 @@ # OpenModelicaBuildScripts +A collection of scripts that can build OpenModelica packages on miscellaneous platforms. -A collection of scripts that can build OpenModelica packages on miscellaneous platforms +Nothing here builds OpenModelica on its own. This repository holds the +*packaging metadata*; the jobs that use it live in the private +[apt-build](gitlab.liu.se/OpenModelica/apt-build) repository and run on the +OpenModelica Jenkins. +Windows build scripts are at +[OpenModelicaSetup](https://github.com/OpenModelica/OpenModelicaSetup/). + +## Layout + +| Path | What it is | +| --- | --- | +| [`debian/`](./debian) | Debian/Ubuntu packaging for the `openmodelica` source package — the one the nightly builds use | +| [`OMPlot/debian/`](./OMPlot/debian), [`OMOptim/debian/`](./OMOptim/debian), [`OpenModelica-doc/debian/`](./OpenModelica-doc/debian) | Older standalone source packages, kept but not built by the current pipeline | +| [`rpm/`](./rpm) | Spec template and patches for the Fedora/EL packages | +| [`macports/`](./macports) | Portfile templates for macOS | +| [`docker/`](./docker) | Dockerfiles for the `build-deps` images on docker.openmodelica.org | +| [`.ci/`](./.ci) | The checks GitHub Actions runs on every pull request | + +`OpenModelica/debian` is a symlink to the top-level [`debian/`](./debian), so every +source project has its packaging under `/debian`. + +## Debian packaging + +### How `debian/` becomes a package + +`debian/` is never built where it sits. The nightly pipeline does roughly this: + +1. **Source package** — `update-source-repo.py` (apt-build) archives the OpenModelica + git tree, drops the testsuite and documentation directories, and copies this repository's + `debian/` in as `openmodelica_/debian`. It substitutes `@REV@` and `@TIME@` in + [`debian/changelog`](./debian/changelog) and runs `debuild -S`. The resulting + `.dsc` / `.orig.tar.xz` / `.debian.tar.xz` are published to + . + The branch taken from this repository is `master` unless `projects.json` pins a + `release-buildscriptbranch` / `stable-buildscriptbranch`. +2. **Binary packages** — the main Jenkins job downloads that `.dsc` into + `docker.openmodelica.org/build-deps:.nightly.` and runs + `dpkg-buildpackage -rfakeroot -b`. That compiles all of OpenModelica, so a full + build takes hours. + +The distributions and architectures built are listed in +`current-linux-os-releases.json` in apt-build. At the time of writing that is +jammy, noble, resolute and trixie on amd64, armhf and arm64. + +### What is in `debian/` + +* [`control`](./debian/control) — one source stanza and 20 binary packages (`omc`, + `libomc`, `omedit`, `omshell`, `omnotebook`, `omsimulator`, `omlibrary`, …). The + build dependencies carry alternatives (`libqt5webkit5-dev | qtwebengine5-dev`) + because a single control file has to satisfy every distribution in the matrix. +* [`rules`](./debian/rules) — a hand-written rules file, *not* the `dh` sequencer. It + configures and builds the tree itself and then calls each `dh_*` helper explicitly + from the `install` and `binary-arch` targets. There are no override targets; edit the + recipes directly. +* `.install` — the file lists. Everything is installed into `debian/tmp` by + `make install DESTDIR=…` first, and these files distribute it into the binary + packages. Paths are globs, e.g. + `debian/tmp/usr/lib/*/omc/libOMSimulator.so`. +* Desktop integration: [`desktops/`](./debian/desktops), [`icons/`](./debian/icons), + `*.menu`, `omnotebook.sharedmimeinfo`. +* The debhelper compatibility level is declared as `debhelper-compat (= 13)` in + `Build-Depends`. + +### What usually breaks it + +* **An `.install` glob stops matching.** When upstream moves or stops building a file, + `dh_install` fails with `Cannot find (any matches for) …` / `missing files, aborting` + and the whole nightly build dies. This is the most common breakage — see the history + of [`libomsimulator.install`](./debian/libomsimulator.install). +* **A helper or option is retired.** Every distribution upgrade brings a newer + debhelper; raising the compat level can remove an option `rules` passes. See + `debhelper-compat-upgrade-checklist(7)`. +* **A typo in a config file name.** `debian/.install` where `` is not + in `control` is ignored silently, and the package ships empty. + +The first one can only be caught by a real build; [`.ci/`](./.ci) catches the other two. + +### Testing a packaging change + +The metadata checks run in seconds: + +```bash +docker run --rm -v "$PWD:/src" -w /src ubuntu:noble sh -c \ + 'apt-get update -qq && apt-get install -qy --no-install-recommends debhelper dpkg-dev \ + && .ci/check-debian-packaging.sh' +``` + +For a real build, reuse the last published source package and swap in your `debian/`: + +```bash +V=1.28.0~dev-489-gda9d1ce # a version from build.openmodelica.org/apt/pool/contrib/ +docker run --rm -it -v "$PWD:/buildscripts" \ + docker.openmodelica.org/build-deps:jammy.nightly.amd64 bash +cd /tmp +for e in -1.dsc -1.debian.tar.xz .orig.tar.xz; do + wget -q "https://build.openmodelica.org/apt/pool/contrib/openmodelica_$V$e" +done +dpkg-source -x "openmodelica_$V-1.dsc" +rm -rf "openmodelica-$V/debian" && cp -a /buildscripts/debian "openmodelica-$V/debian" +sed -i -e "s/@REV@/$V/" -e "s/@TIME@/$(date -R)/" "openmodelica-$V/debian/changelog" +cd "openmodelica-$V" && dpkg-buildpackage -rfakeroot -b -j"$(nproc)" +``` + +The first run takes hours. Afterwards `build-stamp` is cached, so re-running only +`fakeroot debian/rules binary-arch` after another `debian/` tweak takes minutes. + +Or trigger the [`full deb build`](./.github/workflows/build-deb.yml) workflow, which does +the same thing on a runner. + +## RPM packaging + +[`rpm/SPECS/openmodelica.spec.tpl`](./rpm/SPECS/openmodelica.spec.tpl) is a template, +not a valid spec file. The Jenkins job replaces upper-case placeholders (`NAME`, +`RPMVERSION`, `DEBVERSION`, `RELEASENUM`, `PATCHES`, `PRIVATELIBS`, `DATE`, …) with +values from `projects.json` before calling `rpmbuild`, and copies +[`rpm/PATCHES/`](./rpm/PATCHES) into `SOURCES`. Because the substitution is a plain +string replace, any occurrence of those words anywhere in the file is replaced. + +Targets at the time of writing: el8, el9, el10, fc43 and fc44. + +## CI + +Two workflows, split by how long they take. + +### Fast checks — [`packaging.yml`](./.github/workflows/packaging.yml) + +Runs two jobs on every pull request and on pushes to `master`. Neither builds anything; +they check that the packaging metadata is well formed and that every distribution we +ship for still accepts it, which is what silently rots between releases. + +| Job | Script | Runs on | +| --- | --- | --- | +| `debian` | [`.ci/check-debian-packaging.sh`](./.ci/check-debian-packaging.sh) | `ubuntu:jammy`, `ubuntu:noble`, `ubuntu:resolute`, `debian:trixie` | +| `rpm` | [`.ci/check-rpm-spec.sh`](./.ci/check-rpm-spec.sh) | `almalinux:8`, `almalinux:9`, `almalinux:10`, `fedora:43`, `fedora:44` | + +`check-debian-packaging.sh` checks, for each of the four `debian/` trees, that +`control` and the templated `changelog` parse, that no stale `debian/compat` is left +behind, that debhelper on that distribution accepts the declared compatibility level, +that every `dh_*` command `rules` calls still exists and is passed no option removed at +that compat level, and that every `debian/.` file names a real binary +package. + +`check-rpm-spec.sh` performs the same placeholder substitution the Jenkins job does and +has `rpmspec` parse the result, which catches spec syntax mistakes — a missing `%`, an +empty `%define`, a stray comment. + +Both scripts are plain `/bin/sh` and take no arguments; run them from the top of the +repository as shown in their header comments. The image lists mirror +`current-linux-os-releases.json` in apt-build — update them when a distribution is +added or goes EOL, and update `EXPECTED_COMPAT` in `check-debian-packaging.sh` whenever +the compat level in the control files changes. + +### Full build — [`build-deb.yml`](./.github/workflows/build-deb.yml) + +Builds OpenModelica from a git checkout with the Autoconf + Makefile build and then runs +`dpkg-buildpackage` against this repository's `debian/`, the same sequence Jenkins uses, +and uploads the resulting `.deb` files as an artifact. It is the only job that catches a +`.install` glob that stopped matching, and the only one that proves the `Build-Depends` +are still installable. + +It compiles everything, so it takes hours. It runs weekly, on demand via +`workflow_dispatch` (with an input to pick the OpenModelica ref), and on pull requests +that touch `debian/`. Only on `ubuntu-latest` — Jenkins covers the rest of the matrix. + +It uses the Autoconf + Makefile build; switching it to the CMake build is a later change. + +> [!IMPORTANT] +> What no CI here tells you: whether the packages build on the other distributions +> in the matrix, or on armhf and arm64. That is still Jenkins' job. ## Docker Images diff --git a/debian/compat b/debian/compat deleted file mode 100644 index ec63514..0000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -9 diff --git a/debian/control b/debian/control index b8544b2..1eeceb5 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: openmodelica Section: math Priority: optional Maintainer: OpenModelica Build System -Build-Depends: debhelper (>= 9.0.0), +Build-Depends: debhelper-compat (= 13), # sbuild i386 does not handle native, cross-compile armhf requires it... clang:native | clang, gfortran:native | gfortran, @@ -147,8 +147,7 @@ Package: omc-common Section: math Multi-Arch: foreign Architecture: all -Depends: ${shlibs:Depends}, - ${misc:Depends} +Depends: ${misc:Depends} Description: The OpenModelica Compiler lib dependencies This is the core libraries of the OpenModelica project. @@ -217,7 +216,6 @@ Section: math Multi-Arch: foreign Architecture: all Depends: omnotebook (<< 20000), - ${shlibs:Depends}, ${misc:Depends} Description: An OMNotebook course in the Modelica language The course is based on Peter Fritzson's book @@ -228,7 +226,6 @@ Section: math Multi-Arch: foreign Architecture: all Depends: omnotebook (<< 20000), - ${shlibs:Depends}, ${misc:Depends} Description: An OMNotebook course in basic control theory diff --git a/debian/rules b/debian/rules index ad7ce61..f12394c 100755 --- a/debian/rules +++ b/debian/rules @@ -161,7 +161,7 @@ binary-arch: build install dh_installchangelogs dh_installdocs dh_installexamples - dh_install --list-missing + dh_missing --list-missing dh_installmenu dh_installmime dh_link diff --git a/windows/README.txt b/windows/README.txt deleted file mode 100644 index b4e1360..0000000 --- a/windows/README.txt +++ /dev/null @@ -1,2 +0,0 @@ -Windows build scripts are at: -https://github.com/OpenModelica/OpenModelicaSetup/