rename the *_load_time examples, start GUIDE.txt, write the xlist base layer example
parent
a3befc6dcd
commit
40183c2eed
|
@ -0,0 +1,21 @@
|
||||||
|
The main goal of this investigation is to organize shared data and code across
|
||||||
|
multiple binary files. This is especially important for something like a base
|
||||||
|
layer that will be used in a program that supports hot-reloading or plugins.
|
||||||
|
|
||||||
|
Each isolated example in this repository explores a way to set up the base
|
||||||
|
layer, plugin, and main program.
|
||||||
|
|
||||||
|
The examples:
|
||||||
|
|
||||||
|
*_concrete - Concrete examples for each operating system I have investigated
|
||||||
|
showing how to setup and use various types of dynamic linking. In
|
||||||
|
these the "base" layer goes through load-time linking, the
|
||||||
|
"plugin" layer goes through run-time linking, and the "main" layer
|
||||||
|
acts as the executable that must bind it all together.
|
||||||
|
|
||||||
|
xlist - My prefered solution to the problem posed in the investigation which
|
||||||
|
relies only on run-time linking. It uses an xlist to manage the
|
||||||
|
maintenance burden of run-time linking, and a basic outline of the
|
||||||
|
abstracted form of each layer.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
// base symbols shared
|
||||||
|
|
||||||
|
#if defined(BASE_IMPLEMENTOR)
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int x = 0;
|
||||||
|
|
||||||
|
void
|
||||||
|
base_func(void){
|
||||||
|
printf("x = %d\n", x);
|
||||||
|
x += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// dynamic function linkage protocol
|
||||||
|
|
||||||
|
#if defined(BASE_IMPLEMENTOR)
|
||||||
|
|
||||||
|
EXPORT_SYMBOL BASE_Funcs*
|
||||||
|
base_export_functions(void){
|
||||||
|
static BASE_Funcs funcs = {0};
|
||||||
|
if (funcs.base_func == 0){
|
||||||
|
#define X(N,R,P) funcs.N = N;
|
||||||
|
#include "base.xlist.h"
|
||||||
|
#undef X
|
||||||
|
}
|
||||||
|
return(&funcs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(BASE_IMPLEMENTOR)
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
|
# include <Windows.h>
|
||||||
|
#elif OS_LINUX
|
||||||
|
# include <dlfcn.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BEFORE_MAIN(base_dynamic_user_init){
|
||||||
|
BASE_Funcs *funcs = 0;
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
|
HMODULE module = LoadLibraryA("base.dll");
|
||||||
|
if (module != 0){
|
||||||
|
BASE_ExportFuncs *base_export_functions = (BASE_ExportFuncs*)GetProcAddress(module, "base_export_functions");
|
||||||
|
if (base_export_functions != 0){
|
||||||
|
funcs = base_export_functions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif OS_LINUX
|
||||||
|
void *module = dlopen("./base.so", RTLD_NOW);
|
||||||
|
if (module != 0){
|
||||||
|
BASE_ExportFuncs *base_export_functions = (BASE_ExportFuncs*)dlsym(module, "base_export_functions");
|
||||||
|
if (base_export_functions != 0){
|
||||||
|
funcs = base_export_functions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# error base_import_functions not completed for this OS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define X(N,R,P) N = funcs->N;
|
||||||
|
#include "base.xlist.h"
|
||||||
|
#undef X
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,79 @@
|
||||||
|
// baby context cracking
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
# define OS_WINDOWS 1
|
||||||
|
#elif defined(__gnu_linux__)
|
||||||
|
# define OS_LINUX 1
|
||||||
|
#else
|
||||||
|
# error this configuration of compiler & OS is not supported
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(OS_WINDOWS)
|
||||||
|
# define OS_WINDOWS 0
|
||||||
|
#endif
|
||||||
|
#if !defined(OS_LINUX)
|
||||||
|
# define OS_LINUX 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// linkage keyword abstraction
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
|
# define EXPORT_SYMBOL __declspec(dllexport)
|
||||||
|
#elif OS_LINUX
|
||||||
|
# define EXPORT_SYMBOL __attribute__ ((visibility ("default")))
|
||||||
|
#else
|
||||||
|
# error keyword abstractions missing for this OS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
|
|
||||||
|
# pragma section(".CRT$XCU", read)
|
||||||
|
|
||||||
|
# define BEFORE_MAIN(n) extern void n(void); \
|
||||||
|
__declspec(allocate(".CRT$XCU")) void (*n##__)(void) = n; \
|
||||||
|
__pragma(comment(linker, "/include:" #n)) extern void n(void)
|
||||||
|
|
||||||
|
#elif OS_LINUX
|
||||||
|
|
||||||
|
# define BEFORE_MAIN(n) \
|
||||||
|
__attribute__((constructor)) static void n(void)
|
||||||
|
|
||||||
|
#else
|
||||||
|
# error BEFORE_MAIN missing for this OS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// base layer types
|
||||||
|
|
||||||
|
typedef void BASE_Library;
|
||||||
|
|
||||||
|
|
||||||
|
// base symbols shared
|
||||||
|
|
||||||
|
#if defined(BASE_IMPLEMENTOR)
|
||||||
|
|
||||||
|
void base_func(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// dynamic function linkage protocol
|
||||||
|
|
||||||
|
typedef struct BASE_Funcs{
|
||||||
|
#define X(N,R,P) R (*N) P;
|
||||||
|
#include "base.xlist.h"
|
||||||
|
#undef X
|
||||||
|
} BASE_Funcs;
|
||||||
|
|
||||||
|
typedef BASE_Funcs* BASE_ExportFuncs(void);
|
||||||
|
|
||||||
|
#if defined(BASE_IMPLEMENTOR)
|
||||||
|
EXPORT_SYMBOL BASE_Funcs* base_export_functions(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(BASE_IMPLEMENTOR)
|
||||||
|
#define X(N,R,P) R (*N) P = 0;
|
||||||
|
#include "base.xlist.h"
|
||||||
|
#undef X
|
||||||
|
#endif
|
|
@ -0,0 +1,3 @@
|
||||||
|
#define BASE_IMPLEMENTOR 1
|
||||||
|
#include "base.h"
|
||||||
|
#include "base.c"
|
|
@ -0,0 +1 @@
|
||||||
|
X(base_func, void, (void))
|
|
@ -0,0 +1,17 @@
|
||||||
|
@echo off
|
||||||
|
|
||||||
|
REM: Path setup
|
||||||
|
|
||||||
|
SET src=%cd%
|
||||||
|
cd ..
|
||||||
|
if not exist "build\" mkdir build
|
||||||
|
cd build
|
||||||
|
|
||||||
|
REM: Build the base layer
|
||||||
|
cl /nologo /Zi /LD %src%\base.target.c /Febase.dll
|
||||||
|
|
||||||
|
REM: Build the main layer
|
||||||
|
cl /nologo /Zi %src%\main.c
|
||||||
|
|
||||||
|
REM: Build the plugin layer
|
||||||
|
cl /nologo /Zi /LD %src%\plugin.c /Feplugin.dll
|
|
@ -0,0 +1,16 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Path setup
|
||||||
|
src=$PWD
|
||||||
|
cd ..
|
||||||
|
mkdir -p build
|
||||||
|
cd build
|
||||||
|
|
||||||
|
# Build the base layer as base.so
|
||||||
|
gcc -fvisibility=hidden -fPIC -shared $src/base.target.c -o base.so
|
||||||
|
|
||||||
|
# Build the main layer
|
||||||
|
gcc -fvisibility=hidden $src/main.c -o main
|
||||||
|
|
||||||
|
# Build the plugin layer
|
||||||
|
gcc -fvisibility=hidden -fPIC -shared $src/plugin.c -o plugin.so
|
|
@ -0,0 +1,38 @@
|
||||||
|
#include "base.h"
|
||||||
|
|
||||||
|
#include "base.c"
|
||||||
|
|
||||||
|
|
||||||
|
// setup plugin_func as a function pointer so that it can be linked at run time
|
||||||
|
typedef void PLUGIN_Func(void);
|
||||||
|
PLUGIN_Func *plugin_func = 0;
|
||||||
|
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
// base layer initialization is automatic and runs before main - base functions begin working right away
|
||||||
|
base_func();
|
||||||
|
|
||||||
|
|
||||||
|
// to call a function with run-time linking, we must manually load and link it
|
||||||
|
#if OS_WINDOWS
|
||||||
|
HMODULE module = LoadLibraryA("plugin.dll");
|
||||||
|
if (module != 0){
|
||||||
|
plugin_func = (PLUGIN_Func*)GetProcAddress(module, "plugin_func");
|
||||||
|
}
|
||||||
|
#elif OS_LINUX
|
||||||
|
void *module = dlopen("./plugin.so", RTLD_NOW);
|
||||||
|
if (module != 0){
|
||||||
|
plugin_func = (PLUGIN_Func*)dlsym(module, "plugin_func");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// calls to plugin_func only work after the "plugin" loaded successfully
|
||||||
|
if (plugin_func != 0){
|
||||||
|
plugin_func();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// demonstration: the data structures contained in the 'base' are not duplicated in each binary
|
||||||
|
base_func();
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
#include "base.h"
|
||||||
|
|
||||||
|
#include "base.c"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
EXPORT_SYMBOL void
|
||||||
|
plugin_func(void){
|
||||||
|
printf("provided by plugin: {\n");
|
||||||
|
printf(" ");
|
||||||
|
base_func();
|
||||||
|
printf(" ");
|
||||||
|
base_func();
|
||||||
|
printf("}\n");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue