在上一篇日誌中記錄瞭如何在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文件所在同一目錄下,否則可能找不到。這一點我沒有去查找原因,先這樣用着。