I've built an application ("Checkyrs") in C++, and now am doing something external which will use large parts of Checkyrs but is built in Python 3. (This is all something in my free time, so it doesn't need to be Python 3, but that's my preference.)
To get an interface between the python and C++, I'm using SWIG and the python distutils package. I've built a dynamic library containing what I need from Checkyrs, and I've successfully built a Python extension ("checkyrsai") using the tools I mentioned. I've tested it in Python 2.7 and it works fully, all of the C++ classes and functions I need are available and function correctly.
But my preference is to work with Python 3, and while I can build the extension with Python 3 I'm unable to load it successfully:
Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 23 2015, 02:52:03)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import checkyrsai
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/chris/Documents/Programming/eggyolk/checkyrsai.py", line 28, in <module>
_checkyrsai = swig_import_helper()
File "/Users/chris/Documents/Programming/eggyolk/checkyrsai.py", line 24, in swig_import_helper
_mod = imp.load_module('_checkyrsai', fp, pathname, description)
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/imp.py", line 243, in load_module
return load_dynamic(name, filename, file)
ImportError: dlopen(/Users/chris/Documents/Programming/eggyolk/_checkyrsai.so, 2): Symbol not found: __ZN4Game11ExecuteMoveERKSt6vectorI8PositionSaIS1_EE
Referenced from: /Users/chris/Documents/Programming/eggyolk/_checkyrsai.so
Expected in: flat namespace
in /Users/chris/Documents/Programming/eggyolk/_checkyrsai.so
My process for building the extension (for Python 2) is:
swig -c++ -python checkyrsai.i
python setup.py build_ext --inplace
where my setup.py file looks like this:
from distutils.core import setup, Extension
import os
os.environ["CC"] = "g++"
checkyrsai = Extension('_checkyrsai',
sources = ['checkyrsai_wrap.cxx','../checkyrs/checkyrs/ai.cpp'],
include_dirs = ['/usr/local/include','../checkyrs/checkyrs'],
libraries = ['Checkyrs'],
library_dirs = ['../checkyrs/Build/Products/Release/','/usr/local/lib'],
extra_compile_args = ['-std=c++11']
)
setup (name = 'checkyrs',
version = '1.0',
description = 'checkyrs',
ext_modules = [checkyrsai])
As I said above, this works perfectly. From this point I can open my python (2.7) interpreter,
import checkyrsai
and off I go to play with my new toy.
When trying to build for Python 3 I use almost exactly the same process, just with the addition of Python 3 flags for SWIG and running distutils through Python 3:
swig -c++ -python -py3 checkyrsai.i
python3 setup.py build_ext --inplace
this runs through the compilation successfully and produces the extension, but when I try to
import checkyrsai
I get the ImportError […] Symbol not found issue quoted above.
I don't change my code or the setup.py script in any way between the Python 2 and Python 3 versions. The symbol refers to a method which should be found in my libCheckyrs.dylib. It evidently is available there as it is used successfully when I use the Python 2.7 extension - but it seems not to be found when I make the extension for Python 3. Does anybody have any suggestion where I'm going wrong?
I eventually solved this issue by changing XCode project settings for the C++ library I was linking against.
Specifically, changing the "C++ Language Dialect" setting to "C++ [-std=c++11]", i.e. the same version I had specified in the extra_compile_args setting for distutils. Previously it had been GNU++11, hence symbols not matching as there was a mismatch in the namespace (std::vector vs. std::__1::vector).
With that change I'm now happily and successfully able to call my C++ code from Python 3.
I don't really understand why it did work in python 2.7, since it was using all the same distutils settings, with the same C++ version specified and the linking against the same C++ lib. If anybody has an explanation for that I'd love to hear it.