3

I am trying to figure out how to use C/C++ code in python using Cython. I can get the following example working as C code:

sum.h:

#ifndef MY_SUM_H_
#define MY_SUM_H_

int my_sum(int a, int b);

#endif

sum.c:

int my_sum(int a, int b){
    return a + b;
}

test.pyx:

cdef extern from "my_sum.h":
    cdef int my_sum(int a, int b)

cpdef sum_wrap(int a, int b):
    return my_sum(a, b)

setup.py:

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

ext_modules = [Extension("test", ["test.pyx", "my_sum.c"], language = "c")]

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

However, if I try to test it as C++ code it fails. I rename sum.c to sum.cpp and change language to c++ in setup.py. After that, it looks like this:

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

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

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

That should be enough right? It produces the following error:

$ python setup.py build_ext --inplace
running build_ext
cythoning test.pyx to test.cpp
/Users/jensrenders/miniconda3/lib/python3.7/site-packages/Cython/Compiler/Main.py:367: FutureWarning: Cython directive 'language_level' not set, using 2 for now (Py2). This will change in a later release! File: /Users/jensrenders/Dropbox/cython_demo/test.pyx
  tree = Parsing.p_module(s, pxd, full_module_name)
building 'test' extension
gcc -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I/Users/jensrenders/miniconda3/include -arch x86_64 -I/Users/jensrenders/miniconda3/include -arch x86_64 -I/Users/jensrenders/miniconda3/include/python3.7m -c test.cpp -o build/temp.macosx-10.7-x86_64-3.7/test.o
warning: include path for stdlibc++ headers not found; pass '-std=libc++' on the command line to use the libc++ standard
      library instead [-Wstdlibcxx-not-found]
1 warning generated.
gcc -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I/Users/jensrenders/miniconda3/include -arch x86_64 -I/Users/jensrenders/miniconda3/include -arch x86_64 -I/Users/jensrenders/miniconda3/include/python3.7m -c my_sum.cpp -o build/temp.macosx-10.7-x86_64-3.7/my_sum.o
warning: include path for stdlibc++ headers not found; pass '-std=libc++' on the command line to use the libc++ standard
      library instead [-Wstdlibcxx-not-found]
1 warning generated.
g++ -bundle -undefined dynamic_lookup -L/Users/jensrenders/miniconda3/lib -arch x86_64 -L/Users/jensrenders/miniconda3/lib -arch x86_64 -arch x86_64 build/temp.macosx-10.7-x86_64-3.7/test.o build/temp.macosx-10.7-x86_64-3.7/my_sum.o -o /Users/jensrenders/Dropbox/cython_demo/test.cpython-37m-darwin.so
clang: warning: libstdc++ is deprecated; move to libc++ with a minimum deployment target of OS X 10.9 [-Wdeprecated]
ld: library not found for -lstdc++
clang: error: linker command failed with exit code 1 (use -v to see invocation)
error: command 'g++' failed with exit status 1

I do get a test.cpp file as output but no shared object. What causes this, and how can it be solved?

Thanks for your help!


EDIT: As @MaximEgorushkin points out, it is strange that cython tries to compile the C++ files with gcc. I can force it to use g++ by adding os.environ["CC"] = "g++" to setup.py, but this does not solve the problem:

$ python setup.py build_ext --inplace
running build_ext
building 'test' extension
g++ -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I/Users/jensrenders/miniconda3/include -arch x86_64 -I/Users/jensrenders/miniconda3/include -arch x86_64 -I/Users/jensrenders/miniconda3/include/python3.7m -c test.cpp -o build/temp.macosx-10.7-x86_64-3.7/test.o
warning: include path for stdlibc++ headers not found; pass '-std=libc++' on the command line to use the libc++ standard
      library instead [-Wstdlibcxx-not-found]
