Access Common Block variables from ctypes
<p>I am trying to access the data stored in a Fortran 77 common block from a Python script. The question is that I don't know where this data is stored.
The Python application that I am developing makes use of different libraries. These libraries contain functions with the following directives:</p>

<pre><code>#include &lt;tcsisc_common.inc&gt;
</code></pre>

<p>The common block contains:</p>

<pre><code>C
      INTEGER*4 IDEBUG
C
C.... ARRAY DIMENSIONS
      DIMENSION IDEBUG(10)
C
C.... COMMON BLOCK
      COMMON /TCSD/ IDEBUG
C
</code></pre>

<p>On the Python part (on the example I have used iPython), I load the library: </p>

<pre><code>In [1]: import ctypes
In [2]: _libtcsisc= /home/jfreixa/project/bin/libtcsisc.so
In [3]: _tcsisc   = ctypes.CDLL(_libtcsisc, ctypes.RTLD_GLOBAL)
</code></pre>

<p>The problem is that I don't know how to get IDEBUG. I have tried the following, but I just get tcsd as a c_long initialized to 0.</p>

<pre><code>In [4]: tcsd = ctypes.c_int.in_dll(_tcsisc, "TCSD_")
In [5]: tcsd
Out[5]: c_long(0)
In [6]: idebug = ctypes.c_int.in_dll(_tcsisc, "IDEBUG_")
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
&lt;ipython-input-6-ee5018286275&gt; in &lt;module&gt;()

----&gt; 1 idebug = ctypes.c_int.in_dll(_tcsisc,'IDEBUG_')

ValueError: ld.so.1: python2.7: fatal: IDEBUG_: can't find symbol
</code></pre>

<p>Any idea to correctly get the variable?</p>

<p>According to <a href="http://www.yolinux.com/TUTORIALS/LinuxTutorialMixingFortranAndC.html" rel="nofollow">this page</a> (particularly how to access Fortran common blocks from C) and some <a href="http://stackoverflow.com/questions/35346835/how-to-access-to-c-global-variable-structure-by-python-and-ctype">Q/A page</a> about how to access C struct from Python, it seems that we could access common blocks as follows (though this may be not very portable, see below):</p>

<p>mylib.f90</p>

<pre><code>subroutine fortsub()
    implicit none
    integer n
    common /mycom/ n
    print *, "fortsub&gt; current /mycom/ n = ", n
end
</code></pre>

<p>compile:</p>

<pre><code>$ gfortran -shared -fPIC -o mylib.so mylib.f90
</code></pre>

<p>test.py</p>

<pre><code>from __future__ import print_function
import ctypes

class Mycom( ctypes.Structure ):
    _fields_ = [ ( "n", ctypes.c_int ) ]

mylib = ctypes.CDLL( "./mylib.so" )

mycom = Mycom.in_dll( mylib, "mycom_" )

print( " python&gt; modifying /mycom/ n to 777" )

mycom.n = 777

fortsub = mylib.fortsub_
fortsub()
</code></pre>

<p>Test:</p>

<pre><code> $ python test.py 
 python&gt; modifying /mycom/ n to 777
 fortsub&gt; current /mycom/ n =          777
</code></pre>

<p>Here, please note that the name of the common block (here, <code>mycom</code>) is made lowercase and one underscore attached (by assuming gfortran). Because this convention is compiler-dependent, it may be more robust/portable to write new Fortran routines for setting/getting values in common blocks (particularly with the help of <code>iso_c_binding</code>) and call those routines from Python (as suggested by @innoSPG in the first comment).</p>

<hr>

<p>Another example including different types and arrays may look like this:</p>

<p>mylib.f90</p>

<pre><code>subroutine initcom()
    implicit none
    integer          n( 2 ), w  !! assumed to be compatible with c_int
    real             f( 2 )     !!                      ... with c_float
    double precision d( 2 )     !!                      ... with c_double
    common /mycom/ n, f, d, w

    print *, "(fort) initializing /mycom/"
    n(:) = [ 1, 2 ]
    f(:) = [ 3.0, 4.0 ]
    d(:) = [ 5.0d0, 6.0d0 ]
    w    = 7
    call printcom()
end

subroutine printcom()
    implicit none
    integer          n( 2 ), w
    real             f( 2 )
    double precision d( 2 )
    common /mycom/ n, f, d, w

    print *, "(fort) current /mycom/"
    print *, "       n = ", n
    print *, "       f = ", f
    print *, "       d = ", d
    print *, "       w = ", w
end
</code></pre>

<p>test.py</p>

<pre><code>from __future__ import print_function
import ctypes

N = 2

class Mycom( ctypes.Structure ):
    _fields_ = [ ( "x", ctypes.c_int    * N ),
                 ( "y", ctypes.c_float  * N ),
                 ( "z", ctypes.c_double * N ),
                 ( "w", ctypes.c_int        ) ]

mylib = ctypes.CDLL( "./mylib.so" )

mycom = Mycom.in_dll( mylib, "mycom_" )

initcom = mylib.initcom_
initcom()

print( " (python) current /mycom/" )
print( "          x = ", mycom.x[:] )
print( "          y = ", mycom.y[:] )
print( "          z = ", mycom.z[:] )
print( "          w = ", mycom.w    )

print( " (python) modifying /mycom/ ..." )
for i in range( N ):
    mycom.x[ i ] = (i + 1) * 10
    mycom.y[ i ] = (i + 1) * 100
    mycom.z[ i ] = (i + 1) * 0.1
mycom.w = 777

printcom = mylib.printcom_
printcom()
</code></pre>

<p>Test:</p>

<pre><code> $ python test.py

 (fort) initializing /mycom/
 (fort) current /mycom/
        n =            1           2
        f =    3.0000000       4.0000000    
        d =    5.0000000000000000        6.0000000000000000     
        w =            7
 (python) current /mycom/
          x =  [1, 2]
          y =  [3.0, 4.0]
          z =  [5.0, 6.0]
          w =  7
 (python) modifying /mycom/ ...
 (fort) current /mycom/
        n =           10          20
        f =    100.00000       200.00000    
        d =   0.10000000000000001       0.20000000000000001     
        w =          777
</code></pre>

python fortran ctypes