{ lib, stdenv, buildPythonPackage, fetchFromGitHub, # patches qt6, fmpy, replaceVars, # nativeBuildInputs cmake, # build-system hatchling, # dependencies attrs, jinja2, lark, lxml, msgpack, nbformat, numpy, pyside6, # preBuild rpclib, # tests versionCheckHook, # passthru sundials, lapack, runCommand, fmi-reference-fmus, enableRemoting ? true, }: buildPythonPackage rec { pname = "fmpy"; version = "0.3.27"; pyproject = true; # Bumping version? Make sure to look through the commit history for # bumped native/build_cvode.py pins (see above). src = fetchFromGitHub { owner = "CATIA-Systems"; repo = "FMPy"; tag = "v${version}"; fetchSubmodules = true; hash = "sha256-Sx3lHiEMPESbUN8LIb4o0J7t/ZPavsyfh1QJJpocNaA="; }; patches = [ (replaceVars ./0001-gui-override-Qt6-libexec-path.patch { qt6libexec = "${qt6.qtbase}/libexec/"; }) (replaceVars ./0002-sundials-override-shared-object-paths.patch { inherit (fmpy.passthru) cvode; }) # Upstream does not accept pull requests for unknown legal # reasons, see: # . # Thus a fix is vendored here until patched by maintainer. C.f. # ./0003-remoting-client-create-lockfile-with-explicit-r-w.patch ]; # Make forced includes of other systems' artifacts optional in order # to pass build (otherwise vendored upstream from CI) postPatch = '' substituteInPlace pyproject.toml \ --replace-fail "force-include" "source" ''; nativeBuildInputs = [ cmake ]; build-system = [ hatchling ]; dependencies = [ attrs cmake jinja2 lark lxml msgpack nbformat numpy pyside6 ]; dontUseCmakeConfigure = true; dontUseCmakeBuildDir = true; # Don't run upstream build scripts as they are too specialized. # cvode is already built, so we only need to build native binaries. # We run these cmake builds and then run the standard # buildPythonPackage phases. preBuild = '' cmakeFlags="-S native/src -B native/src/build -D CVODE_INSTALL_DIR=${passthru.cvode}" cmakeConfigurePhase cmake --build native/src/build --config Release '' # reimplementation of native/build_remoting.py # 2025-10-25: fix cmake 4 compatibility + lib.optionalString (enableRemoting && stdenv.hostPlatform.isLinux) '' cmakeFlags="-S native/remoting -B remoting/linux64 -D RPCLIB=${rpclib} -D CMAKE_POLICY_VERSION_MINIMUM=3.10" cmakeConfigurePhase cmake --build remoting/linux64 --config Release '' # C.f. upstream build-wheel CI job + '' python native/copy_sources.py # reimplementation of native/compile_resources.py pushd src/ python -c "from fmpy.gui import compile_resources; compile_resources()" popd ''; pythonImportsCheck = [ "fmpy" "fmpy.cross_check" "fmpy.cswrapper" "fmpy.examples" "fmpy.fmucontainer" "fmpy.logging" "fmpy.gui" "fmpy.gui.generated" "fmpy.ssp" "fmpy.sundials" ]; nativeCheckInputs = [ versionCheckHook ]; passthru = { # From sundials, build only the CVODE solver. C.f. # src/native/build_cvode.py cvode = (sundials.overrideAttrs (prev: rec { # hash copied from native/build_cvode.py version = "5.3.0"; src = fetchFromGitHub { owner = "LLNL"; repo = "sundials"; tag = "v${version}"; hash = "sha256-8TvIGhrB9Rq9GgWqeyPTcYFrgn6Q79VkhkLuucNKlg0="; }; # Fix CMake 4 compatibility postPatch = '' substituteInPlace config/SundialsPOSIXTimers.cmake \ --replace-fail \ "CMAKE_MINIMUM_REQUIRED(VERSION 3.0.2)" \ "CMAKE_MINIMUM_REQUIRED(VERSION 3.10)" ''; cmakeFlags = prev.cmakeFlags ++ lib.mapAttrsToList (option: enable: lib.cmakeBool option enable) { # only build the CVODE solver BUILD_CVODE = true; BUILD_CVODES = false; BUILD_ARKODE = false; BUILD_IDA = false; BUILD_IDAS = false; BUILD_KINSOL = false; BUILD_SHARED_LIBS = true; }; # FMPy searches for sundials without the "lib"-prefix; strip it # and symlink the so-files into existence. postFixup = '' pushd $out/lib for so in *.so; do ln --verbose --symbolic $so ''${so#lib} done popd ''; })).override { lapackSupport = false; lapack.isILP64 = stdenv.hostPlatform.is64bit; blas = lapack; kluSupport = false; }; # Simulate reference FMUs from # . # # Just check that the execution passes; don't verify any numerical # results, but save them in case of future or manual check use. tests.simulate-reference-fmus = runCommand "${pname}-simulate-reference-fmus" { } '' mkdir $out # NB(find ! -name): Clocks.fmu is marked TODO upstream and is of a # FMI type that FMPy doesn't support currently (ModelExchange) for fmu in $(find ${fmi-reference-fmus}/*.fmu ! -name "Clocks.fmu"); do name=$(basename $fmu) echo "--- START $name ---" ${lib.getExe fmpy} simulate $fmu \ --fmi-logging \ --output-file $out/$name.csv \ | tee $out/$name.out done ''; }; meta = { # A logging.dylib is built but is not packaged correctly so as to # be found. C.f. # broken = stdenv.hostPlatform.isDarwin; description = "Simulate Functional Mockup Units (FMUs) in Python"; homepage = "https://github.com/CATIA-Systems/FMPy"; license = lib.licenses.bsd2; maintainers = with lib.maintainers; [ tmplt ]; # Supported platforms are not exhaustively and explicitly stated, # but inferred from the artifacts that are vendored in upstream CI # builds. C.f. # platforms = lib.platforms.x86_64 ++ [ "i686-windows" ]; mainProgram = "fmpy"; }; }