1 warning generated.
g++ -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I/Users/jensrenders/miniconda3/include -arch x86_64 -I/Users/jensrenders/miniconda3/include -arch x86_64 -I/Users/jensrenders/miniconda3/include/python3.7m -c my_sum.cpp -o build/temp.macosx-10.7-x86_64-3.7/my_sum.o
warning: include path for stdlibc++ headers not found; pass '-std=libc++' on the command line to use the libc++ standard
      library instead [-Wstdlibcxx-not-found]
1 warning generated.
g++ -bundle -undefined dynamic_lookup -L/Users/jensrenders/miniconda3/lib -arch x86_64 -L/Users/jensrenders/miniconda3/lib -arch x86_64 -arch x86_64 build/temp.macosx-10.7-x86_64-3.7/test.o build/temp.macosx-10.7-x86_64-3.7/my_sum.o -o /Users/jensrenders/Dropbox/cython_demo/test.cpython-37m-darwin.so
clang: warning: libstdc++ is deprecated; move to libc++ with a minimum deployment target of OS X 10.9 [-Wdeprecated]
ld: library not found for -lstdc++
clang: error: linker command failed with exit code 1 (use -v to see invocation)
error: command 'g++' failed with exit status 1
Jens Renders
  • 496
  • 1
  • 4
  • 17
  • 1
    It should use `g++` to compile `.cpp` files, not `gcc ... -c my_sum.cpp -o my_sum.o`. – Maxim Egorushkin Mar 30 '19 at 21:32
  • Just for your info, the C declaration `int my_sum(int, int)` in C++ is `extern "C" int my_sum(int, int)`. If you don't adjust the according declaration in the Cython code, they don't match and thus things fail. BTW: There is no such thing as "C/C++ code", C and C++ are different languages. – Ulrich Eckhardt Mar 30 '19 at 21:33
  • @UlrichEckhardt In C++ `int my_sum(int, int)` is `extern "C++"`. And that is what needed here. – Maxim Egorushkin Mar 30 '19 at 21:37
  • @UlrichEckhardt Yes, they are different languages, but my C code above is also valid C++ code right? I try to treat it as C++ code to later use more C++ features once this works. – Jens Renders Mar 30 '19 at 21:40
  • Reading the warning and error messages, it appears the C++ standard library is not properly installed. The commands being executed to compile as C++ and link both appear to need it (which is fairly normal when building as C++). So you will need to check that your C++ compiler and standard library are properly installed, and that the compiler is finding a version of the standard library and associated headers that it expects. The problem may also be caused by incorrectly set environment variables. – Peter Mar 30 '19 at 22:03
  • @Peter Can you povide guidelines on how to do that? maybe as an answer? BTW: I write and compile pure C++ code on this machine from time to time and that works fine. – Jens Renders Mar 30 '19 at 22:07
  • I don't understand what you are trying to tell me, @MaximEgorushkin. Of course, without an explicit `extern "..."` in the declaration it uses the language default, but that's kind of a given. – Ulrich Eckhardt Mar 30 '19 at 22:09
  • If you installed the various packages (compiler, library, python, etc) you'll need to check what you did - read documentation on the packages and their setup. If the packages were installed by someone else (like an administrator) you'll need to check with them - either they need to fix the installations, or provide guidance on what you need to set up (environment variables, path settings, command line options) to use the applications appropriately. Without knowing how things are set up on your system, it's hard to give specific advice to fix the problem. – Peter Mar 30 '19 at 23:15

1 Answers1

3

Here is a similar problem: https://github.com/pandas-dev/pandas/issues/23424

As they suggest, and as indicated by the line in the output

clang: warning: libstdc++ is deprecated; move to libc++ with a minimum deployment target of OS X 10.9 [-Wdeprecated]

adding extra_link_args=["-stdlib=libc++", "-mmacosx-version-min=10.9"] solves the problem. setup.py then looks like this:

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

ext_modules = [Extension("test",
                         sources=["test.pyx", "my_sum.cpp"],
                         language="c++",
                         extra_link_args=["-stdlib=libc++", "-mmacosx-version-min=10.9"])]

setup(cmdclass = {'build_ext': build_ext}, ext_modules = ext_modules)
Jens Renders
  • 496
  • 1
  • 4
  • 17