allegro5 icon indicating copy to clipboard operation
allegro5 copied to clipboard

al_mangled_main linking issues with bundles

Open SiegeLord opened this issue 8 years ago • 27 comments

See https://www.allegro.cc/forums/thread/615967

SiegeLord avatar Jan 09 '16 20:01 SiegeLord

My thoughts (taken from the thread linked above...)

Configuring CMake on OS X gives this warning:

CMake Warning (dev):
  Policy CMP0042 is not set: MACOSX_RPATH is enabled by default.  Run "cmake
  --help-policy CMP0042" for policy details.  Use the cmake_policy command to
  set the policy and suppress this warning.

  MACOSX_RPATH is not specified for the following targets:

   allegro
   allegro_acodec
   allegro_audio
   allegro_color
   allegro_dialog
   allegro_font
   allegro_image
   allegro_main
   allegro_memfile
   allegro_physfs
   allegro_primitives
   allegro_ttf
   allegro_video

Using _@_rpath with these libraries should make it possible to use them in bundles just by copying them to the Frameworks subdirectory,

except allegro_main - if this can be made into a static library it will be able to link to _al_mangled_main in the user's code even after symbol stripping.

ghost avatar Jan 10 '16 10:01 ghost

Further to this - the rpath stuff is already covered in #532. CMake never works the way I expect it to.

ghost avatar Jan 10 '16 11:01 ghost

One thing I'm seeing as I try this is homebrew is naming libraries like liballegro.5.1.dylib as symlinks to liballegro5.1.12.dylib and so on... once these go into a Framework, the libraries that depend on liballegro.5.1.dylib (example, don't remember if this is one of the actual dependencies) are going to fail because in the .app/Contents/Frameworks there is only liballegro.5.1.12.dylib...

I'm sure it's possible to get this to work using install_name_tool. However, after 30 minutes of changing names I still have a lot left to change. I suggest looking at otool -l and otool -L output of libs and executables. With the example given on allegro.cc, there's a ton of missing links.

On OS X, you have to build libraries a certain way if you want to use them in bundles. Then they won't work right standalone. CMake has things like BUILD_WITH_INSTALL_RPATH and INSTALL_RPATH that help with this. I set the former to on and the latter to "@executable_path/" (you could add ../Frameworks) when I build dynamic libraries. Then, when they're linked to everything is already set to go. I don't know how you'd do it with homebrew though.

ghost avatar Jan 26 '16 12:01 ghost

Would things be better if we generated frameworks instead of dylibs?

SiegeLord avatar Jan 27 '16 04:01 SiegeLord

As an outsider looking in, I get the impression OS X is quite a bit of a moving target. This is jarring for me being a Windows developer, where I could, if I were so inclined, install MSVC 6 on Windows 10 and use it to build programs that would run happily on that OS. Say what you will about Windows, but the API and ABI stability is very much appreciated.

I don't yet have a Mac of my own, but I do intend to acquire one eventually--and I'm not looking forward to officially supporting OS X for minisphere at all. :stuck_out_tongue_closed_eyes:

fatcerberus avatar Jan 27 '16 05:01 fatcerberus

I think I can fix this but I won't have time until the weekend, is that OK? I need to get up to speed with CMake more than anything.

ghost avatar Jan 27 '16 06:01 ghost

It's not urgent, it's just something that probably should take a bit of a priority over other things. Thanks for taking a look at it!

SiegeLord avatar Jan 27 '16 16:01 SiegeLord

Well, I did look at it over the weekend, I just haven't got around to replying here until now.

On the original problem, I think the best way is to always force the alleg_main library to be static. That way the real main function in alleg_main knows the address of the mangled main in the executable at link time, before the symbols are stripped. Otherwise it's got to resolve it at runtime which it can't if the executable has been stripped.

The alternative was as suggested by Malcolm - pass flags into the strip program to ensure it leaves the mangled main entry alone. This seems more complicated and error-prone to me.

To make alleg_main always static is simple enough in CMake. Unfortunately there's a bit more messing about if the user wants the monolith option, which I haven't sorted out yet.

However alleg_main is a funny sort of 'add-on', isn't it? It's actually empty for all platforms except OS X (even iOS, not sure how that can be?) So someone developing on Linux would probably forget to include it and then find it wouldn't build on the Mac. Ideally it would just hitch a ride with the allegro core library, so pkg-config --libs would yield -lalleg_main -lalleg.

