How to expose a function from C++ executable to LuaJIT - c++

I am trying to load a Lua script into my c++ app and run it.
I decided to use LuaJIT to harness its FFI library.
But I have this weird problem where my Lua script cannot see the function symbols I defined in my C++ code and I get this error upon running my app:
undefined symbol: test_func_a
below is my C++ and Lua Code:
//C++//
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <lua.hpp>
#ifdef __cplusplus
extern "C" {
#endif
void test_func_a ( void ) {
printf ( "hello\n" );
}
#ifdef __cplusplus
}
#endif
int main ( int argc, char** argv ) {
lua_State *lua = luaL_newstate();
assert ( lua );
luaL_openlibs ( lua );
const int status = luaL_dostring ( lua, lua_script_content );
if ( status )
printf ( "Couldn't execute LUA code: %s\n", lua_tostring ( lua, -1 ));
lua_close ( lua );
return 0;
}
//Lua//
local ffi = require('ffi');
ffi.cdef[[
void test_func_a (void);
]]
ffi.C.test_func_a()
by default gcc will export all symbols, how come luajit fails to see them?

use:
extern "C" __declspec(dllexport) void test_func_a ( void ) {printf ("hello\n" );}

Related

C++ Unresolved External Symbols Embedded Lua ( based on longjmp issue ) ( not duplicate )

I will describe the problem as follows:
Compiler: Visual Studio 2019
The root of the problem is that longjump crashes the process because I manually map my code to the process.
The code works fine as follows, but crashes on any syntax error in the lua script due to longjump:
extern "C" {
#include "lua.h"
#include "lualib.h"
.....
}
I want C++ exceptions originating from:
#if defined(__cplusplus) && !defined(LUA_USE_LONGJMP) /* { */
/* C++ exceptions */
#define LUAI_THROW(L,c) throw(c)
#define LUAI_TRY(L,c,a) \
try { a } catch(...) { if ((c)->status == 0) (c)->status = -1; }
#define luai_jmpbuf int /* dummy variable */
#elif defined(LUA_USE_POSIX) /* }{ */
/* in POSIX, try _longjmp/_setjmp (more efficient) */
#define LUAI_THROW(L,c) _longjmp((c)->b, 1)
#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a }
#define luai_jmpbuf jmp_buf
#else /* }{ */
/* ISO C handling with long jumps */
#define LUAI_THROW(L,c) longjmp((c)->b, 1)
#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a }
#define luai_jmpbuf jmp_buf
#endif /* } */
Because longjmp crashes my process.
So I decided to compile my code with the C++ compiler (without extern C) and:
#include "lua.h"
#include "lualib.h"
.....
This is how I called it. But this also led to the following problem:
error LNK2019: unresolved external symbol _lua_pcall
...
...
...
I thought a lot about it but couldn't find a solution.It's ridiculous that it's a linker error because all the lua header and c files are joined to my project.
#define LUAI_THROW(L,c) c->throwed = true
#define LUAI_TRY(L,c,a) \
__try { a } __except(filter()) { if ((c)->status == 0 && ((c)->throwed)) (c)->status = -1; }
#define luai_jmpbuf int /* dummy variable */
Btw, i solved my throwing exception issue like that. Im not sure its correct or no but not crashing anymore.
struct lua_longjmp {
struct lua_longjmp *previous;
luai_jmpbuf b;
volatile int status; /* error code */
bool throwed;
};
Works as expected even you build without C++ exceptions

calling .c file inside .cpp

