Skip to content
Merged
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
25 changes: 19 additions & 6 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,25 @@ jobs:
native-image-job-reports: "true"
cache: "maven"

- name: Cache the packed BioNetGen (Windows)
if: runner.os == 'Windows'
id: bionetgen-exe
uses: actions/cache@v4
with:
path: libvcell/vcell_install/bionetgen/win64Standalone/BNG2.exe
key: bionetgen-exe-${{ hashFiles('libvcell/vcell_install/bionetgen/**', 'scripts/pack_bionetgen.sh') }}

- name: Pack BioNetGen for Windows (PAR::Packer)
# VCell runs bionetgen/win64Standalone/BNG2.exe on Windows, not perl BNG2.pl (scripts/pack_bionetgen.sh)
if: runner.os == 'Windows' && steps.bionetgen-exe.outputs.cache-hit != 'true'
run: |
# Strawberry Perl, not the Perl that ships with Git for Windows (Git Bash puts its own first, and it lacks
# the modules cpanm and PAR::Packer need)
export PATH="/c/Strawberry/perl/bin:/c/Strawberry/perl/site/bin:/c/Strawberry/c/bin:$PATH"
perl -v | head -2
perl -S cpanm --notest PAR::Packer
PP="perl -S pp" scripts/pack_bionetgen.sh

- name: Install python dependencies
run: poetry install --no-interaction

Expand All @@ -88,12 +107,6 @@ jobs:
uses: codecov/codecov-action@v4
if: ${{ matrix.python-version == '3.11' }}

- name: Setup tmate
if: failure()
uses: mxschmitt/action-tmate@v3
with:
limit-access-to-actor: true

check-docs:
runs-on: ubuntu-latest
steps:
Expand Down
19 changes: 19 additions & 0 deletions .github/workflows/on-release-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,25 @@ jobs:
CIBW_MANYLINUX_AARCH64_IMAGE: "${{ env.MANYLINUX_IMAGE_TARGET }}"
# CIBW_BUILD_VERBOSITY_LINUX: 2

- name: Cache the packed BioNetGen (Windows)
if: runner.os == 'Windows'
id: bionetgen-exe
uses: actions/cache@v4
with:
path: libvcell/vcell_install/bionetgen/win64Standalone/BNG2.exe
key: bionetgen-exe-${{ hashFiles('libvcell/vcell_install/bionetgen/**', 'scripts/pack_bionetgen.sh') }}

- name: Pack BioNetGen for Windows (PAR::Packer)
# VCell runs bionetgen/win64Standalone/BNG2.exe on Windows, not perl BNG2.pl (scripts/pack_bionetgen.sh)
if: runner.os == 'Windows' && steps.bionetgen-exe.outputs.cache-hit != 'true'
run: |
# Strawberry Perl, not the Perl that ships with Git for Windows (Git Bash puts its own first, and it lacks
# the modules cpanm and PAR::Packer need)
export PATH="/c/Strawberry/perl/bin:/c/Strawberry/perl/site/bin:/c/Strawberry/c/bin:$PATH"
perl -v | head -2
perl -S cpanm --notest PAR::Packer
PP="perl -S pp" scripts/pack_bionetgen.sh

- name: Run cibuildwheel
if: ${{ !startsWith(matrix.os, 'ubuntu') }}
run: |
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,6 @@ cython_debug/
#.idea/

.idea/

# BioNetGen packed for Windows by scripts/pack_bionetgen.sh (a build product, shipped in the Windows wheel)
libvcell/vcell_install/bionetgen/win64Standalone/
2 changes: 2 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# vendored BioNetGen, kept byte-identical to its release
exclude: ^libvcell/vcell_install/bionetgen/
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: "v4.4.0"
Expand Down
14 changes: 14 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,20 @@ Pre-commit hooks run ruff (lint + format) and prettier automatically.

Linux wheels are built inside the `docker/Dockerfile_manylinux_*` images (manylinux 2_28 and 2_34, for both `aarch64` and `x86_64`), which provide the GraalVM toolchain needed for native compilation in CI.

### Bundled BioNetGen

