Trouble calling a .so built with fpm-fortran from python in a nix-shell

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?