I'm trying to build a small Python extension for a certain instantiation of a templated library, using Boost.Python. This library uses extensively the CGAL library, which integrates fairly well with CMake, that I'm therefore using for my project.
Here's the code for my module (python_export.cpp):
#include <boost/python.hpp>
#include <CGAL/Exact_spherical_kernel_3.h>
#include "Sphere_intersecter.h" // header-only
typedef CGAL::Exact_spherical_kernel_3 SK;
template class Sphere_intersecter<SK>; // explicit for "-fno-implicit-templates"
typedef Sphere_intersecter<SK> SI;
BOOST_PYTHON_MODULE(thickness_diag)
{
using namespace boost::python;
class_<SI>("SphereIntersecter", no_init)
.def("add_sphere", &SI::add_sphere)
;
}
And the CMakeLists.txt:
cmake_minimum_required(VERSION 2.6.2)
project(ThicknessDiag-Python)
# CGAL
find_package(CGAL REQUIRED)
include(${CGAL_USE_FILE})
# Boost
find_package(Boost REQUIRED COMPONENTS python)
find_package(PythonLibs 2.7 REQUIRED)
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${PYTHON_INCLUDE_DIRS})
# Shared library
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-implicit-templates")
set(ThicknessDiag-Python "thickness_diag")
add_library(${ThicknessDiag-Python} SHARED python_export.cpp)
set_target_properties(${ThicknessDiag-Python} PROPERTIES PREFIX "")
target_link_libraries(${ThicknessDiag-Python}
${PYTHON_LIBRARIES} ${Boost_LIBRARIES}
${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES})
Detailed output of the compile command:
[100%] Building CXX object CMakeFiles/thickness_diag.dir/python_export.cpp.o
/usr/bin/c++ -Dthickness_diag_EXPORTS -DCGAL_USE_MPFR -DCGAL_USE_GMP -frounding-math -fno-implicit-templates -O3 -DNDEBUG -fPIC -isystem /usr/local/include -I/usr/include/python2.7 -o CMakeFiles/thickness_diag.dir/python_export.cpp.o -c /home/jmcomets/ThicknessDiag/tests/python_export.cpp
Linking CXX shared library thickness_diag.so
/usr/bin/c++ -fPIC -frounding-math -fno-implicit-templates -O3 -DNDEBUG -shared -Wl,-soname,thickness_diag.so -o thickness_diag.so CMakeFiles/thickness_diag.dir/python_export.cpp.o -L/usr/local/lib -lmpfr -lgmp /usr/local/lib/libCGAL.so /usr/local/lib/libboost_thread.so -lpthread /usr/local/lib/libboost_system.so -lpython2.7 /usr/local/lib/libboost_python.so /usr/local/lib/libCGAL.so /usr/local/lib/libboost_thread.so -lpthread /usr/local/lib/libboost_system.so -lpython2.7 /usr/local/lib/libboost_python.so -Wl,-rpath,/usr/local/lib
Output of importing the shared library:
$ python -c 'import thickness_diag'
Traceback (most recent call last):
File "<string>", line 1, in <module>
ImportError: ./thickness_diag.so: undefined symbol: _ZN5boost6python9converter6detail15registered_baseIRVK18Sphere_intersecterIN4CGAL18Spherical_kernel_3INS5_9CartesianINS5_4GmpqEEENS5_32Algebraic_kernel_for_spheres_2_3IS8_EEEEEE10convertersE
$ nm thickness_diag.so | grep _ZN5boost6python9converter6detail15registered_baseIRVK18Sphere_intersecterIN4CGAL18Spherical_kernel_3INS5_9CartesianINS5_4GmpqEEENS5_32Algebraic_kernel_for_spheres_2_3IS8_EEEEEE10convertersE
U _ZN5boost6python9converter6detail15registered_baseIRVK18Sphere_intersecterIN4CGAL18Spherical_kernel_3INS5_9CartesianINS5_4GmpqEEENS5_32Algebraic_kernel_for_spheres_2_3IS8_EEEEEE10convertersE
I've been struggling with this for the past two days, any help would be awesome ! :)
EDIT: output of ldd
$ ldd thickness_diag.so
linux-vdso.so.1 => (0x00007fffdfdff000)
libgmp.so.10 => /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007fd91eadf000)
libCGAL.so.10 => /usr/local/lib/libCGAL.so.10 (0x00007fd91e8b4000)
libboost_thread.so.1.55.0 => /usr/local/lib/libboost_thread.so.1.55.0 (0x00007fd91e699000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fd91e47c000)
libboost_system.so.1.55.0 => /usr/local/lib/libboost_system.so.1.55.0 (0x00007fd91e278000)
libpython2.7.so.1.0 => /usr/lib/libpython2.7.so.1.0 (0x00007fd91dd79000)
libboost_python.so.1.55.0 => /usr/local/lib/libboost_python.so.1.55.0 (0x00007fd91db2c000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fd91d829000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fd91d612000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd91d253000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fd91cf57000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fd91cd4e000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd91ef85000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fd91cb37000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fd91c933000)
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007fd91c72f000)
Okay I figured it out. Turns out that the option -fno-implicit-templates was preventing boost from doing its normal template instanciation (which is actually pretty obvious).
I then fell back on an error that I thought was fixed: undefined symbol: _ZN18Sphere_intersecterIN4CGAL18Spherical_kernel_3INS0_9CartesianINS0_4GmpqEEENS0_32Algebraic_kernel_for_spheres_2_3IS3_EEEEEC1ERKS8_ (./thickness_diag.so)
Which, when translated via c++filt, gives: Sphere_intersecter<...> >::Sphere_intersecter(Sphere_intersecter<...> const&)
The copy-constructor, which wasn't implemented (non-copyable class)...
The solution was to remove the add the boost::noncopyable parameter to boost::python::class_:
#include <boost/python.hpp>
#include <CGAL/Exact_spherical_kernel_3.h>
#include "Sphere_intersecter.h"
typedef CGAL::Exact_spherical_kernel_3 SK;
template class Sphere_intersecter<SK>;
typedef Sphere_intersecter<SK> SI;
BOOST_PYTHON_MODULE(thickness_diag)
{
using namespace boost::python;
class_<SI, boost::noncopyable>("SphereIntersecter")
.def("add_sphere", &SI::add_sphere)
;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With