文档章节

用 C 语言开发 WSTP (Linux)

wangxuwei
 wangxuwei
发布于 2017/06/07 07:42
字数 3397
阅读 48
收藏 0
支持的开发平台 运行 WSTP 程序
安装 WSTP 组件 疑难解答
构建 WSTP 程序  

本文叙述了在 Linux 系统中如何编译和运行用 C 语言编写的 Wolfram Symbolic Transfer Protocol (WSTP) 程序. (“WSTP 和外部程序的通讯”叙述了如何用 Wolfram 语言和 C 语言编写 WSTP 程序.)

本文并不教你如何使用编译器和其它开发工具,也不会教你如何用 C 语言编程. 如果你有任何开发或运行 WSTP 程序的问题,请参阅本文末尾的“疑难解答”章节.

本文所叙述的大部分内容是专门面向 Linux 并适用于所有被支持的 Linux 平台. 若想学习如何在其它平台上编译和运行用 WSTP 程序,请参阅相关平台的开发指南.

支持的开发平台

作为一个共享库,WSTP 可以用于任何符合标准调用约定和由下列编译器指定的二进制接口的开发环境.

当下面的某些编译器与由编译器创建产生的集成开发环境相集成时,它们的功能等价于 make 实用程序.

 

  C compiler C++ compiler
  "Linux" gcc (GCC) 4.4.6 20110731 (Red Hat 4.4.6-3) g++ (GCC) 4.4.6 20110731 (Red Hat 4.4.6-3)
  "Linux-x86-64" gcc (GCC) 4.4.6 20110731 (Red Hat 4.4.6-3) g++ (GCC) 4.4.6 20110731 (Red Hat 4.4.6-3)

除了上面所说的,编译 WSTP API 还需要 libuuid 开发库,在 Debian 系统内称为 uuid-dev,在 Red Hat 和 Suse 中则称为 libuuid-devel.

安装 WSTP 组件

WSTP 开发工具包(WSDK)位于 Wolfram 系统目录内的$InstallationDirectory/SystemFiles/Links/WSTP/DeveloperKit/$SystemID 目录中.

建议安装

CompilerAdditions 安装

构建 WSTP 程序所需要的 WSTP 组件已由 Wolfram 系统安装器安装. 使用这些组件的一种方法是让它们保留在 Wolfram 系统目录中,当调用编译器时指定它们的完整路径. 该方法列在“构建 WSTP 程序”章节中的范例“makefiles”中.

另一种方法是把这些组件 (wstp.h、libWSTP32i4.a、libWSTP32i4.so、libWSTP64i4.a 和 libWSTP64i4.so) 复制到编译器会自动搜索这些文件的目录中. 这些目录一般是 /usr/include 和 /usr/lib,但是你的系统可能会有所不同. 在许多系统中,不是所有用户都可以读写这些目录.

WSTPExamples 安装

把 WSTPExamples 目录复制到主目录.

WSTP 框架组件

下面是 WSDK 中每个文件或目录的说明.

CompilerAdditions 目录

wstp.h

wstp.h 是一个必须包含在 C 和 C++ 源文件中的头文件. 它应该放在你的编译器可以找到的地方. 你可以把它复制到和源文件同样的目录下,或复制到和标准头文件同样的目录下,或者不用管它,但是把 WSTP 目录添加到头文件的搜索路径中.

libWSTP32i4.a/libWSTP64i4.a

这是一个包含所有 WSTP 函数的静态库. 你的项目应该包含它. 你可以把该库复制到与源文件同样的目录下或不做任何改变,但是把 WSTP 目录添加到库文件的搜索路径中. 32/64 表明库是 WSTP 库的 32 位或 64 位版本.

libWSTP32i4.so/libWSTP64i4.so

这是一个包含 WSTP 所有函数的动态共享库. 你的项目应该包含它. 你可以把该库复制到与源文件同样的目录下,或复制到系统位置,例如 /lib 或 /usr/lib,或不做任何改变,但是把 WSTP 目录添加到库搜索路径中. 32/64 表明库是 WSTP 库的 32 位或 64 位版本.