I am trying to call a C file (dispmanx.c) from a C++ file (main.cpp).
dispmanx.c :
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include <unistd.h>
#include <sys/time.h>
#include "bcm_host.h"
#define WIDTH 200
#define HEIGHT 200
#ifndef ALIGN_UP
#define ALIGN_UP(x,y) ((x + (y)-1) & ~((y)-1))
#endif
int run(unsigned char* fileData)
{
typedef struct
{
DISPMANX_DISPLAY_HANDLE_T display;
DISPMANX_MODEINFO_T info;
void *image;
DISPMANX_UPDATE_HANDLE_T update;
DISPMANX_RESOURCE_HANDLE_T resource;
DISPMANX_ELEMENT_HANDLE_T element;
uint32_t vc_image_ptr;
} RECT_VARS_T;
static RECT_VARS_T gRectVars;
RECT_VARS_T *vars;
uint32_t screen = 1;
int ret;
VC_RECT_T src_rect;
VC_RECT_T dst_rect;
VC_IMAGE_TYPE_T type = VC_IMAGE_RGB565;
int width = WIDTH, height = HEIGHT;
int pitch = ALIGN_UP(width*2, 32);
int aligned_height = ALIGN_UP(height, 16);
VC_DISPMANX_ALPHA_T alpha = { DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS,
120, /*alpha 0->255*/
0 };
vars = &gRectVars;
bcm_host_init();
printf("Open display[%i]...\n", screen );
vars->display = vc_dispmanx_display_open( screen );
ret = vc_dispmanx_display_get_info( vars->display, &vars->info);
assert(ret == 0);
printf( "Display is %d x %d\n", vars->info.width, vars->info.height );
vars->image = fileData;
// vars->image = calloc(1, pitch * height);
assert(vars->image);
vars->resource = vc_dispmanx_resource_create( type,
width,
height,
&vars->vc_image_ptr );
assert( vars->resource );
vc_dispmanx_rect_set( &dst_rect, 0, 0, width, height);
ret = vc_dispmanx_resource_write_data( vars->resource,
type,
pitch,
vars->image,
&dst_rect );
assert( ret == 0 );
vars->update = vc_dispmanx_update_start( 10 );
assert( vars->update );
vc_dispmanx_rect_set( &src_rect, 0, 0, width << 16, height << 16 );
vc_dispmanx_rect_set( &dst_rect, ( vars->info.width - width ) / 2,
( vars->info.height - height ) / 2,
width,
height );
vars->element = vc_dispmanx_element_add( vars->update,
vars->display,
2000, // layer
&dst_rect,
vars->resource,
&src_rect,
DISPMANX_PROTECTION_NONE,
&alpha,
NULL, // clamp
VC_IMAGE_ROT0 );
ret = vc_dispmanx_update_submit_sync( vars->update );
assert( ret == 0 );
printf( "Sleeping for 10 seconds...\n" );
sleep( 10 );
vars->update = vc_dispmanx_update_start( 10 );
assert( vars->update );
ret = vc_dispmanx_element_remove( vars->update, vars->element );
assert( ret == 0 );
ret = vc_dispmanx_update_submit_sync( vars->update );
assert( ret == 0 );
ret = vc_dispmanx_resource_delete( vars->resource );
assert( ret == 0 );
ret = vc_dispmanx_display_close( vars->display );
assert( ret == 0 );
return 0;
}
#ifdef __cplusplus
}
#endif
the main.cpp:
#include "dispmanx.c"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
Mat image;
image = imread("t.png", IMREAD_COLOR); // Read the file
run(image.data);
}
the code should take an address of a png file get the data of it using OpenCV libraries and pass it to the C program which shows the picture on the screen.
I could compile the dispmanx.c:
pi#raspberrypi:~/openCVtest.1 $ gcc -I/opt/vc/include/
-I/opt/vc/include/interface/vcos/pthreads
-I/opt/vc/include/interface/vmcs_host/linux
-I/opt/vc/src/hello_pi/libs/ilclient
-I/opt/vc/src/hello_pi/libs/vgfont
-L/opt/vc/lib/ -L/opt/vc/src/hello_pi/libs/ilclient
-L/opt/vc/src/hello_pi/libs/vgfont
-c dispmanx.c
-o dispmanx.o
-lbrcmGLESv2 -lbrcmEGL -lopenmaxil -lbcm_host -lvcos -lvchiq_arm -lpthread -lrt -lm
but when I try to compile the main.cpp:
pi#raspberrypi:~/openCVtest.1 $ g++ -I/opt/vc/include/ -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/interface/vmcs_host/linux -I/opt/vc/src/hello_pi/libs/ilclient -I/opt/vc/src/hello_pi/libs/vgfont -L/opt/vc/lib/ -L/opt/vc/src/hello_pi/libs/ilclient -L/opt/vc/src/hello_pi/libs/vgfont -c main.cpp dispmanx.o -o main.o -lbrcmGLESv2 -lbrcmEGL -lopenmaxil -lbcm_host -lvcos -lvchiq_arm -lpthread -lrt -lm In file included from main.cpp:2:0:
dispmanx.c: In function ‘int run(unsigned char*)’:
dispmanx.c:52:68: error: invalid conversion from ‘int’ to ‘DISPMANX_FLAGS_ALPHA_T’ [-fpermissive]
VC_DISPMANX_ALPHA_T alpha = { DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dispmanx.c:111:63: error: cannot convert ‘VC_IMAGE_TRANSFORM_T’ to ‘DISPMANX_TRANSFORM_T’ for argument ‘10’ to ‘DISPMANX_ELEMENT_HANDLE_T vc_dispmanx_element_add(DISPMANX_UPDATE_HANDLE_T, DISPMANX_DISPLAY_HANDLE_T, int32_t, const VC_RECT_T*, DISPMANX_RESOURCE_HANDLE_T, const VC_RECT_T*, DISPMANX_PROTECTION_T, VC_DISPMANX_ALPHA_T*, DISPMANX_CLAMP_T*, DISPMANX_TRANSFORM_T)’
VC_IMAGE_ROT0 );
I have tested both program separately and the function as they should, however when I tried to mix them I get errors that I cant understand.
I am a student have beginner level of knowledge. what am I doing wrong?
Given these contents of dispmanx.c:
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include <unistd.h>
#include <sys/time.h>
and main.cpp starts with
#include "dispmanx.c"
You are going to have serious problems.
You've wrapped entire standard header files such as unistd.h with extern "C", and then #include'd them in a C++ file.
They're not meant to be used that way in C++ code.
#include'ing a source file (.c, .cpp, etc) is a fundamentally bad idea in the first place. Doing it across different languages such a C and C++ and then improperly wrapping system headers with extern "C" is even worse. You can't safely compile C code as C++ code, and you certainly can't wrap system header files with extern "C" for use in C++ code.
extern "C" does not make it safe to compile C code with a C++ compiler. They are different languages, with subtle distinctions.
The problem is here:
#include "dispmanx.c"
Including a *.c file in a *.cpp file is not a good idea. C and C++ are similar languages, so it may look that it works at first (i.e. the compiler reports the error not at line 1 but at line 111), but actually it doesn't.
One correct way to call C code from C++ code is by providing a declaration like this:
// C++ code
#include <iostream>
extern "C" {
int run(unsigned char* fileData); // declaration for the C code
}
...
int main()
{
...
run(image.data); // calling the C code
}
The declaration for the C code can be in the *.cpp file or, more conventionally, in a separate dedicated *.h file. If your C code is in dispmanx.c, then a conventional name is dispmanx.h:
// dispmanx.h
extern "C" {
int run(unsigned char* fileData); // declaration for the C code
}
// main.cpp
#include <iostream>
#include "dispmanx.h"
...
int main()
{
...
run(image.data); // calling the C code
}
Also, another convention: if you want to make your new dispmanx.h file compilable in both C and C++, you should hide the extern "C" part from the C compiler, as described in this question and answer.

