genbetadev / Genbeta-Dev-Engine

Desarrollo de un Game Engine básico sobre C++ y SFML 2.1
MIT License
63 stars 32 forks source link

Rutas relativas #40

Open adrigm opened 10 years ago

adrigm commented 10 years ago

Este debería ser un problema conocido para el que se haya enfrentado a proyectos multiplataformas.

En el gestor de recursos y en general en cualquier lugar que se trabaje con ficheros normalmente los buscaremos con rutas relativas al ejecutable ("Data/images/player.png"), donde Data está en el mismo directorio que el ejecutable.

El problema es que C++ las rutas relativas las calcula desde el directorio donde se está ejecutando, si tu en linux haces algo como:

$ ./algo/Test

Las rutas relativas te las va a calcular desde el directorio actual y no desde el directorio del ejecutable. Por lo que necesitamos utilizar rutas absolutas para que no falle.

La forma que se suele usar de resolver esto es obteniendo la ruta del ejecutable con argv[0]. No todos los sistema usan argv[0] para almacenar la ruta del ejecutable, pero si es lo más generalizado y en los sistemas a los que vamos a dar soporte sí lo hacen. Así que creo que sería la opción más acertada.

Otra opción es usar algo externo como Boost Filesystem que es un todo terreno para esto, pero prefiero, de momento, no meter grandes bibliotecas externas.

danigomez commented 10 years ago

Por mi parte me gustaria que usaramos Boost, porque nunca lo he usado y estaria bueno aprender alguna tecnología nueva, pero no sé si complica demasiado las cosas, vemos que opinan los demás, igualmente @adrigm tu decides!! jaja

adrigm commented 10 years ago

El problema de Boost es que es pesado de narices para un proyecto tan simple, encima filesystem no es de las que tenga solo headers sino que también tiene binarios.

RdlP commented 10 years ago

yo opto por no usar la librería Boost, más que nada porque puede dificultar la lectura de algo que se hace puramente con una intención didáctica, además se añadir más tamaño al proyecto.

DavidBM commented 10 years ago

Por mi usemos argv[0]. Que sistemas operativos no ponen la ruta ahí?

edoren commented 10 years ago

Voto por usar argv[0].

adrigm commented 10 years ago

Aquí hay una buena colección de formas nativas en cada sistema: http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe

Pero prefiriría huir de esto si es posible.

aarroyoc commented 10 years ago

Yo en mi experiencia de multiplataforma he encontrado dos métodos: 1. Usar las APIs del sistema en proyectos pequeños. En Linux tienes readlink(); usando como path /proc/self/exe y en Windows tienes GetModuleFileName();, puedes usar eso o, 2. usar un script en plataformas UNIX, ya que estas son la únicas que cargan los recursos así, en Windows da igual. El script sería similar a este: http://www.ogre3d.org/tikiwiki/tiki-index.php?page=Deploying%20Your%20Application#Building_and_Packaging_Dynamically

Estos son mis 2 centavos como dirían los ingleses.

ffgiraldez commented 10 years ago

Podríamos usar una interfaz y que en cada sistema operativo se utilize la mas común, cuanto mas código multiplataforma se use mejor, pero llegara un punto en el que no sea posible.

tendriamos una interfaz ResourceReader y luego las distintas implementaciones para cada SO

PD: se nota mucho q vengo del mundo Java, no?

dsocolobsky commented 10 years ago

argv[0] esta mal. Digamos que el binario esta en /usr/bin/genbetadev/juego pero nosotros lo llamamos desde la terminal con juego ... argv[0] va a ser igual a juego lo que, obviamente, esta completamente mal.

La manera "correcta" de hacerlo en C++ sería con boost::filesystem aunque como ya habeis dicho es algo pesado para incluir en un proyecto como este, aunque bueno, eso se puede discutir.

