views:

957

answers:

4

I know this question has been asked before but I still haven't seen a satisfactory answer, or a definitive "no, this cannot be done", so I'll ask again!

All I want to do is get the path to the currently running executable, either as an absolute path or relative to where the executable is invoked from, in a platform-independent fashion. I though boost::filesystem::initial_path was the answer to my troubles but that seems to only handle the 'platform-independent' part of the question - it still returns the path from which the application was invoked.

For a bit of background, this is a game using Ogre, which I'm trying to profile using Very Sleepy, which runs the target executable from its own directory, so of course on load the game finds no configuration files etc. and promptly crashes. I want to be able to pass it an absolute path to the configuration files, which I know will always live alongside the executable. The same goes for debugging in Visual Studio - I'd like to be able to run $(TargetPath) without having to set the working directory.

+1  A: 

This works for me:

#include <iostream>

using namespace std ;

int main( int argc, char** argv)
{
    cout << argv[0] << endl ; ;
    return 0;
}
Clifford
I've seen on other SO questions that this doesn't always work, and that argv[0] can contain the absolute path to the executable, just the file name of the executable, or any other rubbish.
Ben Hymers
Quite possibly so.
Clifford
+2  A: 

This way uses boost + argv. You mentioned this may not be cross platform because it may or may not include the executable name. Well the following code should work around that.

#include "boost/filesystem/operations.hpp"

#include "boost/filesystem/path.hpp"

#include <iostream>

namespace fs = boost::filesystem;


int main(int argc,char** argv)
{
    fs::path full_path( fs::initial_path<fs::path>() );

    full_path = fs::system_complete( fs::path( argv[0] ) );

    std::cout << full_path << std::endl;

    //Without file name
    std::cout << full_path.stem() << std::endl;
    //std::cout << fs::basename(full_path) << std::endl;

    return 0;
}

The following code gets the current working directory which may do what you need

#include "boost/filesystem/operations.hpp"
#include "boost/filesystem/path.hpp"

#include <iostream>

namespace fs = boost::filesystem;


int main(int argc,char** argv)
{
    //current working directory
    fs::path full_path( fs::current_path<fs::path>() );

    std::cout << full_path << std::endl;

    std::cout << full_path.stem() << std::endl;
    //std::cout << fs::basepath(full_path) << std::endl;

    return 0;
}

Note Just realized that basename() was deprecated so had to switch to .stem()

Ryu
stem seems to give me just the executable minus the path and extension on Windows, but that's a minor point. What I'd like to know is how this works around argv[0] being possibly incorrect? It works for me testing on Windows, but then argv[0] is actually being passed in as the absolute path of the executable, which makes system_complete's job pretty easy :)
Ben Hymers
+1  A: 

For Windows you can use GetModuleFilename().
For Linux see BinReloc.

Dmitriy
+9  A: 

There is no cross platform way that I know.

For Linux: readlink /proc/self/exe

Windows: GetModuleFileName

Duck
Platform independence is simply a matter of hiding the platform dependency. In this case using the predefined OS macros detailed at http://predef.sourceforge.net/preos.html to select the method is straightforward.
Clifford
So is this what everyone does whenever they want to find the executable's path in C++? I was hoping something as simple-sounding as this would already be implemented in a library like boost.
Ben Hymers
I suppose I did ask for either a method or 'no', and this is both, so I'll accept it :)
Ben Hymers