gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > Makefile Wizard required...

#104774 - OOPMan - Mon Oct 02, 2006 4:30 pm

Hey all, I've been having some problems with a rather detailed makefile. Basically, I've been adapting a makefile used pretty much as standard in the MTCLib source in order to build demos for the NDS build of the library. After struggling for a while I think I'm pretty close to getting it working, but it seems that one major obstacle remains.

First off, here's the makefile:
Quote:
# GNU makefile to build MTC app with devkitPro
#
# REVISION HISTORY
#
# No Date By Reason
# -------------------------------------------------------------------------
# 01 25 Sep 02 lvr Creation
# 02 11 Feb 06 lvr Modified for SwsMtc
# 03 01 Oct 06 acj Modified for devkitPro
# -------------------------------------------------------------------------
#
# Instructions
# ------------
# type make -f makefile to use. Add "DEBUG=1" to build at debug.

# Default to ndebug build
#
ifndef NDEBUG
ifndef DEBUG
NDEBUG = 1
endif
endif

# Executable
TARGET = demo1.nds.gba

# The filename of this makefile
MAKEFILE = makefile

# The platform
PLATFORM = nds


########################
# Paths
vpath

ifdef DEBUG
OBJ = ./dbg
OBJDIR = ./dbg
else
OBJ = ./rel
OBJDIR = ./rel
endif
vpath %.obj $(OBJ)/
vpath %.elf $(OBJ)/
vpath %.bin $(OBJ)/
vpath %.nds $(OBJ)/

SRC = ..
vpath %.c $(SRC)
vpath %.cpp $(SRC)

INC2 = ../../../include
INCLUDE += -I$(INC2)
INCLUDE += -I$(DEVKITPRO)/libnds/include
vpath %.h $(INC2)

INC3 = $(DEVKITPRO)/libnds/include
INCLUDE += -I$(INC3)
vpath %.h $(INC3)

# Libraries:
MTCDIR = ../../../lib/$(PLATFORM)
NDSLIB_LIB=$(DEVKITPRO)/libnds/lib

########################
# Objects to build

APPOBJS = $(OBJ)/demo1.obj
ELFOBJS = $(OBJ)/arm9.elf
BINOBJS = $(OBJ)/arm9.bin
NDSOBJS = $(OBJ)/demo1.nds

$(TARGET) : $(NDSOBJS)
$(NDSOBJS) : $(BINOBJS)
$(BINOJS) : $(ELFOBJS)
$(ELFOBJS) : $(APPOBJS)

# Common build options
CPPFLAGS += -DMTC_LIB -DNDS -DARM9


########################
# Tools

# C compiler
CC = arm-eabi-g++
CFLAGS = -c -mcpu=arm9tdmi -mtune=arm9tdmi -ffast-math -mthumb-interwork
CCOUT = -o
CPPFLAGS += $(INCLUDE)
CSTRICT = -pedantic

# Warnings
CFLAGS += -Wall -W -Wunused\
-Wpointer-arith -Wwrite-strings -Wcast-qual -Wcast-align -Wshadow \
-Wno-nested-externs -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations

# gcc 2.95.2-9 extras. Linux kernel 2.2.12 ships with gcc 2.7.2
CFLAGS += -Wmultichar -Wunknown-pragmas -Wsign-compare

# C++ compiler
CXX = arm-eabi-g++
CXXFLAGS = -c -x c++ -mcpu=arm9tdmi -mtune=arm9tdmi -ffast-math -mthumb-interwork
CXXSTRICT = -pedantic

# C++ warnings
CXXFLAGS += -Wall -W -Wunused \
-Wpointer-arith -Wwrite-strings -Wcast-qual -Wcast-align -Wshadow \
-ffor-scope \
-Wno-reorder -Wno-ctor-dtor-privacy \
-Wno-effc++ -Wno-old-style-cast

# NB g++ 2.95.2 doesnt put STL iterators in std:: so force no-honor-std
#CXXFLAGS += -fno-honor-std

# Assembler
AS = arm-eabi-as
ASFLAGS =
ASOUT = -o

# Linker
LD = arm-eabi-g++
LDFLAGS = -g -mthumb-interwork -mno-fpu -specs=ds_arm9.specs
LDOUT = -o

# Lib
AR = arm-eabi-ar
ARFLAGS = r

# Elf to Bin Objcopy
OBJCOPY = arm-eabi-objcopy
OBJCOPYFLAGS =
OBJCOPYOUT = -o

# NDSTool
NDSTOOL = ndstool
NDSTOOLFLAGS =
NDSTOOLOUT = -c

# DSBuild
DSBUILD = dsbuild
DSBUILDFLAGS =
DSBUILDOUT = -o

ifdef DEBUG

# Debug options
CFLAGS += -ggdb -g3
CXXFLAGS += -ggdb -g3
CPPFLAGS += -DMTC_DEBUG=$(DEBUG)
#ASFLAGS += -defsym MTC_DEBUG=$(DEBUG) --gdwarf2
ASFLAGS += -DMTC_DEBUG=$(DEBUG) /Zi
LDFLAGS += -ggdb -g3

