Récupère le chemin de l’exécutable

Je sais que cette question a déjà été posée mais je n’ai toujours pas vu de réponse satisfaisante, ni de réponse définitive à un «non, cela ne peut être fait», alors je vous le redemanderai!

Tout ce que je veux faire, c’est obtenir le chemin d’access à l’exécutable en cours d’exécution, soit en tant que chemin absolu, soit par rapport à l’endroit où l’exécutable est appelé, d’une manière indépendante de la plate-forme. Je pensais que boost :: filesystem :: initial_path était la solution à mes problèmes, mais cela ne semble gérer que la partie «indépendante de la plate-forme» de la question – elle renvoie toujours le chemin à partir duquel l’application a été appelée.

Pour un peu d’arrière-plan, il s’agit d’un jeu utilisant Ogre, que j’essaie de profiler avec Very Sleepy, qui exécute l’exécutable cible à partir de son propre répertoire, donc le jeu ne trouve aucun fichier de configuration, etc. . Je veux pouvoir lui transmettre un chemin absolu vers les fichiers de configuration, qui, je le sais, coexisteront toujours avec l’exécutable. Il en va de même pour le débogage dans Visual Studio – j’aimerais pouvoir exécuter $ (TargetPath) sans avoir à définir le répertoire de travail.

Il n’y a pas de plate-forme croisée que je connaisse.

Pour Linux: readlink / proc / self / exe

Windows: GetModuleFileName

Cette façon utilise boost + argv. Vous avez mentionné que cela pourrait ne pas être inter plate-forme car il peut ou non inclure le nom de l’exécutable. Eh bien, le code suivant devrait fonctionner autour de cela.

#include  #include  #include  namespace fs = boost::filesystem; int main(int argc,char** argv) { fs::path full_path( fs::initial_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; } 

Le code suivant obtient le répertoire de travail en cours qui peut faire ce dont vous avez besoin

 #include  #include  #include  namespace fs = boost::filesystem; int main(int argc,char** argv) { //current working directory fs::path full_path( fs::current_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 Juste réalisé que basename( ) était obsolète, il fallait donc passer à .stem()

La fonction boost :: dll :: program_location est l’une des meilleures méthodes multi-plateformes pour obtenir le chemin de l’exécutable en cours d’exécution que je connais. La bibliothèque de DLL a été ajoutée à Boost dans la version 1.61.0.

Voici ma solution. Je l’ai testé sur Windows, Mac OS X, Solaris, Free BSD et GNU / Linux.

Il nécessite un Boost 1.55.0 ou supérieur. Il utilise la bibliothèque Boost.Filesystem directement et la bibliothèque Boost.Locale et la bibliothèque Boost.System indirectement.

