Ich weiß, dass diese Frage schon einmal gestellt wurde, aber ich habe immer noch keine zufriedenstellende Antwort oder ein definitives "Nein, das geht nicht" gesehen, also werde ich noch einmal fragen!
Ich möchte lediglich den Pfad zur aktuell ausgeführten ausführbaren Datei entweder als absoluten Pfad oder relativ zu dem Ort, von dem aus die ausführbare Datei aufgerufen wird, plattformunabhängig abrufen. Ich dachte, boost :: filesystem :: initial_path war die Antwort auf meine Probleme, aber das scheint nur den 'plattformunabhängigen' Teil der Frage zu behandeln - es gibt immer noch den Pfad zurück, von dem aus die Anwendung aufgerufen wurde.
Für ein bisschen Hintergrundwissen ist dies ein Spiel mit Ogre, das ich mit Very Sleepy zu profilieren versuche, das die ausführbare Zieldatei aus seinem eigenen Verzeichnis ausführt, sodass das Spiel beim Laden natürlich keine Konfigurationsdateien usw. findet und sofort abstürzt . Ich möchte in der Lage sein, ihm einen absoluten Pfad zu den Konfigurationsdateien zu übergeben, von denen ich weiß, dass sie immer neben der ausführbaren Datei leben. Gleiches gilt für das Debuggen in Visual Studio. Ich möchte $ (TargetPath) ausführen können, ohne das Arbeitsverzeichnis festlegen zu müssen.
quelle
Antworten:
Es gibt keinen plattformübergreifenden Weg, den ich kenne.
Für Linux: readlink / proc / self / exe
Windows: GetModuleFileName
quelle
Die Funktion boost :: dll :: program_location ist eine der besten plattformübergreifenden Methoden, um den mir bekannten Pfad der laufenden ausführbaren Datei abzurufen. Die DLL-Bibliothek wurde Boost in Version 1.61.0 hinzugefügt.
Das Folgende ist meine Lösung. Ich habe es unter Windows, Mac OS X, Solaris, Free BSD und GNU / Linux getestet.
Es erfordert Boost 1.55.0 oder höher. Es verwendet die Boost.Filesystem-Bibliothek direkt und die Boost.Locale- Bibliothek und die Boost.System- Bibliothek indirekt.
src / executeable_path.cpp
src / detail / executeable_path_internals.cpp
include / boost / executeable_path.hpp
include / boost / detail / executeable_path_internals.hpp
Ich habe ein vollständiges Projekt, einschließlich einer Testanwendung und CMake- Builddateien , die unter SnKOpen - / cpp / executeable_path / trunk verfügbar sind . Diese Version ist vollständiger als die Version, die ich hier bereitgestellt habe. Es werden auch mehr Plattformen unterstützt.
Ich habe die Anwendung auf allen unterstützten Betriebssystemen in den folgenden vier Szenarien getestet.
In allen vier Szenarien funktionieren sowohl die Funktionen "Ausführbarer_Pfad" als auch "Ausführbarer_Pfad_Fallback" und geben dieselben Ergebnisse zurück.
Anmerkungen
Dies ist eine aktualisierte Antwort auf diese Frage. Ich habe die Antwort aktualisiert, um Benutzerkommentare und -vorschläge zu berücksichtigen. Ich habe auch einen Link zu einem Projekt in meinem SVN-Repository hinzugefügt.
quelle
argv[0]
kann auch nur ein ausführbarer Name sein. In diesem Fall wäre es erforderlich,PATH
auf * nix-Systemen danach zu suchen .Auf diese Weise wird Boost + Argv verwendet. Sie haben erwähnt, dass dies möglicherweise nicht plattformübergreifend ist, da es möglicherweise den Namen der ausführbaren Datei enthält oder nicht. Nun, der folgende Code sollte das umgehen.
Der folgende Code ruft das aktuelle Arbeitsverzeichnis ab, das möglicherweise das tut, was Sie benötigen
Hinweis Ich habe gerade festgestellt, dass
basename(
) veraltet war und daher zu wechseln musste.stem()
quelle
.parent_path()
, nicht.stem()
, nein?@Claudiu
gesagt, ich denke es sollte sein.parent_path()
.Ich bin mir bei Linux nicht sicher, aber versuche dies für Windows:
quelle
WCHAR ownPth..
um ein gewickeltes verwenden muss#ifdef UNICODE
. Wenn nicht, verwenden Sie den angegebenen Code.HMODULE hModule = GetModuleHandle(NULL);
Für Windows:
GetModuleFileName
- gibt den exe-Pfad + den exe-Dateinamen zurückDateiname entfernen
PathRemoveFileSpec
quelle
This function is deprecated. We recommend the use of the PathCchRemoveFileSpec function in its place
.C ++ 17, Windows, Unicode, mit Dateisystem neue API:
Ich vermute, diese Lösung sollte portabel sein, weiß aber nicht, wie Unicode auf anderen Betriebssystemen implementiert ist.
schwach_canonical wird nur benötigt, wenn Sie als Oberverzeichnis des Ausgabeverzeichnisses Verweise auf den oberen Ordner ('..') verwenden, um den Pfad zu vereinfachen. Wenn Sie es nicht verwenden - entfernen Sie es.
Wenn Sie mit einer dynamischen Linkbibliothek (.dll /.so) arbeiten, haben Sie möglicherweise kein argv. Dann können Sie die folgende Lösung in Betracht ziehen:
application.h:
application.cpp:
quelle
QT stellt dies mit der Betriebssystemabstraktion als QCoreApplication :: applicationDirPath () bereit.
quelle
QCoreApplication::applicationDirPath: Please instantiate the QApplication object first
. Irgendeine Idee, wie man das löst?QCoreApplication
wie dieseQApplication application(argc, argv);
(tun Sie dies in Ihremmain(argc, argv)
und stellen Sie sicher, dass Sie die nicht ändernargc/argv
, da diese über die Lebensdauer der QCoreApplication gültig bleiben müssen (siehe Dokumentation )Dies ist eine Windows-spezifische Methode, aber mindestens die Hälfte Ihrer Antwort.
GetThisPath.h
GetThisPath.cpp
mainProgram.cpp
Ich würde vorschlagen, die Plattformerkennung als Präprozessoranweisung zu verwenden, um die Implementierung einer Wrapper-Funktion zu ändern, die
GetThisPath
für jede Plattform aufruft .quelle
Verwenden Sie args [0] und suchen Sie nach '/' (oder '\\'):
BEARBEITET: Wenn '/' nicht existiert, pos == - 1, damit das Ergebnis korrekt ist.
quelle
args[0]
möglicherweise überhaupt kein Pfad.args[0]
nicht unbedingt der ausführbare Pfad zu sein, der mich stört. Vielen Dank für die Korrektur Ihrer Antwort für Windows :)Für Windows können Sie GetModuleFilename () verwenden.
Für Linux siehe
BinReloc (alte, nicht mehr funktionierende URL)Spiegel von BinReloc in den GitHub-Repositorys von datenwolf .quelle
Das Folgende funktioniert als schnelle und schmutzige Lösung, aber beachten Sie, dass es alles andere als narrensicher ist:
quelle
Falls Sie Unicode-Pfade für Windows verarbeiten müssen:
quelle
Unter Windows besteht das Problem, wie die ausführbare Datei aus dem Ergebnis von entfernt werden kann
GetModuleFileName()
. Der Windows-API-AufrufPathRemoveFileSpec()
, den Nate in seiner Antwort zu diesem Zweck verwendet hat, hat sich zwischen Windows 8 und seinen Vorgängern geändert. Wie kann man also mit beiden kompatibel und sicher bleiben? Zum Glück gibt es C ++ 17 (oder Boost, wenn Sie einen älteren Compiler verwenden). Ich mache das:quelle
Wie andere bereits erwähnt haben,
argv[0]
ist dies eine gute Lösung, vorausgesetzt, die Plattform übergibt tatsächlich den ausführbaren Pfad, was sicherlich nicht weniger wahrscheinlich ist als das Betriebssystem Windows (wobei WinAPI dabei helfen kann, den ausführbaren Pfad zu finden). Wenn Sie die Zeichenfolge entfernen möchten, um nur den Pfad zu dem Verzeichnis einzuschließen, in dem sich die ausführbare Datei befindet, ist die Verwendung dieses Pfads zum Suchen anderer Anwendungsdateien (z. B. Spiel-Assets, wenn Ihr Programm ein Spiel ist) vollkommen in Ordnung, da das Öffnen von Dateien relativ zu ist das Arbeitsverzeichnis oder, falls angegeben, das Stammverzeichnis.quelle
Damit bin ich gelandet
Die Header-Datei sieht folgendermaßen aus:
Implementierung
quelle
Die SDL2- Bibliothek ( https://www.libsdl.org/ ) verfügt über zwei Funktionen, die auf einem breiten Spektrum von Plattformen implementiert sind:
Wenn Sie also das Rad nicht neu erfinden möchten ... bedeutet dies leider, dass Sie die gesamte Bibliothek einbeziehen, obwohl es eine recht zulässige Lizenz hat und man den Code auch einfach kopieren kann. Außerdem bietet es viele andere plattformübergreifende Funktionen.
quelle
Dies ist wahrscheinlich der natürlichste Weg, dies zu tun, während die meisten wichtigen Desktop-Plattformen abgedeckt werden. Ich bin nicht sicher, aber ich glaube, dass dies mit allen BSDs funktionieren sollte, nicht nur mit FreeBSD, wenn Sie die Plattformmakroprüfung so ändern, dass sie alle abdeckt. Wenn ich jemals Solaris installieren sollte, werde ich diese Plattform sicher zur Liste der unterstützten hinzufügen.
Bietet volle UTF-8-Unterstützung unter Windows, die nicht jedem wichtig genug ist, um so weit zu gehen.
procinfo / win32 / procinfo.cpp
procinfo / macosx / procinfo.cpp
procinfo / linux / procinfo.cpp
procinfo / freebsd / procinfo.cpp
procinfo / procinfo.cpp
procinfo / procinfo.h
Dies ermöglicht es, den vollständigen Pfad zur ausführbaren Datei von so ziemlich jeder Prozess-ID abzurufen, außer unter Windows gibt es einige Prozesse mit Sicherheitsattributen, die dies einfach nicht zulassen. Daher ist diese Lösung nicht perfekt.
Um die Frage genauer zu beantworten, können Sie Folgendes tun:
procinfo.cpp
Erstellen Sie die obige Dateistruktur mit diesem Befehl:
procinfo.sh
Zum Herunterladen einer Kopie der oben aufgeführten Dateien:
Für mehr plattformübergreifende prozessbezogene Güte:
https://github.com/time-killer-games/enigma-dev
In der Readme-Datei finden Sie eine Liste der meisten enthaltenen Funktionen.
quelle
Ab C ++ 17:
Stellen Sie sicher, dass Sie das Standard-Dateisystem einschließen.
und jetzt kannst du das machen.
Das Boost-Dateisystem wurde Teil der Standardbibliothek.
Wenn Sie es nicht finden können, schauen Sie unter:
quelle
Dies war meine Lösung in Windows. Es heißt so:
Wobei 64 die Mindestgröße ist, von der Sie glauben, dass der Pfad sein wird. GetPathOfEXE ruft sich selbst rekursiv auf und verdoppelt jedes Mal die Größe des Puffers, bis er einen Puffer erhält, der groß genug ist, um den gesamten Pfad ohne Kürzung abzurufen.
quelle
new
und die (falsche)delete
? Wenn Sie a verwendet hättenstd::vector
, hätte Ihr Code kein undefiniertes Verhalten gezeigt.GetModuleFileNameW
bei Erfolg nicht der letzte Fehlercode festgelegt. Dieser Code ist in vielerlei Hinsicht kaputt. Nicht verwenden, wenn Sie zufällig darüber stolpern.quelle
PathRemoveFileSpec()
stattdessen die zugehörigen Funktionen an.Versuchen Sie unter Unix (einschließlich Linux) 'which', unter Windows 'where'.
quelle
Diese Methode funktioniert sowohl unter Windows als auch unter Linux:
quelle