wsprep

wsprep 是一个应用程序,通过处理模板文件自动编写 WSTP 程序. 把该应用程序复制到你的项目目录中或创建一个别名会方便应用.

wscc

wscc 是一个预处理和编译 WSTP 源文件的脚本.

WSTPExamples 目录

该目录包含一些非常简单的 WSTP 程序源代码. 通过使用源代码,你可以学习如何构建和运行 WSTP 程序,而无需自己编写任何代码.

PrebuiltExamples 文件夹

该目录包含范例程序的预建版本. “运行 WSTP 程序”描述了如何运行两个这样的程序. “构建 WSTP 程序”描述了如何使用 WSTPExamples 文件夹中的源代码构建自己的程序.

构建 WSTP 程序

构建 WSTP 程序的一般过程是在任何调用 WSTP 函数的 C 或 C++ 源文件中包含 wstp.h,编译源文件,然后把 libWSTP32i4.a、libWSTP64i4.a、libWSTP32i4.so 或 libWSTP64i4.so 与结果对象代码相链接. 如果你的应用程序使用 WSTP 模板机制,那么你的模板文件必须首先使用 wsprep 处理成 C 源文件.

使用 WSTP 模板文件

如果你的程序使用“WSTP 和外部程序通讯”中描述的 WSTP 模板机制,你必须同时使用 wsprep 应用程序预处理包含模板项的源文件.(模板项是包含模板关键字的行序列,每一项定义当调用相关 C 函数时的 Wolfram 语言函数.)当 wsprep 处理这类文件时,它会把模板项转换成 C 函数,传递未改变的文本,并使用 WSTP 应用远程过程调用机制编写其他 C 函数. 结果是可用于编译的 C 源文件.

例如,命令

wsprep addtwo.tm -o addtwotm.c

 

会从模板项中产生一个 C 源文件 addtwotm.c,其他文本保留在 addtwo.tm. 然后你可以使用 C 编译器编译输出文件. 如果你使用 make 工具构建你的程序,你可以添加类似下面的规则至你的 makefile.

addtwotm.c : addtwo.tm
wsprep addtwo.tm -o addtwotm.c

 

构建 WSTP 程序

以下是一个构建 WSDK 中样本程序需要的样本 makefile,包括 addtwo 和 factor. 要构建样本程序,例如 addtwo,在 WSTPExamples 目录中计算以下命令.

make addtwo

 

使用 Makefile

# This makefile can be used to build all or some of the sample
# programs. To build all of them, use the command
# 'make all'. To build one, say addtwo, use the command
# 'make addtwo'.

WSTPLINKDIR = /usr/local/Wolfram/Mathematica/10.0/SystemFiles/Links/WSTP/DeveloperKit
SYS = Linux # Set this value with the result of evaluating $SystemID
CADDSDIR = ${WSTPLINKDIR}/${SYS}/CompilerAdditions

INCDIR = ${CADDSDIR}
LIBDIR = ${CADDSDIR}

EXTRALIBS = -lm -lpthread -lrt -lstdc++ -ldl -libuuid # Set these with appropriate libs for your system.
WSTPLIB = WSTP32i4 # Set this to WSTP64i4 if using a 64-bit system

WSPREP = ${CADDSDIR}/wsprep

all : addtwo bitops counter factor factor2 factor3 quotient reverse sumalist

addtwo : addtwotm.o addtwo.o
    ${CC} -I${INCDIR} addtwotm.o addtwo.o -L${LIBDIR} -l${WSTPLIB} ${EXTRALIBS} -o $@

bitops : bitopstm.o bitops.o
    ${CC} -I${INCDIR} bitopstm.o bitops.o -L${LIBDIR} -l${WSTPLIB} ${EXTRALIBS} -o $@

counter : countertm.o
    ${CC} -I${INCDIR} countertm.o -L${LIBDIR} -l${WSTPLIB} ${EXTRALIBS} -o $@

