¿Cómo uso correctamente SDL2 en mis programas?

Resuelto HolyBlackCat asked hace 3 años • 3 respuestas

Quiero crear un juego usando SDL2, pero no puedo compilar ni ejecutar mi código, ¡por favor ayuda!

SDL2 es muy difícil de configurar y, a menudo, es la primera biblioteca que los aspirantes a desarrolladores de juegos intentan utilizar.

Esta publicación pretende ser un duplicado canónico de problemas comunes con la configuración de SDL2.

HolyBlackCat avatar Oct 17 '20 05:10 HolyBlackCat
Aceptado

Esta respuesta es sobre MinGW/GCC, y no sobre Visual Studio.

Esta respuesta solo se aplica a Windows.


Errores comunes

Los errores comunes son:

  • SDL.h: No such file or directory(al compilar)
  • Varios SDL_mainproblemas: "referencia no definida a SDL_main", "tipos conflictivos para SDL_main" o "el número de argumentos no coincide con el prototipo", etc. (al compilar o vincular)
  • undefined referencea otras funciones (al vincular)
  • Problemas con DLL: (al ejecutar su programa)
    • '??.dll' was not found
    • procedure entry point ... could not be located in ...y otros errores misteriosos relacionados con DLL
    • El programa aparentemente no hace nada cuando se inicia

Esta lista está ordenada de mala a buena. Si cambia algo y obtiene un error diferente, use esta lista para saber si mejoró o empeoró las cosas.


El preámbulo

0. No sigas malos consejos.

Algunos recursos le sugerirán que haga #define SDL_MAIN_HANDLEDo #undef main. No siga ciegamente ese consejo, no es así como se debe utilizar SDL2.

Si haces todo correctamente, nunca será necesario. Aprenda primero el enfoque previsto. Luego podrás investigar qué hace exactamente eso y tomar una decisión informada.

1. Descubra cómo compilar directamente desde la consola; puede comenzar a usar un IDE y/o un sistema de compilación más adelante. Si está utilizando un IDE, le sugiero que primero se asegure de poder compilar su programa directamente desde la consola, para descartar cualquier problema de configuración del IDE. Una vez que lo hayas descubierto, puedes usar las mismas opciones del compilador en tu IDE.

Lo mismo se aplica a los sistemas de compilación, como CMake.

2. Descargue los archivos SDL2 correctos . Asegúrate de tener los archivos correctos. Necesita el archivo llamado SDL2-devel-2.0.x-mingw.tar.gzdesde aquí .

Extráigalo a cualquier directorio, preferiblemente en algún lugar cerca de su código fuente. Extraerlos al directorio de instalación del compilador a menudo se considera una mala práctica (y también lo es copiarlos en C:\Windows, lo cual es una idea horrible).

3. Conozca la diferencia entre indicadores del compilador y indicadores del enlazador . Una "bandera" es una opción que usted especifica en la línea de comando al crear su programa. Cuando usa un solo comando, por ejemplo g++ foo.cpp -o foo.exe, todas sus banderas se agregan al mismo lugar (a este único comando).

Pero cuando construyes tu programa en dos pasos, por ejemplo:

  • g++ foo.cpp -c -o foo.o(compilando)
  • g++ foo.o -o foo.exe(enlace)

tienes que saber a cuál de los dos comandos agregar una bandera. Esos son "indicadores del compilador" y "indicadores del vinculador", respectivamente.

La mayoría de los IDE requerirán que especifiques los indicadores del compilador y del enlazador por separado, por lo que incluso si usas un solo comando ahora , es bueno saber qué indicador va a cada lugar.

A menos que se especifique lo contrario, el orden de las banderas no importa.


SDL.h: No such file or directory

O cualquier error similar relacionado con incluir SDL.ho SDL2/SDL.h.

Debe indicarle a su compilador dónde buscar SDL.h. Está en los archivos SDL que has descargado (ver preámbulo).

Agregue -Ipatha su compilador flags, donde pathestá el directorio donde SDL.hse encuentra.

Ejemplo: -IC:/Users/HolyBlackCat/Downloads/SDL2-2.0.12/x86_64-w64-mingw32/include/SDL2. Las rutas relativas también funcionan, por ejemplo -ISDL2-2.0.12/x86_64-w64-mingw32/include/SDL2.

Tenga en cuenta que la ruta será diferente dependiendo de cómo escriba #include:

  • Si lo hace #include <SDL.h>, entonces la ruta debería terminar en .../include/SDL2(como arriba). Esta es la forma recomendada.
  • Si lo hace #include <SDL2/SDL.h>, entonces la ruta debería terminar en .../include.

