Programmatically retrieving the absolute path of an OS X command-line app

c, macos, unix

Solution

The function `_NSGetExecutablePath` will return a full path to the executable (GUI or not). The path may contain symbolic links, "`..`", etc. but the `realpath` function can be used to clean those up if needed. See `man` `3` `dyld` for more information.

char path[1024];
uint32_t size = sizeof(path);
if (_NSGetExecutablePath(path, &size) == 0)
    printf("executable path is %s\n", path);
else
    printf("buffer too small; need size %u\n", size);

The secret to this function is that the Darwin kernel puts the executable path on the process stack immediately after the `envp` array when it creates the process. The dynamic link editor `dyld` grabs this on initialization and keeps a pointer to it. This function uses that pointer.

Problem

On Linux, an application can easily get its absolute path by querying `/proc/self/exe`. On FreeBSD, it's more involved, since you have to build up a sysctl call: ``` int mib[4]; mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PATHNAME; mib[3] = -1; char buf[1024]; size_t cb = sizeof(buf); sysctl(mib, 4, buf, &cb, NULL, 0); ``` but it's still completely doable. Yet I cannot find a way to determine this on OS X for a command-line application. If you're running from within an app bundle, you can determine it by running `[[NSBundle mainBundle] bundlePath]`, but because command-line applications are not in bundles, this doesn't help. (Note: consulting `argv[0]` is not a reasonable answer, since, if launched from a symlink, `argv[0]` will be that symlink--not the ultimate path to the executable called. `argv[0]` can also lie if a dumb application uses an `exec()` call and forget to initialize argv properly, which I have seen in the wild.)

Original source