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!

7
  • On Windows, GetModuleFileName(NULL, ...). (I doubt you'll find a single cross-platform answer.) Commented Apr 3, 2013 at 19:26
  • 3
    What specific problem do you face from using argv[0]? What platforms are you targeting? Commented Apr 3, 2013 at 19:26
  • The same subject came up yesterday. 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? Commented Apr 3, 2013 at 19:26
  • The part about shebang (e.g. "#/usr/bin/env mylang") is IMHO a hint for linux. Commented Apr 3, 2013 at 19:27
  • 3
    Check this: stackoverflow.com/questions/7051844/… Commented Apr 3, 2013 at 19:31

1 Answer 1

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".

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.