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?
Related
I have created a static library (.lib). The source code looks like this:
Source file:
void foo(void)
{
MyType var;
var.val1 = 40;
var.val2 = 30;
use(var);
}
Header filer (libheader.h):
/* Exported API */
void foo(void);
Main project:
#include "libheader.h" // XX.lib already imported to the main project
int main()
{
// some code
foo(); // Breakpoint here and step in
// some code
return 0;
}
In the main project, I imported the library and included "libheader.h" and I called foo(). When I debug my code and I put a breakpoint on foo()then I click on 'Step in' the assembler code of the static library is shown in the debug console and I can see local variables content like var (in the example). I can even see in the call stack that use(var) has been called.
My question is: This library should be protected before being delivered to the client. Is it normal that the content (variables, function names, calls ...) of a .lib file can be seen during debug? Is there a way to crypt/protect it?
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.
I have a 218KB .dll and a 596KB .so file, both with identical names. I want to link to the .dll to avoid the "unresolved external symbol" error that the linker returns, but I can't find a way to link to the DLL file.
According to this Pelles C forum topic, I need to use the .def file to create a .lib... but I don't have a .def file. This forum topic shows how to use polink to create a .lib from the command line, so I ran polink /? to get some more options. I noticed a /MAKEDEF option, but running this with both the .dll and the .so gives a "No library file specified" fatal error.
I have been trying to do this for three hours, and am out of ideas. I have got to the point where my web searches turn up my own help-requests. There must be a way to do this... How can I link to a .dll?
With information found in the header #include and your details, here is a way to replace the missing function by calling them dynamically from your software.
1- the following prototype is in #include :
typedef float (* XPLMFlightLoop_f)(float inElapsedSinceLastCall, float inElapsedTimeSinceLastFlightLoop, int inCounter, void * inRefcon);
2- some const that you can fill as needed:
const char *sDllPathName = "<Your XPLM_API DLL>.dll";
const char *sXPLMRegisterFlightLoopCallbackName = "XPLMRegisterFlightLoopCallback";
In order to confirm the sXPLMRegisterFlightLoopCallbackName, you can
use the freeware Dependency Walker and check name and format of
the exported functions.
3- declare the prototype of the external function:
Be aware to the calling convention __cdecl or __stdcall
In the current case, the keyword XPLM_API is defined in the XPLMDefs.h as follow:
#define XPLM_API __declspec(dllexport) // meaning __cdecl calling convention
typedef void (__cdecl *XPLMRegisterFlightLoopCallback_PROC)(XPLMFlightLoop_f, float, void *);
4- clone the function to call it in your software:
#include <windows.h>
void XPLMRegisterFlightLoopCallback(XPLMFlightLoop_f inFlightLoop, float inInterval, void * inRefcon)
{
HINSTANCE hInstDLL;
XPLMRegisterFlightLoopCallback_PROC pMyDynamicProc = NULL;
// Load your DLL in memory
hInstDLL = LoadLibrary(sDllPathName);
if (hInstDLL!=NULL)
{
// Search for the XPLM Function
pMyDynamicProc = (XPLMRegisterFlightLoopCallback_PROC) GetProcAddress(hInstDLL, sXPLMRegisterFlightLoopCallbackName);
if (pMyDynamicProc != NULL)
{
// Call the XPLM Function with the orignal parameter
(pMyDynamicProc)(inFlightLoop,inInterval,inRefcon);
return;
}
}
// Do something when DLL is missing or function not found
}
5- just add your described call:
...
XPLMRegisterFlightLoopCallback(callbackfunction, 0, NULL);
...
I’m trying to create ./configure + make set for building C codes in following structure by using autotools. drive.c uses function in mylib.c
[mylib]
+mylib.c
+mylib.h
[src]
+drive.c
More details are here.
[mylib.c]
#include <stdio.h>
#include "mylib.h"
int main(){
mylib();
return 0;
}
void
mylib(void)
{
printf ("Hello world! I AM mylib \n");
}
[mylib.h]
void mylib(void);
[drive.c]
#include <mylib.h>
int
main (int argc, char **argv)
{
mylib();
return 0;
}
Actually I’ve given main() both mylib.c and drive.c.
If I make them on CentOS process is noremally finished however If I make them on MINGW an error message multiple definition ofmain'` is shown
How can I make them on MINGW even if they have multiply have main()?
And those followings are config files for autotools.
[confiugre.ac]
AC_PREREQ([2.69])
AC_INIT([libmylib], [1], [admin#localhost])
AC_CONFIG_SRCDIR([mylib/mylib.c])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([foreign])
LT_INIT
AC_PROG_CC
AC_CONFIG_FILES([mylib/Makefile
src/Makefile
Makefile])
AC_OUTPUT
[Makefile.am]
SUBDIRS = mylib src
ACLOCAL_AMFLAGS = -I m4
[Makefile.am#src]
bin_PROGRAMS = drive
drive_SOURCES = drive.c
LDADD = ../mylib/libmylib.la
AM_CPPFLAGS = -I../mylib
[Makefile.am#mylib]
lib_LTLIBRARIES = libmylib.la
libmylib_la_SOURCES = mylib.c
include_HEADERS = mylib.h
You are confusing things, the idea of having multiple main() is fundamentally wrong. Libraries never ever contain a main() function.
(With the exception of Windows DLLs that contain a DllMain, but that means something different.)
If you want to provide a test case for your library, you make the test case as a separate project which includes the library. The test code should not be inside the library itself, neither should main().
Also, I very much doubt you are able to build a program with several function definitions that have the same name, be it main() or something else. If you believe you have managed this, I would either suspect that you haven't linked the files correctly, or that the linker is crap.
I am working on a C console project in Qt (Mac) because client does not want C++
With everything in a single C file everything was working well but, of course,
it started getting too big.
So I created a new juicy_lucy.h and juicy_lucy.c file and, to start with, just transferred some stuff from main.c to juicy_lucy.h which now looks like this
#ifndef JUICY_LUCY_H
#define JUICY_LUCY_H
#define command_count 14
char *function_names[command_count] = {
"CLEAR_LCD", "PUT_LCD", "SET_VAR", "ADC_READ",
"BIT_WRITE", "BIT_READ", "BIT_WAIT",
"FAIL_LESS", "FAIL_MORE", "FAIL_HIGH","FAIL_LOW",
"AVR_PROG","AVR_READ_SERIAL","AVR_WRITE_SERIAL"
};
int param_count[command_count] = {0,3,2,1,2,1,2,2,2,1,1,1,1,1};
#endif // JUICY_LUCY_H
and, of course, include the header in both main.c and juicy_lucy.c
Now when I build I get
duplicate symbol _function_names in juicy_lucy.o and main.o for architectures x86_64
Can anybody suggest what may be wrong?
You must declare function_names as
const char* const function_names[] = ...
Then the symbol function_names should not appear twice in your linked application.
In your .h:
extern char *function_names[command_count];
extern int param_count[command_count];
In one of your .c files:
char *function_names[command_count] = {
"CLEAR_LCD", "PUT_LCD", "SET_VAR", "ADC_READ",
"BIT_WRITE", "BIT_READ", "BIT_WAIT",
"FAIL_LESS", "FAIL_MORE", "FAIL_HIGH","FAIL_LOW",
"AVR_PROG","AVR_READ_SERIAL","AVR_WRITE_SERIAL"
};
int param_count[command_count] = {0,3,2,1,2,1,2,2,2,1,1,1,1,1};