6

I've got a c++ program I'm trying to wrap/convert to Cython. It uses a particular library that for some reason, will not result in a working module for importing. There is a working c++ program, by the way. Here's the setup.py:

ext_modules = [
Extension(
    name="libnmfpy",
    sources=["interface/nmf_lib.pyx"],
    include_dirs = ["../src/", numpy.get_include()],
    libraries=["nmf","mpi_cxx","mpi","m"],
    library_dirs=["../build/Linux/bin.release","/usr/local/lib/","/usr/lib"],
    language="c++",)
]

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

I should mention it is libnmf that seems to be causing problems. The first build of libnmf would cause this script to generate this error:

/usr/bin/ld: ../build/Linux/bin.release/libnmf.a(nmf.o): relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
../build/Linux/bin.release/libnmf.a: could not read symbols: Bad value
collect2: error: ld returned 1 exit status

When I rebuild libnmf with -fPIC, setup generates a libnmfpy.so, but when I import that in another script, I would get the aforementioned undefined symbol:

Traceback (most recent call last):
File "test.py", line 1, in <module>
    import libnmfpy
ImportError: $path/cython/libnmfpy.so: undefined symbol: _ZN4elem6lapack3SVDEiiPdiS1_

If it would help, here's something my search suggested:

nm libnmfpy.so | grep _ZN4elem6lapack3SVDEiiPdiS1_
             U _ZN4elem6lapack3SVDEiiPdiS1_

nm ../build/Linux/bin.release/libnmf.a | grep _ZN4elem6lapack3SVDEiiPdiS1_
             U _ZN4elem6lapack3SVDEiiPdiS1_

Which is what I guess to the cause of the error. I look in what I think is the offending library that libnmf is built on:

nm $another_path/lib/libelemental.a | grep _ZN4elem6lapack3SVDEiiPdiS1_
0000000000005290 T _ZN4elem6lapack3SVDEiiPdiS1_

I am not too familiar yet with libraries and linkers, so any help would be appreciated. Thanks

edit: a little digging made me realize something. Is there a difference between Mac OS X and Linux that I should watch out for? The people I work for that wrote this originally reported no build errors like this

Ben
  • 2,065
  • 1
  • 13
  • 19
  • Did you solve your problem? About the difference MacOSX/Linux, since 10.9 OSX compiler defaults to `libc++` instead of `libstdc++`, as you can read [here](https://support.enthought.com/entries/26184115-GCC-Clang-and-Cython-in-OS-X-10-9-Mavericks). On a project I was working on I was linking the C++ code to one library and the cython code to the other. This resulted in a similar undefined symbol error. – gg349 May 11 '14 at 17:13

2 Answers2

2

You should use nm -C, to unmangle your symbols. It also looks like you are mixing static and shared libraries which is generally not a good idea. Also, gcc's linker is a one pass linker which means the order of library flags matters. You want to list the libraries in reverse dependency order. In other words, if a depends on b, then b must appear before a in the linker flags.

b4hand
  • 9,550
  • 4
  • 44
  • 49
  • 1
    "it looks like you are mixing static and shared libraries". Can you be more specific? – gg349 Apr 30 '14 at 16:09
  • could you explain what the -C flag does? I tried adding that to the commands and now nothing shows. – Ben Apr 30 '14 at 18:43
  • -C is short for --demangle in [GNU nm](http://sourceware.org/binutils/docs/binutils/nm.html). On Mac you'll need to use [c++filt](http://stackoverflow.com/questions/2424576/unmangling-c-names-on-mac-10-5) . – b4hand May 01 '14 at 15:24
1

Well I can't try to recreate your setup and then work out and test a solution on my setup since I don't have your source, but it seems to me that when you recompiled libnmf with fpic, it was recompiled with dynamic linking, while before it used to be statically linked.

If my guess is correct, then you can try either:

  1. compiling libnmf again with -fPIC , AND -static.
  2. changing your setup.py - add "elemental" to the libraries list - this will make the linker fetch that lib as well.

You should note that approach #1 is usually considered less desirable, but as I said it could be that it was originally compiled that way anyways. #2, however, could take more work because if there are other libs that are required, you will have to find and add them as well.

itai
  • 1,566
  • 1
  • 12
  • 25
  • 1) why both `-fPIC` and `-static`? What's the role of `-static`? 2) what is `elemental`? – gg349 Apr 30 '14 at 16:13
  • I can answer 2 I guess: elemental is a linear algebra library - http://libelemental.org/. And it is compiled as a static library but I have not needed -static outside of this cython integration so I don't know about that – Ben Apr 30 '14 at 16:21
  • basically: -fPIC means that the library will be compiled in such a way that it can be relocated within the process memory. -static, means that it will gather all dependencies to make a standalone library. In this case it seems libnmf needs libelemental. without -static this is just postponed and later the dynamic linker just cant find it. – itai Apr 30 '14 at 17:00