一些废话
在实际应用中笔者被一个问题困扰了很久,就是自己的C++写的环境没办法用上python搭建的深度神经网络和一些强化学习的库(实际是C++搞深度学习实在是恶心,python实在是太香了)。在实际工程中其实也存在这样的问题,因为实际上很多应用都是用C/C++写的。尤其是一些游戏,各种物理引擎渲染都是用C++写的,而且C++接口用起来比较优雅。但是这些软件的应用都没有python接口,而且python官方提供的python语言本身的C++接口Python.h也确实用起来很麻烦,笔者尝试过使用,用了一阵后发现,实在是太恶心人(工期快到)了就打算另辟蹊径。于是某一天在使用一个C++库的时候意外发现了这个SWIG。幸运的是,SWIG支持很多编译器,比如说gcc, Ninjia,Cmake等. 最后在python环境下可以顺利使用C++写好的库。
环境准备
system: Ubuntu 20.04 cmake: 3.16.3 gcc: 10.3 swig: 4.0.2 Vscode: 能用就行
初始文件夹结构
具体步骤
上面结构中example.cpp, .h, .i和CMakeLists为需要写的文件。try.py是用来测试的。 下面我将example三个文件内容贴出来
- example.cpp
#include "example.h"
void try_class::class_func(int a)
{
this->param-=a;
}
ll int fact(ll int n)
{
return n+1;
}
int my_mod(int n, int m)
{
return(n % m);
}
- example.h
#define ll long long
class try_class
{
public:
int param=20;
void class_func(int a);
};
ll int fact(ll int n);
int my_mod(int n, int m);
- example.i
%module example
%{
#include "example.h"
%}
%include "example.h"
- CMakeLists.txt
set(CMAKE_CXX_STANDARD 20)
#寻找PYTHONHOME的环境变量
find_package (Python3 COMPONENTS Interpreter Development)
include_directories(${Python3_INCLUDE_DIRS})
link_libraries(${Python3_LIBRARIES})
#指定你的.cxx等文件的目录
include_directories(${PROJECT_SOURCE_DIR}/src)
#寻找安装好的swig,其实就是去电脑中找你安装好的Swig环境,所以我们需要提前安装环境。
find_package(SWIG REQUIRED)
include(${SWIG_USE_FILE})
#Python文件输出目录 -outdir
set(CMAKE_SWIG_OUTDIR ${CMAKE_CURRENT_BINARY_DIR}/python)
#指定一个输出目录名,用于放置生成的源文件。例如输出的examplePTYHON_wrap.cxx文件等的位置
set(SWIG_OUTFILE_DIR ${CMAKE_CURRENT_BINARY_DIR}/cpp)#use "SWIG" with “CMake” wrapping CPP to python
#注意这一步必须要加上,要不然不能编译c++,只能编译c
set_property(SOURCE src/example.i PROPERTY CPLUSPLUS ON)
#开始生成
swig_add_library(example
LANGUAGE python
SOURCES src/example.i src/example.cpp)
swig相关的函数在VScode中是不会高亮的,但是你可以在Cmake官网上找到用法和各个变量的说明。 然后就是到build文件夹下去编译工程
cd build
cmake ..
make
然后你的工程文件夹结构就变成了下面这样,咱们需要用到的文件并不多。一个是build/python/example.py另一个是build/_example.so。将这两个全部复制出来放到你的测试文件try.py同一个文件夹下就可以直接在try.py中使用了。
├── build
│ ├── CMakeCache.txt
│ ├── CMakeFiles
│ │ ├── 3.16.3
│ │ │ ├── CMakeCCompiler.cmake
│ │ │ ├── CMakeCXXCompiler.cmake
│ │ │ ├── CMakeDetermineCompilerABI_C.bin
│ │ │ ├── CMakeDetermineCompilerABI_CXX.bin
│ │ │ ├── CMakeSystem.cmake
│ │ │ ├── CompilerIdC
│ │ │ │ ├── a.out
│ │ │ │ ├── CMakeCCompilerId.c
│ │ │ │ └── tmp
│ │ │ └── CompilerIdCXX
│ │ │ ├── a.out
│ │ │ ├── CMakeCXXCompilerId.cpp
│ │ │ └── tmp
│ │ ├── cmake.check_cache
│ │ ├── cmake_directory_clean.cmake
│ │ ├── CMakeDirectoryInformation.cmake
│ │ ├── CMakeOutput.log
│ │ ├── CMakeRuleHashes.txt
│ │ ├── CMakeTmp
│ │ ├── _example.dir
│ │ │ ├── build.make
│ │ │ ├── cmake_clean.cmake
│ │ │ ├── cpp
│ │ │ │ └── examplePYTHON_wrap.cxx.o
│ │ │ ├── CXX.includecache
│ │ │ ├── DependInfo.cmake
│ │ │ ├── depend.internal
│ │ │ ├── depend.make
│ │ │ ├── examplePYTHON.stamp
│ │ │ ├── flags.make
│ │ │ ├── link.txt
│ │ │ ├── progress.make
│ │ │ └── src
│ │ │ └── example.cpp.o
│ │ ├── example_swig_compilation.dir
│ │ │ ├── build.make
│ │ │ ├── cmake_clean.cmake
│ │ │ ├── CXX.includecache
│ │ │ ├── DependInfo.cmake
│ │ │ ├── depend.internal
│ │ │ ├── depend.make
│ │ │ └── progress.make
│ │ ├── Makefile2
│ │ ├── Makefile.cmake
│ │ ├── progress.marks
│ │ └── TargetDirectories.txt
│ ├── cmake_install.cmake
│ ├── compile_commands.json
│ ├── cpp
│ │ └── examplePYTHON_wrap.cxx
│ ├── _example.so
│ ├── Makefile
│ └── python
│ └── example.py
├── CMakeLists.txt
├── src
│ ├── example.cpp
│ ├── example.h
│ └── example.i
└── try.py
15 directories, 49 files
try.py
import example
c1=example.try_class()
print(c1.param)
c1.class_func(2)
print(c1.param)
可以看到输出
> python try.py
20
18
|