I've run into a bit of a snag when compiling and linking with libtonc, it seems like the compiler isn't seeing any symbols besides inline functions and macros defined in tonc's .h files.
Here's the full C program I'm trying to compile (only 1 file, uses tonc's irq and input functions, as well as typedefs):
Code: Select all
#include <tonc.h>
// demo.c
#define CANVAS_X 8
#define CANVAS_Y 5
#define CANVAS_WIDTH 64
#define CANVAS_HEIGHT 64
#define PALETTE_COUNT 7
COLOR palette[PALETTE_COUNT];
int cur_x = 0;
int cur_y = 0;
int color_index = 0;
unsigned int frames = 0;
void init(void)
{
// setup interrupts
irq_init(NULL);
irq_add(II_VBLANK, NULL);
// init screen
REG_DISPCNT = DCNT_MODE3 | DCNT_BG2;
// init palette
palette[0] = RGB8(255, 0 , 0 );
palette[1] = RGB8(255, 127, 0 );
palette[2] = RGB8(255, 255, 0 );
palette[3] = RGB8(0 , 255, 0 );
palette[4] = RGB8(0 , 0 , 255);
palette[5] = RGB8(75 , 0 , 130);
palette[6] = RGB8(148, 0 , 211);
}
int wrap_on_keys(int cur, u32 key_up, u32 key_down, int min, int max)
{
if (key_hit(key_up))
{
cur++;
if (cur > max)
{
return min;
}
}
else if (key_hit(key_down))
{
cur--;
if (cur < min)
{
return max;
}
}
return cur;
}
void update(void)
{
key_poll();
if (key_hit(KEY_A))
{
// fill pixel
m3_mem[CANVAS_Y + cur_y][CANVAS_X + cur_x] = palette[color_index];
}
else if (key_hit(KEY_B))
{
// erase pixel
m3_mem[CANVAS_Y + cur_y][CANVAS_X + cur_x] = CLR_BLACK;
}
color_index = wrap_on_keys(color_index, KEY_R, KEY_L, 0, PALETTE_COUNT - 1);
cur_x = wrap_on_keys(cur_x, KEY_RIGHT, KEY_LEFT, 0, CANVAS_WIDTH - 1);
cur_y = wrap_on_keys(cur_y, KEY_DOWN, KEY_UP, 0, CANVAS_HEIGHT - 1);
}
void render(void)
{
// render simple palette GUI
int i;
COLOR selcol;
for(i = 0; i < PALETTE_COUNT; i++)
{
// selection pixel
if (i == color_index)
{
selcol = CLR_WHITE;
}
else
{
selcol = CLR_BLACK;
}
m3_mem[2 + (i * 2)][2] = selcol;
// color pixel
m3_mem[2 + (i * 2)][3] = palette[i];
}
// render pointer guides and canvas box
// box top + bottom
for(i = 0; i < CANVAS_WIDTH; i++)
{
// pointer x guide
if (i == cur_x)
{
m3_mem[CANVAS_Y - 3][CANVAS_X + i] = CLR_WHITE;
}
else
{
m3_mem[CANVAS_Y - 3][CANVAS_X + i] = CLR_BLACK;
}
m3_mem[CANVAS_Y - 1][CANVAS_X + i] = CLR_WHITE;
m3_mem[CANVAS_Y + CANVAS_HEIGHT][CANVAS_X + i] = CLR_WHITE;
}
// box left + right
for(i = 0; i < CANVAS_HEIGHT; i++)
{
// pointer y guide
if (i == cur_y)
{
m3_mem[CANVAS_Y + i][CANVAS_X - 3] = CLR_WHITE;
}
else
{
m3_mem[CANVAS_Y + i][CANVAS_X - 3] = CLR_BLACK;
}
m3_mem[CANVAS_Y + i][CANVAS_X - 1] = CLR_WHITE;
m3_mem[CANVAS_Y + i][CANVAS_X + CANVAS_WIDTH] = CLR_WHITE;
}
}
int main(void)
{
init();
// game loop
for (;;)
{
VBlankIntrWait();
update();
render();
frames++;
}
return 0;
}
Code: Select all
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/gba_rules
ARMPREFIX = arm-none-eabi-
CC = $(ARMPREFIX)gcc
OBJCOPY = $(ARMPREFIX)objcopy
PROJ = demo
SRC = *.c
OBJS = $(SRC:.c=.o)
INCLUDES = -I$(DEVKITPRO)/libtonc/include
LIBS = -L$(DEVKITPRO)/libtonc/lib -ltonc
STEP1ARGS = -mthumb-interwork -mthumb -O2 -Wall -fno-strict-aliasing $(INCLUDES) $(LIBS)
STEP2ARGS = -mthumb-interwork -mthumb -specs=gba.specs $(LIBS)
.PHONY: all
all:
$(CC) $(STEP1ARGS) -c $(SRC)
$(CC) $(STEP2ARGS) $(OBJS) -o $(PROJ).elf
$(OBJCOPY) -v -O binary $(PROJ).elf $(PROJ).gba
gbafix $(PROJ).gba
.PHONY: clean
clean:
rm -f $(PROJ).elf
rm -f $(PROJ).o
rm -f $(PROJ).gba
Code: Select all
> make
arm-none-eabi-gcc -mthumb-interwork -mthumb -O2 -Wall -fno-strict-aliasing -I/opt/devkitpro/libtonc/include -L/opt/devkitpro/libtonc/lib -ltonc -c *.c
arm-none-eabi-gcc -mthumb-interwork -mthumb -specs=gba.specs -L/opt/devkitpro/libtonc/lib -ltonc *.o -o demo.elf
/opt/devkitpro/devkitARM/bin/../lib/gcc/arm-none-eabi/8.2.0/../../../../arm-none-eabi/bin/ld: demo.o: in function `init':
demo.c:(.text+0x4): undefined reference to `irq_init'
/opt/devkitpro/devkitARM/bin/../lib/gcc/arm-none-eabi/8.2.0/../../../../arm-none-eabi/bin/ld: demo.c:(.text+0xc): undefined reference to `irq_add'
/opt/devkitpro/devkitARM/bin/../lib/gcc/arm-none-eabi/8.2.0/../../../../arm-none-eabi/bin/ld: demo.o: in function `wrap_on_keys':
demo.c:(.text+0x88): undefined reference to `__key_prev'
/opt/devkitpro/devkitARM/bin/../lib/gcc/arm-none-eabi/8.2.0/../../../../arm-none-eabi/bin/ld: demo.c:(.text+0x8c): undefined reference to `__key_curr'
/opt/devkitpro/devkitARM/bin/../lib/gcc/arm-none-eabi/8.2.0/../../../../arm-none-eabi/bin/ld: demo.o: in function `update':
demo.c:(.text+0x94): undefined reference to `key_poll'
/opt/devkitpro/devkitARM/bin/../lib/gcc/arm-none-eabi/8.2.0/../../../../arm-none-eabi/bin/ld: demo.c:(.text+0x164): undefined reference to `__key_prev'
/opt/devkitpro/devkitARM/bin/../lib/gcc/arm-none-eabi/8.2.0/../../../../arm-none-eabi/bin/ld: demo.c:(.text+0x168): undefined reference to `__key_curr'
/opt/devkitpro/devkitARM/bin/../lib/gcc/arm-none-eabi/8.2.0/../../../../arm-none-eabi/bin/ld: demo.o: in function `main':
demo.c:(.text.startup+0x8): undefined reference to `VBlankIntrWait'
collect2: error: ld returned 1 exit status
make: *** [all] Error 1
Code: Select all
export PATH="/opt/devkitpro/devkitARM/bin:/opt/devkitpro/tools/bin:$PATH"
I have devkitpro set up on my MacBook running macOS and on a dual-booted Windows 10 installation, and get the same errors on both. Am I doing something wrong?
Thanks for any help! :3