factor : factor.o
    ${CC} -I${INCDIR} factor.o -L${LIBDIR} -l${WSTPLIB} ${EXTRALIBS} -o $@

factor2 : factor2.o
    ${CC} -I${INCDIR} factor2.o -L${LIBDIR} -l${WSTPLIB} ${EXTRALIBS} -o $@

factor3 : factor3.o
    ${CC} -I${INCDIR} factor3.o -L${LIBDIR} -l${WSTPLIB} ${EXTRALIBS} -o $@

quotient : quotient.o
    ${CC} -I${INCDIR} quotient.o -L${LIBDIR} -l${WSTPLIB} ${EXTRALIBS} -o $@

reverse : reversetm.o
    ${CC} -I${INCDIR} reversetm.o -L${LIBDIR} -l${WSTPLIB} ${EXTRALIBS} -o $@

sumalist : sumalisttm.o sumalist.o
    ${CC} -I${INCDIR} sumalisttm.o sumalist.o -L${LIBDIR} -l${WSTPLIB} ${EXTRALIBS} -o $@

.c.o :
    ${CC} -c -I${INCDIR} $<

addtwotm.c : addtwo.tm
    ${WSPREP} $? -o $@

bitopstm.c : bitops.tm
    ${WSPREP} $? -o $@

countertm.c : counter.tm
    ${WSPREP} $? -o $@

reversetm.c : reverse.tm
    ${WSPREP} $? -o $@

sumalisttm.c : sumalist.tm
    ${WSPREP} $? -o $@

 

使用下表确定在你的系统中链接 WSTP 程序时是否需要其他库.

 

  $SystemID EXTRALIBS
  "Linux" -lm -lpthread -lrt -lstdc++ -ldl -luuid
  "Linux-x86-64" -lm -lpthread -lrt -lstdc++ -ldl -luuid

使用 wscc

wscc 是一个预处理和编译 WSTP 源文件的脚本. 它会预处理任何以 .tm 结尾的文件中的 WSTP 模板,然后在结果 C 源代码中调用 cc. wscc 会直接传递命令行选项和其他文件至 cc. 以下是使用 wscc 构建 addtwo 应用的命令.

wscc addtwo.tm addtwo.c -o addtwo

运行 WSTP 程序

构建 WSTP 程序”中的说明描述了如何使用 WSTPExamples 目录中的源代码构建两个 WSTP 程序. 这两个程序,addtwo 和 factor 已存在于 PrebuiltExamples 文件夹. 在构建你自己的之前,应该试着运行预建的范例以验证 WSTP 系统附件是否安装且正常工作,并学习当正确构建时这些范例会有怎样的结果.

有两个 WSTP 的基本类型程序,addtwo 和 factor 程序. 第一个是可安装程序. 一个可安装程序通过调用机制链接 C 程序和内核,为内核提供新的功能. 为了获得此新功能,Wolfram 语言必须运行 Install[] 函数. 在 addtwo 范例中,你会添加一个新的函数,称作 AddTwo[],相加两个数(以参数形式提供). 内核与可安装程序具有特殊的关系,允许它们可互相交流. 当运行可安装程序时,为了连接,它会需要你提供一些信息. 程序的另一个类型是前端. 前端进行所有创建和管理自身链接的工作. 除了 factor 范例之外,Wolfram 系统前端和 Wolfram 语言内核也是前端类型中的一个例子. 前端运行不需要任何其他信息,但是在执行的某点会进行连接.

在 Wolfram 语言内核中运行预建范例

第一个范例程序,addtwo 是安装在 Wolfram 语言中的一个 WSTP 模板程序. 也就是说,该程序在后台运行,为 Wolfram 语言,一个或多个外部编译函数提供服务. 对于 Wolfram 语言用户,这些函数显现为内置的. addtwo 程序使用定义 Wolfram 语言函数的模板文件 AddTwo[] 作为一个对 C 函数 addtwo()的调用. (模板机制的详细描述参见“WSTP 和外部程序通讯”.)该程序的源代码为:

