How do I get the directory that a program is running from?
Asked Answered
P

24

291

Is there a platform-agnostic and filesystem-agnostic method to obtain the full path of the directory from where a program is running using C/C++? Not to be confused with the current working directory. (Please don't suggest libraries unless they're standard ones like clib or STL.)

(If there's no platform/filesystem-agnostic method, suggestions that work in Windows and Linux for specific filesystems are welcome too.)

Pleasant answered 27/9, 2008 at 7:18 Comment(7)
Unless you can reliably extract the path from argv[0], the technique is going to be very OS-dependent.Met
Just to clarify: the 'current directory', or, 'the directory that the program is running from' (in the terminology of the question) is the directory where the image file of the program (~.exe file) is located, and the 'current working directory' is the directory, that is autocompleted if the program uses relative paths?Clotildecloture
When you #include <windows.h>, Windows automatically puts a char* to the executable path in _pgmptr. You don't need to call extra functions or assume junk if you are working on Windows only.Hesson
Does that answer your original question? github.com/gpakosz/whereamiIsolt
Although the comment is from three years ago, I'd like to expand on rsethc's comment about _pgmptr. MSDN documentation states that the _pgmptr and _wpgmptr variables are deprecated, and you should use the function _get_pgmptr(char**) or _get_wpgmptr(wchar_t**) instead. MSDNPaviour
I tried the Windows' version using Borland C++Builder 6, the pBuf and len parameters are not known. Undefined symbol. What headers should I include?Visayan
If you have a modern compiler, you might want to check https://mcmap.net/q/100210/-how-do-i-get-the-directory-that-a-program-is-running-from.Arhat
L
201

Here's code to get the full path to the executing app:

Variable declarations:

char pBuf[256];
size_t len = sizeof(pBuf); 

Windows:

int bytes = GetModuleFileName(NULL, pBuf, len);
return bytes ? bytes : -1;

Linux:

int bytes = MIN(readlink("/proc/self/exe", pBuf, len), len - 1);
if(bytes >= 0)
    pBuf[bytes] = '\0';
return bytes;
Locale answered 13/10, 2008 at 16:1 Comment(12)
I think this is the only answer here that answers the question, and does so for both Windows and Linux. Nice job.Taneshatang
Boo for /proc/pid/exe - Not supported on OS X for some reason.Oxidimetry
When I see code that looks at /proc part of me dies a little. All the world is not Linux, and even on that one platform /proc should be considered subject to change from version to version, arch to arch, etc.Lontson
By the way, a more portable way to get the path to your binary on Unix is to look at argv[0], though this can be forged by the process that launched you.Lontson
@Lontson argv[0] shows the command used to launch the process, so it's only going to show the whole path if the user typed the whole path. If the binary is on their PATH they could just type foo to run it, or ./foo if they're in the current directory -- argv[0] would be insufficient either wayEsbenshade
@Michael Mrozek - These are cases that are easily detected. Imagine logic which does: if argv[0] begins with '/', treat as absolute path, otherwise check if it contains a '/', if so it's a relative path and you need to insert the current working directory, otherwise you need to search for your binary in $PATH. As I said, though, this isn't perfect -- I can call execve() with argv[0] as "omg ponies" and the execve() will still work.Lontson
if they launch using an aliased command on Linux is the argv[0] the "name of the command" or expanded?Cletuscleve
The Windows solution isn't checking the return value correctly (or is expecting the caller to do more error checking). Also, it's returning the full path to the executable. If you want just the directory (as the question poses), you then need to strip the file name from the end of the path.Deploy
How about add char pBuf[256]; size_t len = sizeof(pBuf); to let the solution more clearly.Prepossessing
"Thank you, Mike, you are a hero!" is now proudly present somewhere in the project that I'm currently working on. I also wanted to express my gratitude 'in person', so: thank you, Mike, you are a hero! Yup, it's 3:30 AM.Littell
You should use "/proc/self/exe" instead of this string copy mojo. Apart from that, great answer !Bennett
@ChrisLutz That's because OSX is not Linux (it's sort-of based on FreeBSD).Barrio
C
173

