Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
name: Smoke build

on:
push:
pull_request:
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
linux:
name: Linux smoke (Py3.11 in Docker)
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- name: Install make
run: sudo apt install make -y
- name: Build
run: make build-dev-image && make build
- name: Test
run: make test
- uses: actions/checkout@v4
- name: Install make
run: sudo apt install make -y
- name: Build dev image
run: make build-dev-image
- name: Build PyFMI
run: make build
- name: Run tests
run: make test
# Multi-Python coverage lives in wheels.yml, which exercises every supported
# CPython against its built wheel.
128 changes: 128 additions & 0 deletions .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
name: Build wheels

on:
push:
pull_request:
workflow_dispatch:
inputs:
publish:
description: "Publish wheels to PyPI after building"
type: boolean
default: false
test_release:
description: "Publish under the pyfmi-testing PyPI name instead of PyFMI"
type: boolean
default: false

permissions:
contents: read

jobs:
linux:
name: Linux wheels
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@v4

- name: Rewrite package name to pyfmi-testing
if: github.event_name == 'workflow_dispatch' && inputs.publish && inputs.test_release
run: |
sed -i 's/^name = "PyFMI"$/name = "pyfmi-testing"/' pyproject.toml
sed -i "s/^ 'PyFMI',$/ 'pyfmi-testing',/" meson.build
grep '^name = ' pyproject.toml
grep -n "pyfmi-testing" meson.build

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- run: pip install cibuildwheel

- name: Build manylinux image (FMIL pre-installed)
run: docker build -f Dockerfile.manylinux -t pyfmi-manylinux .

- name: Build wheels
run: cibuildwheel --platform linux --output-dir dist/