Any thoughts on this:

  • Quick fix (once I've sorted out monolith), or
  • Roll it into the core?

ghost avatar Feb 04 '16 20:02 ghost

allegro_main really isn't an add-on in the normal sense of, say, allegro_audio - it's just a shim to make things work properly on all platforms without code changes.

Personally I would be okay with allegro_main always being a separate library and static, even when compiling a dynamic monolith. It doesn't really make much sense being in the core, I don't think.

fatcerberus avatar Feb 04 '16 20:02 fatcerberus

On @trentg 's comments,

It seems to me that homebrew is designed to support the Unix way of organising things, separating /bin and /lib directories for example. In addition there's the 'bundle' approach which I'd say is more Mac-like. It's certainly possible to use homebrew-provided libraries to make bundles but it's sort-of swimming against the tide a bit. If I were making a Mac app I'd go for static linking first, otherwise (embeddable) frameworks, rather than trying to work with homebrew's dylibs. I'd love to hear your input Trent you've had far more experience than me on these things. What we really need is the canonical example on how best to package an Allegro game for Mac (maybe Cosmic Protector is already it, I'm not sure)

@fatcerberus Apple do seem to deprecate things very aggressively in the SDK compared to MS - but once built, the backward compatibility is good. Anyway Allegro should shoulder all that pain for you :grin:

ghost avatar Feb 04 '16 20:02 ghost

It doesn't really make much sense being in the core, I don't think.

Yes sorry I didn't mean make it part of the core, that would be no better than the current situation. What I meant was just make pkg-config always pull in alleg_main when asked for the allegro libs. This applies to OSX, on other platforms it could stay as it is, or it could pull in the current 'do-nothing' alleg_main.

ghost avatar Feb 04 '16 20:02 ghost

When I mentioned homebrew, it was only because the a.cc thread was trying to use it to make bundles. That was essentially the original problem, which might not be fixed completely by making a static allegro_main. I'm Ok with that though... I don't think if you're putting any effort into your game you're going to use homebrew libraries in a bundle if only for the fact that it includes a ton of stuff you probably wouldn't even be using (third party libraries and addons.) Personally I've always used static linking.

I guess at worst this fix would ALLOW using homebrew, you just still have to mess with install_name_tool and stuff.

ghost avatar Feb 04 '16 21:02 ghost

Is static linking considered the norm on OS X? On Linux it's practically blasphemous.

fatcerberus avatar Feb 04 '16 21:02 fatcerberus

It is normal on OS X yes, very few libraries install globally. At the least embedded frameworks are also common. On Linux, things might change since Ubuntu is planning on using a type of static linking for all installed applications soon to make maintenance easier (or just create a whole different set of problems...)

ghost avatar Feb 04 '16 22:02 ghost

So it seems like the solution would be to also build a static version of Allegro for homebrew? I could ask homebrew folks if they would be okay with it (after all, they do have to pay for the servers that build the binaries).

I don't understand the point about pkg-config. Does that even work on OSX?

SiegeLord avatar Feb 06 '16 19:02 SiegeLord

I think the idea was to just build allegro_main statically - the rest can remain dynamic since they don't cause issues.

fatcerberus avatar Feb 06 '16 19:02 fatcerberus

From my understanding, if you want to create a bundle, then it's easiest to link allegro_main statically. For non-bundle programs, dynamically linked allegro_main seems to work fine.

That said, Allegro builds the demos as bundles and they seem to work fine with a dynamic allegro_main as well, so I still don't quite get what is different between what is done for demos and what is done when making a bundle manually.

SiegeLord avatar Feb 06 '16 22:02 SiegeLord

The original problem was that Xcode, when deploying, strips the symbols from the executable so the mangled main can't be found. In development mode it's fine, when making a 'UNIX-style' application it's fine. On Sat, 6 Feb 2016 at 22:28, SiegeLord [email protected] wrote:

From my understanding, if you want to create a bundle, then it's easiest to link allegro_main statically. For non-bundle programs, dynamically linked allegro_main seems to work fine.

That said, Allegro builds the demos as bundles and they seem to work fine with a dynamic allegro_main as well, so I still don't quite get what is different between what is done for demos and what is done when making a binary manually.

— Reply to this email directly or view it on GitHub https://github.com/liballeg/allegro5/issues/555#issuecomment-180874773.

ghost avatar Feb 07 '16 08:02 ghost

I looked a bit closer at what Allegro does for its demo bundles. Indeed, it creates them sort of fine with dynamically linked allegro_main, but it uses absolute paths, so it's not quite ready for distribution. That said, I tried using https://github.com/auriamg/macdylibbundler which tries to automatically copy over things into the bundle and fix up the paths, and that seemed to work just fine. I think the difference is that CMake constructs the bundles manually and maybe it doesn't do the symbol stripping.

So overall, it seems like to me that it's simplest and best to just also provide the entirety of Allegro statically linked, and depending on what's easier, let the user choose whether or not to link allegro_main statically.

SiegeLord avatar Feb 07 '16 20:02 SiegeLord

Hi it's Malcolm. Sorry I didn't realize the conversation was continuing here. Providing a set of static libraries would be great! Fixing the rpath on the dynamic libraries via cmake and also having a static main library is also great!

With regards to why the examples work ok, I can't remember .. But my guess is if you don't specify to use xcodebuild as the tool chain in cmake then it defaults to using gcc? and a different linker ?

Regards Malcolm

harrowm avatar Feb 14 '16 06:02 harrowm

All, Here's the link to my latest effort .. which include my own instructions on how to build Allegro on OSX. Note that I stripped out all the dependencies that I don't use .. e.g. FLAC .. but its still quite complex. Thomas commented on my post that we should look at Cocoapods to automate the dependencies. Has anyone tried this before? I must say that Nuget on Windows is so simple in comparison !

Malcolm

http://www.stardot.org.uk/forums/viewtopic.php?f=44&t=9065&start=90

harrowm avatar May 06 '16 13:05 harrowm

how is this still not fixed?

tonmanayo avatar Jun 19 '17 13:06 tonmanayo

It was considered that the workaround (macdylibbundler) was good enough for now, but in fact recently I've seen people have trouble with it. The way forward is to build Allegro statically on homebrew, which requires fixing https://github.com/liballeg/allegro5/issues/773 at the very least.

SiegeLord avatar Jun 19 '17 15:06 SiegeLord

@SiegeLord so i'm busy creating a dynamic library on osx which statically links to allegro5 but the problem is when you call the new dynamic lib and try and link it, it cries because there is no main. dlopen(libs/lib1-opengl/libOpenGL.so, 8): Symbol not found: __al_mangled_main Referenced from: /nfs/zfs-student-6/users/tmack/.brew/opt/allegro/lib/liballegro_main.5.2.dylib Expected in: flat namespace in /nfs/zfs-student-6/users/tmack/.brew/opt/allegro/lib/liballegro_main.5.2.dylib

and if I take out the linking of the allegro main function no window shows but the program logic works, because it detects the snake crashing into a wall?

all my code and suff is here, under lib/lib1-opengl https://github.com/tonmanayo/nibbler

tonmanayo avatar Jun 19 '17 15:06 tonmanayo

I know "+1" message are bad etiquette, but it's 2020 already.. :-(

bart9h avatar Aug 18 '20 16:08 bart9h

Err... sadly I never got around to testing tonmanayo's code so my answer remains the same, use macdylibbundler. Since then, we wrote a tutorial about how to do that, and as far as I know, that's been working okay: https://github.com/liballeg/allegro_wiki/wiki/Creating-macOS-bundles

I note that #773 has been fixed, so perhaps the static linking works okay too, but then you need to compile Allegro yourself rather than using homebrew.

And either way, no matter what you do you never have to use allegro-main, you can use al_run_main directly.

Please feel free to give me specifics though, I can try to figure out what's the best solution in your case.

SiegeLord avatar Aug 19 '20 00:08 SiegeLord

For anyone facing this, the getting started mentions the signature and format of the main function needed when linking allegro

https://liballeg.org/a5docs/5.2.4/getting_started.html

For the purposes of cross-platform compatibility Allegro puts some requirements on your main function. First, you must include the core header (allegro5/allegro.h) in the same file as your main function. Second, if your main function is inside a C++ file, then it must have this signature: int main(int argc, char **argv). Third, if you're using C/C++ then you need to link with the allegro_main addon when building your program.

mdprasadeng avatar Jan 13 '22 17:01 mdprasadeng