C++17 答案
MinGW 目前似乎与 g++ 6.3 一起提供,我认为它已经很老了。所以,我又写了一个Answer for C++11。
顺便说一句,我在
SO: Get path of executable的帮助下解决了同样的问题
几天前。
我已将相关部分放入 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';
}
首先,我尝试了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"
注意:coliru 上g++ 的版本是g++ 10.2.0(在撰写本文时)。
我添加了一个CMakeLists.txt 来在我的本地盒子上进行测试:
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)
在 Visual Studion 2019 中构建和运行的 MCVE。
输出:
Exec. Path: "D:\\ds32737\\Entwicklung\\tests\\C++\\execPath\\build-VS2019\\bin\\Debug\\testExecPath.exe"
Current Dir.: "D:\\ds32737\\Entwicklung\\tests\\C++\\execPath\\build-VS2019"
最后,我在 Debian-Linux 上进行了测试(在具有 g++ 8.3.0 的 VM 中)。
测试会话:
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$
g++ 8.3 是我最近安装的 Debian 的默认设置。有点老了。
所以,我必须添加 -lstdc++fs 来解决与 std::filesystem 的链接问题。
请注意,我在 coliru 中使用的 g++ 10.2 不需要这样做。
请注意,在每种情况下,我都注意当前工作目录不是可执行文件所在的目录。
为了解决这个任务,我关注了编码问题。
(过去,当文件路径中出现除 ASCII 字符之外的所有字符时,我经常会遇到文件系统和编码问题。)
因此,我在 Windows 实现中使用了GetModuleHandleW(),它以 UTF-16 格式返回文件路径。
在 Linux 上,我假设始终使用 UTF-8。
严格来说,std::filesystem::path 甚至没有必要。
相反,可以返回路径,例如作为std::string。
为此,Windows impl。可以将 UTF-16 转换为 UTF-8,以在任何平台上提供授权的编码。