SDL在包含SDL2/SDL_Image时包含错误



这里有一个简单的SDL2程序,它使用SDL_Image并运行良好:

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
// Manage error messages
void check_error_sdl(bool check, const char* message);
void check_error_sdl_img(bool check, const char* message);
// Load an image from "fname" and return an SDL_Texture with the content of the image
SDL_Texture* load_texture(const char* fname, SDL_Renderer *renderer);

int main(int argc, char** argv) {
// Initialize SDL
check_error_sdl(SDL_Init(SDL_INIT_VIDEO) != 0, "Unable to initialize SDL");

// Create and initialize a 800x600 window
SDL_Window* window = SDL_CreateWindow("Test SDL 2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
800, 600, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);
check_error_sdl(window == nullptr, "Unable to create window");

// Create and initialize a hardware accelerated renderer that will be refreshed in sync with your monitor (at approx. 60 Hz)
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
check_error_sdl(renderer == nullptr, "Unable to create a renderer");

// Set the default renderer color to corn blue
SDL_SetRenderDrawColor(renderer, 100, 149, 237, 255);

// Initialize SDL_img
int flags=IMG_INIT_JPG | IMG_INIT_PNG;
int initted = IMG_Init(flags);
check_error_sdl_img((initted & flags) != flags, "Unable to initialize SDL_image");

// Load the image in a texture
SDL_Texture *texture = load_texture("img_test.png", renderer);

// We need to create a destination rectangle for the image (where we want this to be show) on the renderer area
SDL_Rect dest_rect;
dest_rect.x = 50; dest_rect.y = 50;
dest_rect.w = 337; dest_rect.h = 210;

// Clear the window content (using the default renderer color)
SDL_RenderClear(renderer);

// Copy the texture on the renderer
SDL_RenderCopy(renderer, texture, NULL, &dest_rect);

// Update the window surface (show the renderer)
SDL_RenderPresent(renderer);

// Wait for 10 seconds
SDL_Delay(5000);

// Clear the allocated resources
SDL_DestroyTexture(texture);
IMG_Quit();
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();

return 0;
}
// In case of error, print the error code and close the application
void check_error_sdl(bool check, const char* message) {
if (check) {
std::cout << message << " " << SDL_GetError() << std::endl;
SDL_Quit();
std::exit(-1);
}
}
// In case of error, print the error code and close the application
void check_error_sdl_img(bool check, const char* message) {
if (check) {
std::cout << message << " " << IMG_GetError() << std::endl;
IMG_Quit();
SDL_Quit();
std::exit(-1);
}
}
// Load an image from "fname" and return an SDL_Texture with the content of the image
SDL_Texture* load_texture(const char* fname, SDL_Renderer *renderer) {
SDL_Surface *image = IMG_Load(fname);
check_error_sdl_img(image == nullptr, "Unable to load image");

SDL_Texture *img_texture = SDL_CreateTextureFromSurface(renderer, image);
check_error_sdl_img(img_texture == nullptr, "Unable to create a texture from the image");
SDL_FreeSurface(image);
return img_texture;
}

我用编译它

g++ -std=c++0x -Wall -pedantic sdl2_test.cpp -o sdl2_test `sdl2-config --cflags --libs` -lSDL2_image

它正确地执行和显示图像。

然而,在我在同一系统上的游戏中,我在编译时遇到了这个错误:

g++ -c frogmain.cc
In file included from level.hh:2,
from game.hh:1,
from frogmain.cc:2:
/usr/local/include/SDL2/SDL_image.h:27:10: fatal error: SDL.h: No such file or directory
#include "SDL.h"
^~~~~~~
compilation terminated.
make: *** [makefile:5: frogmain.o] Error 1

这是我的makefile:

FrogGame: frogmain.o game.o level.o sprite.o actor.o vector.o
g++ -std=c++0x -Wall -pedantic -o FrogGame frogmain.o game.o level.o sprite.o actor.o vector.o `sdl2-config --cflags --libs` -lSDL2_image
#g++ -o FrogGame frogmain.o game.o level.o sprite.o actor.o vector.o

frogmain.o: frogmain.cc game.hh level.hh sprite.hh vector.hh
g++ -c frogmain.cc

game.o: game.cc level.hh sprite.hh actor.hh vector.hh
g++ -c game.cc

level.o: level.cc sprite.hh actor.hh vector.hh
g++ -c level.cc
actor.o: actor.cc vector.hh
g++ -c actor.cc
sprite.o: sprite.cc vector.hh
g++ -c sprite.cc
vector.o: vector.cc
g++ -c vector.cc

