在上一篇日志中记录了如何在LaTeX文件中编写、调用Lua脚本语言,本文进一步介绍如何在LaTeX中通过Lua调用C动态链接库。实际上,调用方法基本上只是Lua与C之间的问题,与LaTeX几乎无关。
这里介绍的方法需要使用LuaJIT,请到LuaJIT官网下载安装,上面介绍得很清楚,这里不再赘述。
调用方法的关键在于C源代码的编写方式,所以我们将首先介绍这个。我用的构建工具是CMake,在项目文件夹内,有src与build两个文件夹,主文件main.c放在src文件夹内。CMakeLists.txt文件在项目文件夹内。结构如下:
项目文件夹
├── build
│ └──
├── CMakeLists.txt
└── src
└── main.c
下面列出文件源码
操作系统:Ubuntu 18.04
LaTeX编辑工具:TeXstudio 2.12.6
LaTeX编译方式:LuaLaTeX
构建工具:CMake 3.16.4
C编译器:gcc 7.4.0
Lua解释器:LuaJIT 2.0.5
文件1:CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
set(project_name plotpen)
# 设置库文件的生成目录为工程顶层目录
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR})
project(${project_name})
aux_source_directory(src/ DIR_SRCS)
add_library(${project_name} SHARED ${DIR_SRCS})
# 去掉默认加上的lib前缀
set_target_properties(${project_name} PROPERTIES PREFIX "")
文件2:main.c
// 开源中国,陆巍
#include "/usr/local/include/luajit-2.0/lauxlib.h"
#include "/usr/local/include/luajit-2.0/lua.h"
#include "/usr/local/include/luajit-2.0/lualib.h"
#include <string.h>
#include<stdlib.h>
// 加上声明,以免编译时出现警告
void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup);
static int Hello(lua_State *L)
{
char *str0 = "\\noindent We are here\\\\";
const char * latexStr = luaL_checkstring(L, 1) ;
char *str1 = (char *) malloc(strlen(str0) + strlen(latexStr));
strcpy(str1, str0);
strcat(str1, latexStr);
lua_pushstring(L, str1);
free(str1);
return 1;
}
// 注册函数
static luaL_Reg RegLibs[] = {
{"Hello", Hello},
{NULL, NULL}};
// 这里的函数名luaopen_plotpen是有固定格式的,格式为:luaopen_你的库名
int luaopen_plotpen(lua_State *L)
{
lua_newtable(L);
luaL_setfuncs(L, RegLibs, 0);
return 1;
}
编译后会在项目文件夹内出现名为plotpen.so的动态链接库文件。
说明:
- CMakeLists.txt文件中的最后一行语句是去掉库文件的lib前缀,只有去掉后才能正常调用。包括C++动态链接库也是如此处理。
- test.c代码中注意luaopen_plotpen函数,如果你的库文件名为test.so,那么这个函数的名称就要改为luaopen_test,以此类推。
- 传入的数据并非只是示例中的字符串,还可以传入其他类型的数据,例如luaL_checkint,可在网上查询相关资料,或者看IDE上的提示。我使用的是VSCode,包含那几个LuaJIT的头文件后,上面就会有相关函数的提示。
- 为了方便查看效果,最好先安装Lua,先在终端上调用生成的库文件看看结果,如果有错也可以察看错误原因。
下面是LaTeX方面的文件。
文件1:test.tex
\documentclass{article}
% 开源中国,陆巍
\usepackage{ctex}% 中文支持
\usepackage{geometry}% 用于页面设置
\usepackage[dvipsnames, svgnames, x11names]{xcolor} % 颜色支持
\usepackage{luacode}
\usepackage{tikz}
\usepackage{fancyvrb}
\usepackage{metasequoia}
% 设置为A4纸,并按照MSOffice的默认尺寸设置四周边距
\geometry{
a4paper,
left = 3.17cm,
right = 3.17cm,
top = 2.54cm,
bottom = 2.54cm
}
\begin{document}
\section{通过lua调用C动态链接库}
\pic[We are LINUX]{}
\end{document}
文件2:metasequoia.sty(自定义宏包文件)
% 开源中国,陆巍
\NeedsTeXFormat{LaTeX2e}[2007/10/19]%
\ProvidesPackage{metasequoia}[2020/02/29]%
\newcommand{\pic}[1][]{
\renewcommand{\baselinestretch}{1.0}%
\luaexec{%
local test = require("plotpen")
str = test.Hello("#1")
tex.sprint(str)
}%
}
执行结果如下:
说明:
- 本例中把lua调用单独用一个自定义宏包来完成,里面定义了新命令来调用。从这个自定义宏包的文件上,可以看到lua调用c动态链接库的方法(调用C++也是这样),也可以看到LaTeX宏包的定义方式。
- 最好把链接库文件放在tex文件所在同一目录下,否则可能找不到。这一点我没有去查找原因,先这样用着。