I’m trying to build a program with gfortran15 that I call from python, but I’m running into an issue.
The repository with my code is at https://github.com/pibion/band_distribution and I’m using the dockerfile named Dockerfile_gfortran to build an environment with the nix package manager.
First I clone the repo and checking out the fpm branch:
git clone git@github.com:pibion/band_distribution.git
git branch -v -a
git switch fpm
Then I build with the command
docker build -f Dockerfile_gfortran -t fano_fort .
And then run the container with
docker run -it fano_fort
As part of the docker build, I copy a shell.nix file into my workspace that installs python and my required python packages. So I can run nix-shell and have access to python and numpy.
bash-5.2# nix-shell
these 2 derivations will be built:
/nix/store/8y4vn0r0jwxxh6hclxq6nra10bxrjab1-builder.pl.drv
/nix/store/skdrp4cs4am5kqrnpj07d3657lqvfcdp-python3-3.13.9-env.drv
these 51 paths will be fetched (167.21 MiB download, 796.05 MiB unpacked):
/nix/store/pl2g977j2scjmj37iwpjil8lyjskmbny-bin
...
Once I’m inside my nix shell, I compile the program with fpm and it looks like it’s working:
[nix-shell:/app]# fpm test --compiler gfortran --profile release --flag "-march=native -fopenmp -ftree-parallelize-loops=4 -fcoarray=single -fPIC"
PpqFort_m.f90 done.
julienne_formats_m.F90 done.
julienne_command_line_m.f90 done.
...
driver.f90 done.
libband_distribution.so done.
driver done.
[100%] Project compiled successfully.
Append '-- --help' or '-- -h' to your `fpm test` command to display usage information.
Running all tests.
(Add '-- --contains <string>' to run only tests with subjects or descriptions containing the specified string.)
The PpqFort module
passes on computing the resN array.
passes on computing the resG array.
2 of 2 tests passed. 0 tests were skipped.
Test-suite run time: 73.87E-03 seconds
Number of images: 1
_____ 2 of 2 tests passed. 0 tests were skipped _____
After checking that the fortran runs okay on its own, I “install” the libraries, which I need to be able to call the function from python.
[nix-shell:/app]# fpm install --prefix=. --flag "-march=native -fopenmp -ftree-parallelize-loops=4 -fcoarray=single -fPIC"
Project is up to date
# Update: build/gfortran_45E81D1655512970/libband_distribution.so -> ./lib
# Update: build/gfortran_45E81D1655512970/libjulienne.so -> ./lib
# Update: build/gfortran_45E81D1655512970/libassert.so -> ./lib
# Update: build/gfortran_C8995A04685C4BDA/ppqfort_m.mod -> ./include
# Update: build/gfortran_C8995A04685C4BDA/julienne_m.mod -> ./include
# Update: build/gfortran_C8995A04685C4BDA/julienne_file_m.mod -> ./include
# Update: build/gfortran_C8995A04685C4BDA/julienne_formats_m.mod -> ./include
# Update: build/gfortran_C8995A04685C4BDA/julienne_command_line_m.mod -> ./include
# Update: build/gfortran_C8995A04685C4BDA/julienne_test_result_m.mod -> ./include
# Update: build/gfortran_C8995A04685C4BDA/julienne_test_harness_m.mod -> ./include
# Update: build/gfortran_C8995A04685C4BDA/julienne_one_image_prints_m.mod -> ./include
# Update: build/gfortran_C8995A04685C4BDA/julienne_string_m.mod -> ./include
# Update: build/gfortran_C8995A04685C4BDA/julienne_test_suite_m.mod -> ./include
# Update: build/gfortran_C8995A04685C4BDA/julienne_test_description_m.mod -> ./include
# Update: build/gfortran_C8995A04685C4BDA/julienne_test_m.mod -> ./include
# Update: build/gfortran_C8995A04685C4BDA/julienne_bin_m.mod -> ./include
# Update: build/gfortran_C8995A04685C4BDA/julienne_test_diagnosis_m.mod -> ./include
# Update: build/gfortran_C8995A04685C4BDA/julienne_github_ci_m.mod -> ./include
# Update: build/gfortran_C8995A04685C4BDA/julienne_test_fixture_m.mod -> ./include
# Update: build/gfortran_C8995A04685C4BDA/julienne_assert_m.mod -> ./include
# Update: build/gfortran_C8995A04685C4BDA/assert_m.mod -> ./include
The problem comes when I try to run the python test, which calls the fortran function from within python:
[nix-shell:/app]# python test_PpqFort.py
Traceback (most recent call last):
File "/nix/store/94f70vc9s0m2i1lm0z19wjka857g87z8-python3-3.13.9-env/lib/python3.13/ctypes/__init__.py", line 461, in __getattr__
dll = self._dlltype(name)
File "/nix/store/94f70vc9s0m2i1lm0z19wjka857g87z8-python3-3.13.9-env/lib/python3.13/ctypes/__init__.py", line 390, in __init__
self._handle = _dlopen(self._name, mode)
~~~~~~~^^^^^^^^^^^^^^^^^^
OSError: libassert.so: cannot open shared object file: No such file or directory
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/app/test_PpqFort.py", line 20, in <module>
api = np.ctypeslib.load_library(DLLname,folderpath)
File "/nix/store/94f70vc9s0m2i1lm0z19wjka857g87z8-python3-3.13.9-env/lib/python3.13/site-packages/numpy/ctypeslib/_ctypeslib.py", line 160, in load_library
return ctypes.cdll[libpath]
~~~~~~~~~~~^^^^^^^^^
File "/nix/store/94f70vc9s0m2i1lm0z19wjka857g87z8-python3-3.13.9-env/lib/python3.13/ctypes/__init__.py", line 468, in __getitem__
return getattr(self, name)
File "/nix/store/94f70vc9s0m2i1lm0z19wjka857g87z8-python3-3.13.9-env/lib/python3.13/ctypes/__init__.py", line 463, in __getattr__
raise AttributeError(name)
AttributeError: /app/lib/libband_distribution.so
The file libassert.so is in /app/lib and was created during fpm install. In fact, if I export LD_LIBRARY_PATH=/app/lib, the python program runs without issue.
But I’m wondering if there’s a more nix-appropriate way to deal with this?