getcwd es una función que funciona en todos los sitemas POSIX (y Windows: http://msdn.microsoft.com/en-us/library/windows/desktop/aa364934(v=vs.85).aspx) y aparentemente es la manera correcta de obtenerlo. http://pic.dhe.ibm.com/infocenter/zos/v1r12/index.jsp?topic=%2Fcom.ibm.zos.r12.bpxbd00%2Frtgtc.htm

Por cierto, hay un draft para crear un std::filesystem Aunque siquiera esta implementado en C++11.

aarroyoc commented 10 years ago

getcwd devuelve el directorio desde el que fue llamado el ejecutable. Así puesejecutar test desde el mismo directorio y desde, por ejemplo, la raíz es diferente. Hay una posibilidad que es uniendo getcwd y argv[0], pero yo soy más partidario del script para Unix-like o las llamadas nativas.

angelnavarro commented 10 years ago

Una idea que no sé si es factible, pero por si acaso aquí la dejo. ¿Sería posible, al iniciar el programa, hacer un CD al directorio donde reside el ejecutable y a partir de ahí resolverlo todo con rutas relativas?

DavidBM commented 10 years ago

Buscando un poco he encontrado:

Windows:

int bytes = GetModuleFileName(NULL, pBuf, len);
if(bytes == 0)
        return -1;
else
        return bytes;

Linux:

char szTmp[32];
sprintf(szTmp, "/proc/%d/exe", getpid());
int bytes = MIN(readlink(szTmp, pBuf, len), len - 1);
if(bytes >= 0)
    pBuf[bytes] = '\0';
return bytes;

El código está sacado de: http://stackoverflow.com/questions/143174/how-do-i-get-the-directory-that-a-program-is-running-from

dsocolobsky commented 10 years ago

Hm, y en *nix no podemos hacer "whereis juego" ? Eso debería devolver el directorio donde se encuentra el Binario.

rickyah commented 10 years ago

Cómo exactamente usarías el whereis? No tiene sentido usar una aplicación de línea de comando para averiguar el directorio, invocada desde el propio ejecutable

danigomez commented 10 years ago

Según la documentación de Boost, para obtener el directorio actual del proceso llama current_path http://www.boost.org/doc/libs/1_32_0/libs/filesystem/doc/operations.htm#current_path, en el que usa getcwd en Linux y GetCurrentDirectory en Windows (Dice que son sus equivalentes en cada SO, por lo que podemos estimar que los usa) como mencionó @dysoco anteriormente, por lo que podriamos hacerlo de este modo,

rickyah commented 10 years ago

@LeonardoJegigzem creo que lo que tu dices no es lo que se busca. Esa función de boost te da el directorio actual, pero lo que buscamos es el directorio del ejecutable (que puede ser distinto)

En esta respuesta de SO dan una solución multiplataforma, que básicamente es lo que ha dicho @DavidBM http://stackoverflow.com/questions/933850/how-to-find-the-location-of-the-executable-in-c

adrigm commented 10 years ago

Quizás nos deberíamos plantear usar Boost Filesystem para el manejo del sistema de ficheros, nos ahorraríamos reinventar un sistema multiplataforma bien probado.

Para mi integrarlo no es problema, pero crearíamos dependencia de dos nuevas bibliotecas Boost::Filesystem y Boost::System (Filesystem depende de ella).

Aquí la cuestión sería si como SFML que cada uno copie las librerías o integrarlas en el proyecto. Yo soy de los que siempre compila Boost a pelo tanto en Windows como en Linux, pero quizás para los usuarios noveles deberíamos distribuir los binarios aunque sea de windows ya que en linux tenemos versiones de Boost en los repositorios. En OSX no sé si existe una forma sencillo de instalar binarios sin compilar el código fuente tu mismo.

rickyah commented 10 years ago

Boost en OSX se instala con Homebrew fácilmente: brew install boost

Y si no tienes homebrew en OSX... ¡mal hecho! ;) http://brew.sh

rickyah commented 10 years ago

@adrigm a mi usar Boost no me parece mala idea. Es una librería que se usa mucho, así que es una gran oportunidad para aprender. Además si vamos con cuidado y no abusamos puedes mantener las dependencias con Boost bajo control (e.g. a veces puedes añadir algo simplemente con referenciar un header)

Tienes mi voto :+1:

adrigm commented 10 years ago

Filesystem no es de las de solo headers como lo son la mayoría de Boost es de las pocas que tiene biblioteca, ademas depende de System que también tiene.

Es decir que hay que incluir los headers necesarios (hay que mirar cuantas dependencias hay en total) y a parte la parte compilada de System y Filesystem.

Por mi la usamos, ya he trabajado con Boost y es una delicia. Incluso se me ocurre que en el futuro (mucho más adelante) si queremos meter un lenguaje de scripts podemos hacer uso de Boost Python.

rickyah commented 10 years ago

Lo se lo se, digo que hay otras dependencias que son menos "duras". Que Filesystem tenga dependencias de librerías es lógico, ya que tiene que linkar con las librerías de cada diferente SOs.