ifeq ( 1, 0)
#Force C++ compile/link
CC = $(CXX)
CFLAGS = $(CXXFLAGS)
CSTRICT = $(CXXSTRICT)
LD = $(CXX)
endif

else

# Release options
CFLAGS += -O3 -fomit-frame-pointer
CXXFLAGS += -O3
CPPFLAGS += -DNDEBUG
ASFLAGS += -DNDEBUG=1
LDFLAGS += -s # strip symbols

endif


########################
# SwsMtc library

ifndef DEBUG
MTC = mtcarm9
else
MTC = mtcarm9d
endif

LIBS = -L$(MTCDIR) -L$(NDSLIB_LIB)
LIBS += -l$(MTC) -lnds9

LIBRARY = $(MTCDIR)/lib$(MTC).a

$(LIBRARY) :
$(MAKE) -C $(MTCDIR) lib$(MTC).a

$(TARGET) : $(LIBRARY)


########################
# Implicit rules

.SUFFIXES :
.SUFFIXES : .nds .bin .elf .c .cpp .asm .h .obj .a

$(OBJ)/%.nds : %.bin
$(NDSTOOL) $(NDSTOOLFLAGS) $(NDSTOOLOUT)$@ -9 $<

$(OBJ)/%.bin : %.elf
$(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYOUT)$@ $<

$(OBJ)/%.elf : %.obj
$(LD) $(LDFLAGS) $(LDOUT)$@ $^ $(LIBS)

$(OBJ)/%.obj : %.c
$(CC) $(CSTRICT) $(CFLAGS) $(CPPFLAGS) $(CCOUT)$@ $<

$(OBJ)/%.obj : %.cpp
$(CXX) $(CXXSTRICT) $(CXXFLAGS) $(CPPFLAGS) $(CCOUT)$@ $<

$(OBJ)/%.obj : %.asm
$(AS) $(ASFLAGS) $(ASOUT)$@ $<

########################
# Explicit rules for building objects go here.

all : $(TARGET)

$(OBJ) :
-mkdir $(OBJDIR)

$(TARGET) : $(OBJ) $(NDSOBJS)
$(DSBUILD) $(NDSOBJS) $(DSBUILDFLAGS) $(DSBUILDOUT) $@

$(NDSOBJS) : $(BINOBJS)
$(NDSTOOL) $(NDSTOOLFLAGS) $(NDSTOOLOUT)$@ -9 $<

$(BINOJS) : $(ELFOBJS)
$(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYOUT)$@ $<

$(ELFOBJS) : $(APPOBJS)
$(LD) $(LDFLAGS) $(LDOUT)$@ $^ $(LIBS)

clean :
-rm -r -f $(OBJDIR)
-rm -f $(TARGET)


########################
# Dependencies
DEPEND = $(OBJ) # $(MAKEFILE)

$(APPOBJS): $(DEPEND) $(INC2)/mtc.h

# End of file


Right, so there's the makefile. When I run make I get this:

Quote:
$ make
make: *** No rule to make target `arm9.elf', needed by `rel/arm9.bin'. Stop.


From the looks of it, the problem may be here:

Quote:
$(OBJ)/%.elf : %.obj
$(LD) $(LDFLAGS) $(LDOUT)$@ $^ $(LIBS)


or here:

Quote:
$(ELFOBJS) : $(APPOBJS)
$(LD) $(LDFLAGS) $(LDOUT)$@ $^ $(LIBS)


Is this the case? From the looks of it it seems to be having issue with the rule that calls the linked on .obj files, to the extent that it's not bothering to get to the point of actually compiling the source files...

Or rather, to illustrate it as a chain...

.nds.gba <- .nds <- .bin <- .elf <.o < .c

With the problem occurring when make attempts to follow the rule chain from .elf to .o

Does anyone have any advice on this? What am I doing wrong?

EDIT: Quote has buggered up the tabs, so don't worry about the makefile's tabbing being screwed (Which causes problems in real life :-)
_________________
"My boot, your face..." - Attributed to OOPMan, Emperor of Eroticon VI

You can find my NDS homebrew projects here...

#104784 - sasq - Mon Oct 02, 2006 4:53 pm

I think the problem is that mix between rules for files in the OBJ-dir and not - ie the elf file is created in the OBJ-dir but the elf->bin rule looks for it outside the OBJ-dir

If you want all your created files to end up in the $(OBJ)-dir you need
to do this:

Quote:

$(OBJ)/%.nds : $(OBJ)/%.bin
$(NDSTOOL) $(NDSTOOLFLAGS) $(NDSTOOLOUT)$@ -9 $<

$(OBJ)/%.bin : $(OBJ)/%.elf
$(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYOUT)$@ $<