唯一需要SDL的类是级别类,这里是.cc文件:

#include <iostream>
#include <sys/time.h>
#include <chrono>
#include "level.hh"
#include "sprite.hh"
#include "actor.hh"
#include "vector.hh"
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
using namespace std;
level::level()
{
this->levelPlaying = false;
this->levelPaused = false;
this->levelWon = false;
this->curTime = 0;
this->timeLimit = 0;
this->screen = 0;
this->renderer = 0;
this->imageArray = 0;
this->imLength = 0;

this->createScreen();
}
void level::setLevelPlaying(bool p)
{
this->levelPlaying = p;
}
bool level::getLevelPlaying()
{
return this->levelPlaying;
}
void level::setLevelPaused(bool p)
{
this->levelPlaying = p;
}
bool level::getLevelPaused()
{
return this->levelPlaying;
}
void level::setLevelWon(bool p)
{
this->levelWon = p;
}
bool level::getLevelWon()
{
return this->levelWon;
}
void level::setCurTime(int t)
{
this->curTime = t;
}
int level::getCurTime()
{
return this->curTime;
}
void level::setTimeLimit(int t)
{
this->timeLimit = t;
}
int level::getTimeLimit()
{
return this->timeLimit;
}
bool level::createScreen()
{
bool success = 0;
//get size of screen
SDL_DisplayMode dm;
SDL_GetDesktopDisplayMode(0, &dm);
if (dm.w < 1920 && dm.h < 1080)
{
screenW = dm.w;
screenH = dm.h;
}
else
{
screenW = 1920;
screenH = 1080;
}
success = this->checkSDLError(SDL_Init(SDL_INIT_EVERYTHING) == 0, "SDL Initialization failed");

this->screen = SDL_CreateWindow("Test SDL 2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
screenW, screenH, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);

success = this->checkSDLError(this->screen, "Window Initialization failed");

this->renderer = SDL_CreateRenderer(this->screen, -1, 0);
success = this->checkSDLError(this->renderer, "Renderer Initialization failed");

return success;
}
bool level::loadImageArrayToMemory(const char** imageNames, int length)
{
IMG_Init(IMG_INIT_PNG);
//allocate space for all textures
this->imageArray = new SDL_Texture*[length];
this->imLength = length;
//run through entire list
for (int i = 0; i < length; i++)
{
//load the image to a temp surface
SDL_Surface* tmp = IMG_Load(imageNames[i]);
this->checkSDLError(tmp, "Unable to load image");
//create a texture from the surface, for hardware rendering
this->imageArray[i] = SDL_CreateTextureFromSurface(this->renderer, tmp);
this->checkSDLError(imageArray[i], "Unable to create texture");
//destroy the surface
SDL_FreeSurface(tmp);
}
return 1;
}
bool level::destroyImageArrayFromMemory()
{
//loop through image array
for (int i = 0; i < this->imLength; i++)
{
//destroy the texture in each index of the array
SDL_DestroyTexture(imageArray[i]);
}
//delete the array
delete[] imageArray;

return 1;
}
bool level::loadSoundArrayToMemory()
{
//TODO
return 0;
}
bool level::destroySoundArrayFromMemory()
{
//TODO
return 0;
}
bool level::levelLoop()
{
const int TPF = 33;
auto curT = chrono::high_resolution_clock::now();
auto prevT = curT;
auto diff = 0;

vector p(4,5);
vector d(78,90);

actor a(p, d, 1, 100);

while (this->getLevelPlaying())
{
//create a destination rectangle for the images
SDL_Rect tmp;
tmp.x= 0;
tmp.y = 0;
tmp.w = 1920;
tmp.h = 1080; 

//get current time
curT = chrono::high_resolution_clock::now();
//get the difference of the current time from the last time the screen was updated
diff = chrono::duration_cast<chrono::milliseconds>(curT - prevT).count();
if (diff > TPF)
{
//check for keyboard input
this->checkForInput();

//clear the screen
SDL_RenderClear(this->renderer);

//for every texture in the imageArray
for (int i = 0; i < imLength; i++)
{
tmp.x = tmp.x + 20;
tmp.y = tmp.y + 20;
// Copy the texture on the renderer
SDL_RenderCopy(this->renderer, this->imageArray[i], NULL, &tmp);
// Update the window surface (show the renderer)
SDL_RenderPresent(this->renderer);
}

prevT = curT;

//add to the current level time
this->curTime+=diff;
}
if (this->curTime > 4000)
{
this->setLevelPlaying(false);
}
}
//destroy images in memory to free up space and avoid leaks
this->destroyImageArrayFromMemory();

return this->getLevelWon();
}
void level::checkForInput()
{
cout << "inside checkforinputn";
//create an empty event
//SDL_Event event;
//loop through all events in the queue
while (SDL_PollEvent(&event))
{
cout << "inside while loopn";
switch(event.type)
{
//cout << "inside switchn";
//a keyboard button is pressed down
case SDL_KEYDOWN:
cout << "inside casen";
//if it is escape key
if (event.key.keysym.sym == SDLK_ESCAPE)
{
cout << "Escape key pressed" << endl;
this->setLevelPlaying(false);
}
else if (event.key.keysym.sym == SDLK_q)
{
cout << "Q key pressed" << endl;
}
continue;
default:
cout << "unhandled key pressedn";
}
}
}
bool level::checkSDLError(bool c, const char* s)
{
if (c == 0)
{
std::cout << s << " " << SDL_GetError() << endl;
SDL_Quit();
return 0;
}
return 1;
}