src / executable_path.cpp

 #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #if (BOOST_VERSION > BOOST_VERSION_NUMBER(1,64,0)) # include  #endif #if (BOOST_OS_CYGWIN || BOOST_OS_WINDOWS) # include  #endif #include  #include  namespace boost { #if (BOOST_OS_CYGWIN || BOOST_OS_WINDOWS) std::ssortingng executable_path(const char* argv0) { typedef std::vector char_vector; typedef std::vector::size_type size_type; char_vector buf(1024, 0); size_type size = buf.size(); bool havePath = false; bool shouldContinue = true; do { DWORD result = GetModuleFileNameA(nullptr, &buf[0], size); DWORD lastError = GetLastError(); if (result == 0) { shouldContinue = false; } else if (result < size) { havePath = true; shouldContinue = false; } else if ( result == size && (lastError == ERROR_INSUFFICIENT_BUFFER || lastError == ERROR_SUCCESS) ) { size *= 2; buf.resize(size); } else { shouldContinue = false; } } while (shouldContinue); if (!havePath) { return detail::executable_path_fallback(argv0); } // On Microsoft Windows, there is no need to call boost::filesystem::canonical or // boost::filesystem::path::make_preferred. The path returned by GetModuleFileNameA // is the one we want. std::string ret = &buf[0]; return ret; } #elif (BOOST_OS_MACOS) # include  std::ssortingng executable_path(const char* argv0) { typedef std::vector char_vector; char_vector buf(1024, 0); uint32_t size = static_cast(buf.size()); bool havePath = false; bool shouldContinue = true; do { int result = _NSGetExecutablePath(&buf[0], &size); if (result == -1) { buf.resize(size + 1); std::fill(std::begin(buf), std::end(buf), 0); } else { shouldContinue = false; if (buf.at(0) != 0) { havePath = true; } } } while (shouldContinue); if (!havePath) { return detail::executable_path_fallback(argv0); } std::ssortingng path(&buf[0], size); boost::system::error_code ec; boost::filesystem::path p( boost::filesystem::canonical(path, boost::filesystem::current_path(), ec)); if (ec.value() == boost::system::errc::success) { return p.make_preferred().ssortingng(); } return detail::executable_path_fallback(argv0); } #elif (BOOST_OS_SOLARIS) # include  std::ssortingng executable_path(const char* argv0) { std::ssortingng ret = getexecname(); if (ret.empty()) { return detail::executable_path_fallback(argv0); } boost::filesystem::path p(ret); if (!p.has_root_directory()) { boost::system::error_code ec; p = boost::filesystem::canonical( p, boost::filesystem::current_path(), ec); if (ec.value() != boost::system::errc::success) { return detail::executable_path_fallback(argv0); } ret = p.make_preferred().ssortingng(); } return ret; } #elif (BOOST_OS_BSD) # include  std::ssortingng executable_path(const char* argv0) { typedef std::vector char_vector; int mib[4]{0}; size_t size; mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PATHNAME; mib[3] = -1; int result = sysctl(mib, 4, nullptr, &size, nullptr, 0); if (-1 == result) { return detail::executable_path_fallback(argv0); } char_vector buf(size + 1, 0); result = sysctl(mib, 4, &buf[0], &size, nullptr, 0); if (-1 == result) { return detail::executable_path_fallback(argv0); } std::ssortingng path(&buf[0], size); boost::system::error_code ec; boost::filesystem::path p( boost::filesystem::canonical( path, boost::filesystem::current_path(), ec)); if (ec.value() == boost::system::errc::success) { return p.make_preferred().ssortingng(); } return detail::executable_path_fallback(argv0); } #elif (BOOST_OS_LINUX) # include  std::ssortingng executable_path(const char *argv0) { typedef std::vector char_vector; typedef std::vector::size_type size_type; char_vector buf(1024, 0); size_type size = buf.size(); bool havePath = false; bool shouldContinue = true; do { ssize_t result = readlink("/proc/self/exe", &buf[0], size); if (result < 0) { shouldContinue = false; } else if (static_cast(result) < size) { havePath = true; shouldContinue = false; size = result; } else { size *= 2; buf.resize(size); std::fill(std::begin(buf), std::end(buf), 0); } } while (shouldContinue); if (!havePath) { return detail::executable_path_fallback(argv0); } std::string path(&buf[0], size); boost::system::error_code ec; boost::filesystem::path p( boost::filesystem::canonical( path, boost::filesystem::current_path(), ec)); if (ec.value() == boost::system::errc::success) { return p.make_preferred().string(); } return detail::executable_path_fallback(argv0); } #else std::string executable_path(const char *argv0) { return detail::executable_path_fallback(argv0); } #endif } 

