Using Dev-Cpp to compile static library
Bob Keane

After a bit of a vacation, I decided to return to game programming. I am using Bloodshed's Dev-Cpp ide for simplicity. I entered and compiled a program, but when linking, I get the following errors:

"[linker error] undefined reference to 'backward' (2x)
[linker error] undefined reference to 'rans'
[linker error] undefined reference to 'testprintf-ex'".

I selected project > project options then parameters, under compiler I had "-DALLEGRO_STATICLINK", under C++ compiler I had "_DALLEGRO_STATICLINK", and under linker, I had (in this order) "-lalleg_s -lkernel32 -luser32 -lgdi32 -lcomdlg32 -lole32 -ldinput -lddraw -ldxguid -lwinmm -ldsound".

To create the project, I selected file, new project, multimedia and allegro static library, the programming language was set to C. I was able to compile and link with no problems before, but I cannot remember how. What did I miss? I am using allegro 4.2.0. Thanks in advance.

BAF

Well, I don't know what backward is, rans... what's that. Is that a misspelling of rand()? And testprintf-ex should be textprintf_ex.

[edit] Can you post the source?

Bob Keane
Its a long one. I am trying to adapt Game Programming All In One's tank war to suit my needs. I have not added my changes yet.

Source(main.c):
[code]
/* Sea War By Bob Keane My first attempt at programming a game. This game is
based on the Game Programming All In One sample game Tank War. Changes include multiple enemy ships,
A storyline and random ship movement. I will change as necessary when possible.
*/

#include "seawar.h"

// drawtank function. construct the tank using drawing functions.
void drawtank(int num)
{
int x = tanks[num].x;
int y = tanks[num].y;
int dir = tanks[num].dir;

//draw tank body and turret.

rectfill(screen, x - 11, y - 11, x + 11, y + 11, tanks[num].color);
rectfill(screen, x - 6, y - 6, x + 6, y + 6, 7);

// Draw the treads based on orientation.

if (dir == 0 || dir ==2)
{
rectfill(screen, x - 16, y - 16, x - 11, y + 16, 8);
rectfill(screen, x+11, y-16, x+16, y+16, 8);
}
else
if (dir == 1 || dir == 3)
{
rectfill(screen, x-16, y-16, x+16, y-11, 8);
rectfill(screen, x-16, y+16, x+16, y+11, 8);
}

// Draw the turret based on direction
switch (dir)
{
case 0:
rectfill(screen, x-1, y, x+1, y-16, 8);
break;
case 1:
rectfill(screen, x, y-1, x+16, y+1, 8);
break;
case 2:
rectfill(screen, x-1, y, x+1, y+16, 8);
break;
case 3:
rectfill(screen, x, y-1, x-16, y+1, 8);
break;
}
}

// Erasetank function. erase the tank using rectfill.
void erasetank(int num)
{

// calculate box to encompass the tank.
int left = tanks[num].x - 17;
int top = tanks[num].y - 17;
int right = tanks[num].x + 17;
int bottom = tanks[num].y + 17;

// erase the tank.
rectfill(screen, left, top, right, bottom, 0);
}

// movetank function. move the tank in the current direction.
void movetank(int num)
{
int dir = tanks[num].dir;
int speed = tanks[num].speed;

// update the tank's position based on direction.
switch (dir)
{
case 0:
tanks[num].y-= speed;
break;
case 1:
tanks[num].x+= speed;
break;
case 2:
tanks[num].y+= speed;
break;
case 3:
tanks[num].x-= speed;
}

// keep the tank inside the screen.

if (tanks[num].x > SCREEN_W-22)
{
tanks[num].x = SCREEN_W - 22;
tanks[num].speed = 0;
}

if (tanks[num].x < 22)
{
tanks[num].x = 22;
tanks[num].speed = 0;
}

if (tanks[num].y > SCREEN_H-22)
{
tanks[num].y =SCREEN_H-22;
tanks[num].speed = 0;
}

if (tanks[num].y < 22)
{
tanks[num].y = 22;
tanks[num].speed = 0;
}

}

