Answer for C++17
The MinGW seems to be shipped currently with g++ 6.3 which I consider as quite old. So, I wrote another Answer for C++11.
Incidentally, I solved the same problem with the help of
SO: Get path of executable
a few days ago.
I've put the relevant part into an MCVE:
// Declaration (Header):
// standard C++ header:
#include <filesystem>
// returns file path of this executable
std::filesystem::path getExecPath();
/**************************************************************************/
// Definition (C++ Source):
// standard C++ header:
#include <string>
// OS header:
#ifdef _MSC_VER // Is this MSVC?
#include <windows.h>
#else // (not) _MSC_VER // Then it's hopefully Linux/g++.
#include <unistd.h>
#endif // _MSC_VER
std::filesystem::path getExecPath()
{
#ifdef _MSC_VER // Is this MSVC?
std::wstring path(1024, L'\0');
const DWORD len
= GetModuleFileNameW(NULL, &path[0], (DWORD)path.size());
if (!len) return std::filesystem::path(); // ERROR!
path.resize(len);
return std::filesystem::path(path);
#else // (not) _MSC_VER // Then it's hopefully Linux/g++.
std::string path(1024, '\0');
ssize_t len
= readlink("/proc/self/exe", &path[0], path.size());
if (len < 0) return std::filesystem::path(); // ERROR!
path.resize(len);
return path;
#endif // _MSC_VER
}
/**************************************************************************/
// Test:
// standard C++ header:
#include <iostream>
int main()
{
std::cout
<< "Exec. Path: " << getExecPath() << '\n'
<< "Current Dir.: " << std::filesystem::current_path() << '\n';
}
First, I tried on coliru:
g++ -std=c++17 -O2 -Wall -pedantic -pthread main.cpp && mkdir test ; cd test ; ../a.out
Exec. Path: "/tmp/1609670485.1182494/a.out"
Current Dir.: "/tmp/1609670485.1182494/test"
Note: The version of g++
on coliru is g++ 10.2.0 (at the time of writing).
I added a CMakeLists.txt
to test this on my local box:
project(ExecPath)
cmake_minimum_required(VERSION 3.10.0)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
if (UNIX)
# std::filesystem which was added in C++17
# seems to need an extra lib. in g++.
# This might be version dependent...
link_libraries(-lstdc++fs)
endif()
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
add_executable(testExecPath testExecPath.cc)
The MCVE built and run in Visual Studion 2019.
Output:
Exec. Path: "D:\\ds32737\\Entwicklung\\tests\\C++\\execPath\\build-VS2019\\bin\\Debug\\testExecPath.exe"
Current Dir.: "D:\\ds32737\\Entwicklung\\tests\\C++\\execPath\\build-VS2019"
Finally, I tested this on Debian-Linux (in a VM with g++ 8.3.0).
Test Session:
ds32737@debian:/mnt/hostd/Entwicklung/tests/C++/execPath$ mkdir build-debian
ds32737@debian:/mnt/hostd/Entwicklung/tests/C++/execPath$ cd build-debian/
ds32737@debian:/mnt/hostd/Entwicklung/tests/C++/execPath/build-debian$ cmake ..
-- The C compiler identification is GNU 8.3.0
-- The CXX compiler identification is GNU 8.3.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /mnt/hostd/Entwicklung/tests/C++/execPath/build-debian
ds32737@debian:/mnt/hostd/Entwicklung/tests/C++/execPath/build-debian$ cmake --build .
Scanning dependencies of target testExecPath
[ 50%] Building CXX object CMakeFiles/testExecPath.dir/testExecPath.cc.o
[100%] Linking CXX executable bin/testExecPath
[100%] Built target testExecPath
ds32737@debian:/mnt/hostd/Entwicklung/tests/C++/execPath/build-debian$ bin/testExecPath
Exec. Path: "/mnt/hostd/Entwicklung/tests/C++/execPath/build-debian/bin/testExecPath"
Current Dir.: "/mnt/hostd/Entwicklung/tests/C++/execPath/build-debian"
ds32737@debian:/mnt/hostd/Entwicklung/tests/C++/execPath/build-debian$
The g++ 8.3
is the default on my Debian installation which I did quite recently. It's a bit aged.
So, I had to add -lstdc++fs
to come around link issues with std::filesystem
.
Please, note, that this was not necessary with g++ 10.2
I used in coliru.
Please, note that I took care that the current working directory was not the directory where the executable is located in, in every case.
For the solution of this task, I took care about encoding issues.
(In the past, I've often struggled with file systems and encoding issues as soon as everything else than ASCII characters appear in file paths.)
Thus, I used GetModuleHandleW()
for the Windows implementation which returns the file path in UTF-16.
On Linux, I assume that UTF-8 is used always.
Strictly speaking, std::filesystem::path
is even not really necessary.
Instead, the path could be returned e.g. as std::string
.
For this, the Windows impl. could convert UTF-16 to UTF-8 to provide a granted encoding on any platform.