src / detail / executable_path_internals.cpp

 #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #if (BOOST_VERSION > BOOST_VERSION_NUMBER(1,64,0)) # include  #endif #if (BOOST_OS_CYGWIN || BOOST_OS_WINDOWS) # include  #endif #include  #include  namespace boost { namespace detail { std::ssortingng GetEnv(const std::ssortingng& varName) { if (varName.empty()) return ""; #if (BOOST_OS_BSD || BOOST_OS_CYGWIN || BOOST_OS_LINUX || BOOST_OS_MACOS || BOOST_OS_SOLARIS) char* value = std::getenv(varName.c_str()); if (!value) return ""; return value; #elif (BOOST_OS_WINDOWS) typedef std::vector char_vector; typedef std::vector::size_type size_type; char_vector value(8192, 0); size_type size = value.size(); bool haveValue = false; bool shouldContinue = true; do { DWORD result = GetEnvironmentVariableA(varName.c_str(), &value[0], size); if (result == 0) { shouldContinue = false; } else if (result < size) { haveValue = true; shouldContinue = false; } else { size *= 2; value.resize(size); } } while (shouldContinue); std::string ret; if (haveValue) { ret = &value[0]; } return ret; #else return ""; #endif } bool GetDirectoryListFromDelimitedString( const std::string& str, std::vector& dirs) { typedef boost::char_separator char_separator_type; typedef boost::tokenizer< boost::char_separator, std::ssortingng::const_iterator, std::ssortingng> tokenizer_type; dirs.clear(); if (str.empty()) { return false; } #if (BOOST_OS_WINDOWS) const std::ssortingng os_pathsep(";"); #else const std::ssortingng os_pathsep(":"); #endif char_separator_type pathSep(os_pathsep.c_str()); tokenizer_type strTok(str, pathSep); typename tokenizer_type::iterator strIt; typename tokenizer_type::iterator strEndIt = strTok.end(); for (strIt = strTok.begin(); strIt != strEndIt; ++strIt) { dirs.push_back(*strIt); } if (dirs.empty()) { return false; } return true; } std::ssortingng search_path(const std::ssortingng& file) { if (file.empty()) return ""; std::ssortingng ret; #if (BOOST_VERSION > BOOST_VERSION_NUMBER(1,64,0)) { namespace bp = boost::process; boost::filesystem::path p = bp::search_path(file); ret = p.make_preferred().ssortingng(); } #endif if (!ret.empty()) return ret; // Drat! I have to do it the hard way. std::ssortingng pathEnvVar = GetEnv("PATH"); if (pathEnvVar.empty()) return ""; std::vector pathDirs; bool getDirList = GetDirectoryListFromDelimitedSsortingng(pathEnvVar, pathDirs); if (!getDirList) return ""; std::vector::const_iterator it = pathDirs.cbegin(); std::vector::const_iterator itEnd = pathDirs.cend(); for ( ; it != itEnd; ++it) { boost::filesystem::path p(*it); p /= file; if (boost::filesystem::exists(p) && boost::filesystem::is_regular_file(p)) { return p.make_preferred().ssortingng(); } } return ""; } std::ssortingng executable_path_fallback(const char *argv0) { if (argv0 == nullptr) return ""; if (argv0[0] == 0) return ""; #if (BOOST_OS_WINDOWS) const std::ssortingng os_sep("\\"); #else const std::ssortingng os_sep("/"); #endif if (strstr(argv0, os_sep.c_str()) != nullptr) { boost::system::error_code ec; boost::filesystem::path p( boost::filesystem::canonical( argv0, boost::filesystem::current_path(), ec)); if (ec.value() == boost::system::errc::success) { return p.make_preferred().ssortingng(); } } std::ssortingng ret = search_path(argv0); if (!ret.empty()) { return ret; } boost::system::error_code ec; boost::filesystem::path p( boost::filesystem::canonical( argv0, boost::filesystem::current_path(), ec)); if (ec.value() == boost::system::errc::success) { ret = p.make_preferred().ssortingng(); } return ret; } } } 

inclure / boost / executable_path.hpp

 #ifndef BOOST_EXECUTABLE_PATH_HPP_ #define BOOST_EXECUTABLE_PATH_HPP_ #pragma once #include  namespace boost { std::ssortingng executable_path(const char * argv0); } #endif // BOOST_EXECUTABLE_PATH_HPP_ 

include / boost / detail / executable_path_internals.hpp

 #ifndef BOOST_DETAIL_EXECUTABLE_PATH_INTERNALS_HPP_ #define BOOST_DETAIL_EXECUTABLE_PATH_INTERNALS_HPP_ #pragma once #include  #include  namespace boost { namespace detail { std::ssortingng GetEnv(const std::ssortingng& varName); bool GetDirectoryListFromDelimitedSsortingng( const std::ssortingng& str, std::vector& dirs); std::ssortingng search_path(const std::ssortingng& file); std::ssortingng executable_path_fallback(const char * argv0); } } #endif // BOOST_DETAIL_EXECUTABLE_PATH_INTERNALS_HPP_ 

J'ai un projet complet, comprenant une application de test et des fichiers de construction CMake disponibles sur SnKOpen - / cpp / executable_path / trunk . Cette version est plus complète que la version fournie ici. Il prend également en charge plusieurs plates-formes.

J'ai testé l'application sur tous les systèmes d'exploitation pris en charge dans les quatre scénarios suivants.

  1. Chemin relatif, exécutable dans le répertoire actuel: ie ./executable_path_test
  2. Chemin relatif, exécutable dans un autre répertoire: ie ./build/executable_path_test
  3. Chemin complet: ie / some / rep / executable_path_test
  4. Exécutable dans le chemin, nom du fichier uniquement: ie exécutable_path_test