Nota: SDL2_image (y probablemente otros complementos de SDL) se utilizan #include "SDL.h"en sus encabezados. Por lo tanto, debe usar la opción anterior o copiar includeel directorio SDL2_image encima del includedirectorio SDL2 para tenerlo SDL_image.hen el mismo directorio que SDL.h.


Varios SDL_mainproblemas

Puede obtener varios errores diferentes al mencionar SDL_main, como undefined reference to SDL_main, o conflicting types for 'SDL_main', o number of arguments doesn't match prototype, etc.

Necesitas tener una mainfunción. Tu mainfunción debe verse así int main(int, char **). NO int main() y NO void main() . Esta es una peculiaridad de SDL2, relacionada con su funcionamiento #define main SDL_main.

Se permite agregar nombres de parámetros (y es obligatorio en C), por ejemplo int main(int argc, char **argv). Además, el segundo parámetro se puede escribir como char *[]o con un nombre: char *argv[]. No se permiten otros cambios.

Si su proyecto tiene varios archivos fuente, asegúrese de incluirlos SDL.hen el archivo que define la mainfunción, incluso si no usa SDL directamente.

Intente evitarlo #define SDL_MAIN_HANDLEDo, #undef maincuando lo resuelva, consulte el preámbulo para obtener una explicación.


undefined reference toVarias funciones

undefined reference to SDL_...

El mensaje de error mencionará varias SDL_...funciones y/o WinMain. Si menciona SDL_main, consulte la sección "Varios SDL_mainproblemas" más arriba. Si los nombres de las funciones no comienzan con SDL_, consulte la sección "referencia indefinida a otras funciones" a continuación.

Debe agregar los siguientes indicadores del vinculador: -lmingw32 -lSDL2main -lSDL2 -Lpath, donde pathestá el directorio donde se encuentran libSDL2.dll.ay libSDL2main.a(que ha descargado). El orden de las -l...banderas importa. Deben aparecer DESPUÉS de cualquier archivo .c// ..cpp.o

Ejemplo: -LC:/Users/HolyBlackCat/Desktop/SDL2-2.0.12/x86_64-w64-mingw32/lib. Las rutas relativas también funcionan, por ejemplo -LSDL2-2.0.12/x86_64-w64-mingw32/lib.

Cuando usas -l???, el vinculador buscará un archivo llamado lib???.dll.ao lib???.a(y algunas otras variantes), por lo que necesitamos pasar la ubicación de esos archivos. libmingw32.a(correspondiente a -lmingw32) se envía con su compilador, por lo que ya sabe dónde encontrarlo.

Agregué todas esas banderas y nada cambió, o obtengo skipping incompatible X when searching for Y:

Probablemente utilice .aarchivos SDL incorrectos. El archivo que descargó contiene dos conjuntos de archivos: i686-w64-mingw32(32 bits) y x86_64-w64-mingw32(64 bits). Debe utilizar los archivos que coincidan con su compilador, que también pueden ser de 32 o 64 bits.

Imprima (8*sizeof(void*))para ver si su compilador es de 32 o 64 bits.

Incluso si cree que utiliza los archivos correctos, pruebe con los demás para estar seguro.

Algunas versiones de MinGW se pueden cambiar entre los modos de 32 y 64 bits usando indicadores -m32y -m64(agréguelos a los indicadores del compilador y del vinculador).

Llego undefined referencea una función específica:

undefined reference to WinMainsolo

Hay varias posibilidades, todas las cuales fueron cubiertas en la sección anterior:

  • Olvidaste -lmingw32y/o -lSDL2mainlas banderas del vinculador.
    Debe utilizar los siguientes indicadores del vinculador, en este orden exacto, después de cualquier archivo .c// :.cpp.o-lmingw32 -lSDL2main -lSDL2
  • El libSDL2main.aarchivo que utiliza no coincide con su compilador (archivo de 32 bits con un compilador de 64 bits o viceversa).

Intente evitarlo #define SDL_MAIN_HANDLEDo, #undef maincuando lo resuelva, consulte el preámbulo para obtener una explicación.

undefined reference to SDL_mainsolo

Consulte la sección "Varios SDL_mainproblemas" más arriba.

undefined referencea otras funciones

Su vinculador encontró y usó libSDL2.a, pero debería buscar y usar libSDL2.dll.a. Cuando ambos están disponibles, prefiere el último de forma predeterminada, lo que significa que no copió este último en el directorio al que pasó -L.

Si tenía intención de realizar enlaces estáticos, consulte la sección denominada "¿Cómo distribuyo mi aplicación a otros?" abajo.


No pasa nada cuando intento ejecutar mi aplicación.

Supongamos que intenta ejecutar su aplicación y no sucede nada. Incluso si intenta imprimir algo al principio de main(), no se imprime.

Windows tiene la mala costumbre de no mostrar algunos errores relacionados con DLL cuando el programa se inicia desde la consola.