If you fetch the current directory when your program first starts, then you effectively have the directory your program was started from. Store the value in a variable and refer to it later in your program. This is distinct from the directory that holds the current executable program file. It isn't necessarily the same directory; if someone runs the program from a command prompt, then the program is being run from the command prompt's current working directory even though the program file lives elsewhere.

getcwd is a POSIX function and supported out of the box by all POSIX compliant platforms. You would not have to do anything special (apart from incliding the right headers unistd.h on Unix and direct.h on windows).

Since you are creating a C program it will link with the default c run time library which is linked to by ALL processes in the system (specially crafted exceptions avoided) and it will include this function by default. The CRT is never considered an external library because that provides the basic standard compliant interface to the OS.

On windows getcwd function has been deprecated in favour of _getcwd. I think you could use it in this fashion.

#include <stdio.h>  /* defines FILENAME_MAX */
#ifdef WINDOWS
    #include <direct.h>
    #define GetCurrentDir _getcwd
#else
    #include <unistd.h>
    #define GetCurrentDir getcwd
 #endif

 char cCurrentPath[FILENAME_MAX];

 if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath)))
     {
     return errno;
     }

cCurrentPath[sizeof(cCurrentPath) - 1] = '\0'; /* not really required */

printf ("The current working directory is %s", cCurrentPath);
Casual answered 28/9, 2008 at 6:4 Comment(13)
Good answer, but I thought "current working directory" was not what was wanted.Bunghole
you should add that even if some documentations say that cCurrentpath can be null and will be allocated by getcwd getcwd does not seem to allocate something on Mac OS and quietly crashes your programShanks
why has this been marked as the correct answer when the original poster acknowledges that it's not what they wanted?!Kimmy
There is a small error, but unfortunately I can't edit yet.. line 10: cCurrentpath: should be cCurrentPathUllage
IMO on Windows the POSIXy-named functions (some of which starting with underscores) should be generally avoided. They aren't the real Windows APIs but rather the CRT. The Windows API you want to use is GetCurrentDirectory(). msdn.microsoft.com/en-us/library/aa364934(VS.85).aspxLontson
I needed to add #include <errno.h> and use char instead of TCHAR to get this to work.Stedman
Why would you divide by sizeof(TCHAR) ? Don't you want to divide by sizeof(char)? Also, isn't the size of char always supposed to be 1? If so, dividing would seem to be superfluous.Brocklin
@Brocklin TCHAR takes the value char or wchar_t depending on whether you build using Ascii or Unicode. sizeof(wchar_t) is 2 on Windows.Heckman
Just to clarify: the 'current directory' is the directory where the image file of the program (~.exe file) is located, and the 'current working directory' is the directory, that is autocompleted if the program uses relative paths?Clotildecloture
Mike's answer is correct. The "current directory" is not always as the same as the directory the binary is running from. E.g., if an app runs as a service on Windows, the current directory will probably be C:\Windows\System32, whereas the binary dir is different.Uvea
@LuckyLuke: Or when an application is launched through a shortcut (.lnk), that allows you to specify the current working directory. So querying the CWD before doing anything else in your process won't be helpful either. This answer simply doesn't address the question.Yalu
It should be _WIN32 instead of WINDOWS, WINDOWS is more like compiler specific.Loomis
This may not be what the person asked for but it is the answer I searched Google for and wanted ^_^ (needed to debug some code and this works perfect for me) Thanks!Kissinger
N
47

This is from the cplusplus forum

On windows:

#include <string>
#include <windows.h>

std::string getexepath()
{
  char result[ MAX_PATH ];
  return std::string( result, GetModuleFileName( NULL, result, MAX_PATH ) );
}

On Linux:

#include <string>
#include <limits.h>
#include <unistd.h>

std::string getexepath()
{
  char result[ PATH_MAX ];
  ssize_t count = readlink( "/proc/self/exe", result, PATH_MAX );
  return std::string( result, (count > 0) ? count : 0 );
}

On HP-UX:

#include <string>
#include <limits.h>
#define _PSTAT64
#include <sys/pstat.h>
#include <sys/types.h>
#include <unistd.h>