Dans les quatre scénarios, les fonctions executable_path et executable_path_fallback fonctionnent et renvoient les mêmes résultats.

Remarques

Ceci est une réponse mise à jour à cette question. J'ai mis à jour la réponse pour prendre en compte les commentaires et les suggestions des utilisateurs. J'ai également ajouté un lien vers un projet dans mon référentiel SVN.

Je ne suis pas sûr de Linux, mais essayez ceci pour Windows:

 #include  #include  using namespace std ; int main() { char ownPth[MAX_PATH]; // When NULL is passed to GetModuleHandle, the handle of the exe itself is returned HMODULE hModule = GetModuleHandle(NULL); if (hModule != NULL) { // Use GetModuleFileName() with module handle to get the path GetModuleFileName(hModule, ownPth, (sizeof(ownPth))); cout << ownPth << endl ; system("PAUSE"); return 0; } else { cout << "Module handle is NULL" << endl ; system("PAUSE"); return 0; } } 

Pour les fenêtres:

GetModuleFileName – Retourne le chemin d’exe + le nom de fichier exe

Pour supprimer le nom de fichier
PathRemoveFileSpec

Ceci est une manière spécifique à Windows, mais c’est au moins la moitié de votre réponse.

GetThisPath.h

 /// dest is expected to be MAX_PATH in length. /// returns dest /// TCHAR dest[MAX_PATH]; /// GetThisPath(dest, MAX_PATH); TCHAR* GetThisPath(TCHAR* dest, size_t destSize); 

GetThisPath.cpp

 #include  #pragma comment(lib, "shlwapi.lib") TCHAR* GetThisPath(TCHAR* dest, size_t destSize) { if (!dest) return NULL; if (MAX_PATH > destSize) return NULL; DWORD length = GetModuleFileName( NULL, dest, destSize ); PathRemoveFileSpec(dest); return dest; } 

mainProgram.cpp

 TCHAR dest[MAX_PATH]; GetThisPath(dest, MAX_PATH); 

Je suggère d’utiliser la détection de plate-forme comme directives de préprocesseur pour modifier l’implémentation d’une fonction wrapper qui appelle GetThisPath pour chaque plate-forme.

QT fournit ceci avec l’abstraction du système d’exploitation comme QCoreApplication :: applicationDirPath ()

Pour Windows, vous pouvez utiliser GetModuleFilename ().
Pour Linux, voir BinReloc .

Utiliser args [0] et rechercher ‘/’ (ou ‘\\’):

 #include  #include  // to show the result int main( int numArgs, char *args[]) { // Get the last position of '/' std::ssortingng aux(args[0]); // get '/' or '\\' depending on unix/mac or windows. #if defined(_WIN32) || defined(WIN32) int pos = aux.rfind('\\'); #else int pos = aux.rfind('/'); #endif // Get the path and the name std::ssortingng path = aux.substr(0,pos+1); std::ssortingng name = aux.substr(pos+1); // show results std::cout << "Path: " << path << std::endl; std::cout << "Name: " << name << std::endl; } 

EDITED: Si '/' n'existe pas, pos == - 1 donc le résultat est correct.

Ce qui suit fonctionne comme une solution rapide et sale, mais notez qu’il est loin d’être infaillible:

 #include  using namespace std ; int main( int argc, char** argv) { cout << argv[0] << endl ; return 0; } 

Eh bien, j’ai trouvé une solution très intéressante pour les utilisateurs de Linux (testés) et peut également fonctionner pour Windows.

Voici le lien

Vous pouvez créer le fichier exe dans Linux en le tapant dans le terminal: g ++ -o test test.cpp

C’était ma solution dans Windows. Il s’appelle comme ceci:

 std::wssortingng sResult = GetPathOfEXE(64); 