:Begin:
:Function: addtwo
:Pattern: AddTwo[i_Integer, j_Integer]
:Arguments: { i, j }
:ArgumentTypes: { Integer, Integer }
:ReturnType: Integer
:End:

:Evaluate: AddTwo::usage = "AddTwo[x, y] gives the sum of two machine integers x and y."

int addtwo( int i, int j)
{
    return i+j;
}

int main(int argc; char* argv[])
{
    return WSMain(argc, argv);
}

 

编辑路径字符串并计算下面两个单元.

 

Click for copyable input

 

Click for copyable input

查找最新可用函数的列表,计算下面单元.

 

Click for copyable input

以下会显示定义在文件 addtwo.tm 中的 AddTwo[] 函数的用法信息.

 

Click for copyable input

尝试一下.

 

Click for copyable input

看看如果两个机器整数的和不匹配于一个机器的整数或如果任何一个参数都不是机器整数,会出现什么情况. (2^31-1 是最大的机器整数. 如果您的编译器使用2个字节整数,那么 2^15-1 是最大的 C int.)

 

Click for copyable input

addtwo 程序不适于大的整数.

 

Click for copyable input

以下不匹配 AddTwo[_Integer,_Integer].

 

Click for copyable input

Install[] 调用 LinkOpen[],然后和外部程序交换信息,设置 AddTwo[] 的定义. 你无需考虑这些细节,但是如果你很好奇,可执行以下命令.

 

Click for copyable input

当你不再使用外部程序,执行如下命令.

 

Click for copyable input

从一个预建的范例中调用 Wolfram 语言内核

第二个范例程序,factor 是运行在后台的 Wolfram 语言内核为 factor 提供服务,内核的计算服务,Wolfram 系统的前端对用户的输入整数给出因式分解.

通过执行以下命令,启动 factor 应用.

factor -linkmode launch -linkname 'math -mathlink'

 

过一会会出现提示要求你输入整数. 敲入少于 10 位的整数,然后按下 Enter 键.(其他 factor 例子会放宽对输入整数大小的限制.)

Integer to factor:

 

输出由 Wolfram 语言产生的质因数分解,然后 factor 关闭它与 Wolfram 语言的链接.

Integer to factor: 123456789
3 ^ 2
3607 ^ 1
3803 ^ 1

 

支持的链接协议

C 函数 WSOpenArgcArgv() 和 Wolfram 语言函数 LinkOpen[] 的细节请参见“WSTP 和外部程序通讯”. 在 Linux 机器中,LinkProtocol 选项的合法值为 "TCPIP"、"TCP"、"SharedMemory"、"Pipes" 和 "IntraProcess". LinkProtocol 是用于从一端到另一端传输数据的机制. "SharedMemory" 是 LinkMode->Launch 链接的默认协议. 所有 LinkMode->Listen 和 LinkMode->Connect 链接的默认值是 "SharedMemory".

请注意,"TCPIP" 和 "TCP" 协议的链接名称是 16 位无符号整数. 虽然 "TCPIP" 链接的名称是整数,但是它们仍然以(数字)字符串形式赋给 WSOpenArgcArgv() 和 LinkOpen[].

疑难解答

  • 一旦你的程序正常工作,就可关闭编译器优化功能. 这可使编译速度更快,更容易调试,另外,优化可能被打断,会导致一些问题.(优化代码使用的堆栈和寄存器的方式不同于非优化的代码,可能暴露或掩盖代码中的错误. 例如,返回一个局部变量指针时出现的常见错误可能会或不会导致问题,其取决于堆栈和寄存器使用.)
  • 检查从 WSTP 库函数的返回值或在你的程序关键部分调用 WSError(). WSTP 往往可以告诉你什么地方出了错.
  • 文件 wstp.h、libWSTP32i4.a 和 libWSTP32i4.so(64位平台为 libWSTP64i4.*)是配套的集合. 如果你在使用早期的 WSTP 版本,当建立你的应用程序时,应该注意不要混淆它们.
  • 检查你使用的 C 编译器是否支持雏形,如果不支持,你需要改变代码或构建项目的方式. 详细解释请参见“构建 WSTP 程序”.
  • 检查以确保你的程序与 libstdc++ 和基础框架相链接. 没有这些依赖,构建二进制时会在链接状态时失败.