- uses: actions/upload-artifact@v4
with:
name: wheels-linux
path: dist/*.whl

windows:
name: Windows wheels
runs-on: windows-2022
timeout-minutes: 90
steps:
- uses: actions/checkout@v4

- name: Rewrite package name to pyfmi-testing
if: github.event_name == 'workflow_dispatch' && inputs.publish && inputs.test_release
shell: bash
run: |
sed -i 's/^name = "PyFMI"$/name = "pyfmi-testing"/' pyproject.toml
sed -i "s/^ 'PyFMI',$/ 'pyfmi-testing',/" meson.build
grep '^name = ' pyproject.toml
grep -n "pyfmi-testing" meson.build

- name: Set up MSYS2 UCRT64
uses: msys2/setup-msys2@v2
with:
msystem: UCRT64
update: true
install: >-
git
mingw-w64-ucrt-x86_64-gcc
mingw-w64-ucrt-x86_64-cmake
mingw-w64-ucrt-x86_64-ninja
mingw-w64-ucrt-x86_64-pkg-config

- name: Build FMI Library
shell: msys2 {0}
run: bash tools/wheels/build_dependencies_windows.sh

# cibuildwheel spawns a fresh pwsh; the MSYS2 setup-action's PATH and
# compiler vars are scoped to its own shell and need re-exporting here.
- name: Configure compiler environment
shell: pwsh
run: |
echo "C:\msys64\ucrt64\bin" | Out-File -FilePath $env:GITHUB_PATH -Append
echo "C:\deps\bin" | Out-File -FilePath $env:GITHUB_PATH -Append
echo "CC=gcc" | Out-File -FilePath $env:GITHUB_ENV -Append
echo "CXX=g++" | Out-File -FilePath $env:GITHUB_ENV -Append

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- run: pip install cibuildwheel
shell: pwsh

- name: Build wheels
shell: pwsh
run: cibuildwheel --platform windows --output-dir dist/

- uses: actions/upload-artifact@v4
with:
name: wheels-windows
path: dist/*.whl

upload_pypi:
name: Upload to PyPI
needs: [linux, windows]
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch' && inputs.publish && startsWith(github.ref, 'refs/tags/v')
environment:
name: pypi
url: https://pypi.org/p/PyFMI
permissions:
id-token: write # required for OIDC Trusted Publisher
steps:
- uses: actions/download-artifact@v4
with:
pattern: wheels-*
path: dist/
merge-multiple: true

- uses: pypa/gh-action-pypi-publish@release/v1
54 changes: 12 additions & 42 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,19 @@ FROM ubuntu:22.04

ENV DEBIAN_FRONTEND=noninteractive

# Install Python
RUN apt update && apt install software-properties-common -y && add-apt-repository ppa:deadsnakes/ppa
RUN apt update && apt install python3.11 python3-pip python3.11-dev python3.11-venv -y
RUN apt-get update && apt-get install -y software-properties-common && \
add-apt-repository ppa:deadsnakes/ppa && \
apt-get update && apt-get install -y \
python3.11 python3.11-dev python3.11-venv python3-pip \
build-essential cmake curl git vim bash-completion \
libgfortran5 && \
rm -rf /var/lib/apt/lists/*

# Build FMIL from the same script the wheel pipeline uses, so the dev image
# and the published wheels link against an identical FMIL build.
COPY tools/wheels/build_dependencies.sh /tmp/build_dependencies.sh
RUN bash /tmp/build_dependencies.sh && rm /tmp/build_dependencies.sh

# Install system
RUN python3.11 -m pip install Cython numpy scipy matplotlib setuptools==69.1.0
RUN apt-get -y install cmake liblapack-dev libsuitesparse-dev libhypre-dev curl git make vim bash-completion
RUN cp -v /usr/lib/x86_64-linux-gnu/libblas.so /usr/lib/x86_64-linux-gnu/libblas_OPENMP.so

# Install superlu
RUN cd /tmp && \
curl -fSsL https://github.com/xiaoyeli/superlu_mt/archive/refs/tags/v4.0.1.tar.gz | tar xz && \
cd superlu_mt-4.0.1 && \
cmake -Denable_examples=OFF -Denable_tests=OFF -DPLAT="_OPENMP" -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=lib -DSUPERLUMT_INSTALL_INCLUDEDIR=include . && \
make -j4 && \
make install

# Install sundials
RUN git clone --depth 1 -b v2.7.0 https://github.com/LLNL/sundials /tmp/sundials && \
cd /tmp/sundials && \
echo "target_link_libraries(sundials_idas_shared lapack blas superlu_mt_OPENMP)" >> src/idas/CMakeLists.txt && \
echo "target_link_libraries(sundials_kinsol_shared lapack blas superlu_mt_OPENMP)" >> src/kinsol/CMakeLists.txt && \
cmake -LAH -DSUPERLUMT_BLAS_LIBRARIES=blas -DSUPERLUMT_INCLUDE_DIR=/usr/include -DSUPERLUMT_LIBRARY=/usr/lib/libsuperlu_mt_OPENMP.a -DSUPERLUMT_THREAD_TYPE=OpenMP -DCMAKE_INSTALL_PREFIX=/usr -DSUPERLUMT_ENABLE=ON -DLAPACK_ENABLE=ON -DEXAMPLES_ENABLE=OFF -B build . && \
cd build && \
make -j4 && \
make install

#Install assimulo
RUN git clone --depth 1 -b Assimulo-3.8.0 https://github.com/modelon-community/Assimulo /tmp/Assimulo && \
cd /tmp/Assimulo && \
rm setup.cfg && \
python3.11 setup.py install --user --sundials-home=/usr --blas-home=/usr/lib/x86_64-linux-gnu/ --lapack-home=/usr/lib/x86_64-linux-gnu/ --superlu-home=/usr

# Install fmilib
RUN cd /tmp && \
curl -fSsL https://github.com/modelon-community/fmi-library/archive/3.0.4.tar.gz | tar xz && \
cd fmi-library-3.0.4 && \
cmake -DCMAKE_INSTALL_PREFIX=/usr -DFMILIB_BUILD_TESTS=OFF -B build . && \
cd build && \
make -j4 && \
make install

# Setup a venv to put pip and python on path for convinience running commands
ARG PYTHON_VENV=/src/.venv
ENV PATH=${PYTHON_VENV}/bin:$PATH
WORKDIR /src
9 changes: 9 additions & 0 deletions Dockerfile.manylinux
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM quay.io/pypa/manylinux_2_28_x86_64

# Pre-bake FMIL so cibuildwheel can skip before-all and so local
# `cibuildwheel --platform linux` runs reproduce the CI environment exactly.
COPY tools/wheels/build_dependencies.sh /tmp/build_dependencies.sh
RUN bash /tmp/build_dependencies.sh && rm /tmp/build_dependencies.sh

WORKDIR /src
CMD ["/bin/bash"]
5 changes: 0 additions & 5 deletions MANIFEST.in

This file was deleted.

36 changes: 27 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
.PHONY: build build-dev-image test shell
DOCKER_IMAGE := pyfmi-dev
IN_DOCKER_IMG := $(shell test -f /.dockerenv && echo 1 || echo 0)
SETUPTOOLS_JFLAG=-j$(shell nproc)
.PHONY: build build-dev-image build-manylinux-image test shell compile-deps
DOCKER_IMAGE := pyfmi-dev
MANYLINUX_IMAGE := pyfmi-manylinux
IN_DOCKER_IMG := $(shell test -f /.dockerenv && echo 1 || echo 0)

MESON_SETUP_ARGS := -Dfmil_prefix=/usr
PIP_SETUP_ARGS := $(addprefix -Csetup-args=,$(MESON_SETUP_ARGS))

define _run
@if [ $(IN_DOCKER_IMG) -eq 1 ]; then \
Expand All @@ -15,18 +18,33 @@ define _run
fi
endef

define _run_with_venv
$(call _run, bash -c '. .venv/bin/activate && $(1)')
endef

build-dev-image:
docker build -t ${DOCKER_IMAGE} .

.venv:
$(call _run, python3.11 -m venv .venv --system-site-packages)
$(call _run, pip install pytest)
build-manylinux-image:
docker build -f Dockerfile.manylinux -t ${MANYLINUX_IMAGE} .

.venv: requirements.lock
$(call _run, python3.11 -m venv .venv)
$(call _run_with_venv, pip install -r requirements.lock)
$(call _run, touch .venv)

build: .venv
$(call _run, python setup.py build_ext ${SETUPTOOLS_JFLAG} install --fmil-home=/usr)
$(call _run_with_venv, pip install . -v $(PIP_SETUP_ARGS))

test: build
$(call _run, pytest)
$(call _run_with_venv, pytest tests/)

shell:
$(call _run, /bin/bash,-it)

# Regenerate requirements.lock from pyproject.toml. Run after changing
# build-system requires or runtime dependencies; commit the resulting file.
compile-deps:
$(call _run, python3.11 -m venv .venv)
$(call _run_with_venv, pip install pip-tools)
$(call _run_with_venv, pip-compile --extra=dev --output-file=requirements.lock pyproject.toml)
Loading