std::string getexepath()
{
  char result[ PATH_MAX ];
  struct pst_status ps;

  if (pstat_getproc( &ps, sizeof( ps ), 0, getpid() ) < 0)
    return std::string();

  if (pstat_getpathname( result, PATH_MAX, &ps.pst_fid_text ) < 0)
    return std::string();

  return std::string( result );
}
Nightwear answered 23/10, 2013 at 7:37 Comment(4)
That Windows solution won't handle non-ANSI characters in the path. You probably should use GetModuleFileNameW and convert it to UTF-8 explicitly (being careful to convert it back whenever you need to issue a filesystem command).Deploy
For the Windows solution, I get the error error: cannot convert 'char*' to 'LPWCH {aka wchar_t*}' for argument '2' to 'DWORD GetModuleFileNameW(HMODULE, LPWCH, DWORD)' when compiling with MinGW.Schwinn
@Adrian, Im not generally a windows programmer, but isn't there a DEFINE or someway to tell your compiler to use the _W() flavor of functions automatically?Nightwear
@Octopus: To use the wide calls, you'd need to use WCHAR (instead of char) and std::wstring (instead of std::string).Deploy
G
30

If you want a standard way without libraries: No. The whole concept of a directory is not included in the standard.

If you agree that some (portable) dependency on a near-standard lib is okay: Use Boost's filesystem library and ask for the initial_path().

IMHO that's as close as you can get, with good karma (Boost is a well-established high quality set of libraries)

Gratianna answered 27/9, 2008 at 7:23 Comment(3)
From the Boost docs: template <class Path> const Path& initial_path(); Returns: current_path() at the time of entry to main(). And current_path() is 'as if by POSIX getcwd()'. This is not what the questioner requested.Taratarabar
see boost.org/doc/libs/1_46_1/libs/filesystem/v3/doc/… for boost 1.46.1Yetta
As commented, this gives path from where binary was invoked, not path to the binary...as it could be started from a different folder.Kelleekelleher
B
24

I know it is very late at the day to throw an answer at this one but I found that none of the answers were as useful to me as my own solution. A very simple way to get the path from your CWD to your bin folder is like this:

int main(int argc, char* argv[])
{
    std::string argv_str(argv[0]);
    std::string base = argv_str.substr(0, argv_str.find_last_of("/"));
}

You can now just use this as a base for your relative path. So for example I have this directory structure:

main
  ----> test
  ----> src
  ----> bin

and I want to compile my source code to bin and write a log to test I can just add this line to my code.

std::string pathToWrite = base + "/../test/test.log";

I have tried this approach on Linux using full path, alias etc. and it works just fine.

NOTE:

If you are on windows you should use a '\' as the file separator not '/'. You will have to escape this too for example:

std::string base = argv[0].substr(0, argv[0].find_last_of("\\"));

I think this should work but haven't tested, so comment would be appreciated if it works or a fix if not.

Byelection answered 15/8, 2015 at 10:58 Comment(3)
Yes, it works on Windows as well. I think that is the best solution. As far as I know argv[0] always keeps path to the executable.Predestination
argv[0] is a very nice idea, but unfortunalety what I'm getting on Linux is "./my_executable_name" or "./make/my_executable_name". Basically what I get depends completely how I launch itExoskeleton
@Xeverous: so what? If I have some files relative to my executable that it needs to open, starting from "./" or "./make/" in your cases should work. "." is the current working directory, and argv[0] will tell you the relative path to the executable from there, which is exactly what the OP should want. That is in any case exactly what I need.Arhat
C
19

Filesystem TS is now a standard ( and supported by gcc 5.3+ and clang 3.9+ ), so you can use current_path() function from it:

std::string path = std::experimental::filesystem::current_path();

In gcc (5.3+) to include Filesystem you need to use:

#include <experimental/filesystem>

and link your code with -lstdc++fs flag.

If you want to use Filesystem with Microsoft Visual Studio, then read this.

