I'm currently working on a Python project that is importing a Fortran module. The setup.py
looks similar to that
from numpy.distutils.core import Extension
from numpy.distutils.core import setup
ext = Extension(
name = "fortran_module",
sources = ["fortran_module.f90"],
extra_f90_compile_args = ["-some -compile -arguments"]
)
setup(
...,
...,
...,
ext_modules = [ext],
...,
...,
...
)
I'm currently installing it with pip install -e .
, which works fine.
But sometimes I need to change the extra_f90_compile_args
and I would like to do give them as command line argument during installation with pip
rather than changing the setup.py
file. Something like this for example:
pip install -e --compile_args="-O3 -fbacktrace -fbounds-check -fopenmp" .
Is it possible to pass command line arguments via pip
into the setup.py
file?
Related to that, I would also like to pass different setup options into setup.py
. For example
pip install -e --setup=setup1 .
or
pip install -e --setup=setup2 .
And depending on whether setup1
or setup2
or none of them is passed, I would like to include different Fortran source files and compile them with different extra_f90_compile_args
.
Is this possible?
Edit: Let's consider the following example: The Fortran module is parallelized with OpenMP. Now I want the user to decide, whether to compile parallel or not. Maybe the OpenMP libraries are not available and the user needs to compile the serial version.
My setup.py
now looks as follows
from numpy.distutils.core import Extension
from numpy.distutils.core import setup
import os
from setuptools.command.install import install as _install
extra_f90_compile_args = ""
extra_link_args = ""
class install(_install):
user_options = _install.user_options + [('build=', None, None)]
def initialize_options(self):
_install.initialize_options(self)
self.build = None
def finalize_options(self):
_install.finalize_options(self)
def run(self):
global extra_f90_compile_args
global extra_link_args
if(self.build == "parallel"):
extra_f90_compile_args += "-fopenmp"
extra_link_args += "-lgomp"
os.makedirs("~/test/")
_install.run(self)
ext = Extension(
name="test_module.fortran_module",
sources=["test_module/fortran_module.f90"],
extra_f90_compile_args=[extra_f90_compile_args],
extra_link_args=[extra_link_args]
)
setup(
name="test_module",
packages=["test_module"],
ext_modules=[ext],
cmdclass={'install': install}
)
If I install this with
pip install . --install-option="--build=parallel"
it is executing code in the if
-block. I created the test/
directory just to check this. If build
is not given or different from parallel
, the test/
directory is not created.
However, the code is not compiled with OpenMP. I think this is, because the Extension
object is created before the call of setup()
, where the arguments get evaluated. I would like to first evaluate the arguments, then create the Extension
object depending on the arguments, and then call setup()
.
How can I do that?
After digging through the source code, I can answer this now.
The
setup.py
file:Installing this with
installs the serial version and
installs the parallel version of the Fortran module.