al_mangled_main() issue OSX while creating a standalone bundle
Malcolm Harrow

I'm running Xcode 7.2 on OSX El Capitan 10.11.1

I installed Allegro 5.1.12 using homebrew:
brew install --devel allegro

I copied a simple program from the net, added in the include and lib directories from /usr/local, added to Build Phases the libraries and frameworks. Press the run button, the program compiled and ran perfectly ! See attached screenshots.

Now I want to run the application standalone. I added the libraries to Copy Bundle Resources. I archive the application and run the standalone bundle. I get the dreaded message:

Application Specific Information: dyld: launch, loading dependent libraries Dyld Error Message: Symbol not found: __al_mangled_main Referenced from: /usr/local/opt/allegro/lib/liballegro_main.5.1.dylib Expected in: flat namespace in /usr/local/opt/allegro/lib/liballegro_main.5.1.dylib

Anyone any ideas how to fix this ? The declaration of main() looks ok, its:
int main(int argc, char **argv)

Project file and source code attached.

Regards
Malcolm

Edit:
From the above you can see that I didn't use install_name_tool on the executable. I did this and switched on the logging of library loading with:
export DYLD_PRINT_LIBRARIES=1

The output is attached. The error is now:
dyld: Symbol not found: __al_mangled_main Referenced from: /Users/malcolm/Desktop/A3 2016-01-03 11-35-50/A3.app/Contents/MacOS/./../Frameworks/liballegro_main.5.1.12.dylib Expected in: flat namespace in /Users/malcolm/Desktop/A3 2016-01-03 11-35-50/A3.app/Contents/MacOS/./../Frameworks/liballegro_main.5.1.12.dylib Trace/BPT trap: 5

i.e. its now referencing the dylib in the bundle correctly .. but still can't find al_mangled_main().

Bruce Pascoe

Did you link to allegro_main? This is required on OS X, unlike literally every other platform.

SiegeLord

I don't know of a solution just yet (it is super puzzling that it worked fine before you started creating a bundle, that shouldn't make a bit of difference!), but if you're stuck on this, you can always implementing the 'magic main' functionality yourself:

#define ALLEGRO_NO_MAGIC_MAIN
#include <allegro/allegro5.h>

int real_main(int argc, char **argv)
{
   al_init();
   // ...
}

int main(int argc, char **argv)
{
   return al_run_main(argc, argv, real_main);
}

Make sure not to link allegro_main addon in that case. That code will work cross platform.

Ideally we'd fix your issue though... the whole point of the main addon is to make the above code unnecessary.

EDIT: That said, I do wonder if this is somehow related to rpath stuff. Like I wonder if you do install_name_tool -add_rpath "@executable_path" liballegro_main.5.1.12.dylib or something along those lines, that it might fix itself? I.e. you're explaining to the main addon where it should look for your program? It doesn't really make sense to me, but maybe there's something to this.

EDIT2: Also, perhaps try something along the lines of this: http://stackoverflow.com/questions/3954137/mac-how-to-export-symbols-from-an-executable/3963639#3963639 ?

Bruce Pascoe

Incidentally, why is magic main required on OS X anyway?

Elias

On OSX all API calls must be made on the main thread. When the very first version of the OSX port was written, either there was no way in objective C yet to call something on the main thread (today there is), or the person writing the port did not know how to do that. So instead they opted to create a new thread and run the user main there while doing all of Allegro's OSX API calls directly from the main thread.

The magic main therefore is required to span the thread where the main() function is then run on.

Peter Hull

I can reproduce this exactly.

Is this something to do with stripping symbols? The loader will load up the A3 executable, then its dependent libraries including allegro_main. The main function is in allegro_main, which then has to find _al_mangled_main somewhere. It's in A3, of course, but in release mode the symbolic information has been taken out so it can't be found. This is conjecture, but it does explain why it works from within XCode because the symbols haven't been stripped.

If you use the libraries from Homebrew, it's really geared towards Unix-style executables in /usr/local/bin and so on. For 'native' app bundles I'd recommend building Allegro yourself with CMake and using the static monolith library (or is there a download available?)

Anyway, providing allegro_main as a dynamic library doesn't seem quite right to me.

Finally to add to Elias's comment, the point is that Cocoa applications want to drop into a run loop on the main thread, which never returns (see typical 'non-allegro' main below) - so your code has to run in a second thread. It's the job of the main in allegro_main to start that second thread, and then start the event loop. If you ran allegro code in the main thread there's no guarantee it would process events properly (this was especially true of Allegro 4) and you'd get the beachball of death.