Chickabiddy answered 16/1, 2016 at 22:20 Comment(1)
From the referrenced link, 1-2) Returns the absolute path of the current working directory, obtained as if by POSIX getcwd. (2) returns path() if error occurs. Downvoted, as the OP specifically asks about the current path of the executable rather than the current working directory.Launder
B
10

No, there's no standard way. I believe that the C/C++ standards don't even consider the existence of directories (or other file system organizations).

On Windows the GetModuleFileName() will return the full path to the executable file of the current process when the hModule parameter is set to NULL. I can't help with Linux.

Also you should clarify whether you want the current directory or the directory that the program image/executable resides. As it stands your question is a little ambiguous on this point.

Bunghole answered 27/9, 2008 at 7:22 Comment(0)
S
10

On Windows the simplest way is to use the _get_pgmptr function in stdlib.h to get a pointer to a string which represents the absolute path to the executable, including the executables name.

char* path;
_get_pgmptr(&path);
printf(path); // Example output: C:/Projects/Hello/World.exe
Southwest answered 2/6, 2013 at 22:3 Comment(1)
If that's a compile-time constant, what if someone moves your program?Practitioner
C
8

Maybe concatenate the current working directory with argv[0]? I'm not sure if that would work in Windows but it works in linux.

For example:

#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char **argv) {
    char the_path[256];

    getcwd(the_path, 255);
    strcat(the_path, "/");
    strcat(the_path, argv[0]);

    printf("%s\n", the_path);

    return 0;
}

When run, it outputs:

jeremy@jeremy-desktop:~/Desktop$ ./test
/home/jeremy/Desktop/./test

Cenogenesis answered 27/9, 2008 at 7:32 Comment(3)
You'll need a check to see if an absolute path is given in argv[0]. But more importantly, what if the image is located via the PATH? Does linux fill in the full path or just what's on the command line?Bunghole
As Mike B pointed out, that is a non-general solution; it works in some very limited circumstances only. Basically, only when you run the command by a relative pathname - and it isn't all that elegant when you run ../../../bin/progname instead of ./testTaratarabar
If you resolve possible relative path of argv[0] compared to current directory (because argv[0] could be "../../myprogram.exe"), that's probably the safest way to answer the question. It will always work and is portable (it even works on Android!).Kelleekelleher
R
7

For Win32 GetCurrentDirectory should do the trick.

Romanticism answered 27/9, 2008 at 7:21 Comment(2)
There is big catch with this function: Multithreaded applications and shared library code should not use the GetCurrentDirectory function and should avoid using relative pathnames. If you can work with this assumption than it is the best solution.Irresolvable
Wrong answer, CWD and program's directory can be two very different things.Lowis
W
6

You can not use argv[0] for that purpose, usually it does contain full path to the executable, but not nessesarily - process could be created with arbitrary value in the field.

Also mind you, the current directory and the directory with the executable are two different things, so getcwd() won't help you either.

On Windows use GetModuleFileName(), on Linux read /dev/proc/procID/.. files.

Wolfe answered 27/9, 2008 at 8:17 Comment(0)
A
4

Just my two cents, but doesn't the following code portably work in C++17?

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main(int argc, char* argv[])
{
    std::cout << "Path is " << fs::path(argv[0]).parent_path() << '\n';
}

Seems to work for me on Linux at least.

Based on the previous idea, I now have:

std::filesystem::path prepend_exe_path(const std::string& filename, const std::string& exe_path = "");

With implementation:

fs::path prepend_exe_path(const std::string& filename, const std::string& exe_path)
{
    static auto exe_parent_path = fs::path(exe_path).parent_path();
    return exe_parent_path / filename;
}

And initialization trick in main():

(void) prepend_exe_path("", argv[0]);

Thanks @Sam Redway for the argv[0] idea. And of course, I understand that C++17 was not around for many years when the OP asked the question.

Arhat answered 22/3, 2020 at 19:44 Comment(2)
very clean. great answerSignificancy
Seems to work partially on Windows too (tested on PowerShell Core, Windows PowerShell, MinGW). Running from CMD, this prints a blank string.Piping
J
3

Just to belatedly pile on here,...

