¿Cómo uso correctamente SDL2 en mis programas?
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.
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_main
problemas: "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 reference
a 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_HANDLED
o #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.gz
desde 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.h
o 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 -Ipath
a su compilador flags, donde path
está el directorio donde SDL.h
se 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 include
el directorio SDL2_image encima del include
directorio SDL2 para tenerlo SDL_image.h
en el mismo directorio que SDL.h
.
Varios SDL_main
problemas
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 main
función. Tu main
funció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.h
en el archivo que define la main
función, incluso si no usa SDL directamente.
Intente evitarlo #define SDL_MAIN_HANDLED
o, #undef main
cuando lo resuelva, consulte el preámbulo para obtener una explicación.
undefined reference to
Varias 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_main
problemas" 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 path
está el directorio donde se encuentran libSDL2.dll.a
y 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.a
o 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 .a
archivos 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 -m32
y -m64
(agréguelos a los indicadores del compilador y del vinculador).
Llego undefined reference
a una función específica:
• undefined reference to WinMain
solo
Hay varias posibilidades, todas las cuales fueron cubiertas en la sección anterior:
- Olvidaste
-lmingw32
y/o-lSDL2main
las 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.a
archivo que utiliza no coincide con su compilador (archivo de 32 bits con un compilador de 64 bits o viceversa).
Intente evitarlo #define SDL_MAIN_HANDLED
o, #undef main
cuando lo resuelva, consulte el preámbulo para obtener una explicación.
• undefined reference to SDL_main
solo
Consulte la sección "Varios SDL_main
problemas" más arriba.
• undefined reference
a 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.
??.dll
no fue encontrado
Copie lo .dll
mencionado 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.dll
correos electrónicos diferentes: uno de 32 bits (en el i686-w64-mingw32
directorio) y otro de 64 bits (en x86_64-w64-mingw32
). Consiga el correcto; si es necesario, pruebe ambos.
Cualquier otra DLL estará en bin
el directorio de su compilador (el directorio donde gcc.exe
se 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 .dll
correos 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 .exe
tiene mayor prioridad.
Debe copiar todas las DLL que utiliza su programa (excepto las del sistema) en el directorio donde .exe
se 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 dosSDL2.dll
correos electrónicos diferentes: uno de 32 bits (en eli686-w64-mingw32
directorio) y otro de 64 bits (enx86_64-w64-mingw32
). Consiga el correcto; si es necesario, pruebe ambos.Copie todas las DLL del directorio de su compilador
bin
(el directorio dondegcc.exe
se 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
.exe
se 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 bin
a la RUTA (preferiblemente como la primera entrada) y colocarlo SDL2.dll
en el mismo directorio que .exe
o en algún directorio en la RUTA debería ser suficiente. para que su programa funcione.
Si esto funciona, puede ejecutarlo ntldd
sin 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 bin
directorio de su compilador (excepto SDL2.dll
).
Tenga en cuenta que la posibilidad de tener archivos DLL extraños C:\Windows
es real. Por ejemplo, Wine tiende a colocarse OpenAL32.dll
en C:\Windows
, por lo que si intenta este proceso con OpenAL en Wine, fallará . Si está creando un sciprt que se ejecuta ntldd
automá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 .exe
que no dependa de ningún correo electrónico (que no sea del sistema) .dll
utilizando el -static
indicador 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.pc
enviado con SDL, en la Libs.private
secció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 SDL2
para indicadores del compilador, pkg-config --libs SDL2
para 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
-mwindows
a las banderas del vinculador.
- R: Agregue
P: Recibo un error
'SDL_VideoMode' wasn't declared in this scope
.- R:
SDL_VideoMode
es 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.
- R:
P: Mi programa tiene el ícono de archivo predeterminado , pero quiero uno personalizado.
R: Su ícono debe estar en el
.ico
formato. Si su editor de gráficos no lo admite, cree una serie de.png
correos electrónicos de tamaños comunes (por ejemplo, 16x16, 32x32, 48x48, 64x64), luego conviértalos a uno solo.ico
usando ImageMagick :magick *.png result.ico
(o conconvert
en lugar demagick
).Cree un archivo con la
.rc
extensión (digamos,icon.rc
), con el siguiente contenidoMyIconName ICON "icon.ico"
(dondeMyIconName
es un nombre arbitrario y"icon.ico"
es la ruta al icono). Convierta el archivo a un.o
usandowindres -O res -i icon.rc -o icon.o
(elwindres
programa se envía con su compilador). Especifique el.o
archivo resultante al vincular, por ejemplog++ 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
.
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á vcpkg
un ejecutable. Luego ejecútelo vcpkg integrate install
para 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í .
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:
abrir aplicación de terminal (macOS)
CONFIGURACIÓN DE CONSTRUCCIÓN (seleccione la barra de búsqueda 'todos' y 'combinados', ingrese: "buscar")
haga clic en "rutas de búsqueda del encabezado (haga clic en el lado derecho)
agregar:
/usr/local/include
FASES DE CONSTRUCCIÓN --> ENLACE BIBLIOTECAS BINARIAS (haga clic en más)
escriba
SDL
--> haga clic en "agregar otro"presione: command+ SHIFT+ g(para abrir la barra de búsqueda)
escribir:
usr/local/Cellar
navegue a: SDL2 -->2.0.8 -->lib --> libSDL2-2.2.0.dylib (asegúrese de que no sea un acceso directo)