// Typical main for a cocoa app
int main(int argc, char *argv[])
{
    return NSApplicationMain(argc,  (const char **) argv);
}

SiegeLord

Anyway, providing allegro_main as a dynamic library doesn't seem quite right to me.

What makes you say that? Do you think it's just poor form, or would it not work? In principle, back when I made my iOS app, I used the non-framework Allegro builds, as I found them a little easier to work with for whatever reason. I don't recall having too much trouble.

In terms of homebrew, we can probably do whatever is best, but I sort of mirrored what the existing allegro script did.

Peter Hull
SiegeLord said:

What makes you say that?

Mostly it's just the uneasy feeling that I don't quite understand the inner workings of dyld ... the thought of having main in a dynamically loaded module... . Also, what's in allegro_main should be just the equivalent of a couple of lines of code, so it makes more sense to me to have it statically linked, 'as if' you'd typed it into your main source code. So, no real reason, really.

Unless Malcolm's linker problem is indeed caused by symbol stripping - in which case there's a good technical reason to have a statically linked allegro_main.

Does that make sense?

Malcolm Harrow

Interactive build

Malcolms-iMac:MacOS malcolm$ pwd
/Users/malcolm/Library/Developer/Xcode/DerivedData/A3-bbzktsdnknrrnufqqkajootaoubj/Build/Products/Debug/A3.app/Contents/MacOS
Malcolms-iMac:MacOS malcolm$ nm A3
0000000100001d80 T __al_mangled_main
0000000100000000 T __mh_execute_header
U _al_clear_to_color
U _al_color_html
U _al_create_display
U _al_destroy_display
U _al_destroy_font
U _al_draw_text
U _al_flip_display
U _al_init_font_addon
U _al_init_ttf_addon
U _al_install_system
U _al_load_font
U _al_rest
U _atexit
U _main
U dyld_stub_binder

Release Build

Malcolms-iMac:MacOS malcolm$ cd ~/Desktop/A3\ 2016-01-03\ 11-35-50/A3.app/Contents/MacOS/
Malcolms-iMac:MacOS malcolm$ nm A3
0000000100000000 T __mh_execute_header
U _al_clear_to_color
U _al_color_html
U _al_create_display
U _al_destroy_display
U _al_destroy_font
U _al_draw_text
U _al_flip_display
U _al_init_font_addon
U _al_init_ttf_addon
U _al_install_system
U _al_load_font
U _al_rest
U _atexit
U _main
U dyld_stub_binder
Malcolms-iMac:MacOS malcolm$

Something has removed the definition of __al_mangled_main from the executable.

So next steps .. I should build allegro_main.a and static link that in the build process and see if that makes a difference ?

Regards
Malcolm

PS - I'm live in Singapore, 13h ahead NYC, so expect a delay in replies.:D. I'm so grateful for the responses .. thank you !!

Peter Hull

Malcolm,
I haven't got the Mac in front of me now but if you go to the build settings and search for 'strip' you hopefully will find an option relating to stripping (i.e. removing) symbols from the executable - you should find it will be on for release build and off for debug builds. Try turning it off (i.e. don't strip) for the release build and see how you get on.

