You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
184 lines
6.7 KiB
C
184 lines
6.7 KiB
C
/* Copyright 2013-2016 Philipp Janda <siffiejoe@gmx.net>
|
|
*
|
|
* You may do anything with this work that copyright law would normally
|
|
* restrict, so long as you retain the above notice(s) and this license
|
|
* in all redistributed copies and derived works. There is no warranty.
|
|
*/
|
|
|
|
#ifndef MOON_DLFIX_H_
|
|
#define MOON_DLFIX_H_
|
|
|
|
/* Provides a C function macro that tries to reopen the Lua library
|
|
* in global mode, so that C extension modules do not have to be
|
|
* relinked for Lua VMs in shared libraries.
|
|
*/
|
|
|
|
/* enable/disable debug output */
|
|
#if 0
|
|
#include <stdio.h>
|
|
#define MOON_DLFIX_DBG(_a) (printf _a)
|
|
#else
|
|
#define MOON_DLFIX_DBG(_a) ((void)0)
|
|
#endif
|
|
|
|
/* detect some form of UNIX, so that unistd.h can be included to
|
|
* use other feature macros */
|
|
#if defined(unix) || defined(__unix) || defined(__unix__) || \
|
|
defined(__TOS_AIX__) || defined(_SYSTYPE_BSD) || \
|
|
(defined(__APPLE__) && defined(__MACH__)) || \
|
|
defined(HAVE_UNISTD_H)
|
|
|
|
#include <unistd.h>
|
|
/* check for minimum POSIX version that specifies dlopen etc. */
|
|
#if (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) || \
|
|
defined(HAVE_DLFCN_H)
|
|
|
|
#include <dlfcn.h>
|
|
/* check for the existence of the RTLD_NOLOAD flag
|
|
* - GLIBC has it (since 2.2)
|
|
* - FreeBSD has it
|
|
* - ...
|
|
*/
|
|
#ifdef RTLD_NOLOAD
|
|
|
|
/* Lua VM library names to try
|
|
* Most of them require the dev-package to be installed,
|
|
* but guessing the real library names for multiple distros
|
|
* is pretty difficult ...
|
|
* If the library is not in the default search path you can
|
|
* set LD_LIBRARY_PATH, or use MOON_DLFIX_LIBNAME to specify
|
|
* an absolute path to the library.
|
|
*/
|
|
static char const *const moon_dlfix_lib_names[] = {
|
|
/* you can define your own custom name via compiler define: */
|
|
#ifdef MOON_DLFIX_LIBNAME
|
|
MOON_DLFIX_LIBNAME,
|
|
#endif /* custom Lua library name */
|
|
"liblua5.4.so", /* Lua 5.4, Debian/Ubuntu naming */
|
|
"liblua5.4.so.0", /* same with common SONAME */
|
|
"liblua54.so",
|
|
"liblua5.3.so", /* Lua 5.3, Debian/Ubuntu naming */
|
|
"liblua5.3.so.0", /* same with common SONAME */
|
|
"liblua53.so",
|
|
"liblua5.2.so", /* Lua 5.2, Debian/Ubuntu naming */
|
|
"liblua5.2.so.0", /* same with common SONAME */
|
|
"liblua52.so",
|
|
"liblua.so", /* default name from Lua's makefile */
|
|
"liblua5.1.so", /* Lua 5.1, Debian/Ubuntu naming */
|
|
"liblua5.1.so.0", /* same with common SONAME */
|
|
"liblua51.so",
|
|
"libluajit-5.1.so", /* LuaJIT default name */
|
|
"libluajit-5.1.so.2", /* common SONAME */
|
|
};
|
|
|
|
/* On some OSes we can iterate over all loaded libraries to
|
|
* find the Lua shared object.
|
|
*/
|
|
#if defined(__linux__) && defined(_GNU_SOURCE)
|
|
#define MOON_DLFIX_DL_ITERATE_PHDR
|
|
#include <link.h>
|
|
#endif /* Linux with dl_iterate_phdr() function */
|
|
#if defined(__FreeBSD__) || defined(__DragonFly__) || \
|
|
defined(__NetBSD__) || defined(__OpenBSD__)
|
|
#define MOON_DLFIX_DL_ITERATE_PHDR
|
|
#include <link.h>
|
|
#endif /* BSDs with dl_iterate_phdr() function */
|
|
|
|
#if !defined(MOON_DLFIX_FIND) && \
|
|
defined(MOON_DLFIX_DL_ITERATE_PHDR)
|
|
#include <string.h>
|
|
|
|
#ifndef MOON_DLFIX_LIBPREFIX
|
|
#define MOON_DLFIX_LIBPREFIX "liblua"
|
|
#endif
|
|
|
|
static int moon_dlfix_cb(struct dl_phdr_info *info, size_t size,
|
|
void *data)
|
|
{
|
|
int *found = data;
|
|
void *dl = dlopen(info->dlpi_name, RTLD_LAZY);
|
|
(void)size;
|
|
MOON_DLFIX_DBG(("Checking ELF object '%s'.\n", info->dlpi_name));
|
|
if (dl)
|
|
{
|
|
if (dlsym(dl, "lua_gettop"))
|
|
{
|
|
MOON_DLFIX_DBG(("'%s' does have Lua symbols.\n", info->dlpi_name));
|
|
/* the Lua API could be in a dependency, so test the library
|
|
* name for "liblua" */
|
|
char const *libname = strrchr(info->dlpi_name, '/');
|
|
if (libname)
|
|
++libname; /* skip slash */
|
|
else
|
|
libname = info->dlpi_name;
|
|
if (0 == strncmp(libname, MOON_DLFIX_LIBPREFIX,
|
|
sizeof(MOON_DLFIX_LIBPREFIX) - 1))
|
|
{
|
|
void *dl2 = dlopen(info->dlpi_name,
|
|
RTLD_LAZY | RTLD_GLOBAL | RTLD_NOLOAD);
|
|
if (dl2)
|
|
{
|
|
MOON_DLFIX_DBG(("Found and fixed Lua SO!\n"));
|
|
dlclose(dl2);
|
|
*found = 1;
|
|
}
|
|
}
|
|
}
|
|
dlclose(dl);
|
|
}
|
|
return *found;
|
|
}
|
|
|
|
static int moon_dlfix_find(void)
|
|
{
|
|
int found = 0;
|
|
MOON_DLFIX_DBG(("Iterating all loaded ELF objects ...\n"));
|
|
return dl_iterate_phdr(moon_dlfix_cb, &found);
|
|
}
|
|
#define MOON_DLFIX_FIND() (moon_dlfix_find())
|
|
#endif /* has dl_iterate_phdr() function */
|
|
|
|
#if !defined(MOON_DLFIX_FIND)
|
|
/* dummy definition (always returns failure) */
|
|
#define MOON_DLFIX_FIND() (0)
|
|
#endif
|
|
|
|
/* Try to iterate all loaded shared libraries using a platform-
|
|
* specific way to find a loaded Lua shared library.
|
|
* If that fails, try a list of common library names.
|
|
* In all cases reopen the Lua library using RTLD_GLOBAL and
|
|
* RTLD_NOLOAD.
|
|
*/
|
|
#define MOON_DLFIX() \
|
|
do \
|
|
{ \
|
|
if (!MOON_DLFIX_FIND()) \
|
|
{ \
|
|
unsigned i = 0; \
|
|
MOON_DLFIX_DBG(("Trying some common Lua library names ...\n")); \
|
|
for (; i < sizeof(moon_dlfix_lib_names) / sizeof(*moon_dlfix_lib_names); ++i) \
|
|
{ \
|
|
void *dl = dlopen(moon_dlfix_lib_names[i], RTLD_LAZY | RTLD_GLOBAL | RTLD_NOLOAD); \
|
|
MOON_DLFIX_DBG(("Trying '%s'.\n", moon_dlfix_lib_names[i])); \
|
|
if (dl) \
|
|
{ \
|
|
MOON_DLFIX_DBG(("Fixed Lua SO.\n")); \
|
|
dlclose(dl); \
|
|
break; \
|
|
} \
|
|
} \
|
|
} \
|
|
} while (0)
|
|
|
|
#endif /* has RTLD_NOLOAD */
|
|
#endif /* has dlfcn.h */
|
|
#endif /* has unistd.h */
|
|
|
|
/* define fallback */
|
|
#ifndef MOON_DLFIX
|
|
#define MOON_DLFIX() \
|
|
(MOON_DLFIX_DBG(("moon_dlfix functionality not available!\n")))
|
|
#endif
|
|
|
|
#endif /* MOON_DLFIX_H_ */
|