Si estaba ejecutando su aplicación desde la consola (o desde un IDE), intente hacer doble clic en el EXE en el explorador. Lo más probable es que ahora vea algún error relacionado con la DLL; luego consulte una de las siguientes secciones.


??.dllno fue encontrado

Copie lo .dllmencionado en el mensaje de error y colóquelo junto a su archivo .exe.

Si la DLL se llama SDL2.dll, entonces está en los archivos SDL que descargó (consulte el preámbulo). Tenga en cuenta que hay dos SDL2.dllcorreos electrónicos diferentes: uno de 32 bits (en el i686-w64-mingw32directorio) y otro de 64 bits (en x86_64-w64-mingw32). Consiga el correcto; si es necesario, pruebe ambos.

Cualquier otra DLL estará en binel directorio de su compilador (el directorio donde gcc.exese encuentra).

Es posible que tengas que repetir este proceso de 3 a 4 veces, esto es normal.

Para conocer una forma automática de determinar las DLL necesarias, consulte la siguiente sección.


procedure entry point ... could not be located in ...y otros errores crípticos de DLL

Su programa necesita varios .dllcorreos electrónicos para ejecutarse y encontró una versión incorrecta de uno, sobrante de algún otro programa que haya instalado.

Busca archivos DLL en varios lugares diferentes, pero el directorio con el .exetiene mayor prioridad.

Debe copiar todas las DLL que utiliza su programa (excepto las del sistema) en el directorio donde .exese encuentra.

Una forma confiable de obtener una lista de las DLL necesarias es copiar ciegamente un montón de DLL y luego eliminar las que resulten innecesarias:

  • Copiar SDL2.dll. Está en los archivos SDL que has descargado (ver preámbulo). Tenga en cuenta que hay dos SDL2.dllcorreos electrónicos diferentes: uno de 32 bits (en el i686-w64-mingw32directorio) y otro de 64 bits (en x86_64-w64-mingw32). Consiga el correcto; si es necesario, pruebe ambos.

  • Copie todas las DLL del directorio de su compilador bin(el directorio donde gcc.exese encuentra).

  • Ahora su programa debería ejecutarse, pero aún no hemos terminado.

  • Descargue NTLDD (o algún otro programa que muestre una lista de DLL usados). Correr ntldd -R your_program.exe.

  • Cualquier DLL que no se mencione en su resultado debe eliminarse del directorio actual. Su programa utiliza todo lo que queda.

Terminé con las siguientes DLL, espero algo similar: SDL2.dll, libgcc_s_seh-1.dll, libstdc++-6.dll(solo C++), libwinpthread-1.dll.

¿Puedo determinar las DLL necesarias sin copiar las excesivas?

Sí, pero es menos confiable.

Su programa busca archivos DLL en las siguientes ubicaciones, en este orden:

  • El directorio donde .exese encuentra.
  • C:\Windows, incluidos algunos de sus subdirectorios.
  • Los directorios enumerados en PATH .

Suponiendo que usted (o algún instalador basura) no haya colocado ninguna DLL personalizada C:\Windows, agregar el directorio de su compilador bina la RUTA (preferiblemente como la primera entrada) y colocarlo SDL2.dllen el mismo directorio que .exeo en algún directorio en la RUTA debería ser suficiente. para que su programa funcione.

Si esto funciona, puede ejecutarlo ntlddsin copiar ninguna DLL de antemano y copiar sólo las necesarias. La razón por la que querrás copiarlos en este momento (ya que tu aplicación ya funciona) es para poder distribuirla a otras personas, sin que tengan que instalar el compilador para sus DLL. Omita cualquier archivo DLL ubicado fuera del bindirectorio de su compilador (excepto SDL2.dll).

Tenga en cuenta que la posibilidad de tener archivos DLL extraños C:\Windowses real. Por ejemplo, Wine tiende a colocarse OpenAL32.dllen C:\Windows, por lo que si intenta este proceso con OpenAL en Wine, fallará . Si está creando un sciprt que se ejecuta ntlddautomáticamente, prefiera copiar las DLL (o al menos vincularlas simbólicamente; escuché que MSYS2 puede emular enlaces simbólicos en Windows).

¿Puedo crear un EXE que no dependa de ninguna DLL?

Es posible crear un enlace .exeque no dependa de ningún correo electrónico (que no sea del sistema) .dllutilizando el -staticindicador del vinculador, esto se denomina "enlace estático". Esto rara vez se hace y no debería ser necesario hacerlo si realizó los pasos anteriores correctamente. Esto requiere algunas banderas de enlazador adicionales; se enumeran en el archivo ??-w64-mingw32/lib/pkgconfig/sdl2.pcenviado con SDL, en la Libs.privatesección. Observe que hay dos archivos, para x32 y x64 respectivamente.


