tags:

views:

430

answers:

2

I'm new to Cython and I'm tring to use Cython to wrap a C/C++ static library. I made a simply example as following.

Test.h:

#ifndef TEST_H
#define TEST_H

int add(int a, int b);
int multipy(int a, int b);

#endif

Test.cpp

#include "test.h"
int add(int a, int b)
{
    return a+b;

}

int multipy(int a, int b)
{
    return a*b;
} 

Then I used g++ to compile and build it.

g++ -c test.cpp -o libtest.o
ar rcs libtest.a libtest.o

So now I got a static library called libtest.a.

Test.pyx:

cdef extern from "test.h":
        int add(int a,int b)
        int multipy(int a,int b)

print add(2,3)

Setup.py:

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

ext_modules = [Extension("test",
                     ["test.pyx"],
                     language='c++',
                     include_dirs=[r'.'],
                     library_dirs=[r'.'],
                     libraries=['libtest']
                     )]

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

The I called:

python setup.py build_ext --compiler=mingw32 --inplace

The output was:

running build_ext
cythoning test.pyx to test.cpp
building 'test' extension
creating build
creating build\temp.win32-2.6
creating build\temp.win32-2.6\Release
C:\Program Files\pythonxy\mingw\bin\gcc.exe -mno-cygwin -mdll -O -Wall -I. -IC:\
Python26\include -IC:\Python26\PC -c test.cpp -o build\temp.win32-2.6\Release\test.o
writing build\temp.win32-2.6\Release\test.def
C:\Program Files\pythonxy\mingw\bin\g++.exe -mno-cygwin -mdll -static --entry _D
llMain@12 --output-lib build\temp.win32-2.6\Release\libtest.a --def build\temp.w
in32-2.6\Release\test.def -s build\temp.win32-2.6\Release\test.o -L. -LC:\Python
26\libs -LC:\Python26\PCbuild -ltest -lpython26 -lmsvcr90 -o test.pyd
g++: build\temp.win32-2.6\Release\libtest.a: No such file or directory
error: command 'g++' failed with exit status 1

I also tried to use libraries=['test'] instead of libraries=['libtest']. It gave me the same errors.

Any clue about those?

Thanks!

+1  A: 

I think you can fix this specific problem by specifying the right library_dirs (where you actually put libtest.a -- apparently it's not getting found), but I think then you'll have another problem -- your entry points are not properly declared as extern "C", so the function's names will have been "mangled" by the C++ compiler (look at the names exported from your libtest.a and you'll see!), so any other language except C++ (including C, Cython, etc) will have problems getting at them. The fix is to declare them as extern "C".

Alex Martelli
Where should I declare extern "C"? However, i think the problem now is that the build complains it can't find libtest.a instead of one of the function, i.e. add() or mulitpy(). So I'm not sure whether this will work.It is quite weird to me that it complained there is no libtest.a in 'build\temp.win32-2.6\Release'. Isn't that the build folder generated by Cython itself? Why did Cython try to look for the libtest.a there?
zyq524
`extern "C"` goes in the functions' declarations in the `.h`, and as I said that's the next problem you'll face after you fix the incorrect `library_dirs` (you say libraries are "in the current directory" and the `Release` one happens to be the current directory at the time the compiler/linker is looking for the library).
Alex Martelli
+2  A: 

If your C++ code is only used by the wrapper, another option is to let the setup compile your .cpp file, like this:

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

ext_modules = [Extension("test",
                     ["test.pyx", "test.cpp"],
                     language='c++',
                     )]

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

For linking to a static library you have to use the extra_objects argument in your Extension:

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

ext_modules = [Extension("test",
                     ["test.pyx"],
                     language='c++',
                     extra_objects=["libtest.a"],
                     )]

setup(
  name = 'test',
  cmdclass = {'build_ext': build_ext},
  ext_modules = ext_modules
)
Luper Rouch
No, I made 'test.cpp' only for testing. In the real project, I only have a head file and a static library.
zyq524
It seems like what you want is the `extra_objects` option, edited answer.
Luper Rouch