Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
机器未来
Paddle
提交
e6dca9e5
P
Paddle
项目概览
机器未来
/
Paddle
与 Fork 源项目一致
Fork自
PaddlePaddle / Paddle
通知
1
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
P
Paddle
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1
Issue
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
e6dca9e5
编写于
3月 17, 2017
作者:
Y
Yu Yang
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Follow comments
上级
952f8c13
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
41 addition
and
23 deletion
+41
-23
doc/design/multi_language_interface/why_plain_c.md
doc/design/multi_language_interface/why_plain_c.md
+41
-23
未找到文件。
doc/design/multi_language_interface/why_plain_c.md
浏览文件 @
e6dca9e5
...
...
@@ -4,9 +4,9 @@
Paddle需要一个多语言接口,这个接口需要做到:
*
有标准的,良好的文档
*
例如Python可以使用
[
Sphinx
](
http://www.sphinx-doc.org/en/stable/
)
生成API文档,golang可以使用
[
GoDoc
](
https://godoc.org/golang.org/x/tools/cmd/godoc
)
生成文档。这都需要这个接口按照约定俗成的规则来注释完备。
*
例如Python可以使用
[
Sphinx
](
http://www.sphinx-doc.org/en/stable/
)
生成API文档,golang可以使用
[
GoDoc
](
https://godoc.org/golang.org/x/tools/cmd/godoc
)
生成文档。这都需要这个接口按照约定俗成的规则来注释完备。
*
不同语言的接口适应不同语言的特性
*
例如Java与Python的错误处理是直接扔出来Exception,而对于golang错误处理应该使用返回值。
*
例如Java与Python的错误处理是直接扔出来Exception,而对于golang错误处理应该使用返回值。
## 基本要求
...
...
@@ -23,9 +23,9 @@ Paddle的多语言接口实现包括一下几个方面:
### 使用动态库来分发Paddle
*
Paddle的链接方式比较复杂
*
Paddle链接静态库使用了GCC的--whole-archieve参数,它要求使用Paddle静态库的二进制,在链接参数中指定
`--whole-archieve paddle_xxx_lib --no-whole-archive`
。且这个链接参数是GCC独有的。对于clang或者msvc,参数会不同。这增加了用户使用Paddle静态库的难度
。
*
编译型语言,例如C/C++使用静态库和动态库难度差不多。但是
含有解释器的语言,例如
[
Python
](
http://stackoverflow.com/questions/19560594/how-to-import-static-library-in-python
)
或者
[
Java
](
http://stackoverflow.com/questions/24493337/linking-static-library-with-jni
)
,调用动态库远比调用静态库方便
。
*
解释性语言实际运行的二进制是解释器本身,如果调用静态库只能将静态库与解释器链接。例如对于Java来说,便是将静态库加入JVM中。这对于通常的Java的开发者来说,是不常见的做法。
*
如果用户要把Paddle的静态库(libpaddle.a)链接到自己的程序里,得使用
`--whole-archive`
(for GCC) 或者
`--force_load`
(for Clang) 参数,来确保把 libpaddle.a 里所有的符号都写入自己的程序的二进制文件里。这是因为 Paddle 的源码里使用了
[
object factory design pattern
](
http://stackoverflow.com/a/1310326/724872
)
。
*
编译型语言,例如C/C++使用静态库和动态库难度差不多。但是
解释性语言,例如
[
Python
](
http://stackoverflow.com/questions/19560594/how-to-import-static-library-in-python
)
或者
[
Java
](
http://stackoverflow.com/questions/24493337/linking-static-library-with-jni
)
,只能调用Paddle的动态库,否则得把Paddle静态库链接到解释器里
。
*
解释性语言实际运行的二进制是解释器本身,如果调用静态库只能将静态库与解释器链接。例如对于Java来说,便是将静态库加入JVM中。这对于通常的Java的开发者来说,是不常见的做法。
### 动态库中不嵌入任何其他语言的解释器
...
...
@@ -51,36 +51,54 @@ Paddle的多语言接口实现包括一下几个方面:
*
Paddle内部的类为C++书写,直接导出到C的接口比较困难。
*
在C-API中使用
`void*`
来表示Paddle内部类。再在每一个API中自己检查类型。
```
C
在C的头文件
`paddle_matrix.h`
中:
// in Paddle.h
```
C
typedef void* paddle_matrix;
typedef int paddle_error;
extern "C"
paddle_error paddle_matrix_shape(paddle_matrix matrix,
uint64_t* width,
uint64_t* height);
```
而在CPP里面实现这个C的接口,文件
`paddle_matrix.cpp`
```
cpp
#include "paddle/math/matrix.hpp"
extern
"C"
paddle_error
paddle_matrix_shape
(
paddle_matrix
matrix
,
uint64_t
*
width
,
uint64_t
*
height
)
{
auto
m
=
(
paddle
::
math
::
matrix
*
)(
matrix
);
*
width
=
m
->
width
();
*
height
=
m
->
height
();
}
```
extern "C" paddle_error getShape(paddle_matrix mat, uint64_t* height, uint64_t* width);
其中
`paddle/math/matrix.hpp`
文件内容为:
```
cpp
namespace
paddle
{
namespace
math
{
// in matrix.cpp
struct PaddleMatrix {
int type;
paddle::MatrixPtr mat;
class
Matrix
{
//...
};
paddle_error get_shape(paddle_matrix m, uint64_t* height, uint64_t* width) {
PaddleMatrix* realMat = (PaddleMatrix*)(m);
...
}
}
// namespace math
}
// namespace paddle
```
### 不使用SWIG这种代码生成器,而是手写多语言绑定
*
[
SWIG
](
http://www.swig.org/
)
是一个多语言接口的代码生成器。他的目标是使用C/C++写代码,SWIG直接读取C/C++的头文件,生成各种语言的绑定代码。
*
对于多语言接口,SWIG需要写一个interface文件。这个文件具有独特的语法,学习成本高。且增加一个第三方语言,就需要对这个第三方语言增加一些定义。有的时候,interface文件的写法非常
[
tricky
](
https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/api/Paddle.swig#L36
)
。社区贡献代码学习成本高。
*
SWIG暴露的接口保留了C++的接口样式,很难保证多语言代码风格的一致性。(函数命名,错误处理)
*
因为SWIG在第三方语言中暴露的函数名,类名和C++中完全一致。C++的命名风格并不能适应其他第三方语言。如果使用SWIG我们需要将在interface文件里,将大量的
`SomeCppClass`
重命名成
`some_python_class`
,或者
`SomeGoTypes`
。
*
对于不同语言,错误处理的方式也不尽相同。例如对于Java或者Python,最常见的错误处理方式是Exception,而对于Golang,错误处理方式是返回值。而SWIG只能简单的暴露C++接口,无法做到对于各种语言错误处理方式的适配。
*
对于大多数语言,直接使用C语言的.h并不困难。例如Python的
[
cffi
](
https://cffi.readthedocs.io/en/latest/overview.html#simple-example-abi-level-in-line
)
或者
[
Cython
](
http://cython.org/
)
, golang的
[
cgo
](
https://golang.org/cmd/cgo/
)
。
*
SWIG支持的语言或者解释器有局限。例如对于Python,使用SWIG只支持CPython解释器,而不支持PyPy解释器。
*
对于多语言接口,SWIG需要写一个interface文件。这个文件具有独特的语法,学习成本高。且增加一个第三方语言,就需要对这个第三方语言增加一些定义。有的时候,interface文件的写法非常
[
tricky
](
https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/api/Paddle.swig#L36
)
。社区贡献代码学习成本高。
*
SWIG暴露的接口保留了C++的接口样式,很难保证多语言代码风格的一致性。(函数命名,错误处理)
*
因为SWIG在第三方语言中暴露的函数名,类名和C++中完全一致。C++的命名风格并不能适应其他第三方语言。如果使用SWIG我们需要将在interface文件里,将大量的
`SomeCppClass`
重命名成
`some_python_class`
,或者
`SomeGoTypes`
。
*
对于不同语言,错误处理的方式也不尽相同。例如对于Java或者Python,最常见的错误处理方式是Exception,而对于Golang,错误处理方式是返回值。而SWIG只能简单的暴露C++接口,无法做到对于各种语言错误处理方式的适配。
*
对于大多数语言,直接使用C语言的.h并不困难。例如Python的
[
cffi
](
https://cffi.readthedocs.io/en/latest/overview.html#simple-example-abi-level-in-line
)
或者
[
Cython
](
http://cython.org/
)
, golang的
[
cgo
](
https://golang.org/cmd/cgo/
)
。
*
SWIG支持的语言或者解释器有局限。例如对于Python,使用SWIG只支持CPython解释器,而不支持PyPy解释器。
## 原因列表
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录