![]() |
|
Allegro 5, static font library problem |
Karadoc ~~
Member #2,749
September 2002
![]() |
I'm having trouble getting A5 to work when statically linked. Maybe I'm doing something wrong... but I don't know what else to try. The following program crashes: 1#include <allegro5/allegro5.h>
2#include <allegro5/allegro_font.h>
3#include <allegro5/allegro_image.h>
4#include <allegro5/allegro_primitives.h>
5#include <allegro5/allegro_color.h>
6#include <allegro5/allegro_native_dialog.h>
7
8#include <stdio.h>
9
10int main(int argc, char *argv[])
11{
12 if (!al_init())
13 {
14 printf("Could not init Allegro.\n");
15 return 1;
16 }
17
18 if (
19 !al_init_primitives_addon() ||
20 !al_install_keyboard() ||
21 !al_install_mouse() ||
22 !al_init_image_addon())
23 {
24 printf("failed to initialize Allegro components.\n");
25 return 1;
26 }
27
28 al_init_font_addon(); // void funciton.
29
30 printf("about to load font...\n");
31 ALLEGRO_FONT *p_font = al_load_font("fixed_font.tga", 0, 0);
32 printf("finished loading font.\n");
33
34 if (p_font == 0)
35 {
36 printf("fixed_font.tga not found\n");
37 return 1;
38 }
39
40 printf("success\n");
41 return 0;
42}
The only output is "about to load font...". Here is the makefile (which builds with no warnings or errors): CC=gcc CFLAGS=-Wall -DMINGW32 -DNDEBUG -O2 -DALLEGRO_STATICLINK LDFLAGS=-static-libgcc -static-libstdc++ LIBS=-lallegro -lallegro_primitives -lallegro_font -lallegro_image -lallegro_color LIBS+=-lstdc++ -lgdiplus -luuid -lkernel32 -lwinmm -lpsapi -lopengl32 -lglu32 -luser32 -lcomdlg32 -lgdi32 -lshell32 -lole32 -ladvapi32 -lws2_32 LIBS:=$(LIBS:-lallegro%=-lallegro%-static) test.exe: test.c $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LIBS) It produces a command like this: gcc -Wall -DMINGW32 -DNDEBUG -O2 -DALLEGRO_STATICLINK -static-libgcc -static-libstdc++ test.c -o test.exe -lallegro-static -lallegro_primitives-static -lallegro_font-static -lallegro_image-static -lallegro_color-static -lstdc++ -lgdiplus -luuid -lkernel32 -lwinmm -lpsapi -lopengl32 -lglu32 -luser32 -lcomdlg32 -lgdi32 -lshell32 -lole32 -ladvapi32 -lws2_32
Which includes all of the libraries listed here except -lgcc_eh, which gcc says it cannot find. To build allegro, downloaded v5.0.3 [1], I unzipped it to C:\tools\allegro5, and from that directory I typed mkdir build cd build cmake-gui .. First I selected mingw-makefiles, and generated the makefiles with the default settings. make make install
It seemed to work with no problems. So I think I've installed allegro properly with shared and static libraries, and I think I'm linking to all the right stuff, and I'm compiling with ALLEGRO_STATICLINK defined as you can see - and it compiles without warnings or errors - but it crashes. (The non-static version works without problems.) Have I missed something, or is this an allegro bug? [edit] ----------- |
Elias
Member #358
May 2000
|
Can you try with the debug version (set CMAKE_BUILD_TYPE to Debug)? It should create an allegro.log which may help, but more importantly you should be able to get a gdb backtrace telling why it crashes. My suspicion is it has to do with gcc 4.6. -- |
Karadoc ~~
Member #2,749
September 2002
![]() |
allegro.log: system W C:\tools\allegro5\src\win\wsystem.c:550 load_library_at_path [ 0.00024] Failed to load C:\Programming\scratch\bug\d3d9.dll (error: 126) system I C:\tools\allegro5\src\win\wsystem.c:543 load_library_at_path [ 0.02992] Loaded C:\Windows\system32\d3d9.dll d3d I C:\tools\allegro5\src\win\d3d_disp.cpp:879 _al_d3d_init_display [ 0.13966] Render-to-texture: 1 system I C:\tools\allegro5\src\system.c:268 al_install_system [ 0.13970] Allegro version: 5.0.3 backtrace: 0 _al_register_destructor dtor.c 161 0x407782 1 al_create_bitmap bitmap.c 145 0x423591 2 _al_load_tga_f tga.c 355 0x4c85d6 3 _al_load_tga tga.c 553 0x4c8ec5 4 al_load_bitmap bitmap_io.c 219 0x40ba5a 5 _al_load_bitmap_font fontbmp.c 149 0x4c5595 6 al_load_font font.c 350 0x4c472d 7 main test.c 31 0x4013f3 more detailed backtrace: Thread 1 (Thread 4032.0xaa8): #0 0x00407782 in _al_register_destructor (dtors=0x8e31f8, object=0x8e5e98, func=0x423596 <al_destroy_bitmap>) at C:\tools\allegro5\src\dtor.c:161 dtor_owner_count = 0xd8 __func__ = "_al_register_destructor" #1 0x00423591 in al_create_bitmap (w=513, h=97) at C:\tools\allegro5\src\bitmap.c:145 bitmap = 0x8e5e98 #2 0x004c85d6 in _al_load_tga_f (f=0x8e5e30) at C:\tools\allegro5\addons\image\tga.c:355 image_id = <data>} id_length = 0 '\000' palette_type = 0 '\000' image_type = 2 '\002' palette_entry_size = 0 '\000' bpp = 32 ' ' descriptor_bits = 8 '\b' first_color = 0 palette_colors = 0 left = 0 top = 0 image_width = 513 image_height = 97 left_to_right = true top_to_bottom = false c = 5130702 i = 5297452 y = 5124283 compressed = 8 bmp = 0x50d52c lr = 0x4e30bb buf = 0x40e8fe "UôB\004EôÇ@\030" premul = true __func__ = "_al_load_tga_f" #3 0x004c8ec5 in _al_load_tga (filename=0x4e30bb "fixed_font.tga") at C:\tools\allegro5\addons\image\tga.c:553 f = 0x8e5e30 bmp = 0x8e5810 #4 0x0040ba5a in al_load_bitmap (filename=0x4e30bb "fixed_font.tga") at C:\tools\allegro5\src\bitmap_io.c:219 ext = 0x4e30c5 ".tga" h = 0x8e5810 ret = 0x0 __func__ = "al_load_bitmap" #5 0x004c5595 in _al_load_bitmap_font (fname=0x4e30bb "fixed_font.tga", size=0, flags=0) at C:\tools\allegro5\addons\font\fontbmp.c:149 import_bmp = 0x4 f = 0x8e5ba0 backup = {_tls = <data>} range = {12582912, 127} #6 0x004c472d in al_load_font (filename=0x4e30bb "fixed_font.tga", size=0, flags=0) at C:\tools\allegro5\addons\font\font.c:350 i = 1992920277 ext = 0x4e30c5 ".tga" handler = 0x8e5ba0 #7 0x004013f3 in main (argc=1, argv=0x8e2e90) at test.c:31 p_font = 0x7efde000
apparently dtor_owner_count = _al_tls_get_dtor_owner_count(); returned NULL, then *dtor_owner_count caused a seg fault. ----------- |
Elias
Member #358
May 2000
|
Hmm 160 dtor_owner_count = _al_tls_get_dtor_owner_count(); 161 if (*dtor_owner_count > 0) 162 return; and 871 int *_al_tls_get_dtor_owner_count(void) 872 { 873 thread_local_state *tls; 875 tls = tls_get(); 876 return &tls->dtor_owner_count; 877 } So &tls->dtor_owner_count can't possibly be 0 or 0xd8 - I assume the crash means tls is NULL already and gdb just is confused because the function was inlined. Which means, it's probably hitting an old bug with the Tls* functions. For some reason they are only called in DllMain but not when static linking but nobody ever fixed it so far. I don't know that Tls* API but assuming it's anything like pthread_create_key there should be no reason to need DllMain and it should be very easy to fix. I could be wrong though. [edit:] Here's an example how to use the Tls functions: http://msdn.microsoft.com/en-us/library/ms686991%28v=vs.85%29.aspx It doesn't mention DllMain. So it looks that whoever implemented this way back only implemented it for the DLL version but not for the static version (which is the much simpler case). And it was forgotten ever since -- |
Karadoc ~~
Member #2,749
September 2002
![]() |
Alright. I'm looking into it now. The thing is, I don't know anything about DllMain (other than what I read a few seconds ago), and I don't know anything about thread local storage or what it's purpose in allegro is. From what I understand, allegro's DllMain function is responsible for allocating thread local storage for each thread allegro uses on windows. It is called every time a dll is loaded or unloaded. (it frees the allocated memory on the unload event.) So I suppose the problem is that when Allegro is statically linked, no dlls are loaded and so no thread local storage is allocated for new threads. My job then is to find where the threads are actually being created, and put the storage allocation there instead of in DllMain (or as well as in DllMain, depending on how it works.) I guess you're suggesting that I check out how the pthreads version works for comparison. It is strange that no one else has reported this problem. I've seen a bunch of threads where people discuss the steps required to get static linking working on Windows, so presumably at least some of these people did get it to work in the end... [edit] static thread_local_state *tls_get(void) { thread_local_state *t = TlsGetValue(tls_index); return t; } which is inside the following preprocessor condition #if (defined ALLEGRO_MINGW32 && ( \ __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2) || \ (__GNUC__ == 4 && __GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ < 1))) || \ defined ALLEGRO_CFG_DLL_TLS I ran the following test: printf("gcc v%d.%d.%d\n", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); It prints 4.6.0. So my guess now is that there is something wrong somewhere in the allegro build system. ... It looks like this is the culprit: option(WANT_DLL_TLS "Force use of DllMain for TLS (Windows)" on) I'm recompiling now with WANT_DLL_TLS turned off. ... lo and behold, the test program ran without crashing. Now for the final test... I'll recompile the static release version of allegro, and the static release version of my actual game - then try to run it on a computer that doesn't have the allegro dlls. ... Yes. It all works. Static link, dynamic link, everything. So, based on that, I suggest the following patch: --- CMakeLists-old.txt 2011-05-27 13:40:49 +1000 +++ CMakeLists.txt 2011-05-27 13:40:03 +1000 @@ -152,7 +152,7 @@ endif(NOT IPHONE) option(NO_FPU "No floating point unit" off) -option(WANT_DLL_TLS "Force use of DllMain for TLS (Windows)" on) +option(WANT_DLL_TLS "Force use of DllMain for TLS (Windows)" off) option(WANT_DEMO "Build demo programs" on) option(WANT_EXAMPLES "Build example programs" on) option(WANT_POPUP_EXAMPLES "Use popups instead of printf for fatal errors" on)
By the way, does anyone want my collection of Allegro 5.0.3 binaries for MinGW 4.6.0? ----------- |
Elias
Member #358
May 2000
|
Oh, indeed, I had read the code wrong. So the situation appears to be like this:
Does that sound right? But for some reason there was this commit setting WANT_DLL_TLS to true: http://allefant.com/gitweb/?p=allegro.git;a=commitdiff;h=7ee13023bda58f83b66d54327ae8e157b6dc00fc Which likely has broken static mingw versions since. The official binaries aren't built with cmake so they don't have WANT_DLL_TLS set so they always worked. I'll apply your patch if nobody else does first... -- |
Karadoc ~~
Member #2,749
September 2002
![]() |
Yes. That sounds right. I don't know much about these different thread systems, but I searched the code for "ALLEGRO_CFG_DLL_TLS" and the only place it comes up is in the #if statement I quoted earlier. As far as I know, the DllMain stuff is only required for gcc v4.2.0 and earlier versions - and the #if already checks for that regardless of ALLEGRO_CFG_DLL_TLS. Anyway. Thanks for your help. ----------- |
Elias
Member #358
May 2000
|
I asked Trent and he says it's better to use the TLS API, also with MSVC. So I'll try to change that #ifdef to never use the TLS API when static linking is on instead. -- |
Karadoc ~~
Member #2,749
September 2002
![]() |
I've posted a patch for this on sourceforge. I don't think I've ever officially sent my patches like that before, so let me know if I've done it wrong. ----------- |
|