Gotchas when porting UNIX software to OS X

Posted 14 Feb 2003 at 20:51 UTC by etrepum Share This

Over the past year and change I've worked on porting quite a few projects to OS X. At first, it's a pretty scary ordeal, but most of the issues you'll run into are easily solved if you know how.
To save yourself the trouble of figuring this out yourself, read on...

The simple fixes

Where do I start?
Simple, RTFM :) The UNIX Porting Guide is a great starting point. Unfortunately, I spent a lot of time figuring things out before that documentation was available.

libtool problems (aka ./configure doesn't work!)
If you're porting an app that uses an older version of libtool, you'll notice some fatal errors during ./configure. Most notably, it can't autodetect the darwin platform. In almost every case, you can just do:
cp /usr/share/libtool/* .
This should fix your issues with libtool right off, and save you the trouble of trying to hack at what came with the project, write custom makefiles, etc.

What to do before attempting to compile ANY Perl extensions
more information: man 1 dyld
The first thing you should do is change line 596 of /System/Library/Perl/darwin/Config.pm to:
lddlflags='-bundle -bundle_loader /usr/bin/perl -lperl -L/System/Library/Perl/darwin/CORE'
This causes perl extensions to be compiled with two-level namespaces. If you use flat namespaces, you will have problems if two different dynamically modules define the same symbol (the second one won't import at all). It has the added benefit that it lets you know in advance if you're going to run into undefined symbol problems, where undefined symbols are suppressed in the flat namespace case.

What to do before attempting to compile ANY Python extensions
more information: man 1 dyld
Similar to Perl, you'll want to change linker flags as well. Change lines 99-100 of /usr/lib/python2.2/config/Makefile to the following:
LDSHARED= $(CC) $(LDFLAGS) -bundle -bundle_loader /usr/bin/python
BLDSHARED= $(CC) $(LDFLAGS) -bundle -bundle_loader /usr/bin/python

Why won't my C application compile? It doesn't do anything platform specific!
You probably just have to add:
#include <unistd.h>
That's where most of your "standard" definitions are.

How do I use a framework?
more information: The Framework as a Library Package I'm going to use OpenGL as an example. One thing you have to know about the OpenGL framework is that they've renamed the headers. It's not gl.h, it's OpenGL.h. You'll want to change all the includes for OpenGL, GLE, etc to be:
#include <OpenGL/HeaderName.h>
The linker flag you need to use is simply -framework OpenGL and no compiler flags are necessary! However, in some cases, you may wish to reference headers as <HeaderName.h> in which case you'll need to use the compiler flag:
-I/System/Library/Frameworks/OpenGL.framework/Versions/Current/Headers
Note that GLUT is a separate framework, and will chdir to the Resources folder of your application bundle on glutInit! If you don't want this to happen, the easiest way is to getcwd(...);glutInit(...);chdir(...);. There is a command line argument flag that you may pass to it, but I think getcwd/chdir is easier than stuffing an extra flag into the argv.

It gets harder

How do I port an application that needs to load plug-ins on the fly?
more information: man 1 dyld, man 3 dyld, Bundles, libcompat
There's a couple ways you can go. The most straightforward way is to use libcompat, it's a wrapper that emulates libdl. I would consider this just a temporary solution, most GUI ports use the Bundles mechanism, and most console ports use dyld directly. This works best for GUI applications. For console applications, you may wish to use dyld directly. The source for Python (I recommend CVS HEAD) is a good reference for using dyld in a cross-platform application.

Is it possible to run a GUI application that doesn't reside in a bundle?
Yes and no, there's an undocumented function in the CoreGraphics framework:
void CPSEnableForegroundOperation(ProcessSerialNumber *psn);
It's not something Apple wants you to use. Although, Apple uses it in GLUT (since 10.2) and the JAR launcher (last I checked, which was 10.1). All I'm saying is that it is possible, yet in 99% of the cases you REALLY ought to distribute your application as a bundle. There has been rumor that Apple considers the inability for console applications to register with WindowServer if they're outside of a bundle, but it's been over a year since this hack has been floating around. It still works, and it's still the only way. As far as I know, I was the first person outside of Apple to find it :) The only "ethical" way to use it, in my opinion, is for GUI extensions to scripting languages (PyObjC, pygame, SDL Perl, etc.). Obviously, if you are distributing an application that *uses* one of these, it should be an application bundle.

Objective C is your friend.
more information: Cocoa Developer Documentation
Learn Objective C. It's a lot easier to write Objective C on the Foundation framework than it is to write C/C++ on the CoreFoundation framework. It's actually also really quite easy and enjoyable to write Cocoa applications, Interface Builder is a great tool. If you're a Python programmer, pick up PyObjC, it rocks. Perl has two ObjC bridges (PerlObjCBridge, CamelBones), but neither are nearly as good as PyObjC. If you're porting C++ code, you can use Objective C++ (a nasty beast) to wrap those frameworks.

How do I make a startup script?
more information: HOWTO

Notes

I only support OS X 10.2.x, most of these worked in 10.1, and some of them may break in a future versions. I do not use Fink, and I've seen fink solve some problems, and cause a lot of others. You're on your own if you're using fink, it's pretty easy to turn off though. It's also a really bad idea to replace the stock perl or python at this point, all of my suggestions are tailored specifically to the versions of Perl and Python that Apple distrites with OS X 10.2. Also, you should RTFM on your own as much as possible, Apple's documentation isn't bad. I'm only trying to cover the issues where the "M" is hard to find, is incomplete, or doesn't exist.


what about assembly, posted 14 Feb 2003 at 22:03 UTC by walken » (Master)

I'm serious here. I know assembly is not particularly portable, but - I made some PPC G4 optimizations for libmepg2, and I could not get these to compile on macOS X just because even though they do use gcc, they use a non-GNU assembler and my inline asm just won't work there.

As a result, mpeg2dec does compile on macOS X, but without the G4 optimizations.

Anyone knows what I could do about it ? Also is it hard at all for someone to add a gnu assembler to their macOS X system ? if it's easy enough, I might just recommand that and be done with it.

RE: what about assembly, posted 14 Feb 2003 at 23:51 UTC by etrepum » (Journeyer)

Well, I haven't tried it personally. All of my optimization interests these days are purely Altivec, and you don't need to use inline assembly to do any of that... but I've never heard of this "non-GNU assembler" situation, you are using GCC right?? I just peeked at some of the Darwin codebase and I see some pretty normal looking GCC asm statements:

#if defined(__ppc__)
    __asm__ volatile("lwz %0,0x0008(%1)" : "=r" (ret) : "b" (addr));
#elif defined(__i386__)
    __asm__ volatile("movl 0x4(%1),%0" : "=r" (ret) : "r" (addr));
#elif defined(hppa)
    __asm__ volatile("ldw 0x4(%1),%0" : "=r" (ret) : "r" (addr));
#elif defined(sparc)
    __asm__ volatile("ta 0x3");
    __asm__ volatile("ld [%1 + 60],%0" : "=r" (ret) : "r" (addr));
#else
#error Do not know how to define _CFBundleReturnAddressFromFrameAddress on this architecture
#endif
That was a snippet from CFBundle.c from CoreFoundation.. Maybe I'll checkout mpeg2dec and take a look at it to see what you're referring to?

RE: what about assembly, posted 15 Feb 2003 at 00:49 UTC by walken » (Master)

The issue I seem to have is in an IDCT routine, where I need to load a few multiplication constants from memory.

So I do stuff like

static const int16_t constants[5][8] ATTR_ALIGN(16) = { ... snipped ... };

asm (" lis %r10, constants@ha \n" " la %r10, constants@l(%r10) \n" " lvx %v8, 0, %r10 \n" );

I think the @ha and @l(%r) syntax is different on the assembler provided with macOS X, which seems to be what's causing me issues.

possibly I could solve that with a macro, though that will be ugly. I'm not sure what the proper syntax would be though.

Re : Assembly, posted 15 Feb 2003 at 12:44 UTC by softkid » (Journeyer)

Take a look at the distributed.net client which heavelly uses Assembly.

Obj-C++ rocks, posted 24 Feb 2003 at 09:24 UTC by hub » (Master)

you can also write everything in C++ and call AppKit and Foundation (a.k.a. Cocoa) using Obj-C++. This is what I do for Abiword on MacOS X.

Re: Obj-C++ rocks, posted 24 Feb 2003 at 17:37 UTC by etrepum » (Journeyer)

I had a sentence about Obj C++ in there. I used Obj C++ the other way in my (second) port of Celestia.. I wrote a suite of Obj C++ classes to wrap C++ classes (with the selectors that require C++ in a private namespace).. I did this for a few reasons, I think that it makes it a lot more powerful (at the expense of a lot of boring wrapper code): I can expose it as a framework to any Obj C application, I can just use it from PyObjC (or some other ObjC-friendly scripting language) without writing any more compiled code, compiling Obj C is a lot faster than compiling Obj C++ (I made all the UI code is pure Obj C), I find it quicker to write Obj C code than C++ code for UI stuff, etc. I'm sure I find more reasons to justify all those wrappers :)

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!

X
Share this page