there is no standard solution, because the languages are agnostic of underlying file systems, so as others have said, the concept of a directory based file system is outside the scope of the c / c++ languages.

on top of that, you want not the current working directory, but the directory the program is running in, which must take into account how the program got to where it is - ie was it spawned as a new process via a fork, etc. To get the directory a program is running in, as the solutions have demonstrated, requires that you get that information from the process control structures of the operating system in question, which is the only authority on this question. Thus, by definition, its an OS specific solution.

Jule answered 27/1, 2010 at 23:50 Comment(0)
W
3
#include <windows.h>
using namespace std;

// The directory path returned by native GetCurrentDirectory() no end backslash
string getCurrentDirectoryOnWindows()
{
    const unsigned long maxDir = 260;
    char currentDir[maxDir];
    GetCurrentDirectory(maxDir, currentDir);
    return string(currentDir);
}
Watcher answered 19/2, 2014 at 17:15 Comment(1)
The question did not ask for the current directory.Deploy
M
3

Works with starting from C++11, using experimental filesystem, and C++14-C++17 as well using official filesystem.

application.h:

#pragma once

//
// https://en.cppreference.com/w/User:D41D8CD98F/feature_testing_macros
//
#ifdef __cpp_lib_filesystem
#include <filesystem>
#else
#include <experimental/filesystem>

namespace std {
    namespace filesystem = experimental::filesystem;
}
#endif

std::filesystem::path getexepath();

application.cpp:

#include "application.h"
#ifdef _WIN32
#include <windows.h>    //GetModuleFileNameW
#else
#include <limits.h>
#include <unistd.h>     //readlink
#endif

std::filesystem::path getexepath()
{
#ifdef _WIN32
    wchar_t path[MAX_PATH] = { 0 };
    GetModuleFileNameW(NULL, path, MAX_PATH);
    return path;
#else
    char result[PATH_MAX];
    ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
    return std::string(result, (count > 0) ? count : 0);
#endif
}
Menado answered 10/6, 2019 at 12:22 Comment(2)
Nice answer, but it is undefined behavior to add declarations or definitions to namespace std. To avoid this, you can add both the namespaces std::filesystem and std::experimental::filesystem to a third namespace of your choice, or just use using std::filesystem::path, if you don't mind adding the declaration of path to the global namespace.Burglar
I guess after C++14 experimental::filesystem is not used anymore, so you can just forget about this ? (goes into first #if branch)Menado
T
2

For Windows system at console you can use system(dir) command. And console gives you information about directory and etc. Read about the dir command at cmd. But for Unix-like systems, I don't know... If this command is run, read bash command. ls does not display directory...

Example:

int main()
{
    system("dir");
    system("pause"); //this wait for Enter-key-press;
    return 0;
}
Treenware answered 10/6, 2013 at 16:52 Comment(0)
I
1

For relative paths, here's what I did. I am aware of the age of this question, I simply want to contribute a simpler answer that works in the majority of cases:

Say you have a path like this:

"path/to/file/folder"

For some reason, Linux-built executables made in eclipse work fine with this. However, windows gets very confused if given a path like this to work with!

As stated above there are several ways to get the current path to the executable, but the easiest way I find works a charm in the majority of cases is appending this to the FRONT of your path:

"./path/to/file/folder"

Just adding "./" should get you sorted! :) Then you can start loading from whatever directory you wish, so long as it is with the executable itself.

EDIT: This won't work if you try to launch the executable from code::blocks if that's the development environment being used, as for some reason, code::blocks doesn't load stuff right... :D

EDIT2: Some new things I have found is that if you specify a static path like this one in your code (Assuming Example.data is something you need to load):

"resources/Example.data"

If you then launch your app from the actual directory (or in Windows, you make a shortcut, and set the working dir to your app dir) then it will work like that. Keep this in mind when debugging issues related to missing resource/file paths. (Especially in IDEs that set the wrong working dir when launching a build exe from the IDE)

Indefatigable answered 21/4, 2015 at 5:21 Comment(0)
C
1

A library solution (although I know this was not asked for). If you happen to use Qt: QCoreApplication::applicationDirPath()