// explode function. Display random boxes to simulate an explosion.
void explode(int num, int x, int y)
{
int n;

//retrieve the location of the enemy tank
int tx = tanks[!num].x;
int ty = tanks[!num].y;

// Is bullet inside the boundary of the enemy tank?
if (x > tx-16 && x < tx+16 && y > ty-16 && y < ty+16)
score(num);

// Draw some random circles for the "explosion"
for (n = 0; n < 10; n++)
{
rectfill(screen, x-16, y-16, x+16, y+16, rand() % 16);
rest(1);
}

// Clear the field of debris
rectfill(screen, x-16, y-16, x+16, y+16, 0);

}

// updatebullet function Update the position of the bullet.
void updatebullet(int num)
{
int x = bullets[num].x;
int y = bullets[num].y;

if (bullets[num].alive)
{
// erase bullet.
rect(screen, x-1, y-1, x+1, y+1, 0);

// move bullet
bullets[num].x += bullets[num].xspd;
bullets[num].y += bullets[num].yspd;
x = bullets[num].x;
y = bullets[num].y;

// Stay within the screen.
if (x<5 || x> SCREEN_W-5 || y<20 || y> SCREEN_H-5)
{
bullets[num].alive = 0;
return;
}

// draw bullet
x = bullets[num].x;
y = bullets[num].y;
rect(screen, x-1, y-1, x+1, y+1, 4);

// look for a hit
if (getpixel(screen, bullets[num].x, bullets[num].y))
{
bullets[num].alive = 0;
explode(num, x, y);
}

// print the bullet's position.
textprintf_ex(screen, font, SCREEN_W/2-50,1,2,-1,"B1 %-3dx%-3d B2 %-3dx-3d",bullets[0].x, bullets[0].y, bullets[1].x,bullets[1].y);

}
}

// checkpath function check to see if a point on the screen is black.
int checkpath(int x1, int y1, int x2, int y2, int x3, int y3)
{
if (getpixel(screen, x1, y1) || getpixel(screen, x2, y2) || getpixel(screen, x3, y3))
return 1;
else
return 0;
}

// clearpath function verify that the tank can move in thte current direction
void clearpath(int num)
{
// shortcut vars
int dir = tanks[num].dir;
int speed = tanks[num].speed;
int x = tanks[num].x;
int y = tanks[num].y;

switch (dir)
{
// check pixels north
case 0:
if (speed > 0)
{
if (checkpath(x-16, y-20, x, y-20, x+16, y-20))
tanks[num].speed = 0;
}
else
//if reverse direction, check south
if (checkpath(x-16, y+20, x, y+20, x+16, y+20))
tanks[num].speed = 0;
break;

// check pixels east
case 1:
if (speed > 0)
{
if (checkpath(x+20, y-16, x+20, y, x+20, y+16))
tanks[num].speed = 0;
}
else
// if reverse dir, check west
if (checkpath(x-20, y-16, x-20, y, x-20, y+16))
tanks[num].speed = 0;
break;

// Check pixels south
case 2:
if (speed > 0)
{
if (checkpath(x-16, y-20, x, y-20, x+16, y-20))
tanks[num].speed = 0;
}

else
// if reverse direction, check north
if (checkpath(x-16, y-20, x, y-20, x+16, y-20))
tanks[num].speed = 0;
break;

//check pixels west
case 3:
if (speed > 0)
{
if (checkpath(x-20, y-16, x-20, y, x-20, y+16))
tanks[num].speed = 0;
}
else
// if reverse dir, check east
if (checkpath(x+20, y-16, x+20, y, x+20, y+16))
tanks[num].speed = 0;
break;
}
}

