1

I'm writing a simple language interpreter / translator using C++, flex and GNU bison. I need to know path to executable. For simple cases such as "mylang mysource.ext" I can get the path using argc and argv, but what can I do if the file is called through shebang (e.g. "#/usr/bin/env mylang")?

There are other cases where argc and argv combination won't work. Is it possible to override such situations? If so, I'd like to get the full path to executable. Solution must be cross-platform. If possible, I'd like to avoid using external libraries, especially boost, which is extremely large for my aims. Thanks!

Lesmana
  • 25,663
  • 9
  • 82
  • 87
ghostmansd
  • 3,285
  • 5
  • 30
  • 44
  • On Windows, `GetModuleFileName(NULL, ...)`. (I doubt you'll find a single cross-platform answer.) – RichieHindle Apr 03 '13 at 19:26
  • 3
    What specific problem do you face from using `argv[0]`? What platforms are you targeting? – jxh Apr 03 '13 at 19:26
  • The same subject came up [yesterday](http://stackoverflow.com/questions/15776269/how-to-get-apppath-to-executable-files-directory-using-c-language-on-windows-u/). The usual solutions include argv[0] (Linux) or GetModuleFileName() (Windows). SUGGESTION: why not require the user to define an $ENVIRONMENT variable pointing to your root directory? – paulsm4 Apr 03 '13 at 19:26
  • The part about *shebang (e.g. "#/usr/bin/env mylang")* is IMHO a hint for linux. – rekire Apr 03 '13 at 19:27
  • 3
    Check this: http://stackoverflow.com/questions/7051844/how-to-find-the-full-path-of-the-c-linux-program-from-within – Sharath Apr 03 '13 at 19:31
  • First of all I aim Linux, then Windows and MacOS. But the more the less. :-) – ghostmansd Apr 03 '13 at 19:37
  • Thank you very much! Sorry that I've created а duplicate: it is not very easy to search in StackOverflow with mobile phone. :-) I'll use hints given in the link. Thanks again! – ghostmansd Apr 03 '13 at 19:47

1 Answers1

0

This will be extremely platform dependent, but for linux, the symlink "/proc/self/exe" points to the physical path of the current image. From here, you can use readlink to determine the path. I recently used this:

#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string>
#include <stdexcept>
#include <boost/scoped_array.hpp>

std::string path;

size_t size = 1024;
const ssize_t err = static_cast<ssize_t>(-1);
while (true)
{
    boost::scoped_array<char> buffer(new char[size]);

    ssize_t res = readlink("/proc/self/exe", buffer.get(), size);

    if (res == err)
    {
        if (errno == ENAMETOOLONG)
            size *= 2; // try again
        else
            throw std::runtime_error("unexpected error during readlink");
    }
    else
    {
        path.assign(buffer.get(), res);
        break;
    }
}

This was done using G++ 4.1.2, so no unique_ptr available, one could also easily remove the reference to boost::scoped_array.

Note: this gives you the full path to the current image, not the directory in which the image exists. To get the directory, you'll need to do some manipulation. Boost Filesystem also has some good functionality to do this. Otherwise, you'll have to figure out to parse it yourself.

Also, the above method is great if you're, for instance, a library, and cannot depend upon another portion of code changing the current working directory, or don't have access to argv. getcwd + argv[0] would work fine if and only if you can guarantee nothing in your application or libraries changes the current working directory (CWD) out from underneath of you. argv[0] works only if the CWD is unchanged.

Additionally, if the executable is located via an environment variable lookup a la $PATH, you'd need to implement path resolution to find where you really are. argv[0] merely returns how you were launched. i.e. if you ran the command "ls -al", argv[0] to the command "ls" would just be "ls". If you ran "/usr/bin/ls -al", argv[0] would be "/usr/bin/ls".

Nathan Ernst
  • 4,540
  • 25
  • 38