Finding out executable location from a c program

  • Hi!

      I would need to find out the directory where the current executable
    resides to find some stuff whose location I know relative to the
    executable location.

      On linux /proc/{pid}/exe is a symbolic link to the executable, on
    solaris the corresponding symlink is /proc/{pid}/path/a.out, on windows I
    can use GetModuleFileNameA, but I haven't been able to find any way to do
    this on os-x.

      Any ideas?

          -Antti-
  • > I would need to find out the directory where the current executable
    > resides to find some stuff whose location I know relative to the
    > executable location.

    The first argument ( argv[0] ) is the path to your executable.

    --
    I.S.
  • On Mon, 19 Nov 2007 18:12:23 +0200, I. Savant
    <idiotsavant2005...> wrote:

    >> I would need to find out the directory where the current executable
    >> resides to find some stuff whose location I know relative to the
    >> executable location.
    >
    > The first argument ( argv[0] ) is the path to your executable.

      On other systems (at least on windows and AFAIK on linux / solaris as
    well) argv[0] is the string how the program was invoked. This is
    different; if the program was invoked with full or relative path, then I
    can get the info I want. However, if the program is found on PATH argv[0]
    is pretty useless. Ok, I could replicate the functionality of "which"
    command to find out where the program was, but this seems clumsy.
      Or is this different on os-x so that argv[0] always contains the full
    path to the executable?

            -Antti-
  • On 19 Nov 2007, at 16:12, I. Savant wrote:

    >> I would need to find out the directory where the current executable
    >> resides to find some stuff whose location I know relative to the
    >> executable location.
    >
    > The first argument ( argv[0] ) is the path to your executable.

    Not true. Argv[0] is the first argument given on the command line when
    your code was invoked. This might be a full path, or it might be just
    the executable name.

    #include <stdio.h>

    int main(int argc, char** argv) {
      printf("Arg 0 is %s\n", argv[0]);
      return 0;
    }

    Compiled and then placed into my path.

    Dr-Stupid:~ pauls$ /Users/pauls/bin/a.out
    Arg 0 is /Users/pauls/bin/a.out
    Dr-Stupid:~ pauls$ bin/a.out
    Arg 0 is bin/a.out
    Dr-Stupid:~ pauls$ a.out
    Arg 0 is a.out

    There's no guaranteed consistency there, unless you know how it'll be
    invoked.

    I can't think of a way of doing it. It's normal practise to put
    support files in a location like /usr/local/lib or similar rather than
    with the executable on Unix. On a Mac the solution is normally to
    package it inside the app bundle and use the API to access that.
  • > Not true. Argv[0] is the first argument given on the command line when
    > your code was invoked. This might be a full path, or it might be just
    > the executable name.

      Ack! An excellent point!

    --
    I.S.
  • On 19 Nov 2007, at 5:37 PM, Paul Sargent wrote:

    >
    > On 19 Nov 2007, at 16:12, I. Savant wrote:
    >
    >>> I would need to find out the directory where the current
    >>> executable
    >>> resides to find some stuff whose location I know relative to the
    >>> executable location.
    >>
    >> The first argument ( argv[0] ) is the path to your executable.
    >
    > Not true. Argv[0] is the first argument given on the command line
    > when your code was invoked. This might be a full path, or it might
    > be just the executable name.
    >
    > #include <stdio.h>
    >
    > int main(int argc, char** argv) {
    > printf("Arg 0 is %s\n", argv[0]);
    > return 0;
    > }
    >
    > Compiled and then placed into my path.
    >
    > Dr-Stupid:~ pauls$ /Users/pauls/bin/a.out
    > Arg 0 is /Users/pauls/bin/a.out
    > Dr-Stupid:~ pauls$ bin/a.out
    > Arg 0 is bin/a.out
    > Dr-Stupid:~ pauls$ a.out
    > Arg 0 is a.out
    >
    > There's no guaranteed consistency there, unless you know how it'll
    > be invoked.
    >

    It can even be the location of a symlink if called that way.

    > I can't think of a way of doing it. It's normal practise to put
    > support files in a location like /usr/local/lib or similar rather
    > than with the executable on Unix. On a Mac the solution is normally
    > to package it inside the app bundle and use the API to access that.

    I also wouldn't know. There should be a way though, as internally
    NSBundle does.

    Christiaan
  • >>
    >>>> I would need to find out the directory where the current
    >>>> executable
    >>>> resides to find some stuff whose location I know relative to the
    >>>> executable location.
    >>>

    if you aren't adverse to linking to carbon,

    GetCurrentProcess(&applicationSerialNumber);
    GetProcessInformation(&applicationSerialNumber, &application);

    will return the executable's fsspec in processAppSpec.
  • On Nov 19, 2007, at 8:51 AM, Christiaan Hofman wrote:

    >> I can't think of a way of doing it. It's normal practise to put
    >> support files in a location like /usr/local/lib or similar rather
    >> than with the executable on Unix. On a Mac the solution is normally
    >> to package it inside the app bundle and use the API to access that.
    >
    > I also wouldn't know. There should be a way though, as internally
    > NSBundle does.

    I believe CFBundle is open source.

        - Scott
  • On Nov 19, 2007 2:55 PM, Scott Stevenson <sstevenson...> wrote:
    >
    > On Nov 19, 2007, at 8:51 AM, Christiaan Hofman wrote:
    >
    >>> I can't think of a way of doing it. It's normal practise to put
    >>> support files in a location like /usr/local/lib or similar rather
    >>> than with the executable on Unix. On a Mac the solution is normally
    >>> to package it inside the app bundle and use the API to access that.
    >>
    >> I also wouldn't know. There should be a way though, as internally
    >> NSBundle does.
    >
    > I believe CFBundle is open source.

    Why bother with CFBundle's source? Just *use* CFBundle. (composed in
    e-mail, but should give a basic idea):

    #include <CoreFoundation/CFBundle.h>
    #include <stdlib.h>
    #include <stdio.h>

    char *GetExecutableLocation() {
        CFBundleRef bundle          = CFBundleGetMainBundle();
        CFURLRef    executableURL  = CFBundleCopyExecutableURL(bundle);
        CFStringRef executablePath  =
    CFURLCopyFileSystemPath(executableURL, kCFURLPOSIXPathStyle);
        CFIndex    maxLength      =
    CFStringGetMaximumSizeOfFileSystemRepresentation(executablePath);
        char        *result        = malloc(maxLength);

        if(result) {
            if(!CFStringGetFileSystemRepresentation(executablePath,
    result, maxLength)) {
                free(result);
                result = NULL;
            }
        }

        CFRelease(executablePath);
        CFRelease(executableURL);

        return result;
    }

    int main() {
        char    *path  = GetExecutableLocation();
        printf("path = \"%s\"\n", path);
        free(path);

        return 0;
    }

    int main() {
        char    *path  = GetExecutableLocation();
        printf("path = \"%s\"\n", path);
        free(path);

        return 0;
    }

    --
    Clark S. Cox III
    <clarkcox3...>
  • On Nov 19, 2007, at 6:09 PM, Clark Cox wrote:

    > Why bother with CFBundle's source? Just *use* CFBundle. (composed in
    > e-mail, but should give a basic idea):
    >
    > #include <CoreFoundation/CFBundle.h>
    > #include <stdlib.h>
    > #include <stdio.h>
    >
    > char *GetExecutableLocation() {
    > CFBundleRef bundle          = CFBundleGetMainBundle();

    I got the impression from the description that this is a program which
    does not necessarily have a bundle. Does CFBundle actually work some
    magic in that situation?

        - Scott
  • In a word: yes.

    CFBundle works in single-file executables as well as bundled
    executables.

    Clark Cox III
    <Clark.cox...>
    Sent from my iPhone

    On Nov 19, 2007, at 21:31, Scott Stevenson <sstevenson...> wrote:

    >
    > On Nov 19, 2007, at 6:09 PM, Clark Cox wrote:
    >
    >> Why bother with CFBundle's source? Just *use* CFBundle. (composed in
    >> e-mail, but should give a basic idea):
    >>
    >> #include <CoreFoundation/CFBundle.h>
    >> #include <stdlib.h>
    >> #include <stdio.h>
    >>
    >> char *GetExecutableLocation() {
    >> CFBundleRef bundle          = CFBundleGetMainBundle();
    >
    > I got the impression from the description that this is a program
    > which does not necessarily have a bundle. Does CFBundle actually
    > work some magic in that situation?
    >
    > - Scott
    > _______________________________________________
    > MacOSX-dev mailing list
    > <MacOSX-dev...>
    > http://www.omnigroup.com/mailman/listinfo/macosx-dev
  • On 19 Nov 2007, at 16:51, Christiaan Hofman wrote:

    > I also wouldn't know. There should be a way though, as internally
    > NSBundle does.

    You can use _NSGetExecutablePath() from <mach-o/dyld.h>.  According to
    the header, it might return the path to a symlink, so you may want to
    use realpath() as well, and you could potentially create a security
    hole if you use this the wrong way.

    (I should add that this function is "officially sanctioned" in as much
    as it's used in MoreIsBetter: <http://developer.apple.com/samplecode/MoreIsBetter/listing208.html>; it used to be documented in the NSModule man page, but it looks
    like that no longer exists.)

    It's perhaps worth saying though that using the path of your tool is
    generally an evil thing to do.  It's normally best, for command line
    tools, to hard-code paths to any resources they need in the normal
    UNIX places, or to stick them inside an associated application and use
    Launch Services to locate that (you probably want
    LSFindApplicationForInfo()), then use CF or NSBundle to grab
    references to the relevant files from there.

    Kind regards,

    Alastair.

    --
    http://alastairs-place.net
  • On Tue, 20 Nov 2007 04:09:36 +0200, Clark Cox
    <clarkcox3...> wrote:

    > Why bother with CFBundle's source? Just *use* CFBundle. (composed in
    > e-mail, but should give a basic idea):

      Works fine. Thank you very much, this is exactly what I was looking for.

          -Antti-
  • On Tue, 20 Nov 2007 14:36:53 +0200, Alastair Houghton
    <alastair...> wrote:

    > You can use _NSGetExecutablePath() from <mach-o/dyld.h>.

      I didn't try this as using cfbundle as proposed by another poster did
    the trick. Thanks anyway.

    > It's perhaps worth saying though that using the path of your tool is
    > generally an evil thing to do.

      Why is it evil?

      Perhaps I should explain a little background on what I am doing and why
    I'm doing it the way I am. I am open to suggestions and corrections, of
    course. I admit being quite unfamiliar w/ os-x, as on my payjob I work on
    windows and at home use linux (due to having gotten the x86 hardware dirt
    cheap - if I had to pay the normal price I would have gone for apple
    having heard so much praise for it ; ).

      I am developing a small c program to launch groovy scripts (see
    groovy.codehaus.org). The launcher used at the moment is a shell script
    (bash script I believe) that relies on environment variable GROOVY_HOME to
    be set to find the resources needed to start groovy runtime (java jars
    containing the actual program + a conf file). My native launcher does not
    depend on that environment variable to be set.

      The c-launcher I've written
    (http://docs.codehaus.org/display/GROOVY/Native+Launcher) is
    multi-platform, sticking to ansi-c and posix functions as much as possible
    for maximum portability. Currently it works on windows, linux, os-x and
    solaris.

      Groovy is written in Java and the distribution is the same (files) for
    all platforms (except for my native launcher, which atm is only included
    on windows installer by default). Thus my launcher can rely on finding the
    resources needed for startup in the same location relative to the
    distribution root. The distribution root, in turn, can be deduced from the
    location of the executable.
      I'm not in control of how groovy distribution is laid out, but even if I
    was I can not see what would be the benefit of separating the launcher
    executable and the rest of the distribution (into "normal UNIX places")
    versus keeping the distribution file layout the same on all platforms.

            -Antti-
  • On Nov 20, 2007, at 4:36 AM, Alastair Houghton wrote:

    > It's perhaps worth saying though that using the path of your tool is
    > generally an evil thing to do.  It's normally best, for command line
    > tools, to hard-code paths to any resources they need in the normal
    > UNIX places, or to stick them inside an associated application and
    > use Launch Services to locate that (you probably want
    > LSFindApplicationForInfo()), then use CF or NSBundle to grab
    > references to the relevant files from there.

    I might also mention that the path to the executable is not
    necessarily well-defined in general.  For example, by the time your
    executable is launched and running, the file system might have changed
    so that the file that was there no longer exists; something else
    entirely might be in its place.  There are a number of cases in which
    the executable content is actually defined by something other than the
    currently running Mach-o binary--for example, shell scripts, CFM
    executables, Java, and so forth.  If consistency with other behavior
    on the platform is an issue, I would recommend using CFBundle/NSBundle
    to obtain the executable path; it does its best to give a reasonable
    result, and it is the mechanism most generally used on the system.
    However, keep in mind that it may fail, and that no mechanism of this
    sort can succeed in all cases.  In particular, don't make security
    mechanisms dependent on being able to locate your executable.  If you
    need to examine the binary contents of your executable, you can look
    at the loaded version in your address space.

    Douglas Davidson
  • On 23 Nov 2007, at 20:52, Antti Karanta wrote:

    > On Tue, 20 Nov 2007 14:36:53 +0200, Alastair Houghton <alastair...>
    >> wrote:
    >
    >> It's perhaps worth saying though that using the path of your tool
    >> is generally an evil thing to do.
    >
    > Why is it evil?

    Because you can't guarantee that you can get the path, in general.
    You have to use system-specific hacks to obtain it, and on some
    systems there's no way to reliably find the path of the running
    program.  Even on systems that do let you obtain such a path, you may
    find that the path is that of a symlink (which may or may not be an
    issue, depending on what you do with it).

    Furthermore, even if you do find the path somehow, a malicious (or
    just misguided) user could move things around between the time you
    obtain the path and the time your code is actually running.  This has
    the potential to create security holes in certain circumstances (e.g.
    by causing you to load corrupted files and/or execute processes or
    scripts with the privileges of the user running your program).

    > I'm not in control of how groovy distribution is laid out, but even
    > if I was I can not see what would be the benefit of separating the
    > launcher executable and the rest of the distribution (into "normal
    > UNIX places") versus keeping the distribution file layout the same
    > on all platforms.

    For the type of application you're talking about, hard-coded paths
    seem the most sensible choice, possibly allowing GROOVY_HOME to
    override them if it's set.  You can easily find the paths to use when
    your users build your program (it looks like the type that's built
    from source, right?)

    And if you want to package-up pre-built versions of your launcher with
    Groovy itself, you can do that too, using the various system-specific
    packaging tools (e.g. PackageMaker on OS X).  Certainly on OS X, many
    users would prefer to be able to double-click a "Groovy.pkg" file
    anyway.  The same is true, I think, for other systems.

    If you do that, you can delete all the grotty code to find the
    executable path on all the systems you currently support, *and* the
    program will be more likely to run without modification on other
    systems too.

    Kind regards,

    Alastair.

    --
    http://alastairs-place.net
previous month november 2007 next month
MTWTFSS
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    
Go to today