Calling Lua function from string_t

I have some functions declared and initialized in .lua file. Then, when I receive signal, I read string_t variable with the name of function to call from file. The problem is that I don't know how to push function to stack by its name or call it.
For example:
test.lua
function iLoveVodka()
--some text
end
function iLoveFish()
--another text
end
C File:
string_t a = "iLoveVodka()"
How can i call function from C/C++ code iLoveVodka() only by having its name?
Here is some sample code that does two things:
Loads the file "test.lua" from the same directory.
Tries to call the function iLoveVodka(), if it can be found.
You should be able to build this easily enough:
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[])
{
lua_State *l = luaL_newstate ();
luaL_openlibs (l);
int error = luaL_dofile (l, "test.lua");
if (error)
{
printf( "Error loading test.lua: %s\n",luaL_checkstring (l, -1) );
exit(1);
}
/**
* Get the function and call it
*/
lua_getglobal(l, "iLoveVodka");
if ( lua_isnil(l,-1) )
{
printf("Failed to find global function iLoveVodka\n" );
exit(1);
}
lua_pcall(l,0,0,0);
/**
* Cleanup.
*/
lua_close (l);
return 0;
}
This can be compiled like this:
gcc -O -o test `pkg-config --libs --cflags lua5.1` test.c
Just define your iLoveVodka() function inside test.lua, and you should be OK.

How to run c++ module in apache?

i have wrote the c++ module in apache. The following is the code ::
mod_foo.hpp
#ifndef MOD_FOO_HPP
#define MOD_FOO_HPP
#ifdef __cplusplus
#define EXTERN_C_BLOCK_BEGIN extern "C" {
#define EXTERN_C_BLOCK_END }
#define EXTERN_C_FUNC extern "C"
#else
#define EXTERN_C_BLOCK_BEGIN
#define EXTERN_C_BLOCK_END
#define EXTERN_C_FUNC
#endif
#include <httpd.h>
#include <http_protocol.h>
#include <http_config.h>**
#endif /* MOD_FOO_HPP */
mod_foo.c
#include "mod_foo.hpp"
EXTERN_C_FUNC
int foo_handler( request_rec* inpRequest )
{
int nReturnVal = DECLINED;
if ( inpRequest->handler != NULL && strcmp( inpRequest->handler, "foo" ) == 0 )
{
ap_rputs( "Hello World from FOO", inpRequest );
nReturnVal = OK;
}
return nReturnVal;
}
EXTERN_C_FUNC
void foo_hooks( apr_pool_t* inpPool )
{
ap_hook_handler( foo_handler, NULL, NULL, APR_HOOK_MIDDLE );
}
EXTERN_C_BLOCK_BEGIN
module AP_MODULE_DECLARE_DATA foo_module =
{
STANDARD20_MODULE_STUFF,
NULL,
NULL,
NULL,
NULL,
NULL,
foo_hooks
};
EXTERN_C_BLOCK_END
The module is compiling successfully and it's also installing on the apache server but when i restart the apache server after installing it The following Error occurs:
apache2: Syntax error on line 234 of /etc/apache2/apache2.conf: Syntax error on line 1 of /etc/apache2/conf.d/foo.conf: API module structure 'foo_module' in file /usr/lib/apache2/modules/mod_foo.so is garbled - expected signature 41503232 but saw 41503234 - perhaps this is not an Apache module DSO, or was compiled for a different Apache version?
I added the LoadModule thing in httpd.conf to load the module but only c++ modules is giving this error. Any idea about how to resolve this problem?
I think the handler should be declared as static, this could cause fault, beside that you should add a prefix extern "C" in front of the module, but adding every function with a extern "C" prefix is unnecessary.

