UPDATED: Problem solved. The dll must not be statically linking to lua, otherwise it crashes with a multiple Lua VMs detected exception. The code blow actually works fine, just leave it here in case someone got this problem too.
And wireshark uses lua5.2 because there's a "lua52.dll" in it's folder.
I'm writing wireshark plugin, some algorithm in C is difficult to implement in Lua, so I try to use these algorithm through dll.
Most examples online use the old version of Lua, which use luaL_register in the dll code. The luaL_register is replaced by lua_newtable/luaL_setfuncs in newer version, but I didn't find any working example online.
Here's what I tried :
#include <stdio.h>
#include <string.h>
#include "lua.hpp"
#include <windows.h>
extern "C" {
static int add(lua_State* L)
{
MessageBox(0, "", "", 0);
double op1 = luaL_checknumber(L,1);
double op2 = luaL_checknumber(L,2);
lua_pushnumber(L,op1 + op2);
return 1;
}
static luaL_Reg mylibs[] = {
{"add", add},
{0, 0}
};
__declspec(dllexport)
int luaopen_mylib(lua_State* L)
{
lua_newtable(L);
luaL_setfuncs(L, mylibs, 0);
lua_setglobal(L, "mylib");
return 1;
}
}
and the lua code:
require "mylib" -- <----------crashes
-- local mylib = package.loadlib("mylib.dll","luaopen_mylib");
print (mylib)
if(mylib)then
--mylib();
else
-- Error
end
local b=mylib.add(11,33);
print("sum:", b);
The lua code crashes at first line. How to fix it?
Another question, how to verify which version of Lua is wireshark using? Calling print(_VERSION) in wireshark's lua console, it shows nothing.
The crash occurs when statically linking to lua.lib, I guess there is already a lua VM in lua.lib, so use dynamic linking and the problem is gone.
Related
I am building a DLL to embed Python 2.7 (2.7.18 to be specific) in a larger application largely following python.org's C API documentation. When I believe I am applying Py_DECREF correctly to a PyString PyObject, any linking application crashes without error. The code is largely copied from a similar application built with python 3.8, 3.9 and 3.10 that in fact works.
// python_functions.h
__declspec(dllexport) int init_python();
// python_functions.c
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <stdio.h> // printf
#include <string.h>
//#include <wchar.h> // wchar_t for python3 only
#include "python_functions.h"
__declspec(dllexport) int init_python() {
int rv = -1;
printf("attempting to initialize Python interpreter...\n");
// I have other python versions, Python27 not on path. set PYTHONHOME
Py_SetPythonHome("C:\\Python27\\"); // python27
//Py_SetPythonHome(L"C:\\Python38\\"); // python3X
Py_Initialize();
PyObject * pModule_Name = PyString_FromString("python_functions"); // python27 only
//PyObject * pModule_Name = PyUnicode_FromString("python_functions"); // python3X
if (!pModule_Name) {
printf("failed to convert module name to python string object\n");
return rv;
}
// can confirm pModule_Name != NULL && Py_REFCNT(pModule_Name) == 1 here
/*
load python module named "python_functions"
*/
// can also confirm pModule_Name != NULL && Py_REFCNT(pModule_Name) == 1 here
//Py_DECREF(pModule_Name); // If I uncomment this line, application linking .dll crashes
printf("pModule_Name successfully used\n");
rv = 0;
return rv;
}
// main.c
#include <stdio.h>
#include "python_functions.h"
int main(int argc, char **argv) {
int rv = 0;
// crashes without error if Py_DECREF(pModule_Name) in python_functions.c uncommented
printf("%d\n", init_python());
return rv;
}
Compiling the .dll with gcc 8.1.0 (MinGW-64) linking against C:\Python27\python27.dll:
gcc -IC:\Python27\include -LC:\Python27\libs -IC:\Python27 python_functions.c -shared -o python_functions.dll -lpython27
Compiling main with python27.dll and python_functions.dll in the same directory:
gcc main.c -o main.exe -L./ -lpython_functions
If I uncomment the line Py_DECREF(pModule_Name), which I thought I must do since PyString_FromString returns a new reference, then running main.exe crashes without return.
Should I be using something else or not doing reference counting on result from PyString_FromString or is this a larger problem with linking to python27?
If I make the commented/corresponding compiler changes to link against python 3.8+, no problems...
The only differences I know of are the significant changes to the Python C API between 2.7 and e.g. 3.8+ as well as the differences in python 2.X vs 3.X string representations. I believe PyString is appropriate here because when I actually implement and load a module name python_functions.py, it works...so long as I leave Py_DECREF(pModule_Name) commented out and the pointer leaked.
I also thought PyString_FromString might have a problem passing a string literal, but it accepts a const char *, documentation says it creates a copy, and even passing a copy of the string literal to another variable does not work.
I have looked at every post pertaining the "multiple Lua VMs detected" error and none of their answers worked. I have done everything the lua.org building guide says to compile it and it still shows the error. Using visual studio 2019 causes an unresolved external symbol error and using the GCC command without -llua also causes unresolved symbols. Any ideas. I am using version lua 5.3.2 from the binary compiled with the provided make file.
this is the code I am trying to use
#include "lua.h"
#include "lauxlib.h"
#include <Windows.h>
int test_function(lua_State* L)
{
return 0;
}
static const luaL_Reg testlib[] = {
{"test_function", test_function},
{NULL, NULL}
};
__declspec(dllexport) int __cdecl luaopen_testlib(lua_State* L)
{
luaL_newlib(L, testlib);
return 1;
};
local lib, err = package.loadlib([[module.dll]], "luaopen_testlib")
if lib ~= nil then
--multiple Lua VMs detected
lib()
else
print(err)
end
I am mostly working on Go projects atm, but I have to use CGO for part of my project on the purpose of editing TIF files from Go with C, because of parameter pass-through. I am not familiar with C, but it seems the only way to solve our problem.
The problem is when I theoretically set up the Go part, and wanted to use my C code, it drops undefined reference to xxxx'` with TIFFGetField,_TIFFmalloc,TIFFReadRGBAImage function calls.
Probably I am not even importing the libtiff libary in the right way.
The funny thing is the first code of the C code itself is TIFF* tif = TIFFOpen("foo.tif", "w"); does not have reference error to TIFFOpen, only the others (TIFFGetField,_TIFFmalloc,TIFFReadRGBAImage,_TIFFfree,TIFFClose)
my go code is
package main
// #cgo CFLAGS: -Ilibs/libtiff/libtiff
// #include "tiffeditor.h"
import "C"
func main() {
C.tiffEdit()
}
#include "tiffeditor.h"
#include "tiffio.h"
void tiffEdit(){
TIFF* tif = TIFFOpen("foo.tif", "w");
if (tif) {
uint32 w, h;
size_t npixels;
uint32* raster;
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
npixels = w * h;
raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));
if (raster != NULL) {
if (TIFFReadRGBAImage(tif, w, h, raster, 0)) {
//
}
_TIFFfree(raster);
}
TIFFClose(tif);
}
}
My goal on first is just to establish libtiff with my go code and make it to recognise the functions libtiff, so I can focus on solving the problem itself.
If you see the message "undefined reference to xxx" in cgo. It is very likely that you're missing the linking to the shared library.
I'm not quite familiar to this package, but i suggest you could try add something as below to make your program link to the C dynamic library:
// #cgo LDFLAGS: -lyour-lib
In case above, i link my go program to a C dynamic library called "libyour-lib.so".
Example
Assumed that your TIFF source comes from http://www.simplesystems.org/libtiff/
Steps
Download the source codes
Check README.md (or INSTALL) to read the guide about how to compile this C library
Follows provided instructions and install the C library
If you're doing correctly without modifying default settings, you should find tiff headers in /usr/local/include and its dynamic libraries in /usr/local/lib
Integrates these stuffs to your go program by having proper hints for cgo compiler.
Codes
I've build this program successfully, and executed as expected. It might be a good starting point for you.
package main
// #cgo LDFLAGS: -ltiff
// #include "tiffio.h"
// #include <stdlib.h>
import "C"
import (
"fmt"
"unsafe"
)
func main() {
path, perm := "foo.tif", "w"
// Convert Go string to C char array. It will do malloc in C,
// You must free these string if it no longer in use.
cpath := C.CString(path)
cperm := C.CString(perm)
// Defer free the memory allocated by C.
defer func() {
C.free(unsafe.Pointer(cpath))
C.free(unsafe.Pointer(cperm))
}()
tif := C.TIFFOpen(cpath, cperm)
if tif == nil {
panic(fmt.Errorf("cannot open %s", path))
}
C.TIFFClose(tif)
}
I would like to build a .dll filled with Lua bindings written in C compiled using VS 2017, but I don't seem to be having any luck, and the resources available to me are confusing and, by majority, outdated.
Here is what I've done.
I've already compiled lua from source and added it to my path so that I can lua.exe anything. This also created lua53.dll.
I've taken all of the .c and .h files of the lua source and added them to my VS project, along with one main.c which I am using to test. I added the .dll file as well, but only in the same way that I added the .c and .h files. I don't think it's doing anything.
Here's main.c:
#define LUA_LIB
#include "lua/lua.h"
#include "lua/lualib.h"
#include "lua/lauxlib.h"
#include "tg/tg.h"
static int lua_TG(lua_State *L) {
return 1;
}
static int lua_useTGHandle(lua_State *L) {
struct TGHandle *tgHandle = malloc(sizeof(struct TGHandle));
*tgHandle = TG();
lua_pushlightuserdata(L, tgHandle);
return 1;
}
static const luaL_Reg tglib[] = {
{"TG", lua_TG},
{"useTGHandle", lua_useTGHandle},
{NULL, NULL}
};
LUALIB_API int luaopen_libtg(lua_State* L) {
luaL_newlib(L, tglib);
return 1;
}
One function implemented, one not, but the lib should register.
I have changed the build type to a .dll, and I get the .dll generated without any errors, but when I try to use it in a Lua script I get:
%1 is not a valid Win32 application.
Surely I just have no clue what I'm doing. How would I just set up a lua-binding-building environment in VS2017?
First things first, I am very new to C programming and the whole idea of compilation, so I would really appreciate some very straightforward and step-by-step guidance on this.
Here is my problem: I am trying to write some C code that I can dyn.load into R to speed up my R task. My C code would involve some very complex matrix operation that is only available in an external library with the header file "matrix.h" and the static library file "matrix.lib". It would also make use of some basic R header files such as "Rdefines.h", etc. The files "matrix.h" and "matrix.lib" are located at C:\lcc\include and C:\lcc\lib, respectively. Here is a sample test C code:
#include <Rmath.h>
#include <R.h>
#include <Rdefines.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <matrix.h>
void foo(double *cdegree, double *fdegree, int *size) {
int i;
for(i=0; i<*size; i++) {
cdegree[i] = 5.0/9.0*(fdegree[i]-32.0);
}
}
As you can see, this is simple code converting Fahrenheit to Celsius. Although the test code does not make use of anything in the matrix library, the goal here is to be able to include both the R header files and matrix.h from the external library. If I try R CMD SHLIB this C code I get the "no such file or directory" error for trying to include "matrix.h". How can I tell R to compile this with the external library? Everything is done on a Windows 8.1 X64 system.
Honestly, you will find it much easier if you start exploring Rcpp. Here is a link to introduce you to Rcpp. There are many examples to be found throughout the documentation.
f2c.cpp
#include <Rcpp.h>
// [[Rcpp::export]]
void foo(Rcpp::NumericVector fdegree, Rcpp::NumericVector cdegree, int size){
int i;
for(i=0; i < size; i++){
cdegree[i] = 5.0/9.0*(fdegree[i]-32.0);
}
}
R code
library(Rcpp)
sourceCpp("f2c.cpp")
fdegree <- c(98.6, 212, 32)
cdegree <- c(0,0,0)
foo(fdegree, cdegree, length(fdegree))
cdegree
[1] 37 100 0
Naturally this makes some assumptions but it demonstrates how you can quickly use some C code and not fiddle with all the R headers and SHLIB.
Regarding your concern to use some external headers, just simply set the PKG_CXXFLAGS environmental variable to the location of your header(s).
Sys.setenv("PKG_CXXFLAGS" = '-I"path/to/headers"')
followed by the same compilation.
sourceCpp("f2c.cpp")
However, it should be noted that if you are doing more than a few of these functions you should build a package with Rcpp and provide an appropriate Makevars file. You can find further information on Rcpp package development here.