[edit]
See picture. This works for me when run from the archive.
{"name":"610005","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/d\/7\/d708febeea11a8a92a11321576a22001.png","w":1121,"h":507,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/d\/7\/d708febeea11a8a92a11321576a22001"}610005

Bruce Pascoe

Now the question is, why does the linker think it's okay to strip out the mangled main in the first place?

Peter Hull

I suppose it strips all symbols from the executable because it 'knows' they won't be used. Or there may be another explanation I haven't thought of.

[edit] What I mean is, it's normal to strip out symbols after linking, and al_mangled_main is not special to the linker in any way.

Malcolm Harrow

A way around the issue is to add an additional strip flag to keep the __al_mangled_main symbol. To do this use "-s filename" and create a file that contains a list of line separated symbols you want to keep. See attached screenshot. The file /Users/malcolm/test contains one line "__al_mangled_main".

I wanted to see if the same thing happens on Linux. I installed a new copy of Ubuntu 14.0.3 on a new VirtualBox VM on my Mac.

I installed the Ubuntu ppas as per the instructions.

I compiled the simple program:

#SelectExpand
1#include <allegro5/allegro.h> 2#include <allegro5/allegro_color.h> 3#include <allegro5/allegro_font.h> 4#include <allegro5/allegro_ttf.h> 5 6int main(int argc, char **argv) { 7 al_init(); 8 al_init_font_addon(); 9 al_init_ttf_addon(); 10 11 ALLEGRO_DISPLAY* display = al_create_display(640, 480); 12 //ALLEGRO_FONT* font = al_load_font("/Library/Fonts/Futura.ttc", 40, 0); 13 ALLEGRO_FONT* font = al_load_ttf_font("/usr/share/fonts/truetype/freefont/FreeSans.ttf", 40, 0); 14 15 al_clear_to_color(al_color_html("#FF9900")); 16 al_draw_text(font, al_color_html("#EFEFEF"), 320, 200, ALLEGRO_ALIGN_CENTER, "LOOK AT THIS!"); 17 al_flip_display(); 18 al_rest(5.0); 19 20 al_destroy_font(font); 21 al_destroy_display(display); 22 23 return 0; 24}

Compiled with:
gcc A3Linux.c -o A3Linux -I/usr/include/allegro5 -L/usr/lib -lallegro -lallegro_font -lallegro_color -lallegro_ttf

It runs fine. Result of "nm ./A3Linux":
malcolm@UbuntuAllegroTest:~/AllegroTest$ nm ./A3Linux
U al_clear_to_color
U al_color_html
U al_create_display
U al_destroy_display
U al_destroy_font
U al_draw_text
U al_flip_display
U al_init_font_addon
U al_init_ttf_addon
U al_install_system
U al_load_ttf_font
U al_rest
0000000000400c80 T atexit
00000000006020a0 B __bss_start
00000000006020a0 b completed.6973
U __cxa_atexit@@GLIBC_2.2.5
0000000000602090 D __data_start
0000000000602090 W data_start
0000000000400a00 t deregister_tm_clones
0000000000400a70 t __do_global_dtors_aux
0000000000601dd8 t __do_global_dtors_aux_fini_array_entry
0000000000602098 D __dso_handle
0000000000601de8 d _DYNAMIC
00000000006020a0 D _edata
00000000006020a8 B _end
0000000000400c9c T _fini
0000000000400a90 t frame_dummy
0000000000601dd0 t __frame_dummy_init_array_entry
0000000000400e58 r _FRAME_END_
0000000000602000 d GLOBAL_OFFSET_TABLE
w _gmon_start_
00000000004008b0 T _init
0000000000601dd8 t __init_array_end
0000000000601dd0 t __init_array_start
0000000000400ca8 R _IO_stdin_used
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
0000000000601de0 d _JCR_END_
0000000000601de0 d _JCR_LIST_
w _Jv_RegisterClasses
0000000000400c70 T __libc_csu_fini
0000000000400c00 T __libc_csu_init
U __libc_start_main@@GLIBC_2.2.5
0000000000400abd T main
0000000000400a30 t register_tm_clones
00000000004009d0 T _start
00000000006020a0 D _TMC_END_

.. no al_mangled_main .. the program runs fine. If I strip the executable ("strip ./A3Linux") then all the symbols get stripped, the executable still works fine.

Is the al_mangled_main() construct only used on OSX ?

Regards
Malcolm

Bruce Pascoe

Yes, the 'magic main' is apparently only needed on OS X due to threading requirements.

Peter Hull

My first thought on these types of issue is usually - what does SDL do?

They do indeed have a libSDL2main.a, but, although it does something on Windows it doesn't do anything on OS X. SDL programs instead rely on SDL_PumpEvents being called (explicitly or implicity as by calling SDL_PollEvent) on a regular basis to handle system events. In other words they use their own run loop, which my (possibly faulty) memory tells me Apple recommended against.

SiegeLord

I feel like we should have just kept END_OF_MAIN() ;)

I'll play around with this at some point. In terms of symbols being stripped, we do have that __attribute__ ((visibility("default"))) for _al_mangled_main. Perhaps it's not cutting it anymore?

Bruce Pascoe

Maybe it has to be marked dllexport? (or whatever the gcc/clang equivalent is) That would prevent the linker from stripping it.

SiegeLord

I've submitted an issue so this doesn't get forgotten: https://github.com/liballeg/allegro5/issues/555 I'll look into it myself sometime this weekend.

Thread #615967. Printed from Allegro.cc