我安装了SDL2和SDL2Image。我的makefile有问题吗?这就是为什么我可以在这个简单的例子中使用SDLImage,但不能在我更复杂的程序中使用?我有另一个树莓派,我的游戏的例子和makefile都能正常工作。

编译.cc[到.o]时,您没有在生成文件中将-I传递到c++

您只传递c++行上用于链接.o文件的标志。

.o目标之一的c++命令也需要sdl2-config


这是你眼前的问题。然而

当您执行:sdl2-config --cflags时,它[部分]生成(例如(-I/usr/local/include/SDL2,因此如果执行了:#include <SDL.h>,则源.cc文件将工作。

但是,您的.cc文件确实是:#include <SDL2/SDL.h>

这可能不起作用,因为它位于不同的目录级别[除非您添加-I/usr/local/include,这是次优的,因为您正在硬布线路径]。

如果正常工作,这是因为编译器假设/usr/local/include.h文件路径的默认部分


更新:

对不起,我还不太擅长编译。我试着在一些不同的地方添加-I/usr/local/include/SDL2/SDL.h,但它没有改变任何东西。你能帮我再拼写一下吗?

您是否想要:指向文件-I/usr/local/include/SDL2/SDL.h

您想要:指向目录-I/usr/local/include/SDL2

但是,您应该做两件事情:(1(修复makefile和(2(将level.cc中的#include指令更改为兼容

这是我对你的makefile的调整:

OBJS += frogmain.o
OBJS += game.o
OBJS += level.o
OBJS += sprite.o
OBJS += actor.o
OBJS += vector.o
SDLCFG := sdl2-config
CPLSDL = $(shell $(SDLCFG) --cflags)
LIBSDL = $(shell $(SDLCFG) --libs)
LIBSDL += -lSDL2_image
COPTS += -std=c++0x
COPTS += -Wall
COPTS += -Werror
COPTS += -pedantic
FrogGame: $(OBJS)
g++ -o FrogGame $(OBJS) $(LIBSDL)
frogmain.o: frogmain.cc game.hh level.hh sprite.hh vector.hh
g++ -c $(COPTS) frogmain.cc
game.o: game.cc level.hh sprite.hh actor.hh vector.hh
g++ -c $(COPTS) game.cc
level.o: level.cc sprite.hh actor.hh vector.hh
g++ -c $(COPTS) $(CPLSDL) level.cc
actor.o: actor.cc vector.hh
g++ -c $(COPTS) actor.cc
sprite.o: sprite.cc vector.hh
g++ -c $(COPTS) sprite.cc
vector.o: vector.cc
g++ -c $(COPTS) vector.cc
clean:
rm -f $(OBJS) FrogGame

如果您从中复制并粘贴,那么TAB应该是四个空格[因为代码块在SO中是如何格式化的]。因此,您需要手动编辑才能将其更改回。(即make对前导TAB挑剔(。

level.cc中,您使用的不是两个#include指令:

#include <SDL2/SDL.h>
#include <SDL2/SDL_Image.h>

您想要:

#include <SDL.h>
#include <SDL_Image.h>

sudo pacman -S sdl2_image可以修复此错误,请参阅SDL/SDL_image.h:没有这样的文件或目录

最新更新