Wiem, że to pytanie zadawano już wcześniej, ale nadal nie widziałem satysfakcjonującej odpowiedzi lub ostatecznego „nie, nie da się tego zrobić”, więc zapytam ponownie!
Chcę tylko uzyskać ścieżkę do aktualnie uruchomionego pliku wykonywalnego, jako ścieżkę bezwzględną lub w odniesieniu do miejsca, z którego plik wykonywalny jest wywoływany, w sposób niezależny od platformy. Myślałem, że boost :: filesystem :: initial_path był odpowiedzią na moje problemy, ale wydaje się, że rozwiązuje tylko część pytania „niezależną od platformy” - nadal zwraca ścieżkę, z której aplikacja została wywołana.
Dla trochę tła jest to gra wykorzystująca Ogre, którą próbuję profilować za pomocą Very Sleepy, która uruchamia docelowy plik wykonywalny z własnego katalogu, więc oczywiście po załadowaniu gra nie znajduje żadnych plików konfiguracyjnych itp. I natychmiast się zawiesza . Chcę móc przekazać mu absolutną ścieżkę do plików konfiguracyjnych, o których wiem, że zawsze będą istnieć razem z plikiem wykonywalnym. To samo dotyczy debugowania w Visual Studio - chciałbym móc uruchomić $ (TargetPath) bez konieczności ustawiania katalogu roboczego.
źródło
Odpowiedzi:
Nie ma sposobu, który znam na wielu platformach.
W systemie Linux: readlink / proc / self / exe
Windows: GetModuleFileName
źródło
Plik boost :: dll :: program_location jest jedną z najlepszych znanych mi metod międzyplatformowego uzyskiwania ścieżki do działającego pliku wykonywalnego. Biblioteka DLL została dodana do Boost w wersji 1.61.0.
Oto moje rozwiązanie. Przetestowałem go na Windows, Mac OS X, Solaris, Free BSD i GNU / Linux.
Wymaga Boost 1.55.0 lub nowszego. Korzysta z biblioteki Boost.Filesystem bezpośrednio i Boost.Locale biblioteka i Boost.System biblioteki pośrednio.
src / executable_path.cpp
src / detail / executable_path_internals.cpp
include / boost / executable_path.hpp
include / boost / detail / executable_path_internals.hpp
Mam kompletny projekt, w tym aplikację testową i pliki kompilacji CMake dostępne w SnKOpen - / cpp / executable_path / trunk . Ta wersja jest bardziej kompletna niż wersja, którą tutaj podałem. Obsługuje również więcej platform.
Przetestowałem aplikację na wszystkich obsługiwanych systemach operacyjnych w następujących czterech scenariuszach.
We wszystkich czterech scenariuszach funkcje executable_path i executable_path_fallback działają i zwracają te same wyniki.
Uwagi
To jest zaktualizowana odpowiedź na to pytanie. Zaktualizowałem odpowiedź, aby uwzględnić komentarze i sugestie użytkowników. Dodałem również link do projektu w moim repozytorium SVN.
źródło
argv[0]
może być również nazwą pliku wykonywalnego, w którym to przypadku konieczne byłoby wyszukanie go wPATH
systemach * nix.W ten sposób używa boost + argv. Wspomniałeś, że to może nie być wieloplatformowe, ponieważ może, ale nie musi, zawierać nazwę pliku wykonywalnego. Poniższy kod powinien to obejść.
Poniższy kod pobiera bieżący katalog roboczy, który może zrobić to, czego potrzebujesz
Uwaga Właśnie zdałem sobie sprawę, że
basename(
) jest przestarzały, więc musiałem przejść na.stem()
źródło
.parent_path()
, nie.stem()
, nie?@Claudiu
powiedziałem, myślę, że powinno.parent_path()
.Nie jestem pewien co do Linuksa, ale wypróbuj to dla Windows:
źródło
WCHAR ownPth..
owiniętego wokół a#ifdef UNICODE
w przypadku kompilacji z obsługą Unicode. Jeśli nie, użyj podanego kodu.HMODULE hModule = GetModuleHandle(NULL);
Dla Windowsa:
GetModuleFileName
- zwraca ścieżkę do exe + nazwę pliku exeAby usunąć nazwę pliku
PathRemoveFileSpec
źródło
This function is deprecated. We recommend the use of the PathCchRemoveFileSpec function in its place
.C ++ 17, windows, unicode, przy użyciu nowego interfejsu API systemu plików:
Podejrzewam, że to rozwiązanie powinno być przenośne, ale nie wiem, jak unicode jest zaimplementowany w innych systemach operacyjnych.
slave_canonical jest potrzebny tylko wtedy, gdy używasz jako odniesień do górnego folderu katalogu wyjściowego („..”) w celu uproszczenia ścieżki. Jeśli go nie używasz - usuń.
Jeśli korzystasz z biblioteki dołączanej dynamicznie (.dll /.so), możesz nie mieć argv, możesz rozważyć następujące rozwiązanie:
application.h:
application.cpp:
źródło
QT zapewnia to z abstrakcją systemu operacyjnego jako QCoreApplication :: applicationDirPath ()
źródło
QCoreApplication::applicationDirPath: Please instantiate the QApplication object first
. Masz jakiś pomysł, jak to rozwiązać?QCoreApplication
podobnąQApplication application(argc, argv);
(zrób to w swoimmain(argc, argv)
i upewnij się, że nie modyfikujeszargc/argv
, ponieważ muszą one pozostać ważne przez cały okres eksploatacji aplikacji QCore (sprawdź dokumentację )Jest to sposób specyficzny dla systemu Windows, ale to przynajmniej połowa odpowiedzi.
GetThisPath.h
GetThisPath.cpp
mainProgram.cpp
Sugerowałbym użycie wykrywania platformy jako dyrektyw preprocesora, aby zmienić implementację funkcji opakowującej, która wywołuje
GetThisPath
każdą platformę.źródło
Używając argumentów [0] i szukając „/” (lub „\\”):
EDYTOWANE: Jeśli „/” nie istnieje, pos == - 1, więc wynik jest poprawny.
źródło
args[0]
może wcale nie być ścieżką.args[0]
przeszkadza mi to, że niekoniecznie jest to ścieżka wykonywalna. Dzięki za poprawienie odpowiedzi dla systemu Windows :)W systemie Windows możesz użyć funkcji GetModuleFilename ().
W przypadku systemu Linux zobacz
BinReloc (stary, nieistniejący adres URL)kopia lustrzana BinReloc w repozytoriach GitHub datenwolf .źródło
Poniższe rozwiązanie działa jako szybkie i brudne rozwiązanie, ale pamiętaj, że nie jest ono niezawodne:
źródło
W przypadku konieczności obsługi ścieżek Unicode w systemie Windows:
źródło
W systemie Windows masz problem, jak usunąć plik wykonywalny z wyniku
GetModuleFileName()
. Wywołanie Windows API,PathRemoveFileSpec()
którego Nate użył w tym celu w swojej odpowiedzi, zmieniło się między Windows 8 a jego poprzednikami. Jak więc pozostać kompatybilnym i bezpiecznym? Na szczęście jest C ++ 17 (lub Boost, jeśli używasz starszego kompilatora). Robię to:źródło
Jak wspominali inni,
argv[0]
jest to całkiem fajne rozwiązanie, pod warunkiem, że platforma faktycznie przechodzi ścieżkę do pliku wykonywalnego, co z pewnością jest nie mniej prawdopodobne niż w przypadku systemu operacyjnego Windows (gdzie WinAPI może pomóc w znalezieniu ścieżki do pliku wykonywalnego). Jeśli chcesz usunąć ciąg, aby uwzględnić tylko ścieżkę do katalogu, w którym znajduje się plik wykonywalny, użycie tej ścieżki do znalezienia innych plików aplikacji (takich jak zasoby gry, jeśli program jest grą) jest całkowicie w porządku, ponieważ otwieranie plików jest względne katalog roboczy lub, jeśli jest dostępny, katalog główny.źródło
Na tym skończyłem
Plik nagłówkowy wygląda następująco:
Realizacja
źródło
Biblioteka SDL2 ( https://www.libsdl.org/ ) posiada dwie funkcje zaimplementowane na szerokim spektrum platform:
Więc jeśli nie chcesz wymyślać koła na nowo ... niestety oznacza to włączenie całej biblioteki, chociaż ma dość liberalną licencję i można też po prostu skopiować kod. Poza tym zapewnia wiele innych funkcji międzyplatformowych.
źródło
Jest to prawdopodobnie najbardziej naturalny sposób na zrobienie tego, obejmujący większość głównych platform stacjonarnych. Nie jestem pewien, ale uważam, że powinno to działać ze wszystkimi BSD, a nie tylko z FreeBSD, jeśli zmienisz sprawdzanie makr platformy tak, aby obejmowało je wszystkie. Jeśli kiedykolwiek przejdę do instalacji Solaris, na pewno dodam tę platformę do listy obsługiwanych.
Zawiera pełną obsługę UTF-8 w systemie Windows, co nie wszystkim zależy na tym, aby posunąć się tak daleko.
procinfo / win32 / procinfo.cpp
procinfo / macosx / procinfo.cpp
procinfo / linux / procinfo.cpp
procinfo / freebsd / procinfo.cpp
procinfo / procinfo.cpp
procinfo / procinfo.h
Pozwala to na uzyskanie pełnej ścieżki do pliku wykonywalnego prawie dowolnego identyfikatora procesu, z wyjątkiem tego, że w systemie Windows są pewne procesy z atrybutami bezpieczeństwa, które po prostu na to nie pozwalają, więc wysiwyg, to rozwiązanie nie jest idealne.
Aby dokładniej odpowiedzieć na pytanie, o które chodzi, możesz zrobić to:
procinfo.cpp
Zbuduj powyższą strukturę plików za pomocą tego polecenia:
procinfo.sh
Aby pobrać kopię plików wymienionych powyżej:
Aby uzyskać więcej korzyści związanych z procesami międzyplatformowymi:
https://github.com/time-killer-games/enigma-dev
Zobacz plik readme, aby zapoznać się z listą większości zawartych funkcji.
źródło
Jeśli używasz C ++ 17, możesz wykonać następujące czynności, aby uzyskać ścieżkę do pliku wykonywalnego.
Powyższa odpowiedź została przetestowana na Debianie 10 przy użyciu G ++ 9.3.0
źródło
Od C ++ 17:
Upewnij się, że dołączasz system plików std.
a teraz możesz to zrobić.
boost stał się częścią standardowego lib.
jeśli nie możesz go znaleźć, poszukaj pod:
źródło
To było moje rozwiązanie w systemie Windows. Nazywa się to tak:
Gdzie 64 to minimalny rozmiar, który Twoim zdaniem będzie. GetPathOfEXE wywołuje siebie rekurencyjnie, podwajając rozmiar bufora za każdym razem, aż otrzyma wystarczająco duży bufor, aby uzyskać całą ścieżkę bez obcięcia.
źródło
new
i (źle)delete
? Gdybyś użył astd::vector
, twój kod nie wykazywałby niezdefiniowanego zachowania.GetModuleFileNameW
nie ustawia ostatniego kodu błędu w przypadku sukcesu. Ten kod jest złamany na wiele sposobów. Nie używaj, jeśli się na to natkniesz.źródło
PathRemoveFileSpec()
Zamiast tego spójrz na i powiązane funkcje.w Uniksie (w tym Linuksie) spróbuj „który”, w Windows spróbuj „gdzie”.
źródło
Ta metoda działa zarówno w systemie Windows, jak i Linux:
źródło