Sé que esta pregunta se ha hecho antes, pero todavía no he visto una respuesta satisfactoria o un "no, esto no se puede hacer" definitivo, ¡así que volveré a preguntar!
Todo lo que quiero hacer es obtener la ruta al ejecutable que se está ejecutando actualmente, ya sea como una ruta absoluta o en relación con el lugar desde donde se invoca el ejecutable, de forma independiente de la plataforma. Pensé que boost :: filesystem :: initial_path era la respuesta a mis problemas, pero parece que solo maneja la parte 'independiente de la plataforma' de la pregunta: todavía devuelve la ruta desde la que se invocó la aplicación.
Para un poco de fondo, este es un juego que usa Ogre, que estoy tratando de perfilar usando Very Sleepy, que ejecuta el ejecutable de destino desde su propio directorio, por lo que, por supuesto, al cargar el juego no encuentra archivos de configuración, etc. y se bloquea rápidamente . Quiero poder pasarle una ruta absoluta a los archivos de configuración, que sé que siempre estarán junto al ejecutable. Lo mismo ocurre con la depuración en Visual Studio: me gustaría poder ejecutar $ (TargetPath) sin tener que configurar el directorio de trabajo.
fuente
Respuestas:
No hay una forma multiplataforma que yo sepa.
Para Linux: readlink / proc / self / exe
Windows: GetModuleFileName
fuente
La función boost :: dll :: program_location es uno de los mejores métodos multiplataforma para obtener la ruta del ejecutable en ejecución que conozco. La biblioteca DLL se agregó a Boost en la versión 1.61.0.
La siguiente es mi solución. Lo he probado en Windows, Mac OS X, Solaris, Free BSD y GNU / Linux.
Requiere Boost 1.55.0 o superior. Utiliza la biblioteca Boost.Filesystem directamente y la biblioteca Boost.Locale y la biblioteca Boost.System indirectamente.
src / ruta_ejecutable.cpp
src / detail / ruta_ejecutable_internals.cpp
incluir / boost / ruta_ejecutable.hpp
incluir / boost / detail / ruta_ejecutable_internals.hpp
Tengo un proyecto completo, que incluye una aplicación de prueba y archivos de compilación de CMake disponibles en SnKOpen - / cpp / ejecutable_path / trunk . Esta versión es más completa que la versión que proporcioné aquí. También es compatible con más plataformas.
He probado la aplicación en todos los sistemas operativos compatibles en los siguientes cuatro escenarios.
En los cuatro escenarios, las funciones ejecutable_path y ejecutable_path_fallback funcionan y devuelven los mismos resultados.
Notas
Ésta es una respuesta actualizada a esta pregunta. Actualicé la respuesta para tener en cuenta los comentarios y sugerencias de los usuarios. También agregué un enlace a un proyecto en mi Repositorio SVN.
fuente
argv[0]
también puede ser solo un nombre ejecutable, en cuyo caso sería necesario buscarlo en losPATH
sistemas * nix.De esta manera usa boost + argv. Mencionaste que esto puede no ser multiplataforma porque puede o no incluir el nombre del ejecutable. Bueno, el siguiente código debería solucionarlo.
El siguiente código obtiene el directorio de trabajo actual que puede hacer lo que necesita
Nota Acabo de darme cuenta de que
basename(
) estaba en desuso, así que tuve que cambiar a.stem()
fuente
.parent_path()
, no.stem()
, ¿no?@Claudiu
dije, creo que debería serlo.parent_path()
.No estoy seguro de Linux, pero prueba esto para Windows:
fuente
WCHAR ownPth..
, envuelto alrededor de a#ifdef UNICODE
en caso de que se compile con soporte Unicode. Si no es así, utilice el código proporcionado.HMODULE hModule = GetModuleHandle(NULL);
Para ventanas:
GetModuleFileName
- devuelve la ruta exe + nombre de archivo exePara eliminar el nombre de archivo
PathRemoveFileSpec
fuente
This function is deprecated. We recommend the use of the PathCchRemoveFileSpec function in its place
.C ++ 17, windows, unicode, usando la nueva api del sistema de archivos:
Sospecho que esta solución debería ser portátil, pero no sé cómo se implementa Unicode en otros sistemas operativos.
Débilly_canonical solo es necesario si utiliza como directorio de salida las referencias de la carpeta superior ('..') para simplificar la ruta. Si no lo usa, elimínelo.
Si está operando desde la biblioteca de enlaces dinámicos (.dll /.so), entonces es posible que no tenga argv, entonces puede considerar la siguiente solución:
application.h:
application.cpp:
fuente
QT proporciona esto con la abstracción del sistema operativo como QCoreApplication :: applicationDirPath ()
fuente
QCoreApplication::applicationDirPath: Please instantiate the QApplication object first
. ¿Alguna idea de cómo solucionar eso?QCoreApplication
like soQApplication application(argc, argv);
(haga esto en sumain(argc, argv)
, y asegúrese de no modificar elargc/argv
, ya que estos deben permanecer válidos durante la vida útil de QCoreApplication (consulte la documentación )Esta es una forma específica de Windows, pero es al menos la mitad de su respuesta.
GetThisPath.h
GetThisPath.cpp
mainProgram.cpp
Sugeriría usar la detección de plataforma como directivas de preprocesador para cambiar la implementación de una función contenedora que llama
GetThisPath
a cada plataforma.fuente
Usando args [0] y buscando '/' (o '\\'):
EDITADO: Si '/' no existe, pos == - 1 para que el resultado sea correcto.
fuente
args[0]
posible que en realidad no sea una ruta.args[0]
no ser necesariamente la ruta ejecutable lo que me molesta. Sin embargo, gracias por arreglar su respuesta para Windows :)Para Windows, puede usar GetModuleFilename ().
Para Linux, vea
BinReloc (URL antigua y difunta)espejo de BinReloc en los repositorios GitHub de datenwolf .fuente
Lo siguiente funciona como una solución rápida y sucia, pero tenga en cuenta que está lejos de ser infalible:
fuente
En caso de que necesite manejar rutas Unicode para Windows:
fuente
Para Windows, tiene el problema de cómo quitar el ejecutable del resultado de
GetModuleFileName()
. La llamada a la API de WindowsPathRemoveFileSpec()
que Nate usó para ese propósito en su respuesta cambió entre Windows 8 y sus predecesores. Entonces, ¿cómo seguir siendo compatible y seguro con ambos? Afortunadamente, existe C ++ 17 (o Boost, si está usando un compilador más antiguo). Hago esto:fuente
Como otros mencionaron,
argv[0]
es una solución bastante buena, siempre que la plataforma pase la ruta ejecutable, lo que seguramente no es menos probable que el sistema operativo Windows (donde WinAPI puede ayudar a encontrar la ruta ejecutable). Si desea quitar la cadena para incluir solo la ruta al directorio donde reside el ejecutable, entonces usar esa ruta para encontrar otros archivos de la aplicación (como activos del juego si su programa es un juego) está perfectamente bien, ya que abrir archivos es relativo a el directorio de trabajo o, si se proporciona, la raíz.fuente
Esto es con lo que terminé
El archivo de encabezado se ve así:
Implementación
fuente
La biblioteca SDL2 ( https://www.libsdl.org/ ) tiene dos funciones implementadas en un amplio espectro de plataformas:
Entonces, si no desea reinventar la rueda ... lamentablemente, significa incluir toda la biblioteca, aunque tiene una licencia bastante permisiva y también se podría simplemente copiar el código. Además, proporciona muchas otras funciones multiplataforma.
fuente
Esta es probablemente la forma más natural de hacerlo, al tiempo que cubre la mayoría de las principales plataformas de escritorio. No estoy seguro, pero creo que esto debería funcionar con todos los BSD, no solo con FreeBSD, si cambia la comprobación de macros de la plataforma para cubrirlos todos. Si alguna vez llego a instalar Solaris, me aseguraré de agregar esa plataforma a la lista compatible.
Cuenta con soporte completo para UTF-8 en Windows, que no a todos les importa lo suficiente como para llegar tan lejos.
procinfo / win32 / procinfo.cpp
procinfo / macosx / procinfo.cpp
procinfo / linux / procinfo.cpp
procinfo / freebsd / procinfo.cpp
procinfo / procinfo.cpp
procinfo / procinfo.h
Esto permite obtener la ruta completa al ejecutable de prácticamente cualquier ID de proceso, excepto que en Windows hay algunos procesos con atributos de seguridad que simplemente no lo permiten, así que wysiwyg, esta solución no es perfecta.
Para abordar lo que la pregunta preguntaba con mayor precisión, puede hacer lo siguiente:
procinfo.cpp
Construya la estructura de archivo anterior con este comando:
procinfo.sh
Para descargar una copia de los archivos enumerados anteriormente:
Para obtener más ventajas relacionadas con los procesos multiplataforma:
https://github.com/time-killer-games/enigma-dev
Consulte el archivo Léame para obtener una lista de la mayoría de las funciones incluidas.
fuente
Si usa C ++ 17, puede hacer lo siguiente para obtener la ruta al ejecutable.
La respuesta anterior ha sido probada en Debian 10 usando G ++ 9.3.0
fuente
A partir de C ++ 17:
Asegúrese de incluir el sistema de archivos std.
y ahora puedes hacer esto.
El sistema de archivos boost se convirtió en parte de la lib estándar.
si no puede encontrarlo, intente buscar debajo:
fuente
Esta fue mi solución en Windows. Se llama así:
Donde 64 es el tamaño mínimo que cree que tendrá la ruta. GetPathOfEXE se llama a sí mismo de forma recursiva, duplicando el tamaño del búfer cada vez hasta que obtiene un búfer lo suficientemente grande como para obtener la ruta completa sin truncamiento.
fuente
new
y el (incorrecto)delete
? Si hubiera utilizado unstd::vector
, su código no habría mostrado un comportamiento indefinido.GetModuleFileNameW
no establece el último código de error en caso de éxito. Ese código está roto de muchas maneras. No lo use si se encuentra con esto.fuente
PathRemoveFileSpec()
las funciones relacionadas.en Unix (incluido Linux) intente 'cuál', en Windows intente 'dónde'.
fuente
Este método funciona tanto para Windows como para Linux:
fuente