Où 64 est la taille minimale que vous pensez que le chemin sera. GetPathOfEXE s’appelle lui-même de manière récursive, doublant la taille du tampon jusqu’à ce qu’il obtienne un tampon suffisamment grand pour obtenir l’intégralité du chemin sans être tronqué.

 std::wssortingng GetPathOfEXE(DWORD dwSize) { WCHAR* pwcharFileNamePath; DWORD dwLastError; HRESULT hrError; std::wssortingng wsResult; DWORD dwCount; pwcharFileNamePath = new WCHAR[dwSize]; dwCount = GetModuleFileNameW( NULL, pwcharFileNamePath, dwSize ); dwLastError = GetLastError(); if (ERROR_SUCCESS == dwLastError) { hrError = PathCchRemoveFileSpec( pwcharFileNamePath, dwCount ); if (S_OK == hrError) { wsResult = pwcharFileNamePath; if (pwcharFileNamePath) { delete pwcharFileNamePath; } return wsResult; } else if(S_FALSE == hrError) { wsResult = pwcharFileNamePath; if (pwcharFileNamePath) { delete pwcharFileNamePath; } //there was nothing to truncate off the end of the path //returning something better than nothing in this case for the user return wsResult; } else { if (pwcharFileNamePath) { delete pwcharFileNamePath; } std::ossortingngstream oss; oss << "could not get file name and path of executing process. error truncating file name off path. last error : " << hrError; throw std::runtime_error(oss.str().c_str()); } } else if (ERROR_INSUFFICIENT_BUFFER == dwLastError) { if (pwcharFileNamePath) { delete pwcharFileNamePath; } return GetPathOfEXE( dwSize * 2 ); } else { if (pwcharFileNamePath) { delete pwcharFileNamePath; } std::ostringstream oss; oss << "could not get file name and path of executing process. last error : " << dwLastError; throw std::runtime_error(oss.str().c_str()); } } 

Si vous devez gérer des chemins Unicode pour Windows:

 #include  #include  int wmain(int argc, wchar_t * argv[]) { HMODULE this_process_handle = GetModuleHandle(NULL); wchar_t this_process_path[MAX_PATH]; GetModuleFileNameW(NULL, this_process_path, sizeof(this_process_path)); std::wcout << "Unicode path of this app: " << this_process_path << std::endl; return 0; } 

Pour Windows, vous avez le problème de GetModuleFileName() le fichier exécutable du résultat de GetModuleFileName() . L’API Windows appelle PathRemoveFileSpec() que Nate a utilisé à cette fin dans sa réponse a changé entre Windows 8 et ses prédécesseurs. Alors, comment restr compatible avec les deux et en toute sécurité? Heureusement, il existe C ++ 17 (ou Boost, si vous utilisez un compilateur plus ancien). Je fais ça:

 #include  #include  #include  namespace fs = std::experimental::filesystem; // We could use fs::path as return type, but if you're not aware of // std::experimental::filesystem, you probably handle filenames // as ssortingngs anyway in the remainder of your code. I'm on Japanese // Windows, so wide chars are a must. std::wssortingng getDirectoryWithCurrentExecutable() { int size = 256; std::vector charBuffer; // Let's be safe, and find the right buffer size programmatically. do { size *= 2; charBuffer.resize(size); // Resize until filename fits. GetModuleFileNameW returns the // number of characters written to the buffer, so if the // return value is smaller than the size of the buffer, it was // large enough. } while (GetModuleFileNameW(NULL, charBuffer.data(), size) == size); // Typically: c:/program files (x86)/something/foo/bar/exe/files/win64/baz.exe // (Note that windows supports forward and backward slashes as path // separators, so you have to be careful when searching through a path // manually.) // Let's extract the interesting part: fs::path path(charBuffer.data()); // Contains the full path including .exe return path.remove_filename() // Extract the directory ... .w_str(); // ... and convert to a ssortingng. } 

Cette méthode fonctionne à la fois pour Windows et Linux:

 #include  #include  #ifdef _WIN32 #include  #define GetCurrentDir _getcwd #elif __linux__ #include  #define GetCurrentDir getcwd #endif std::ssortingng GetCurrentWorkingDir() { char buff[FILENAME_MAX]; GetCurrentDir(buff, FILENAME_MAX); std::ssortingng current_working_dir(buff); return current_working_dir; } 
 char exePath[512]; CSsortingng strexePath; GetModuleFileName(NULL,exePath,512); strexePath.Format("%s",exePath); strexePath = strexePath.Mid(0,strexePath.ReverseFind('\\')); 

sous Unix (y compris Linux), essayez “qui”, dans Windows, essayez “où”.

 #include  #define _UNIX int main(int argc, char** argv) { char cmd[128]; char buf[128]; FILE* fp = NULL; #if defined(_UNIX) sprintf(cmd, "which %s > my.path", argv[0]); #else sprintf(cmd, "where %s > my.path", argv[0]); #endif system(cmd); fp = fopen("my.path", "r"); fgets(buf, sizeof(buf), fp); fclose(fp); printf("full path: %s\n", buf); unlink("my.path"); return 0; }