Link to Python with MinGW
Question: I wan't want to create a cross-plattform programm that embedds the python
interpreter, and compile it with MinGW. But the Python Binary distribution
provides no libraries for MinGW to link with (only `python32.lib` for Visual
C++), and the Python Source package provides no support for compiling with
MinGW.

I tried linking to `python32.lib` in Mingw with `-lpython32` but it still
generates errors like:

    
    
    main.cpp: undefined reference to `_imp__Py_Initialize'
    main.cpp: undefined reference to `_imp__Py_Finalize'
    

How do I link Python in MinGW? I really don't want to switch to using Visual
C++.


Answer: With nm and dlltool from binutils, you should be able to rebuild the library
for gcc:

    
    
    echo EXPORTS > python32.def
    nm python32.lib | grep " T _" | sed "s/.* T _//" >> python32.def
    dlltool --input-def python32.def --dllname python32 --output-lib libpython32.a
    

python_test.c:

    
    
    #include "Python.h"
    
    int main(int argc, char *argv[]) {
        Py_Initialize();
        PyRun_SimpleString("from time import time,ctime\n"
                           "print('Today is',ctime(time())\n)");
        Py_Finalize();
        return 0;
    }
    

Compile:

    
    
    gcc -Wall -IC:\Python32\include -LC:\Python32\libs -o python_test.exe python_test.c -lpython32
    

Test:

    
    
    C:\python_test.exe
    Today is Mon Jul 18 08:50:53 2011
    

**Edit** : If you'd prefer to skip building this yourself on x64, you can
download it for several versions from Christoph Gohlke's [Unofficial Windows
Binaries for Python Extension
Packages](http://www.lfd.uci.edu/~gohlke/pythonlibs/#libpython).

**Edit** : Here's a Python version based on the existing function that's
distributed in Tools/msi/msi.py:

    
    
    import subprocess
    import warnings
    import re
    
    NM = 'x86_64-w64-mingw32-nm'
    DLLTOOL = 'x86_64-w64-mingw32-dlltool'
    EXPORT_PATTERN = r'^[_]{1,2}imp_(?P<export>.*) in python\d+\.dll'
    
    def build_libpython(ver, nm=NM, dlltool=DLLTOOL,
                        export_pattern=EXPORT_PATTERN):
        pylib = 'python%s.lib' % ver
        pydef = 'python%s.def' % ver
        pydll = 'python%s.dll' % ver
        libpy = 'libpython%s.a' % ver
        warning = '%s failed - ' + '%s not built' % libpy
        match_export = re.compile(export_pattern).match
        cmd_nm = [nm, '-Cs', pylib]
        cmd_dlltool = [dlltool, 
                       '--dllname', pydll, 
                       '--def', pydef,
                       '--output-lib', libpy]
        with open(pydef, 'w') as f:
            f.write('LIBRARY %s\nEXPORTS\n' % pydll)
            p_nm = subprocess.Popen(cmd_nm, 
                                    stdout=subprocess.PIPE,
                                    universal_newlines=True)
            for line in sorted(p_nm.stdout):
                m = match_export(line)
                if m:
                    f.write(m.group('export') + '\n')
            if p_nm.wait() != 0:
                warnings.warn(warning % nm)
                return False
        if subprocess.call(cmd_dlltool) != 0:
            warnings.warn(warning % dlltool)
            return False
        return True
    

For example:

    
    
    import os
    for n in (27, 33, 35):
        pylib = 'python%s.lib' % n
        if os.path.exists(pylib):
            build_libpython(n)
            pydef = 'python%s.def' % n            
            lc_def = sum(1 for line in open(pydef))
            libpy = 'libpython%s.a' % n
            lc_lib = sum(1 for line in os.popen('ar -t %s' % libpy))
            assert lc_def == lc_lib
    