`libvcell/vcell_install/bionetgen/` is the Perl part of BioNetGen 2.9.3 (MIT; `BNG2.pl` and `Perl2/`, copied
unchanged from the official release; see its `README.md`, and keep it byte-identical: pre-commit excludes it). VCell
runs `perl <vcell.installDir>/bionetgen/BNG2.pl` to expand a rule-based application's reaction rules into a network
when it generates the math. The Python package sets `LIBVCELL_VCELL_INSTALL_DIR` to `libvcell/vcell_install`
(`_internal/native_utils.py`), and `BioNetGenSupport.configure()`, called at the start of every model-building method,
turns it into `vcell.installDir` (each call runs in a fresh isolate). Without `perl` or BioNetGen,
`vcml_to_ode_input` falls back to the document's stored math and says why in its message. The recorder run in
`build.py` sets the variable too, so native-image records the BioNetGen path. On Windows VCell runs
`bionetgen/win64Standalone/BNG2.exe` instead of `perl BNG2.pl`: `scripts/pack_bionetgen.sh` packs it from the same
files with PAR::Packer (and smoke-tests it); the Windows jobs of both workflows run it before the build (cached on a
hash of the BioNetGen files and the script), and the exe is git-ignored but included in the wheel.

### Key dependencies

- `vcell_submodule/` — Git submodule pointing to the full VCell Java repository (provides vcell-core). After cloning or pulling a submodule pointer bump, run `git submodule update --init --recursive` — git does NOT auto-update the submodule working tree, so it can sit at an older commit than the recorded pointer (shows as `M vcell_submodule` in `git status`). A stale checkout causes `vcell-native` to fail compiling against vcell-core. To make vcell-core/math available for a local `vcell-native` build, install them into `.m2` first: `mvn -DskipTests clean install -f vcell_submodule` (or run the full `scripts/local_build_native.sh`).
Expand Down
12 changes: 12 additions & 0 deletions build.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
import shutil
import subprocess
import sys
Expand Down Expand Up @@ -61,8 +62,19 @@ def main() -> None:
"unnamed_spatialGeom "
"target/sbml-input",
cwd=vcell_native_dir,
# the bundled BioNetGen, so the recording covers generating a rule-based reaction network (perl BNG2.pl)
env={**os.environ, "LIBVCELL_VCELL_INSTALL_DIR": str(root_dir / "libvcell" / "vcell_install")},
)

# On Windows VCell runs BioNetGen as bionetgen/win64Standalone/BNG2.exe, packed by scripts/pack_bionetgen.sh
if sys.platform == "win32":
bng2_exe = root_dir / "libvcell" / "vcell_install" / "bionetgen" / "win64Standalone" / "BNG2.exe"
if not bng2_exe.is_file():
print(
f"WARNING: {bng2_exe} is missing (run scripts/pack_bionetgen.sh): on Windows, rule-based models "
"will use their stored math instead of regenerating it"
)

# Build vcell-native as native shared object library
install_message_4: str = """
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
Expand Down
14 changes: 14 additions & 0 deletions libvcell/_internal/native_utils.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
import ctypes
import os
import platform
from _ctypes import byref
from importlib.resources import files

import libvcell

#: The environment variable the native library reads to find VCell's resources (org.vcell.libvcell.BioNetGenSupport).
VCELL_INSTALL_DIR_ENV = "LIBVCELL_VCELL_INSTALL_DIR"


def _use_bundled_bionetgen() -> None:
"""Point the native library at the BioNetGen this package bundles (``vcell_install/bionetgen/BNG2.pl``), which
VCell runs with ``perl`` to generate a rule-based application's reaction network. A value already in the
environment wins."""
install_dir = files(libvcell).joinpath("vcell_install")
if install_dir.joinpath("bionetgen", "BNG2.pl").is_file():
os.environ.setdefault(VCELL_INSTALL_DIR_ENV, str(install_dir))


class VCellNativeLibraryLoader:
lib: ctypes.CDLL

def __init__(self) -> None:
_use_bundled_bionetgen()
self.lib = self._load_library()
self._define_entry_points()

Expand Down
Loading
Loading