Compiling forpy to call Python object in Fortran

Viewed 142

My question
I am realizing the need to implement a formal connection from Fortran to Python in my project (the context is below) and my scenario seems perfect scenario for either f2py or forpy. I chose forpy because it seems more geared to calling Python FROM Fortran which appears to be more difficult in f2py.

I cloned the git repo and went through the Getting Started section but get a weird error (pasted below) when compiling forpy_mod.F90. Does anyone know the cause/fix to this error?

  • Running miniconda with python 3.8.8 on a linux machine
  • [EDIT: ] Using GNU Fortran (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)

Possibly Unnecessary Context:
I am working with a large Fortran-based orbit software that is composed of thousands of Fortran subroutines. My task is to call a python code in one of these subroutines that then calls a Python API that has been reduced to return a single value back to the Fortran program. This sequence will happen tens to hundreds of thousands of times in a single orbit run.

I have successfully achieved a connection between these two programs using Fortran's EXECUTE_COMMAND_LINE() function, but the Python code itself has a good amount of overhead and when called from the command line it re-imports the packages (of which there are many) each time the function is called. This results in extremely long runtimes (on the order of days when it should only take about 6 mins using the defaults). I have already reduced the overhead of the Python API as much as I can imagine.

Error from attempt to compile forpy

 $ gfortran -c forpy_mod.F90

forpy_mod.F90:1924.54:

  character(kind=C_CHAR, len=:), pointer :: doc_string
                                                      1
Error: Deferred-length character component 'doc_string' at (1) is not yet supported
forpy_mod.F90:1961.54:

  character(kind=C_CHAR, len=:), pointer :: doc_string
                                                      1
Error: Deferred-length character component 'doc_string' at (1) is not yet supported
forpy_mod.F90:1961.54:

  character(kind=C_CHAR, len=:), pointer :: doc_string
                                                      1
Error: Deferred-length character component 'doc_string' at (1) is not yet supported
forpy_mod.F90:11788.12:

  m = c_loc(self%methods)
            1
Error: Argument 'self' to 'c_loc' at (1) must be an associated scalar POINTER
forpy_mod.F90:9581.41:

      flag = strcmp(buffer_format, c_loc(format_code))
                                         1
Error: CHARACTER argument 'format_code' to 'c_loc' at (1) must have a length of 1
forpy_mod.F90:9586.43:

        flag = strcmp(buffer_format, c_loc(format_code))
                                           1
Error: CHARACTER argument 'format_code' to 'c_loc' at (1) must have a length of 1
forpy_mod.F90:9595.41:

      flag = strcmp(buffer_format, c_loc(format_code))
                                         1
Error: CHARACTER argument 'format_code' to 'c_loc' at (1) must have a length of 1
forpy_mod.F90:9600.43:

        flag = strcmp(buffer_format, c_loc(format_code))
                                           1
Error: CHARACTER argument 'format_code' to 'c_loc' at (1) must have a length of 1
forpy_mod.F90:9606.43:

        flag = strcmp(buffer_format, c_loc(format_code))
                                           1
Error: CHARACTER argument 'format_code' to 'c_loc' at (1) must have a length of 1
forpy_mod.F90:9613.37:

  flag = strcmp(buffer_format, c_loc(format_c_string))
                                     1
Error: CHARACTER argument 'format_c_string' to 'c_loc' at (1) must have a length of 1
forpy_mod.F90:9292.24:

  buffer%format = c_loc(format_c_string)
                        1