// Fireweapon function configure a bullet's direction and speed and activate it.
void fireweapon(int num)
{
int x = tanks[num].x;
int y = tanks[num].y;

// ready to fire again?
if (!bullets[num].alive)
{
bullets[num].alive = 1;

//fire weaponin direction tank is facing
switch (tanks[num].dir)
{
// north
case 0:
bullets[num].x = x;
bullets[num].y = y-22;
bullets[num].xspd = 0;
bullets[num].yspd = -BULLETSPEED;
break;

//east
case 1:
bullets[num].x = x+22;
bullets[num].y = y;
bullets[num].xspd = BULLETSPEED;
bullets[num].yspd = 0;
break;

//south
case 2:
bullets[num].x = x;
bullets[num].y = y+22;
bullets[num].xspd = 0;
bullets[num].yspd = BULLETSPEED;
break;

//west
case 3:
bullets[num].x = x-22;
bullets[num].y = y;
bullets[num].xspd = -BULLETSPEED;
bullets[num].yspd = 0;
}
}
}

// forward function increase the tank's speed
void forward(int num)
{
tanks[num].speed++;
if (tanks[num].speed > MAXSPEED)
tanks[num].speed = MAXSPEED;
}

//reverse function decrease the tank's speed.
void reverse(int num)
{
tanks[num].speed--;
if (tanks[num].speed < -MAXSPEED)
tanks[num].speed = -MAXSPEED;
}

// turnleft function rotate the tank counter-clockwise
void turnleft(int num)
{
tanks[num].dir--;
if (tanks[num].dir < 0)
tanks[num].dir = 3;
}

// turnright function rotate the tank clockwise.
void turnright(int num)
{
tanks[num].dir++;
if (tanks[num].dir > 3)
tanks[num].dir = 0;
}

//getinput function check for player input keys (2 player support)
void getinput()
{
// hit esc to quit.
if (key[KEY_ESC])
gameover = 1;

// WASD / SPACE keys control tank 1
if (key[KEY_W])
forward(0);
if (key[KEY_D])
turnright(0);
if (key[KEY_A])
turnleft(0);
if (key[KEY_S])
backward(0);
if (key[KEY_SPACE])
fireweapon(0);

// arrow / ENTER keys control tank 2
if (key[KEY_UP])
forward(1);
if (key[KEY_RIGHT])
turnright(1);
if (key[KEY_LEFT])
turnleft(1);
if (key[KEY_DOWN])
backward(1);
if (key[KEY_ENTER])
fireweapon(1);

// short delay after keypress
rest(10);
}

// score function add a point to the specified player's score
void score(int player)
{
// update score
int points = ++tanks[player].score;

// display score
textprintf_ex(screen, font, SCREEN_W-70*(player+1), 1, BURST, -1, "P%d", player+1, points);
}

// setuptanks function set up the starting condition of each tank
void setuptanks()
{
// player 1
tanks[0].x = 30;
tanks[0].y = 40;
tanks[0].dir = 1;
tanks[0].speed = 0;
tanks[0].color = 9;
tanks[0].score = 0;

// player 2
tanks[1].x = SCREEN_W-30;
tanks[1].y = SCREEN_H-30;
tanks[1].dir = 3;
tanks[1].speed = 0;
tanks[1].color = 12;
tanks[1].score = 0;
}

// setupdebris function set up the debris on the battlefield
void setupdebris()
{
int n, x, y, size, color;

// fill the battlefield with random debris
for (n=0; n<BLOCKS; n++)
{
x = BLOCKSIZE + rand() % (SCREEN_W-BLOCKSIZE*2);
y = BLOCKSIZE + rand() % (SCREEN_H-BLOCKSIZE*2);
size = (10 + rand() % BLOCKSIZE)/2;
color = makecol(rans()%255, rand()%255, rand()%255);
rectfill(screen, x-size, y-size, x+size, y+size, color);
}
}

// setupscreen function set up the graphics mode and game screen
void setupscreen()
{
// set video mode
int ret = set_gfx_mode(MODE, WIDTH, HEIGHT, 0, 0);
if (ret != 0)
{
allegro_message(allegro_error);
return;
}
// print title
testprintf_ex(screen, font, 1, 1, BURST, 0, "Tank War - %dx%d", SCREEN_W, SCREEN_H);

// draw screen border
rect(screen, 0, 12, SCREEN_W -1, SCREEN_H-1, TAN);
rect(screen, 1, 13, SCREEN_W-2, SCREEN_H-2, TAN);
}