dlclose crashes when copying dynamic libraries

I have an interesting problem that seems to be unresolved by my research on the internet.
I'm trying to load libraries dynamically in my c++ project with the functions from dlfcn.h. The problem is that when I try to reload the plugins at running time (because I made a change on any of them), the main program crashes (Segmentation fault (core dumped)) when dlclose() is called.
Here is my example that reproduces the error:
main.cpp:
#include <iostream>
#include <dlfcn.h>
#include <time.h>
#include "IPlugin.h"
int main( )
{
void * lib_handle;
char * error;
while( true )
{
std::cout << "Updating the .so" << std::endl;
lib_handle = dlopen( "./test1.so", RTLD_LAZY );
if ( ! lib_handle )
{
std::cerr << dlerror( ) << std::endl;
return 1;
}
create_t fn_create = ( create_t ) dlsym( lib_handle, "create" );
if ( ( error = dlerror( ) ) != NULL )
{
std::cerr << error << std::endl;
return 1;
}
IPlugin * ik = fn_create( );
ik->exec( );
destroy_t fn_destroy = ( destroy_t ) dlsym( lib_handle, "destroy" );
fn_destroy( ik );
std::cout << "Waiting 5 seconds before unloading..." << std::endl;
sleep( 5 );
dlclose( lib_handle );
}
return 0;
}
IPlugin.h:
class IPlugin
{
public:
IPlugin( ) { }
virtual ~IPlugin( ) { }
virtual void exec( ) = 0;
};
typedef IPlugin * ( * create_t )( );
typedef void ( * destroy_t )( IPlugin * );
Test1.h:
#include <iostream>
#include "IPlugin.h"
class Test1 : public IPlugin
{
public:
Test1( );
virtual ~Test1( );
void exec( );
};
Test1.cpp:
#include "Test1.h"
Test1::Test1( ) { }
Test1::~Test1( ) { }
void Test1::exec( )
{
std::cout << "void Test1::exec( )" << std::endl;
}
extern "C"
IPlugin * create( )
{
return new Test1( );
}
extern "C"
void destroy( IPlugin * plugin )
{
if( plugin != NULL )
{
delete plugin;
}
}
To compile:
g++ main.cpp -o main -ldl
g++ -shared -fPIC Test1.cpp -o plugin/test1.so
The problem occurs when for example I change something on the Test1::exec method (changing the string to be printed or commenting the line) and while the main program sleeps I copy the new test1.so to main running directory (cp). If I use the move command (mv), no error occurs. What makes the difference between using cp or mv? Is there any way to solve this problem or to do that using cp?
I'm using Fedora 14 with g++ (GCC) 4.5.1 20100924 (Red Hat 4.5.1-4).
Thanks in advance.
The difference between cp and mv that is pertinent to this question is as follows:
cp opens the destination file and writes the new contents into it. It therefore replaces the old contents with the new contents.
mv doesn't touch the contents of the original file. Instead, it makes the directory entry point to the new file.
This turns out to be important. While the application is running, the OS keeps open handles to the executable and the shared objects. When it needs to consult one of the these files, it uses the relevant handle to access the file's contents.
If you've used cp, the contents has now been corrupted, so anything can happen (a segfault is a pretty likely outcome).
If you've used mv, the open file handle still refers to the original file, which continues to exist on disk even though there's no longer a directory entry for it.
If you've used mv to replace the shared object, you should be able to dlclose the old one and dlopen the new one. However, this is not something that I've done or would recommend.
Try this:
extern "C"
void destroy( IPlugin * plugin )
{
if( plugin != NULL && dynamic_cast<Test1*>(plugin))
{
delete static_cast<Test1*>(plugin);
}
}