This question already has answers here:
Why does the order of '-l' option in gcc matter? [duplicate]
(3 answers)
Closed 5 years ago.
I have just started to use C++ and SDL, and I have begun to create a basic Breakout clone to get my head around the semantics. To modularise what I have so far, I have created two header files core.h and paddle.h.
I am having difficulty with correctly including SDL with these modules. Initially, the project compiled when all I had was the main file breakout.cpp, paddle.h and paddle.cpp. At this stage, the 'Core' class was located in breakout.cpp, and as soon as I migrated it into its own file, the compiler started to get upset.
As it stands, it's a very simple set up that can be illustrated as follows:
breakout ---> core ---> paddle
Which leads me to believe that I am making a rookie oversight. Or that I'm linking the files incorrectly in Makefile.
Here is the code:
breakout.cpp
#include "SDL2/SDL.h"
#include "SDL2/SDL_image.h"
#include <stdio.h>
#include <string>
#include "core.h"
int main(int argc, char* args[]) {
Core gCore;
gCore.runGame();
return 0;
}
core.h
#pragma once
#include "paddle.h"
class Core {
public:
Core();
~Core();
void runGame();
private:
static const int SCREEN_WIDTH = 640, SCREEN_HEIGHT = 480;
SDL_Window* gWindow;
SDL_Renderer* gRenderer;
Paddle* p1;
void render();
};
paddle.h
#pragma once
#include <string>
class Paddle {
friend class Core;
public:
Paddle( SDL_Renderer* gRenderer );
~Paddle();
void free();
private:
static const int VELOCITY = 5;
int xPos, yPos, pWidth, pHeight;
SDL_Texture* pSprite;
SDL_Rect* pRect;
bool loadFromFile( SDL_Renderer* gRenderer, std::string path );
int getXPos(); int getYPos();
int getWidth(); int getHeight();
};
core.cpp
#include "SDL2/SDL.h"
#include "SDL2/SDL_image.h"
#include <stdio.h>
#include "paddle.h"
#include "core.h"
Core::Core() {
// Set up SDL
if ( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {
printf( "SDL could not initialise! SDL Error: %s\n", SDL_GetError() );
}
else {
if ( !SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" ) ) {
printf( "Warning: Linear texture filtering not enabled!" );
}
else {
gWindow = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT,
SDL_WINDOW_SHOWN );
if ( gWindow == NULL ) {
printf( "Could not create window. SDL Error: %s\n", SDL_GetError() );
}
else {
gRenderer = SDL_CreateRenderer( gWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );
if ( gRenderer == NULL ) {
printf( "Renderer could not be created! SDL Error: %s\n", SDL_GetError() );
}
else {
// Initialise renderer colour
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
// Initialise PNG loading
int imgFlags = IMG_INIT_PNG;
if ( !( IMG_Init( imgFlags ) & imgFlags ) ) {
printf( "SDL_image could not be initialised! SDL_image Error: %s\n", IMG_GetError() );
}
}
}
}
}
}
Core::~Core() {
SDL_DestroyRenderer( gRenderer ); gRenderer = NULL;
SDL_DestroyWindow( gWindow ); gWindow = NULL;
// Quit SDL subsystems
IMG_Quit();
SDL_Quit();
}
void Core::runGame() {
// Main loop flag
bool quit = false;
// Event handler
SDL_Event e;
// p1 = new Paddle( gRenderer );
while ( !quit ) {
while( SDL_PollEvent( &e ) != 0 ) {
//User requests quit
if( e.type == SDL_QUIT ) {
quit = true;
}
}
// Clear screen
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderClear( gRenderer );
// Render game assets
render();
// Update screen
SDL_RenderPresent( gRenderer );
}
}
void Core::render() {
// Set rendering space and render to screen
SDL_Rect pRenderQuad = { p1->xPos, p1->yPos, p1->pWidth, p1->pHeight };
// Render to screen
SDL_RenderCopy( gRenderer, p1->pSprite, NULL, &pRenderQuad );
}
paddle.cpp
#include "SDL2/SDL.h"
#include "SDL2/SDL_image.h"
#include <stdio.h>
#include <string>
#include "paddle.h"
Paddle::Paddle(SDL_Renderer* gRenderer) {
xPos = 300; yPos = 400;
pWidth = 0; pHeight = 0;
loadFromFile( gRenderer, "paddle.png" );
}
Paddle::~Paddle() {
free();
}
bool Paddle::loadFromFile(SDL_Renderer* gRenderer, std::string path) {
// Get rid of preexisting texture
free();
SDL_Texture* nTexture = NULL;
SDL_Surface* lSurface = IMG_Load( path.c_str() );
if ( lSurface == NULL ) { printf( "Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError() ); }
else {
nTexture = SDL_CreateTextureFromSurface( gRenderer, lSurface );
if ( nTexture == NULL ) { printf( "Unable to load texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError() ); }
else {
pWidth = lSurface->w;
pHeight = lSurface->h;
}
SDL_FreeSurface( lSurface ); // Surface no longer needed
}
pSprite = nTexture;
return pSprite != NULL;
}
void Paddle::free() {
if ( pSprite != NULL ) {
SDL_DestroyTexture( pSprite );
pWidth = 0; pHeight = 0;
}
}
// Getter methods
int Paddle::getXPos() { return xPos; } int Paddle::getYPos() { return yPos; }
int Paddle::getWidth() { return pWidth; } int Paddle::getHeight() { return pHeight; }
And I have also included the Makefile, as there could easily be something wrong there too.
Makefile
OBJS = breakout.cpp
DEPS = paddle.h core.h
CC = g++
COMPILER_FLAGS = -w
LINKER_FLAGS = -lSDL2 -lSDL2_image
OBJ_NAME = breakout
%.o: %.cpp $(DEPS)
$(CC) -c -o $# $< $(COMPILER_FLAGS)
all : $(OBJS)
$(CC) $(OBJS) $(COMPILER_FLAGS) $(LINKER_FLAGS) paddle.cpp core.cpp -o $(OBJ_NAME)
Error log
g++ breakout.cpp -w -lSDL2 -lSDL2_image paddle.cpp core.cpp -o breakout
/tmp/cc0H2fKM.o: In function `Paddle::loadFromFile(SDL_Renderer*, std::basic_string<char, std::char_traits<char>, std::allocator<char> >)':
paddle.cpp:(.text+0x111): undefined reference to `IMG_Load'
paddle.cpp:(.text+0x121): undefined reference to `SDL_GetError'
paddle.cpp:(.text+0x15a): undefined reference to `SDL_CreateTextureFromSurface'
paddle.cpp:(.text+0x16a): undefined reference to `SDL_GetError'
paddle.cpp:(.text+0x1b8): undefined reference to `SDL_FreeSurface'
/tmp/cc0H2fKM.o: In function `Paddle::free()':
paddle.cpp:(.text+0x203): undefined reference to `SDL_DestroyTexture'
/tmp/ccDHGaLY.o: In function `Core::Core()':
core.cpp:(.text+0x12): undefined reference to `SDL_Init'
core.cpp:(.text+0x1e): undefined reference to `SDL_GetError'
core.cpp:(.text+0x44): undefined reference to `SDL_SetHint'
core.cpp:(.text+0x86): undefined reference to `SDL_CreateWindow'
core.cpp:(.text+0xa1): undefined reference to `SDL_GetError'
core.cpp:(.text+0xd1): undefined reference to `SDL_CreateRenderer'
core.cpp:(.text+0xee): undefined reference to `SDL_GetError'
core.cpp:(.text+0x127): undefined reference to `SDL_SetRenderDrawColor'
core.cpp:(.text+0x138): undefined reference to `IMG_Init'
core.cpp:(.text+0x149): undefined reference to `SDL_GetError'
/tmp/ccDHGaLY.o: In function `Core::~Core()':
core.cpp:(.text+0x17a): undefined reference to `SDL_DestroyRenderer'
core.cpp:(.text+0x195): undefined reference to `SDL_DestroyWindow'
core.cpp:(.text+0x1a5): undefined reference to `IMG_Quit'
core.cpp:(.text+0x1aa): undefined reference to `SDL_Quit'
/tmp/ccDHGaLY.o: In function `Core::runGame()':
core.cpp:(.text+0x1ea): undefined reference to `SDL_PollEvent'
core.cpp:(.text+0x218): undefined reference to `SDL_SetRenderDrawColor'
core.cpp:(.text+0x228): undefined reference to `SDL_RenderClear'
core.cpp:(.text+0x244): undefined reference to `SDL_RenderPresent'
/tmp/ccDHGaLY.o: In function `Core::render()':
core.cpp:(.text+0x2d1): undefined reference to `SDL_RenderCopy'
collect2: ld returned 1 exit status
make: *** [all] Error 1
I'd would really appreciate your support on not just the problem at hand. But also if any general suggestions about my code can be made.
Thanks
The order of the flags on your compiler switch matter.
Libraries to be passed to the linker should be last.
And using a -w makes no sense as it's usually -W (capital) followed by some kind of directive, such as -Werror -Wall etc.
Suggesto: remove -w flag and move the -l switches to the end.
Related
I have been trying to make a simple game in SDL. I Found that keeping every thing in on file was getting messy so i moved some functions into their own file and set up a global header file to store all the global things i would use. but from there it has been all errors!
Files:
-Main.cpp
-Makefile
-Assets/
-Player.bmp
-Build/
-build.deb
-Modules/
-Global.h
-HandleKeys.cpp
-HandleKeys.h
Main.cpp:
#include <stdio.h>
#include "Modules/Global.h"
#include "Modules/HandleKeys.h"
//Starts up SDL and creates window
bool init();
//Loads media
bool loadMedia();
extern int SCREEN_WIDTH = 640;
extern int SCREEN_HEIGHT = 480;
//Frees media and shuts down SDL
void close();
//Loads individual image
SDL_Surface* loadSurface( std::string path );
//The window we'll be rendering to
SDL_Window* gWindow = NULL;
//The surface contained by the window
SDL_Surface* gScreenSurface = NULL;
//The images that correspond to a keypress
SDL_Surface* Entity[ KEY_PRESS_SURFACE_TOTAL ];
//Current displayed image
SDL_Surface* gCurrentSurface = NULL;
int PlayerX;
int PlayerY;
bool init()
{
//Initialization flag
bool success = true;
//Initialize SDL
if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
printf( "SDL could not initialize! SDL Error: %s\n", SDL_GetError() );
success = false;
}
else
{
//Create window
gWindow = SDL_CreateWindow( title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
if( gWindow == NULL )
{
printf( "Window could not be created! SDL Error: %s\n", SDL_GetError() );
success = false;
}
else
{
//Get window surface
gScreenSurface = SDL_GetWindowSurface( gWindow );
}
}
return success;
}
string get(list<string> _list, int _i){
list<string>::iterator it = _list.begin();
for(int i=0; i<_i; i++){
++it;
}
return *it;
}
bool loadMedia()
{
//Loading success flag
bool success = true;
for( int i = 0; i <= KEY_PRESS_SURFACE_TOTAL; ++i )
{
if (i != KEY_PRESS_SURFACE_TOTAL){
Entity[ PLAYER_SURFACE ] = loadSurface( get(EntityPaths, i) );
}
}
return success;
}
void close()
{
//Deallocate surfaces
for( int i = 0; i < KEY_PRESS_SURFACE_TOTAL; ++i )
{
SDL_FreeSurface( Entity[ i ] );
Entity[ i ] = NULL;
}
//Destroy window
SDL_DestroyWindow( gWindow );
gWindow = NULL;
//Quit SDL subsystems
SDL_Quit();
}
SDL_Surface* loadSurface( std::string path )
{
//Load image at specified path
SDL_Surface* loadedSurface = SDL_LoadBMP( path.c_str() );
if( loadedSurface == NULL )
{
printf( "Unable to load image %s! SDL Error: %s\n", path.c_str(), SDL_GetError() );
}
return loadedSurface;
}
int main( int argc, char* args[] )
{
//Start up SDL and create window
if( !init() )
{
printf( "Failed to initialize!\n" );
}
else
{
//Load media
if( !loadMedia() )
{
printf( "Failed to load media!\n" );
}
else
{
//Main loop flag
bool quit = false;
//Event handler
SDL_Event e;
//Set default current surface
gCurrentSurface = Entity[ PLAYER_SURFACE ];
//While application is running
while( !quit )
{
//Handle events on queue
while( SDL_PollEvent( &e ) != 0 )
{
//User requests quit
if( e.type == SDL_QUIT )
{
quit = true;
}
HandelKey(e);
}
SDL_Rect rect;
rect.x = PlayerX;
rect.y = PlayerY;
rect.w = 0;
rect.h = 0;
//Apply the current image
SDL_BlitSurface( gCurrentSurface, NULL, gScreenSurface, &rect );
//Update the surface
SDL_UpdateWindowSurface( gWindow );
}
}
}
//Free resources and close SDL
close();
return 0;
}
Makefile:
#OBJS specifies which files to compile as part of the project
OBJS = Main.cpp
#MODS specifies which Modules to Compile.
#NOTE: only add .cpp files, no .h files!
MODS = Modules/HandleKeys.cpp
#CC specifies which compiler we're using
CC = g++
#COMPILER_FLAGS specifies the additional compilation options we're using
# -w suppresses all warnings
COMPILER_FLAGS = -w
#LINKER_FLAGS specifies the libraries we're linking against
LINKER_FLAGS = -lSDL2
#OBJ_NAME specifies the name of our exectuable
OBJ_NAME = Build/build.deb
#This is the target that compiles our executable
all : $(OBJS)
$(CC) $(OBJS) $(MODS) $(COMPILER_FLAGS) $(LINKER_FLAGS) -o $(OBJ_NAME)
Global.h
#ifndef __GLOBAL_H__
#define __GLOBAL_H__
//Included by all files!
#include <SDL2/SDL.h>
#include <string>
#include <list>
using namespace std;
extern int SCREEN_WIDTH = 640;
extern int SCREEN_HEIGHT = 480;
extern char* title = "Top Down";
enum Entity
{
PLAYER_SURFACE,
KEY_PRESS_SURFACE_TOTAL
};
extern list<string> EntityPaths
{
"Assets/Player.bmp",
};
//Starts up SDL and creates window
extern bool init();
//Loads media
extern bool loadMedia();
//Frees media and shuts down SDL
extern void close();
//Loads individual image
extern SDL_Surface* loadSurface( std::string path );
//The window we'll be rendering to
extern SDL_Window* gWindow;
//The surface contained by the window
extern SDL_Surface* gScreenSurface;
//The images that correspond to a keypress
extern SDL_Surface* Entity[ KEY_PRESS_SURFACE_TOTAL ];
//Current displayed image
extern SDL_Surface* gCurrentSurface;
extern int PlayerX;
extern int PlayerY;
extern const int PlayerSpeed;
#endif
HandleKeys.cpp:
#include "Global.h"
#include "HandleKeys.h"
void HandleKey(SDL_Event e){
if( e.type == SDL_KEYDOWN )
{
//Select surfaces based on key press
switch( e.key.keysym.sym )
{
case SDLK_UP:
PlayerY -= PlayerSpeed;
break;
case SDLK_DOWN:
PlayerY += PlayerSpeed;
break;
case SDLK_LEFT:
PlayerX -= PlayerSpeed;
break;
case SDLK_RIGHT:
PlayerX += PlayerSpeed;
break;
}
}
}
HandleKeys.h:
#ifndef __HANDLEKEYS_H__
#define __HANDLEKEYS_H__
extern void HandelKey(SDL_Event e);
#endif
Make file output:
g++ Main.cpp Modules/HandleKeys.cpp -w -lSDL2 -o Build/build.deb
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: /tmp/ccvPJ1dy.o:(.data+0x0): multiple definition of `SCREEN_WIDTH'; /tmp/ccdTvusg.o:(.data+0x0): first defined here
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: /tmp/ccvPJ1dy.o:(.data+0x4): multiple definition of `SCREEN_HEIGHT'; /tmp/ccdTvusg.o:(.data+0x4): first defined here
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: /tmp/ccvPJ1dy.o:(.data.rel.local+0x0): multiple definition of `title'; /tmp/ccdTvusg.o:(.data.rel.local+0x0): first defined here
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: /tmp/ccvPJ1dy.o:(.bss+0x0): multiple definition of `EntityPaths[abi:cxx11]'; /tmp/ccdTvusg.o:(.bss+0x0): first defined here
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: /tmp/ccvPJ1dy.o: warning: relocation against `PlayerSpeed' in read-only section `.text'
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: /tmp/ccdTvusg.o: in function `main':
Main.cpp:(.text+0x3e0): undefined reference to `HandelKey(SDL_Event)'
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: /tmp/ccvPJ1dy.o: in function `HandleKey(SDL_Event)':
HandleKeys.cpp:(.text+0x49): undefined reference to `PlayerSpeed'
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: HandleKeys.cpp:(.text+0x5f): undefined reference to `PlayerSpeed'
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: HandleKeys.cpp:(.text+0x75): undefined reference to `PlayerSpeed'
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: HandleKeys.cpp:(.text+0x8b): undefined reference to `PlayerSpeed'
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: warning: creating DT_TEXTREL in a PIE
collect2: error: ld returned 1 exit status
make: *** [Makefile:23: all] Error 1
i have messed around with using the "extern" parameter but nothing relay works, i have also messed around with how i define things in both global.h and main.cpp.
I am on pop OS (a Ubuntu based Linux distro).
Edit: I added the wrong main.cpp (I Had another open in my vscode workspace!)
Edit2: I now have a new error:
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: /tmp/ccwvE6bo.o: in function `main':
Main.cpp:(.text+0x3e0): undefined reference to `HandelKey(SDL_Event)'
collect2: error: ld returned 1 exit status
make: *** [Makefile:23: all] Error 1
The lines
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
in Main.cpp and the lines
extern int SCREEN_WIDTH = 640;
extern int SCREEN_HEIGHT = 480;
in Global.h are definitions. A declaration with an initializer is always a definition.
By defining the same variable in more than one translation unit (i.e. .cpp file), you are violating the one-definition rule.
I suggest that you change
extern int SCREEN_WIDTH = 640;
extern int SCREEN_HEIGHT = 480;
in Global.h to the following:
extern const int SCREEN_WIDTH;
extern const int SCREEN_HEIGHT;
That way, it is only a declaration and no longer a definition.
You have a similar problem with title defined in Global.h:
extern char* title = "Top Down";
This line is a definition.
Header files should generally only contain declarations of variables, not definitions, because otherwise, if the header files is included by more than one translation unit, it will violate the one-definition rule.
Therefore, I suggest that you change this line to a declaration:
extern const char* title;
In one of the translation units, for example Main.cpp, you should then provide the definition:
const char* title = "Top Down";
The variable EntityPaths has a similar problem:
extern list<string> EntityPaths
{
"Assets/Player.bmp",
};
This is a definition. You should not define it in the header file. Instead, you should only provide a declaration:
extern list<string> EntityPaths;
You should define it in exactly one translation unit, for example in Main.cpp.
In Global.h, you have declared PlayerSpeed:
extern const int PlayerSpeed;
However, you did not define it anywhere. I suggest that you add
const int PlayerSpeed;
to Main.cpp.
The line
extern void HandelKey(SDL_Event e);
in HandleKeys.h has a typo. It should be HandleKey, not HandelKey.
I am attempting to set up SDL2 for creating a C++ game for windows. When I run the below make file with just a single source file, I get no errors, and the program can run. When I attempt to run the make file with multiple source files, the compilation goes smoothly, but when I attempt to run the program, i get the error seen in the title. It appears to only happen when I attempt to create an instance of a class in the second source file, and try to access either members or instance functions.
I have tried redownloading and setting up my environment, updating mingw (didnt hurt to try) and triple checking my code. I have included the makefile, as well as the source files I am using. Thank you for any help.
EDIT: It seems that the delete call in the main function causes this error... Not sure if that is a coincidence or if the cause does lie somewhere there...
#OBJS specifies which files to compile as part of the project
OBJS = src/*.cpp src/*.hpp
#CC specifies which compiler we're using
CC = g++
#INCLUDE_PATHS specifies the additional include paths we'll need
INCLUDE_PATHS = -Iinclude/SDL2
#LIBRARY_PATHS specifies the additional library paths we'll need
LIBRARY_PATHS = -Llib
#COMPILER_FLAGS specifies the additional compilation options we're using
# -w suppresses all warnings
# -Wl,-subsystem,windows gets rid of the console window
COMPILER_FLAGS =
#LINKER_FLAGS specifies the libraries we're linking against
LINKER_FLAGS = -lmingw32 -lSDL2main -lSDL2
#OBJ_NAME specifies the name of our exectuable
OBJ_NAME = demoGame
#This is the target that compiles our executable
all : $(OBJS)
$(CC) $(OBJS) $(INCLUDE_PATHS) $(LIBRARY_PATHS) $(COMPILER_FLAGS) $(LINKER_FLAGS) -o $(OBJ_NAME)
#include <SDL.h>
#include <stdio.h>
#include "grid.hpp"
#include <iostream>
//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
int main( int argc, char* args[] )
{
//The window we'll be rendering to
SDL_Window* window = NULL;
//The surface contained by the window
SDL_Surface* screenSurface = NULL;
//Initialize SDL
if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
}
else
{
//Create window
window = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
if( window == NULL )
{
printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError() );
}
else
{
//Get window surface
screenSurface = SDL_GetWindowSurface( window );
//Fill the surface white
SDL_FillRect( screenSurface, NULL, SDL_MapRGB( screenSurface->format, 0xFF, 0xFF, 0xFF ) );
//Update the surface
SDL_UpdateWindowSurface( window );
//Wait two seconds
SDL_Delay( 2000 );
}
}
Grid* grid = new Grid(1, 2);
// These two lines seem to cause an issue.
std::cout << grid->getRows() << std::endl;
delete grid;
//Destroy window
SDL_DestroyWindow( window );
//Quit SDL subsystems
SDL_Quit();
return 0;
}
class Grid {
public:
Grid(int rows, int columns) {
this->rows = rows;
this->columns = columns;
}
int getRows() {
return this->rows;
}
private:
int rows;
int columns;
};
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am having a lot of trouble with my header files and the compilation. I have everything linked with header guards but for some reason I am still getting a lot of multiple definition errors. I'm also look for help on better way to organize code. Whatever help is appreciated!
This is the out output of my console when I do the g++ call:
g++ main.cpp close.cpp init.cpp load_media.cpp texture.cpp -w -lSDL2 -lSDL2_image -lSDL2_mixer -lSDL2_ttf -o run
/tmp/cc3oNgPs.o:(.bss+0x0): multiple definition of `g_font'
/tmp/ccg0hCKW.o:(.bss+0x0): first defined here
/tmp/cc3oNgPs.o:(.bss+0x8): multiple definition of `g_window'
/tmp/ccg0hCKW.o:(.bss+0x8): first defined here
/tmp/cc3oNgPs.o:(.bss+0x10): multiple definition of `g_renderer'
/tmp/ccg0hCKW.o:(.bss+0x10): first defined here
/tmp/cc3oNgPs.o:(.bss+0x20): multiple definition of `g_text_texture'
/tmp/ccg0hCKW.o:(.bss+0x20): first defined here
/tmp/ccIgzhbZ.o:(.bss+0x0): multiple definition of `g_font'
/tmp/ccg0hCKW.o:(.bss+0x0): first defined here
/tmp/ccIgzhbZ.o:(.bss+0x8): multiple definition of `g_window'
/tmp/ccg0hCKW.o:(.bss+0x8): first defined here
/tmp/ccIgzhbZ.o:(.bss+0x10): multiple definition of `g_renderer'
/tmp/ccg0hCKW.o:(.bss+0x10): first defined here
/tmp/ccIgzhbZ.o:(.bss+0x20): multiple definition of `g_text_texture'
/tmp/ccg0hCKW.o:(.bss+0x20): first defined here
/tmp/ccQs9gPv.o:(.bss+0x0): multiple definition of `g_font'
/tmp/ccg0hCKW.o:(.bss+0x0): first defined here
/tmp/ccQs9gPv.o:(.bss+0x8): multiple definition of `g_window'
/tmp/ccg0hCKW.o:(.bss+0x8): first defined here
/tmp/ccQs9gPv.o:(.bss+0x10): multiple definition of `g_renderer'
/tmp/ccg0hCKW.o:(.bss+0x10): first defined here
/tmp/ccQs9gPv.o:(.bss+0x20): multiple definition of `g_text_texture'
/tmp/ccg0hCKW.o:(.bss+0x20): first defined here
/tmp/ccxzUgM2.o:(.bss+0x0): multiple definition of `g_font'
/tmp/ccg0hCKW.o:(.bss+0x0): first defined here
/tmp/ccxzUgM2.o:(.bss+0x8): multiple definition of `g_window'
/tmp/ccg0hCKW.o:(.bss+0x8): first defined here
/tmp/ccxzUgM2.o:(.bss+0x10): multiple definition of `g_renderer'
/tmp/ccg0hCKW.o:(.bss+0x10): first defined here
/tmp/ccxzUgM2.o:(.bss+0x20): multiple definition of `g_text_texture'
/tmp/ccg0hCKW.o:(.bss+0x20): first defined here
collect2: error: ld returned 1 exit status
here are my 2 header files:
isolation.h
//include //include guard
#ifndef ISOLATION_H
#define ISOLATION_H
//include dependencies
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
#include <stdio.h>
#include <string>
//include headers
#include "texture.h"
//Screen dimension constants
const int SCREEN_WIDTH = 1280;
const int SCREEN_HEIGHT = 800;
//forward delcarlation
//class Texture;
//start up SDL create window
bool init();
//load all media
bool load_media();
//free all and shut down SDL
void close();
//load global front
TTF_Font* g_font = NULL;
//window
SDL_Window* g_window = NULL;
//renderer
SDL_Renderer* g_renderer = NULL;
//load jpeg + font
//Texture background_texture;
//rendered font texture
Texture g_text_texture;
#endif
texture.h
//include guard
#ifndef TEXTURE_H
#define TEXTURE_H
//include dependencies
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
#include <stdio.h>
#include <string>
//include headers
//#include "isolation.h"
class Texture {
public:
//initializes variables
Texture();
//deallocates memory
~Texture();
//load image from path
bool load_from_file( std::string path );
//create image from font string
bool load_from_rendered_text( std::string textureText, SDL_Color text_color );
//deallocates texture
void free();
//set color modulation
void set_color( Uint8 red, Uint8 green, Uint8 blue );
//set blend mode
void set_blend_mode( SDL_BlendMode blending );
//set alpha
void set_alpha( Uint8 alpha );
//render texture at point
void render( int x, int y, SDL_Rect* clip = NULL, double angle = 0.0, SDL_Point* center = NULL, SDL_RendererFlip flip = SDL_FLIP_NONE ) const;
//get image dimensions
int get_width() const;
int get_height() const;
private:
//texture pointer
SDL_Texture* m_texture;
//dimensions
int m_width;
int m_height;
};
#endif
init.cpp
#include "isolation.h"
//#include "texture.h"
bool init() {
//initialization flag
bool success = true;
//initialize SDL
if ( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {
printf( "SDL could not initialized. SDL Error: %s\n", SDL_GetError() );
success = false;
}
else {
//set texture filtering linear
if ( !SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" ) ) {
printf( "Warning: Linear filtering not enabled\n" );
}
//create window
g_window = SDL_CreateWindow( "Isolation", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
if ( g_window == NULL ) {
printf( "Window could not be created. SDL Error: %s\n", SDL_GetError() );
success = false;
}
else {
//create vsynced renderer
g_renderer = SDL_CreateRenderer( g_window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );
if ( g_renderer == NULL ) {
printf( "Renderer could not be created. SDL Error: %s\n", SDL_GetError() );
success = false;
}
else {
//initialize renderer color
SDL_SetRenderDrawColor (g_renderer, 0xFF, 0xFF, 0xFF, 0xFF );
//initialize JPEG loading
int img_flags = IMG_INIT_JPG;
if ( !( IMG_Init( img_flags ) & img_flags ) ) {
printf( "SDL_image could not be initialize. SDL_image Error: %s\n", IMG_GetError() );
success = false;
}
//initialize SDL_ttf
if (TTF_Init() == -1 ) {
printf( "SDL_ttf could not be initialize. SDL_ttf Error: %s\n", TTF_GetError() );
}
}
}
}
return success;
}
load_media.cpp
#include "isolation.h"
//s#include "texture.h"
bool load_media() {
bool success = true;
//load background img
//if( !background_texture.load_from_file( "img/vancouver.jpg" ) ) {
// printf( "Failed to load background texture!\n" );
// success = false;
//}
//open font
g_font = TTF_OpenFont( "lazy.ttf", 28 );
if ( g_font == NULL ) {
printf( "Failed to load lazy font. SDL_ttf Error: %s\n", TTF_GetError() );
success = false;
}
else {
//render texture
SDL_Color text_color = { 0, 0, 0 };
if ( !g_text_texture.load_from_rendered_text( "hello from the other side ", text_color ) ) {
printf( "Failed to render text texture\n" );
success = false;
}
}
return success;
}
close.cpp
#include "isolation.h"
//#include "texture.h"
void close() {
//free loaded text
g_text_texture.free();
//free font
TTF_CloseFont( g_font );
g_font = NULL;
//destroy window
SDL_DestroyWindow( g_window );
SDL_DestroyRenderer( g_renderer );
g_window = NULL;
g_renderer = NULL;
//quit SDL subsystems
TTF_Quit();
IMG_Quit();
SDL_Quit();
}
main.cpp
#include "isolation.h"
//#include "texture.h"
int main( int argc, char* args[] ) {
//start up SDL
if ( !init() ) {
printf( "Failed to initialize.\n" );
}
else {
//load media
if ( !load_media() ) {
printf( "Failed to load media.\n" );
}
else{
//main loop flag
bool quit = false;
//event handler
SDL_Event e;
//while running
while ( !quit ) {
//handle events on queue
while ( SDL_PollEvent( &e ) != 0 ) {
//user quit
if ( e.type == SDL_QUIT ) {
quit = true;
}
}
//clear screen
SDL_SetRenderDrawColor( g_renderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderClear( g_renderer );
//render frame
g_text_texture.render( ( SCREEN_WIDTH - g_text_texture.get_width() ) / 2, ( SCREEN_HEIGHT - g_text_texture.get_height() ) / 2 );
//update screen
SDL_RenderPresent( g_renderer );
}
}
}
//free memory and close SDL
close();
return 0;
}
Do not mix declaration with definition/instantiation in a .h file. Your are instantiating g_font, g_window and g_renderer in isolation.h file. The correct is instantiating only once, usually, in a .cpp
To solve your problem, change isolation.h to declare those variables as external linkage:
//load global front
extern TTF_Font* g_font;
//window
extern SDL_Window* g_window;
//renderer
extern SDL_Renderer* g_renderer;
and instantiate them only once in an appropriate .cpp file, for example, init.cpp
I am currently attempting to write a very simple 2d game engine using SDL in order to help myself get more comfortable with coding. Unfortunately, I made the mistake of starting with a single source file, and now that my code is getting bigger, I am trying to split the existing code (which works fine before the split) into multiple header and source files. The first major issue I've encountered is that when I try to define SCREEN_HEIGHT, SCREEN_WIDTH, Window, and Renderer in init.cpp after declaring them in init.h, I get error: 'blank' does not name a type (blank being Window, Renderer, etc.). I am also trying to make them global, which may be part of the issue. Included below is the relevant code (I took out all the stuff I think is irrelevant in this case). I suspect I'm just missing something really simple here, but I've been unable to find an existing answer online like I have with my previous problems.
main.cpp
#include "globals.h"
#include "texture.h"
....
globals.h
#ifndef GLOBALS
#define GLOBALS
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#include <stdio.h>
#include <string>
#endif //GLOBALS
texture.h
#ifndef TEXTURE
#define TEXTURE
#include "globals.h"
#include "init.h"
....
#endif // TEXTURE
texture.cpp
#include "texture.h"
....
init.h
#ifndef INIT
#define INIT
#include "globals.h"
//screen dimensions
int SCREEN_WIDTH;
int SCREEN_HEIGHT;
//initiates SDL and creates a window and renderer
bool init();
//the created window
SDL_Window* Window;
//the renderer that will be used
SDL_Renderer* Renderer;
#endif // INIT
init.cpp
#include "init.h"
SCREEN_WIDTH = 640;
SCREEN_HEIGHT = 480;
Window = NULL;
Renderer = NULL;
bool init()
{
bool success = true;
if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
printf( "SDL was unable to initialize! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
if( !SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1"))
{
printf( "Linear texture filtering not enabled!");
}
else
{
Window = SDL_CreateWindow( "Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if( Window == NULL)
{
printf( "Window could not be created! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
Renderer = SDL_CreateRenderer( Window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if( Renderer == NULL)
{
printf( "Renderer could not be created! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
SDL_SetRenderDrawColor( Renderer, 0xFF, 0xFF, 0xFF, 0xFF);
int PNGImage = IMG_INIT_PNG;
if( !(IMG_Init( PNGImage) & PNGImage))
{
printf( "Image loading not enabled! SDL_Image Error: %s\n", IMG_GetError());
success = false;
}
if( TTF_Init() == -1)
{
printf( "True type fonts not enabled! SDL_TTF Error: %s\n", TTF_GetError());
success = false;
}
}
}
}
}
return success;
}
I get the error in init.cpp at the top of the code before bool init()
Renderer = NULL; is an assignment statement, which you cannot have in global scope. You can only have declarations in global scope. Since you have already declared Renderer in your header file, you don't need to redeclare it either. Just set it to null within one of your initialization functions (e.g. your current init() function).
Apologize if this is too long of a post. I'm merely trying to get SDL to work in an object oriented fashion - there's no point in me moving on until I get past this point. Been spending a fair amount of time compiling this and getting errors. I'll post my header files and sources, along with my makefile and an output to see what's going on.
Here's render.h:
#ifndef RENDER_H
#define RENDER_H
#include <string>
#include <SDL/SDL.h>
using std::string;
class Render
{
public:
Render(string filename, int x, int y, SDL_Surface * destination);
~Render();
private:
SDL_Surface * m_optimizedImage;
void load_image(string filename);
void apply_surface(int x, int y, SDL_Surface * source, SDL_Surface * destination);
};
#endif
...and render.cpp:
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <string>
#include "render.h"
using std::string;
Render::Render(string filename, int x, int y, SDL_Surface * destination)
{
this->m_optimizedImage = NULL;
load_image(filename);
apply_surface(x, y, m_optimizedImage, destination);
}
Render::~Render()
{
delete m_optimizedImage;
}
void Render::load_image(string filename)
{
SDL_Surface * loadedImage = IMG_Load(filename.c_str());
if (loadedImage != NULL)
{
m_optimizedImage = SDL_DisplayFormat(loadedImage);
SDL_FreeSurface(loadedImage);
}
}
void Render::apply_surface(int x, int y, SDL_Surface * source, SDL_Surface * destination)
{
SDL_Rect offset;
offset.x = x;
offset.y = y;
SDL_BlitSurface(source, NULL, destination, &offset);
}
...and screenwriter.h:
#include <iostream>
#include <SDL/SDL.h>
#ifndef SCREENWRITER_H
#define SCREENWRITER_H
class ScreenWriter
{
public:
~ScreenWriter();
bool flip_screen();
void delay_screen(int milliseconds);
bool get_screen_state() const;
static ScreenWriter& get_instance();
SDL_Surface * get_screen() const;
private:
ScreenWriter();
void initialize();
bool m_screenFailure;
SDL_Surface * m_screen;
};
#endif
...and screenwriter.cpp:
#include <SDL/SDL.h>
#include "screenwriter.h"
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
#define SCREEN_BPP 32
ScreenWriter::ScreenWriter()
{
this->m_screenFailure = false;
initialize();
}
ScreenWriter::~ScreenWriter()
{
SDL_Quit();
}
ScreenWriter& ScreenWriter::get_instance()
{
static ScreenWriter instance;
return instance;
}
SDL_Surface * ScreenWriter::get_screen() const
{
return m_screen;
}
bool ScreenWriter::get_screen_state() const
{
return this->m_screenFailure;
}
void ScreenWriter::delay_screen(int milliseconds)
{
SDL_Delay(milliseconds);
}
int ScreenWriter::flip_screen()
{
if (SDL_Flip(m_screen) == -1)
{
return 1;
}
else
{
SDL_Flip(m_screen);
return 0;
}
}
void ScreenWriter::initialize()
{
if (SDL_Init(SDL_INIT_EVERYTHING == -1))
{
std::cout << "SDL_Init has failed";
}
else
{
SDL_Init(SDL_INIT_EVERYTHING);
//initialize screen
this->m_screen = SDL_SetVideoMode(SCREEN_WIDTH,
SCREEN_HEIGHT,
SCREEN_BPP,
SDL_SWSURFACE);
if (m_screen == NULL)
{
this->m_screenFailure = true;
}
else
{
this->m_screenFailure = false;
}
//set caption header
SDL_WM_SetCaption("Hello WOrld", NULL);
}
}
...and of course main.cpp:
#include <iostream>
#include <SDL/SDL.h>
#include "screenwriter.h"
#include "render.h"
int main(int argc, char * args[])
{
std::cout << "hello world!" << std::endl;
ScreenWriter * instance = ScreenWriter::get_instance();
instance->flip_screen();
Render render = new Render("look.png", 0, 0, instance->get_screen());
delete instance();
return 0;
}
...my output:
g++ -c main.cpp render.h screenwriter.h -lSDL -lSDL_image
main.cpp: In function ‘int main(int, char**)’:
main.cpp:10:55: error: cannot convert ‘ScreenWriter’ to ‘ScreenWriter*’ in initialization
main.cpp:12:69: error: conversion from ‘Render*’ to non-scalar type ‘Render’ requested
make: *** [main.o] Error 1
...my makefile
program : main.o render.o screenwriter.o
g++ -o program main.o render.o screenwriter.o -lSDL -lSDL_image
main.o : main.cpp render.h screenwriter.h
g++ -c main.cpp render.h screenwriter.h -lSDL -lSDL_image
render.o : render.h render.cpp
g++ -c render.h render.cpp -lSDL
screenwriter.o : screenwriter.h screenwriter.cpp
g++ -c screenwriter.h screenwriter.cpp -lSDL -lSDL_image
clean:
rm program main.o render.o screenwriter.o
the nitty gritty:
My goal with this is to have ScreenWriter implemented as a singleton to setup allegro and flag everything as needed through initialization. The second objective relies on render to just render by specifying x and y coordinates, along with a path to the file to render to load on the map. This is easy to do procedurally, but I'm ready to experiment with OO design on this.
So, any thoughts?
You have two syntax errors which are clear from your errors:
ScreenWriter * instance = ScreenWriter::get_instance();
should be
ScreenWriter & instance = ScreenWriter::get_instance();
because get_instance returns a reference, not a pointer, and
Render render = new Render("look.png", 0, 0, instance->get_screen());
should be
Render * render = new Render("look.png", 0, 0, instance->get_screen());
because new returns a pointer, not an object or reference.
Also,
delete instance();
should be
delete render;
because not only is the former completely wrong, but it's not being used on anything allocated by new. render is, however. So you have to delete it to avoid a memory leak.
I don't understand the "any thoughts" part of the question because it doesn't say about what. English isn't my first language though, so forgive me if I missed something.
Flip the screen after rendering the image. When you blit something, it's blitted on a buffer. SDL_Flip() just swaps those buffers so that your o/p can be seen. So you should be replacing those two lines, I guess.