Error: CHARACTER argument 'format_c_string' to 'c_loc' at (1) must have a length of 1
forpy_mod.F90:9186.51:

  ierror = ndarray_create_nocopy_helper(res, c_loc(array), shape(array, kind=PY
                                                   1
Error: Assumed-shape array 'array' at (1) cannot be an argument to the procedure 'c_loc' because it is not C interoperable
forpy_mod.F90:9102.51:

  ierror = ndarray_create_nocopy_helper(res, c_loc(array), shape(array, kind=PY
                                                   1
Error: Assumed-shape array 'array' at (1) cannot be an argument to the procedure 'c_loc' because it is not C interoperable
forpy_mod.F90:9018.51:

  ierror = ndarray_create_nocopy_helper(res, c_loc(array), shape(array, kind=PY
                                                   1
Error: Assumed-shape array 'array' at (1) cannot be an argument to the procedure 'c_loc' because it is not C interoperable
forpy_mod.F90:8934.51:

  ierror = ndarray_create_nocopy_helper(res, c_loc(array), shape(array, kind=PY
                                                   1
Error: Assumed-shape array 'array' at (1) cannot be an argument to the procedure 'c_loc' because it is not C interoperable
forpy_mod.F90:8850.51:

  ierror = ndarray_create_nocopy_helper(res, c_loc(array), shape(array, kind=PY
                                                   1
Error: Assumed-shape array 'array' at (1) cannot be an argument to the procedure 'c_loc' because it is not C interoperable
forpy_mod.F90:8766.51:

  ierror = ndarray_create_nocopy_helper(res, c_loc(array), shape(array, kind=PY
                                                   1
Error: Assumed-shape array 'array' at (1) cannot be an argument to the procedure 'c_loc' because it is not C interoperable
forpy_mod.F90:8682.51:

  ierror = ndarray_create_nocopy_helper(res, c_loc(array), shape(array, kind=PY
                                                   1
Error: Assumed-shape array 'array' at (1) cannot be an argument to the procedure 'c_loc' because it is not C interoperable
forpy_mod.F90:8598.51:

  ierror = ndarray_create_nocopy_helper(res, c_loc(array), shape(array, kind=PY
                                                   1
Error: Assumed-shape array 'array' at (1) cannot be an argument to the procedure 'c_loc' because it is not C interoperable
forpy_mod.F90:8514.51:

  ierror = ndarray_create_nocopy_helper(res, c_loc(array), shape(array, kind=PY
                                                   1
Error: Assumed-shape array 'array' at (1) cannot be an argument to the procedure 'c_loc' because it is not C interoperable
forpy_mod.F90:8430.51:

  ierror = ndarray_create_nocopy_helper(res, c_loc(array), shape(array, kind=PY
                                                   1
Error: Assumed-shape array 'array' at (1) cannot be an argument to the procedure 'c_loc' because it is not C interoperable
forpy_mod.F90:8346.51:

  ierror = ndarray_create_nocopy_helper(res, c_loc(array), shape(array, kind=PY
                                                   1
Error: Assumed-shape array 'array' at (1) cannot be an argument to the procedure 'c_loc' because it is not C interoperable
forpy_mod.F90:8262.51:

  ierror = ndarray_create_nocopy_helper(res, c_loc(array), shape(array, kind=PY
                                                   1
Error: Assumed-shape array 'array' at (1) cannot be an argument to the procedure 'c_loc' because it is not C interoperable
forpy_mod.F90:8178.51:

  ierror = ndarray_create_nocopy_helper(res, c_loc(array), shape(array, kind=PY
                                                   1
Error: Assumed-shape array 'array' at (1) cannot be an argument to the procedure 'c_loc' because it is not C interoperable
forpy_mod.F90:8094.51:

  ierror = ndarray_create_nocopy_helper(res, c_loc(array), shape(array, kind=PY
                                                   1
Error: Assumed-shape array 'array' at (1) cannot be an argument to the procedure 'c_loc' because it is not C interoperable
Fatal Error: Error count reached limit of 25.
1 Answers

You are using a version of the compiler which does not support several features used in the code. You should use a later compiler release or a different compiler (or avoid using those features).

There are two different aspects to look at here.

First:


  character(kind=C_CHAR, len=:), pointer :: doc_string
                                                      1
Error: Deferred-length character component 'doc_string' at (1) is not yet supported
forpy_mod.F90:1961.54:

Here the compiler is quite explicitly saying "I know your code is fine, but I don't know what to do with it. Yet." This "not yet supported" is a big hint to look for a later compiler release.

Deferred-length character components of a derived type are a Fortran 2003 feature, but this feature was not supported until gfortran 4.9 even though the syntax is understood.

Second:

  buffer%format = c_loc(format_c_string)
                        1
Error: CHARACTER argument 'format_c_string' to 'c_loc' at (1) must have a length of 1
forpy_mod.F90:9186.51:

  ierror = ndarray_create_nocopy_helper(res, c_loc(array), shape(array, kind=PY
                                                   1
Error: Assumed-shape array 'array' at (1) cannot be an argument to the procedure 'c_loc' because it is not C interoperable
forpy_mod.F90:9102.51:

Here the compiler is complaining in a slightly different way. While our first case was "I know your code is fine, but I don't know what to do with it." here we have "Your code is wrong and I'm not doing what you ask."

Fortran is an evolving language. As with deferred-length characters being added (and being available as a component of a derived type), restrictions may change with the language.

Fortran 2003 c_loc often required its argument to be C-interoperable. Under a Fortran 2003 interpretation an assumed-shape array cannot be an argument to c_loc, and neither can a character not of length 1. Fortran 2008 relaxes the restrictions on c_loc's arguments: for this code you need a compiler which implements the rules as they are in Fortran 2008 (or later) not as they were in Fortran 2003.

Related