Rename main() function?

I have a cross-platform C++ API I want to run on Linux, Windows, and Mac. On Mac, it uses a main() function in Objective-C to initialize some stuff, and then calls the C++ main() function, which on Mac is renamed to main_() as follows:

#ifdef __APPLE__
    int main_(int argc,const char *argv[])
#else
    int main(int argc,const char *argv[])
#endif
{

This is pretty ugly and I'd like to do away with it. Is there any way to set the entry point to an Objective-C function that isn't named main(), or somehow make it so all our code examples don't have to have an ugly hack like this for Mac?

I tried adding the link flag -emymain or -e_mymain and renaming my Objective-C main() function to mymain() but the linker says the function is not found for the architecture x86_64.

Replies

The actual entry point to an executable is controlled by the

LC_MAIN
load command:
$ otool -l build/Debug/MainTest | grep -A 3 LC_MAIN
      cmd LC_MAIN
  cmdsize 24
  entryoff 3872
stacksize 0

but that doesn’t point to

main
directly. Rather, it points to
start
, which then calls
main
.
start
comes from the ‘C runtime’ (aka crt), which is code that the build system links into your executable automatically. You can find this within the platform SDK:
$ nm /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib/crt1.o
…
                U _main
…
0000000000000000 T start

The reason why

-e
isn’t doing what you expect is pretty clear based on its description in
ld
:

Specifies the entry point of a main executable. By default the entry name is

start
which is found in
crt1.o
which contains the glue code need to set up and call
main
.

You could certainly play linker games to resolve this issue but I don’t think that’s the best option. You’re basically transferring the ugliness from the source code to the build system, and it seems likely that that will make things harder to understand.

Does the Obj-C

main
need to ‘wrap’ the C++ ‘main’? That is, both run before and after it? Or does it just need to run first? If it just needs to run first, the simplest solution would be something like this:
int main(…) {
    PlatformMainStart();
    … do whatever your C++ `main` does …
}

and then define

PlatformMainStart
to do stuff on Apple platforms and be a no-op on other platforms.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Several years later, I have the answer to this.

In the main header file I added this definition: #ifdef __APPLE__ #define main cppmain #endif Declare your C++ main function just like normal and the compiler will internally rename it to "cppmain".

And then in main.mm I have the real main function: #undef main int main(int argc, const char* args) {     return NSApplicationMain(); } #define main cppmain And in AppDelegate.mm the C++ main function is called with arguments passed to it: ` extern int cppmain(int argc, const char* argv[]);

- (void)applicationDidFinishLaunching:(NSNotification )aNotification {     int argc = _NSGetArgc();     char argv = _NSGetArgv();     cppmain(argc, (const char*)argv);     [NSApp terminate:self]; } ` As a result all our existing examples work just fine with the normal main() function declared in C++: https://www.ultraengine.com/learn/CPP/CreateTreeView

Nice, I can't edit my answer above to fix the formatting.