¿Cómo distribuyo mi aplicación a otros?

Siga los pasos de la sección anterior, titulada procedure entry point ... could not be located in ....


¿Una alternativa más sensata?

Existe MSYS2 .

Tiene un administrador de paquetes que le permite descargar bibliotecas prediseñadas y, como beneficio adicional, una versión nueva del compilador.

Instale SDL2 desde su administrador de paquetes. Utilice una herramienta llamada pkg-config(también del administrador de paquetes) para determinar automáticamente todos los indicadores necesarios ( pkg-config --cflags SDL2para indicadores del compilador, pkg-config --libs SDL2para indicadores del enlazador).

Esta es la misma experiencia que tendría en Linux (tal vez excepto por algunos problemas de administración de DLL).


Bonificación: otros problemas

  • P: Mi programa siempre abre una ventana de consola cuando lo ejecuto, ¿cómo lo oculto?

    • R: Agregue -mwindowsa las banderas del vinculador.
  • P: Recibo un error'SDL_VideoMode' wasn't declared in this scope .

    • R: SDL_VideoModees de SDL1.2, no forma parte del SDL2 más nuevo. Su código fue escrito para la versión obsoleta de SDL. Encuentre un tutorial mejor que trate específicamente con SDL2.
  • P: Mi programa tiene el ícono de archivo predeterminado , pero quiero uno personalizado.

    • R: Su ícono debe estar en el .icoformato. Si su editor de gráficos no lo admite, cree una serie de .pngcorreos electrónicos de tamaños comunes (por ejemplo, 16x16, 32x32, 48x48, 64x64), luego conviértalos a uno solo .icousando ImageMagick : magick *.png result.ico(o con converten lugar de magick).

      Cree un archivo con la .rcextensión (digamos, icon.rc), con el siguiente contenido MyIconName ICON "icon.ico"(donde MyIconNamees un nombre arbitrario y "icon.ico"es la ruta al icono). Convierta el archivo a un .ousando windres -O res -i icon.rc -o icon.o(el windresprograma se envía con su compilador). Especifique el .oarchivo resultante al vincular, por ejemplo g++ foo.cpp icon.o -o foo.exe.

      Las versiones recientes de SDL2 tienen la buena propiedad de usar el mismo ícono que el ícono de la ventana, por lo que no es necesario usarlo SDL_SetWindowIcon.

HolyBlackCat avatar Oct 16 '2020 22:10 HolyBlackCat

Una solución para Visual Studio:

¿Por qué no utilizar un administrador de paquetes? Yo uso vcpkg y hace que sea muy fácil consumir bibliotecas de terceros. Tome la fuente de vcpkg y extráigala a un lugar seguro, como C:/, luego ejecute su script de arranque bootstrap-vcpkg.bat, esto generará vcpkgun ejecutable. Luego ejecútelo vcpkg integrate installpara que las bibliotecas instaladas con vcpkg estén disponibles en Visual Studio.

Busque la biblioteca que necesita:

vcpkg search sdl

imgui[sdl2-binding]                   Make available SDL2 binding
libwebp[vwebp-sdl]                    Build the vwebp viewer tool.
magnum[sdl2application]               Sdl2Application library
sdl1                 1.2.15#12        Simple DirectMedia Layer is a cross-platform development library designed to p...
sdl1-net             1.2.8-3          Networking library for SDL
sdl2                 2.0.12-1         Simple DirectMedia Layer is a cross-platform 
...

Instálalo con: vcpkg install sdl2.

Ahora sólo necesita incluir encabezados SDL2 y todo funcionará de inmediato. La biblioteca se vinculará automáticamente.

Puede obtener más información sobre vcpkg aquí .

 avatar Oct 20 '2020 20:10

En Mac, esto es lo que sigo para XCode (debo instalar g++):

enlace sdl:

g++ main.cpp -o main $(sdl2-config --cflags --libs)

Pasos del proyecto XCODE:

  1. abrir aplicación de terminal (macOS)

  2. CONFIGURACIÓN DE CONSTRUCCIÓN (seleccione la barra de búsqueda 'todos' y 'combinados', ingrese: "buscar")

  3. haga clic en "rutas de búsqueda del encabezado (haga clic en el lado derecho)

  4. agregar:/usr/local/include

  5. FASES DE CONSTRUCCIÓN --> ENLACE BIBLIOTECAS BINARIAS (haga clic en más)

  6. escriba SDL--> haga clic en "agregar otro"

  7. presione: command+ SHIFT+ g(para abrir la barra de búsqueda)

  8. escribir:usr/local/Cellar

  9. navegue a: SDL2 -->2.0.8 -->lib --> libSDL2-2.2.0.dylib (asegúrese de que no sea un acceso directo)

Skyy avatar Oct 16 '2020 23:10 Skyy