相关指南

相关教程

本文转载自:http://reference.wolfram.com/language/tutorial/WSTPDeveloperGuide-Unix.html#26966

wangxuwei
粉丝 27
博文 343
码字总数 137316
作品 0
杭州
其他
私信 提问
顶级 Linux 开发者推荐的编程书籍

毫无疑问,Linux 是由那些拥有深厚计算机知识背景而且才华横溢的程序员发明的。让那些大名鼎鼎的 Linux 程序员向如今的开发者分享一些曾经带领他们登堂入室的好书和技术参考资料吧,你会不会...

作者: Steven Vaughan-nichols
2018/11/22
0
0
请大家为这只无头的苍蝇提提自己的意见与建议!

本人现是一名普通本科大三的学生,学的是计算机相关的专业(嵌入式方向)。 大一是从C++语言开始学习的,后期学过Java,C#,Qt(这三种都不太深入) 外加sqlserver数据库和简单的html5网页设...

芮淼一线
2015/02/11
2.6K
20
招聘linux 驱动工程师及linux GUI工程师

公司信息: http://www.allwinnertech.com/ 工作地点:深圳市南山区 (深圳分公司) 联系方式: leeking@allwinnertech.com 待遇: 7K~12K Linux 驱动工程师 职位说明: 负责嵌入式linux系统的应用...

leeking19
2011/01/13
2.6K
15
Linux开放实验室

简介 为方便广大Linux软件开发爱好者,轩辕高端IT培训中心于2009年10月设立了Linux开放实验室,轩辕Linux开放实验室提供了完整的 Linux软件开发环境,包括:Redhat Enterprise Linux 5.4、C...

athxy
2010/04/01
297
0
嵌入式linux系统下web+JAVA/CGI+apache开发求助 !!!

我现在在嵌入式liunx 系统下通过apache服务开发网页。我现在要在JAVA CGI语言开发代码下更改。我该怎么开始?这些代码我看不懂,我本是linux系统下C/C++ ,shell,linux c 开发的。现在很急。...

Stafen
2012/06/15
627
1

没有更多内容

加载失败,请刷新页面

加载更多

代理模式之JDK动态代理 — “JDK Dynamic Proxy“

动态代理的原理是什么? 所谓的动态代理,他是一个代理机制,代理机制可以看作是对调用目标的一个包装,这样我们对目标代码的调用不是直接发生的,而是通过代理完成,通过代理可以有效的让调...

code-ortaerc
今天
5
0
学习记录(day05-标签操作、属性绑定、语句控制、数据绑定、事件绑定、案例用户登录)

[TOC] 1.1.1标签操作v-text&v-html v-text:会把data中绑定的数据值原样输出。 v-html:会把data中值输出,且会自动解析html代码 <!--可以将指定的内容显示到标签体中--><标签 v-text=""></......

庭前云落
今天
8
0
VMware vSphere的两种RDM磁盘

在VMware vSphere vCenter中创建虚拟机时,可以添加一种叫RDM的磁盘。 RDM - Raw Device Mapping,原始设备映射,那么,RDM磁盘是不是就可以称作为“原始设备映射磁盘”呢?这也是一种可以热...

大别阿郎
今天
12
0
【AngularJS学习笔记】02 小杂烩及学习总结

本文转载于:专业的前端网站☞【AngularJS学习笔记】02 小杂烩及学习总结 表格示例 <div ng-app="myApp" ng-controller="customersCtrl"> <table> <tr ng-repeat="x in names | orderBy ......

前端老手
昨天
16
0
Linux 内核的五大创新

在科技行业,创新这个词几乎和革命一样到处泛滥,所以很难将那些夸张的东西与真正令人振奋的东西区分开来。Linux内核被称为创新,但它又被称为现代计算中最大的奇迹,一个微观世界中的庞然大...

阮鹏
昨天
20
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部