How to statically link a library when compiling a python module extension

6 - 7 years later, static linking with Python extensions is still poorly documented. As the OP points out in a comment, the usage is OS dependend.

On Linux / Unix

Static libraries are linked just as object files and should go with the path and its extension into extra_objects.

On Windows

The compiler sees if the linked library is static or dynamic and the static library name goes to the libraries list and the directories to library_dir

Solution for both platforms

For the example below, I will use the same library scenario as OP, linking igraph static and z, xml2 and gmp dynamic. This solution is a bit hackish, but at least does for each platform the right thing.

static_libraries = ['igraph']
static_lib_dir = '/system/lib'
libraries = ['z', 'xml2', 'gmp']
library_dirs = ['/system/lib', '/system/lib64']

if sys.platform == 'win32':
    libraries.extend(static_libraries)
    library_dirs.append(static_lib_dir)
    extra_objects = []
else: # POSIX
    extra_objects = ['{}/lib{}.a'.format(static_lib_dir, l) for l in static_libraries]

ext = Extension('igraph.core',
                 sources=source_file_list,
                 libraries=libraries,
                 library_dirs=library_dirs,
                 include_dirs=include_dirs,
                 extra_objects=extra_objects)

On MacOS

I guess this works also for MacOS (using the else path) but I have not tested it.


If all else fails, there's always the little-documented extra_compile_args and extra_link_args options to the Extension builder. (See also here.)

You might need to hack in some OS-dependent code to get the right argument format for a particular platform though.