Как связать пользовательский C (который сам требует специальных параметров компиляции) с Cython?

поэтому я пытаюсь создать модуль Cython, который использует написанный мной файл .c. Этот файл .c нуждается в специальной опции компоновки (для его компиляции мне нужен gcc -o mycode mycode.c -lfftw3f). Потенциально я мог бы просто переписать свой файл .c на Cython, но я хочу знать, как это сделать.

Я использую fftw3, и при компиляции вам нужно использовать параметр -lfftw3f ДОПОЛНИТЕЛЬНО к #include <fftw3.h> в файле .c, если вы хотите использовать версию с плавающей запятой, что я и делаю.

Мой setup.py выглядит следующим образом:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

sourcefiles = ['mycode_caller.pyx', 'mycode.c']

ext_modules = [Extension("myext", sourcefiles, libraries=['fttw3f'])]

setup(
  name = 'My Extension',
  cmdclass = {'build_ext': build_ext},
  ext_modules = ext_modules
)

Я создал заголовочный файл с именем mycode.h, который выглядит следующим образом и включает прототип функции transform(), которая определена в mycode.c:

#include <fftw3.h>
#include <math.h>

#ifndef FOURIER_H_INCLUDED
#define FOURIER_H_INCLUDED
fftwf_complex** transform(float** in, int length);
#endif

И мой файл Cython, mycode_caller.pyx, выглядит так:

import numpy as np
cimport numpy as np

cdef extern from "stdlib.h":
    void free(void* ptr)
    void* malloc(size_t size)

cdef extern from "fftw3.h":
    struct fftwf_complex:
        pass

cdef extern from "fourier.h":
    fftwf_complex** transform(float** in_arr, int length)

cdef float** npy2c_float2d(np.ndarray[float, ndim=2] a):
    cdef float** a_c = <float**>malloc(a.shape[0] * sizeof(float*))
    for k in range(a.shape[0]):
        a_c[k] = &a[k, 0]
    return a_c

cpdef test_transform(data):
    nparr = np.zeros([14, 31])
    c_array = npy2c_float2d(nparr)
    ans = transform(c_array, 31)

Когда я запускаю python setup.py build_ext --inplace, он строится нормально, но если я попытаюсь его импортировать, он будет утверждать следующее:

ImportError: ./myext.so: undefined symbol: fftwf_execute

Эта ошибка возникает из-за того, что параметр -lfftw3f не был передан в gcc во время компиляции. Как решить эту проблему? Невозможно указать команды компоновщика в исходном файле .c, верно? Нужно ли как-то указывать Cython.Distutils, чтобы использовать эту опцию? Спасибо за помощь!

РЕДАКТИРОВАТЬ: Итак, я добавил libraries=[fttw3f] в свой файл setup.py, и теперь он выдает ошибку при сборке:

gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -Wl,-z,relro build/temp.linux-x86_64-2.7/emodsp.o build/temp.linux-x86_64-2.7/fourier.o -lfftw3f -o /home/carson/Documents/Caltech/Senior/Winter/art89/Project/openepoc/emodsp.so
/usr/bin/ld: /usr/local/lib/libfftw3f.a(alloc.o): relocation R_X86_64_32 against `.rodata.str1.1' can not be used when making a shared object; recompile with -fPIC
/usr/local/lib/libfftw3f.a: could not read symbols: Bad value
collect2: error: ld returned 1 exit status
error: command 'gcc' failed with exit status 1

person Carson McNeil    schedule 19.02.2013    source источник


Ответы (1)


Просто используйте параметр libraries для Extension:

Extension("myext", sourcefiles, libraries = ['fftw3f'], library_dirs = ['/path/to/fftw/libs'])
person nneonneo    schedule 19.02.2013
comment
Это полезно, спасибо! Но теперь выдает другую ошибку. - person Carson McNeil; 19.02.2013
comment
У вас есть версия fftw3f с общей библиотекой или только статическая версия? Связывание статической библиотеки с общей библиотекой иногда приводит к подобным проблемам. - person nneonneo; 19.02.2013
comment
@nneonneo Если загрузка общей библиотеки невозможна, как можно решить проблему привязки статической библиотеки к общей библиотеке? - person paulinho; 22.03.2018