//main function start point of the program
int main(void)
{
// initialize everything
allegro_init();
install_keyboard();
install_timer();
srand(time(NULL));
setupscreen();
setupdebris();
setuptanks();

// game loop
while (!gameover)
{
// erase the tanks
erasetank(0);
erasetank(1);

// check for collisions
clearpath(0);
clearpath(1);

// move the tanks
movetank(0);
movetank(1);

//draw the tanks
drawtank(0);
drawtank(1);

//update the bullets
updatebullet(0);
updatebullet(1);

//check for keypresses
if (keypressed())
getinput();

// slow the game down, adjust as necessary
rest(30);
}

// end program
allegro_exit();
return 0;
}
END_OF_MAIN();
[/code]


Header (seawar.h):
[code]
/* SeaWar.h This file contains basic information for the game SeaWar. Written by Bob Keane
*/

#ifndef _SEAWAR_H
#define _SEAWAR_H
#include <stdio.h>
#include <stdlib.h>
#include "allegro.h"

// define some game constants
#define MODE GFX_AUTODETECT_WINDOWED
#define WIDTH 640
#define HEIGHT 480
#define BLOCKS 5
#define BLOCKSIZE 100
#define MAXSPEED 2
#define BULLETSPEED 10
#define TAN makecol(255,242,169)
#define CAMO makecol (64,142,66)
#define BURST makecol(255,189,73)

// Define the tank structure
struct tagTank
{
int x,y;
int dir, speed;
int color;
int score;
} tanks[2];

// define the bullet structure
struct tagBullet
{
int x,y;
int alive;
int xspd,yspd;
} bullets[2];

int gameover = 0;

// function prototypes
void drawtank(int num);
void erasetank(int num);
void movetank(int num);
void explode(int num, int x, int y);
void updatebullet(int num);
int checkpath(int x1, int y1, int x2, int y2, int x3, int y3);
void clearpath(int num);
void fireweapon(int num);
void forward(int num);
void backward(int num);
void turnleft(int num);
void turnright(int num);
void getinput();
void setuptanks();
void score(int);
void print(const char *s, int c);
void setupdebris();
void setupscreen();

#endif

[/code]

Errors (compile log):

Compiler: Default compiler
Building Makefile: "C:\Dev-Cpp\SeaWar\Makefile.win"
Executing make...
make.exe -f "C:\Dev-Cpp\SeaWar\Makefile.win" all
gcc.exe main.o seawar_private.res -o "seawar.exe" -L"C:/Dev-Cpp/lib" -mwindows -lalleg_s -lkernel32 -luser32 -lgdi32 -lcomdlg32 -lole32 -ldinput -lddraw -ldxguid -lwinmm -ldsound

main.o(.text+0x12bf):main.c: undefined reference to `backward'
main.o(.text+0x1332):main.c: undefined reference to `backward'
main.o(.text+0x1654):main.c: undefined reference to `rans'
main.o(.text+0x17cb):main.c: undefined reference to `testprintf_ex'
collect2: ld returned 1 exit status

make.exe: *** [seawar.exe] Error 1

Execution terminated


[edit] Sorry about that.
spunit262

Please put that in [code][/code] tags.

gnolam

Solution:

Quote:

main.o(.text+0x1654):main.c: undefined reference to `rans'

Misspelling of rand.
Referenced in: color = makecol(rans()%255, rand()%255, rand()%255);

Quote:

main.o(.text+0x17cb):main.c: undefined reference to `testprintf_ex'

Misspelling of textprintf_ex.
Referenced in: testprintf_ex(screen, font, 1, 1, BURST, 0, "Tank War - %dx%d", SCREEN_W, SCREEN_H);

Quote:

main.o(.text+0x12bf):main.c: undefined reference to `backward'

Just plain doesn't exist. The "reverse()" function is probably what's intended.
Referenced in:

 if (key[KEY_S])
     backward(0);

and

if (key[KEY_DOWN])
     backward(1);

BAF

Just what I said, just less detailed because I didn't have the source. :P

Bob Keane

Looks like I need a new pair of glasses. Thanks.

Thread #587037. Printed from Allegro.cc