Contaminant answered 4/10, 2017 at 9:38 Comment(0)
O
1

Path to the current .exe


#include <Windows.h>

std::wstring getexepathW()
{
    wchar_t result[MAX_PATH];
    return std::wstring(result, GetModuleFileNameW(NULL, result, MAX_PATH));
}

std::wcout << getexepathW() << std::endl;

//  -------- OR --------

std::string getexepathA()
{
    char result[MAX_PATH];
    return std::string(result, GetModuleFileNameA(NULL, result, MAX_PATH));
}

std::cout << getexepathA() << std::endl;

Overrule answered 28/12, 2020 at 7:36 Comment(2)
This duplicates another previous answer and, unlike that one, will fail in ANSI builds because the unqualified GetModuleFileName will resolve to GetModuleFileNameA instead of GetModuleFileNameW.Palmapalmaceous
I have modified the answer to include both. Much loveOverrule
A
0

On POSIX platforms, you can use getcwd().

On Windows, you may use _getcwd(), as use of getcwd() has been deprecated.

For standard libraries, if Boost were standard enough for you, I would have suggested Boost::filesystem, but they seem to have removed path normalization from the proposal. You may have to wait until TR2 becomes readily available for a fully standard solution.

Aha answered 27/9, 2008 at 7:31 Comment(4)
getcwd() does not do what the questioner asked.Taratarabar
is it not that the accepted answer uses getcwd(), or am I not just understanding?Patch
I upvoted because you are the one who came with what is considered the correct answer first.Androsterone
This answer doesn't even attempt to address the question. Shame on writing it.Lytta
W
0

Boost Filesystem's initial_path() behaves like POSIX's getcwd(), and neither does what you want by itself, but appending argv[0] to either of them should do it.

You may note that the result is not always pretty--you may get things like /foo/bar/../../baz/a.out or /foo/bar//baz/a.out, but I believe that it always results in a valid path which names the executable (note that consecutive slashes in a path are collapsed to one).

I previously wrote a solution using envp (the third argument to main() which worked on Linux but didn't seem workable on Windows, so I'm essentially recommending the same solution as someone else did previously, but with the additional explanation of why it is actually correct even if the results are not pretty.

Wellhead answered 28/9, 2008 at 4:28 Comment(0)
T
0

As Minok mentioned, there is no such functionality specified ini C standard or C++ standard. This is considered to be purely OS-specific feature and it is specified in POSIX standard, for example.

Thorsten79 has given good suggestion, it is Boost.Filesystem library. However, it may be inconvenient in case you don't want to have any link-time dependencies in binary form for your program.

A good alternative I would recommend is collection of 100% headers-only STLSoft C++ Libraries Matthew Wilson (author of must-read books about C++). There is portable facade PlatformSTL gives access to system-specific API: WinSTL for Windows and UnixSTL on Unix, so it is portable solution. All the system-specific elements are specified with use of traits and policies, so it is extensible framework. There is filesystem library provided, of course.

Troll answered 28/1, 2010 at 0:26 Comment(0)
C
0

The linux bash command which progname will report a path to program.

Even if one could issue the which command from within your program and direct the output to a tmp file and the program subsequently reads that tmp file, it will not tell you if that program is the one executing. It only tells you where a program having that name is located.

What is required is to obtain your process id number, and to parse out the path to the name

In my program I want to know if the program was executed from the user's bin directory or from another in the path or from /usr/bin. /usr/bin would contain the supported version. My feeling is that in Linux there is the one solution that is portable.

Chubby answered 22/8, 2016 at 15:46 Comment(0)
D
-1

The following worked well for me on macOS 10.15.7

brew install boost

main.cpp

#include <iostream>
#include <boost/filesystem.hpp>

int main(int argc, char* argv[]){
  boost::filesystem::path p{argv[0]};
  p = absolute(p).parent_path();
  std::cout << p << std::endl;
  return 0;
}

Compiling

g++ -Wall -std=c++11 -l boost_filesystem main.cpp
Diorama answered 27/2, 2022 at 0:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.