ctp接口python封装学习笔记01 vvipi 发表于2018年12月2日,阅读:4236 #### 任务: 编译boost.python的extending示例代码,生成python可以import的库文件,并测试效果。 #### 环境: Ubuntu 16.04.1 LTS,python3.5, Boost1.66 #### 编译方式: g++, cmake boost官方教程推荐使用bjam,但未详细介绍linux下bjam编译的流程。因此尝试使用之前使用过的g++和cmake两种方式进行编译。 #### 说明: - boost.python连接python和C++有两种方式:extending(扩展)和embedding(嵌入),extending是装饰封装c++代码为python可识别的库文件后,在python中import库文件。embedding则相反,是在C++下调用python。我们的目标是在python下调用ctp接口开发策略,因此学习extending方式。 - boost安装包解压后,在主目录下libs/python/example/quickstart下有几个示例程序,其中extending.cpp是待编译的c++源代码,test_extending.py用于测试编译生成的库文件是否能正常工作。 - boost的安装在[之前的日志](http://www.wepin.online/blog/0015423531636106a227723e4d74f21b6febcdef77a493f000 "http://www.wepin.online/blog/0015423531636106a227723e4d74f21b6febcdef77a493f000")中已经提到,这里不再重复。 #### g++编译方式: 进入源代码所在目录,运行 `g++ extending.cpp -shared -fpic -I /usr/include/python3.5m -I /usr/local/include/boost -lboost_python3 -lpython3 -o extending.so` 查看是否生成extending.so文件,有则继续测试 `python3 test_extending.py` 查看输出内容,是否通过测试。 #### cmake编译方式: - 创建目录 ```shell mkdir build-extending cd build-extending mkdir source cp boost_1_66_0/libs/python/example/quickstart/* ./source ``` - 配置CMakeLists.txt,用编译ctpapi时的配置稍微修改,去掉不需要的部分即可。 ```shell cmake_minimum_required(VERSION 2.8) project(extendingexample) # 设置使用的编译器 set(CMAKE_BUILD_TYPE "Release") if (CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -std=c++11") endif () # 设置输出目录 set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib) # 使用64位编译 option(USE_64BITS "comiple 64bits" ON) if (USE_64BITS) add_definitions(-DUSE_64BITS) endif() # 设置编译源文件 set (extending ) option(BUILD_EXTENDING "build extending" ON) if (BUILD_EXTENDING) add_definitions(-DBUILD_EXTENDING) set(CODE_PATH ${CMAKE_BINARY_DIR}/source) include_directories(${CODE_PATH}) set(EXTENDING_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/source/extending.cpp) add_library(extending SHARED ${EXTENDING_SOURCE}) endif() # 设置Python所在的目录 set(PYTHON_LIBRARY ) set(PYTHON_INCLUDE_PATH /usr/include/python3.5m) find_library(PYTHON_LIBRARY NAMES python3.5m PATHS /urs/lib/x86_64-linux-gnu) include_directories(${PYTHON_INCLUDE_PATH}) # 链接boost库 find_package(Boost 1.66.0 COMPONENTS python3 REQUIRED) if(Boost_FOUND) include_directories(${BOOST_INCLUDE_DIRS}) endif() # 去掉生成的so文件名中前缀的lib set_target_properties(extending PROPERTIES PREFIX "") # 链接其他依赖的库,并生成.so文件 target_link_libraries(extending ${Boost_LIBRARIES} ${PYTHON_LIBRARY}) ``` - 配置build.sh,基本上不需要改 ``` #!/bin/bash set -e BUILDDIR=build rm -rf $BUILDDIR if [ ! -f $BUILDDIR ]; then mkdir -p $BUILDDIR fi pushd $BUILDDIR cmake .. make VERBOSE=1 -j 1 cp ./lib/*.so ../source/ popd ``` - `chmod a+x build.sh` 使脚本可直接执行 - 配置完成,运行`./build.sh`开始编译。然后查看source目录下是否正确生成extending.so,并运行`python3 test_extending.py`查看输出内容,是否通过测试。 #### 填坑指南: - 使用g++编译时,通过-I 引入的include路径和通过-l 引入的lib路径都是必须的。否则编译不成功,或者编译成功但import时各种出错。 - `ImportError: libboost_python3.so.1.66.0: cannot open shared object file: No such file or directory`可能原因是自行编译安装boost,系统不知道boost库的路径。尝试运行`export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH`解决这个问题 - `undefined reference to '_Py_NoneStruct' /urs/lib/x86_64-linux-gnu`可能原因是没有添加-lpython3参数。 - `undefined symbol: _ZTIN5boost6python15instance_holderE`可能原因时没有链接依赖的boostpython库,比如漏掉CMakeLists.txt最后一句就会这样。 - g++编译能通过但无法导入,可以试试加入`-Wl,--no-undefined`参数,则编译过程就会告诉你缺少哪些东西。 #### 参考链接: https://www.boost.org/doc/libs/1_68_0/libs/python/doc/html/tutorial/tutorial/hello.html https://stackoverflow.com/questions/46934760/importerror-libboost-python-so-1-65-1-cannot-open-shared-object-file-no-such https://stackoverflow.com/questions/11893996/why-does-the-order-of-l-option-in-gcc-matter/11894098#11894098 https://stackoverflow.com/questions/13604926/undefined-reference-in-basic-boostpyton-program