$(OBJ)/%.elf : $(OBJ)/%.obj
$(LD) $(LDFLAGS) $(LDOUT)$@ $^ $(LIBS)


or if you want say the bin,elf and nds files outside, and only o-files in OBJ, do this:

Quote:

%.nds : %.bin
$(NDSTOOL) $(NDSTOOLFLAGS) $(NDSTOOLOUT)$@ -9 $<

%.bin : %.elf
$(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYOUT)$@ $<

%.elf : $(OBJ)/%.obj
$(LD) $(LDFLAGS) $(LDOUT)$@ $^ $(LIBS)

#104790 - OOPMan - Mon Oct 02, 2006 5:53 pm

Thanks for that, it helped...

I've come across another problem though, a funny one really...

Changing the makefile as you suggested works fine, but with one caveat.

Calling make the first time produces:

Quote:
$ make
mkdir ./rel
make: *** No rule to make target `rel/arm9.bin', needed by `demo1.nds'. Stop.


However, running make again works fine. At the moment the makefile is setup to produce and .nds and .nds.gba file in the root directory.

A dirty fix is to change the $(OBJ) rule as follows:
Quote:
$(OBJ) :
-mkdir $(OBJDIR)
make


While I'm happy to leave it like this, it would be nice if I could get it working without a recursive call to make.

From the look if it the error is occuring because the rel directory hasn't registered as being created when the rule to make arm9.bin is called.

Any suggestions?
_________________
"My boot, your face..." - Attributed to OOPMan, Emperor of Eroticon VI

You can find my NDS homebrew projects here...

#104792 - sasq - Mon Oct 02, 2006 6:06 pm

First its strange that you have both OBJ and OBJDIR that seems to mean the same thing - you can get rid of OBJDIR.

What you want is this

Code:

all : $(OBJ) $(TARGET)

$(OBJ) :
    -mkdir $(OBJ)

#104799 - OOPMan - Mon Oct 02, 2006 8:22 pm

Okay, but doing that doesn't actually have any effect on the problem, it's just a quirk that the author of the makefile uses...
_________________
"My boot, your face..." - Attributed to OOPMan, Emperor of Eroticon VI

You can find my NDS homebrew projects here...

#104804 - sasq - Mon Oct 02, 2006 8:45 pm

yeah but the code I quoted should make sure the objdir is created before the target is built

#104847 - OOPMan - Tue Oct 03, 2006 7:49 am

Unfortunately I tried that, figuring pretty much the same thing, and it didn't work :-(

It's a little strange, don't you think?

Well, anyway, I'm actually happy to leave it using the recursive make call as a fix. It may not look ultra-professional or anything, but it works :-)
_________________
"My boot, your face..." - Attributed to OOPMan, Emperor of Eroticon VI

You can find my NDS homebrew projects here...

#104860 - gmiller - Tue Oct 03, 2006 1:33 pm

Not sure if this would help but to see the actual order that the rules are being evaluated in do a "make -n" in your start state and it will show you the commands without executing them. You proably already knew this so it is just useless information. There is also the "-d" switch which will turn on makefile debugging as well.

#104862 - sasq - Tue Oct 03, 2006 3:18 pm

OOPMan wrote:
Unfortunately I tried that, figuring pretty much the same thing, and it didn't work :-(

It's a little strange, don't you think?

Well, anyway, I'm actually happy to leave it using the recursive make call as a fix. It may not look ultra-professional or anything, but it works :-)


Very strange, especially since the Makefile you quoted has the problem described since I think it evalulates the NDSOBJ-dependies of TARGET before the OBJS-dependency - thats why putting it before TARGET int the 'all:' rule instead should have worked...

You should maybe also try removing these initial rules;

$(TARGET) : $(NDSOBJS)
$(NDSOBJS) : $(BINOBJS)
$(BINOJS) : $(ELFOBJS)
$(ELFOBJS) : $(APPOBJS)

since they are repeated later with proper commands after them.

#104926 - OOPMan - Wed Oct 04, 2006 9:53 am

Hmmmmm, removing those initial targets causes the makefile to think it'
s trying to build the base MTC library :-) (This is because the next target is for the library :-)

I also tried adding $(OBJ) to the first $(TARGET) rule, but to no effect...

Very peculiar...

Still, at least the recursive make call works :-)
_________________
"My boot, your face..." - Attributed to OOPMan, Emperor of Eroticon VI

You can find my NDS homebrew projects here...

#104931 - sasq - Wed Oct 04, 2006 12:23 pm

Ah, that's true - the ALL rule should normally be the first explicit rule. If you type "make all" it should create the OBJDIR first like expected.

#104961 - masscat - Wed Oct 04, 2006 6:54 pm

If you do not give make a target on the command line then it will set its goal (the target it is ultimately trying to make) as the first target it finds in the makefile. The 'all' target does not have a special meaning, it is just convention that it gets used as the target to make all the top-level targets.

See the GNU make manual page for full description.