Yesterday, I wrote:
>
> Hacking alone won't cut the mustard on this occasion, I need divine inspiration.
I have this working now. Here's what I did:
Step 1: Link statically with the wxWidgets libraries, and don't link dynamically with the other libraries such as gdk, pango and cairo.
So where you would normally have the following in the Makefile:
$(shell wx-config --libs all)
Replace it with:
$(shell wx-config --libs all | tr ' ' '\n' | grep "\.a$$" | tr '\n' ' ')
Step 2: Allow unresolved symbols in the final executable file, list all symbols, and link lazily:
-Wl,--unresolved-symbols=ignore-in-object-files,--export-dynamic,-z,lazy
Step 3: Write thunks for the two functions whose address is required at runtime (there's only two of them):
gboolean gtk_true(void)
{
static gboolean (*const p)(void) = reinterpret_cast<gboolean(*)(void)>( dlsym(RTLD_NEXT, "gtk_true") );
return p();
}
void gtk_main_do_event(GdkEvent *const arg)
{
static void (*const p)(GdkEvent*) = reinterpret_cast<void(*)(GdkEvent*)>( dlsym(RTLD_NEXT, "gtk_main_do_event") );
p(arg);
}
Step 4: In main, if you need to use the GUI, then load the GUI libraries:
int main(int argc, char **argv)
{
// Before main has been entered, we had:
// pre_start -> _start -> _libc_start_main -> main
if ( argc < 2 )
{
Load_GUI_Libraries();
return wxEntry(argc, argv);
}
cout << "This is the console program :-)" << endl;
}
And finally here's the function for loading the GUI libraries at runtime:
char const *const g_strs_dyn_libs[] = {
"libpng16.so.16",
"libfontconfig.so.1",
"libglib-2.0.so.0",
"libgobject-2.0.so.0",
"libpango-1.0.so.0",
"libpangoft2-1.0.so.0",
"libgio-2.0.so.0",
"libgdk_pixbuf-2.0.so.0",
"libcairo.so.2",
"libpangocairo-1.0.so.0",
"libgdk-3.so.0",
"libgtk-3.so.0",
"libSM.so.6",
"libX11.so.6",
nullptr
};
void Load_GUI_Libraries(void)
{
using std::cerr; using std::endl;
for ( char const *const *pp = g_strs_dyn_libs; nullptr != *pp; ++pp )
{
if ( nullptr == dlopen(*pp, RTLD_LAZY | RTLD_GLOBAL) )
{
cerr << "ERROR loading library: " << *pp << endl;
std::abort();
}
}
}
So now I have an executable file that can run in two modes:
(1) GUI mode - it loads the GUI libraries in 'main'
(2) Console mode - it never loads the GUI libraries
Most importantly - the console mode can run on PC's that don't have the GUI libraries installed.
They're talking about making a movie about my endeavours to get his working, "I Am Legend". I'm not black but Will Smith just wowed them all in the audition so I promptly approved his appointment to play my role.