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.

C/C++ > compile individual file

#106198 - snowsquirrel - Mon Oct 16, 2006 7:00 pm

How do I compile an individual file? Normallay if I want to build MyFile.cpp, I just do a make MyFile.o.

But the generated makefile does not seem to have that target, though a .o:.cpp rule exists. I also tried make build/MyFile.o.

I understand basic makefiles, but not sure that the problem is here.

THanks,

~S

#106238 - keldon - Tue Oct 17, 2006 3:14 am

Have a look at this makefile tutorial first( http://www.eng.hawaii.edu/Tutor/Make/ )

#106275 - snowsquirrel - Tue Oct 17, 2006 1:14 pm

I already knew most of what is is in that tutorial.

Specifically:
Code:

%.o : %.c
   @echo $(notdir $<)
   @$(CC) -MM $(CFLAGS) -o $*.d $<
   @$(CC)  $(CFLAGS) -c $< -o$@


should allow me to do this:
Code:
make -C build MyFile.o

But it does not work, neither does make build/MyFile.o

My directory structure is nothing fancy:

+
|
+-build
|
+-gfx
|
+-source


Here is my complete make file, though it does not really differ from the genrated one:
Code:

PROGNAME =PAlib
OFILES   +=
ADD_LIBS +=

PATH       := $(DEVKITARM)/bin:$(PATH)

ARM7BIN      := -7 $(PAPATH)/lib/arm7/arm7.bin
TEXT1       := PAlib Demo
TEXT2       := using PAlib
TEXT3       := www.palib.com
ICON       := -b $(CURDIR)/../logo/logo.bmp
LOGO      := -o $(CURDIR)/../logo/logo_wifi.bmp

#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM)
endif
#---------------------------------------------------------------------------------
# TARGET is the name of the output, if this ends with _mb generates a multiboot image
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
#---------------------------------------------------------------------------------
TARGET   :=   $(shell basename $(CURDIR))
BUILD      :=   build
SOURCES   :=   source data
INCLUDES   := gfx include build data

EXPORT_DIR := build
#---------------------------------------------------------------------------------
# ARM7BIN is the path to an arm7 binary other than the default
#   usage: ARM7BIN := -7 binaryName.bin
#
# ICON is the path to an icon to be used int the header plus text
#   usage: ICON := -t iconName.bmp "text line one; text line 2; text line 3"
#
#---------------------------------------------------------------------------------



#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH   :=   -mthumb-interwork

# note: arm9tdmi isn't the correct CPU arch, but anything newer and LD
# *insists* it has a FPU or VFP, and it won't take no for an answer!
CFLAGS   :=   -g -Wall -O2\
       -mcpu=arm9tdmi -mtune=arm9tdmi -fomit-frame-pointer\
      -ffast-math \
      $(ARCH)

CFLAGS   +=   $(INCLUDE) -DARM9 -I$(DEVKITPRO)/PAlib/include/nds

ASFLAGS   :=   -g $(ARCH)
LDFLAGS   :=   -g $(ARCH) -mno-fpu -L$(DEVKITPRO)/PAlib/lib


#---------------------------------------------------------------------------------
# path to tools - this can be deleted if you set the path in windows
#---------------------------------------------------------------------------------
# export PATH      :=   /d/dev/ds/devkitARM_r11/bin:/bin
 
#---------------------------------------------------------------------------------
# PATH to ndslib - just make a system variable called NDSLIBPATH and be done with it
#---------------------------------------------------------------------------------
# NDSLIBPATH   :=   /d/dev/ds/ndslib/
 
#---------------------------------------------------------------------------------
# the prefix on the compiler executables
#---------------------------------------------------------------------------------
PREFIX         :=   arm-eabi-
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS   := -lnds9
LIBSPA   := -lpa9
 
 
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS   :=   $(DEVKITPRO)/libnds
LIBDIRPA   :=   $(PAPATH)
 
 
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
 
export OUTPUT   :=   $(CURDIR)/$(TARGET)
 
export VPATH   :=   $(foreach dir,$(SOURCES),$(CURDIR)/$(dir))
 
export CC      :=   $(PREFIX)gcc
export CXX      :=   $(PREFIX)g++
export AR      :=   $(PREFIX)ar
export OBJCOPY   :=   $(PREFIX)objcopy
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
export LD      :=   $(CXX)
#export LD      :=   $(CC)
 
CFILES      :=   $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES   :=   $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES      :=   $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
PCXFILES   :=   $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.pcx)))
BINFILES   :=   $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.bin)))
PALFILES   :=   $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.pal)))
RAWFILES   :=   $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.raw)))
MAPFILES   :=   $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.map)))
JPEGFILES   :=   $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.jpg)))
MODFILES   :=   $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.mod)))
GIFFILES   :=   $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.gif)))
BMPFILES   :=   $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.bmp)))
 
export OFILES   :=   $(MAPFILES:.map=.o) $(RAWFILES:.raw=.o) $(PALFILES:.pal=.o) $(BINFILES:.bin=.o) $(PCXFILES:.pcx=.o) $(JPEGFILES:.jpg=.o) $(MODFILES:.mod=.o) $(GIFFILES:.gif=.o) $(BMPFILES:.bmp=.o)\
               $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
 
export INCLUDE   :=   $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
               $(foreach dir,$(LIBDIRS),-I$(dir)/include) \
               $(foreach dir,$(LIBDIRS),-I$(dir)/include/nds) \
               -I$(PAPATH)/include/nds\
               -I$(CURDIR)/$(BUILD)
 
export LIBPATHS   :=   $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
export LIBPATHPA   :=   $(foreach dir,$(LIBDIRPA),-L$(dir)/lib)
 
.PHONY: $(BUILD) clean export
 
#---------------------------------------------------------------------------------
$(BUILD):
   @[ -d $@ ] || mkdir -p $@
   @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
 
#---------------------------------------------------------------------------------
clean:
   @echo clean ...$(TARGET)
   @rm -fr $(BUILD) *.elf *.*ds*
 
export:
   @echo exporting ...$(TARGET)
   @cp *.nds $(EXPORT_DIR)/$(TARGET).nds

#---------------------------------------------------------------------------------
else
 
DEPENDS   :=   $(OFILES:.o=.d)
 
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).ds.gba   :    $(OUTPUT).nds

$(OUTPUT).nds   :    $(OUTPUT).bin

$(OUTPUT).bin   :   $(OUTPUT).elf
 
$(OUTPUT).elf   :   $(OFILES)
 
#---------------------------------------------------------------------------------
%.ds.gba: %.nds
   @echo built ... $(notdir $@)
   @dsbuild $<
   @cp $(CURDIR)/../$(notdir $@) ../$(notdir $(OUTPUT)).sc.nds

#---------------------------------------------------------------------------------
%.nds: %.bin
   
   @ndstool -c $@ -9 $(TARGET).bin $(ARM7BIN) $(LOGO) $(ICON) "$(TEXT1);$(TEXT2);$(TEXT3)"


#---------------------------------------------------------------------------------
%.bin: %.elf
   
   @$(OBJCOPY) -O binary $(TARGET).elf $(TARGET).bin
 
#---------------------------------------------------------------------------------
%.elf:
   @echo $(LD)  $(LDFLAGS) -specs=ds_arm9.specs $(OFILES) $(LIBPATHPA) $(LIBSPA) $(LIBPATHS) $(LIBS) -o $(TARGET).elf
   @$(LD)  $(LDFLAGS) -specs=ds_arm9.specs $(OFILES) $(LIBPATHPA) $(LIBSPA) $(LIBPATHS) $(LIBS) -o $(TARGET).elf
 
 
 
#---------------------------------------------------------------------------------
# Compile Targets for C/C++
#---------------------------------------------------------------------------------
 
#---------------------------------------------------------------------------------
%.o : %.cpp
   @echo $(notdir $<)
   @$(CXX) -MM $(CFLAGS) -o $*.d $<
   @$(CXX) $(CFLAGS) -c $< -o$@
 
#---------------------------------------------------------------------------------
%.o : %.c
   @echo $(notdir $<)
   @$(CC) -MM $(CFLAGS) -o $*.d $<
   @$(CC)  $(CFLAGS) -c $< -o$@
 
#---------------------------------------------------------------------------------
%.o : %.s
   @echo $(notdir $<)
   @$(CC) -MM $(CFLAGS) -o $*.d $<
   @$(CC)  $(ASFLAGS) -c $< -o$@
 
define bin2o
   cp $(<) $(*).tmp
   $(OBJCOPY) -I binary -O elf32-littlearm -B arm \
   --rename-section .data=.rodata \
   --redefine-sym _binary_$*_tmp_start=$*\
   --redefine-sym _binary_$*_tmp_end=$*_end\
   --redefine-sym _binary_$*_tmp_size=$*_size\
   $(*).tmp $(@)
   echo "extern const u8" $(*)"[];" > $(*).h
   echo "extern const u32" $(*)_size[]";" >> $(*).h
   rm $(*).tmp
endef
 
#---------------------------------------------------------------------------------
%.o   :   %.pcx
#---------------------------------------------------------------------------------
   @echo $(notdir $<)
   @$(bin2o)
 
#---------------------------------------------------------------------------------
%.o   :   %.bin
#---------------------------------------------------------------------------------
   @echo $(notdir $<)
   @$(bin2o)
 
#---------------------------------------------------------------------------------
%.o   :   %.raw
#---------------------------------------------------------------------------------
   @echo $(notdir $<)
   @$(bin2o)
 
#---------------------------------------------------------------------------------
%.o   :   %.pal
#---------------------------------------------------------------------------------
   @echo $(notdir $<)
   @$(bin2o)
 
#---------------------------------------------------------------------------------
%.o   :   %.map
#---------------------------------------------------------------------------------
   @echo $(notdir $<)
   @$(bin2o)

#---------------------------------------------------------------------------------
%.o   :   %.mdl
#---------------------------------------------------------------------------------
   @echo $(notdir $<)
   @$(bin2o)

#---------------------------------------------------------------------------------
%.o   :   %.jpg
#---------------------------------------------------------------------------------
   @echo $(notdir $<)
   @$(bin2o)

#---------------------------------------------------------------------------------
%.o   :   %.mod
#---------------------------------------------------------------------------------
   @echo $(notdir $<)
   @$(bin2o)

#---------------------------------------------------------------------------------
%.o   :   %.gif
#---------------------------------------------------------------------------------
   @echo $(notdir $<)
   @$(bin2o)

#---------------------------------------------------------------------------------
%.o   :   %.bmp
#---------------------------------------------------------------------------------
   @echo $(notdir $<)
   @$(bin2o)

 
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

#106313 - strager - Tue Oct 17, 2006 8:31 pm

snowsquirrel wrote:
Code:

# ...
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
 
export OUTPUT   :=   $(CURDIR)/$(TARGET)
 
# ...

.PHONY: $(BUILD) clean export
 
#---------------------------------------------------------------------------------
$(BUILD):
   @[ -d $@ ] || mkdir -p $@
   @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
 
#---------------------------------------------------------------------------------
clean:
   @echo clean ...$(TARGET)
   @rm -fr $(BUILD) *.elf *.*ds*
 
export:
   @echo exporting ...$(TARGET)
   @cp *.nds $(EXPORT_DIR)/$(TARGET).nds

#---------------------------------------------------------------------------------
else
# Everything above is executed in "/"
####################################
####################################
####################################
####################################
####################################
# Everything below is executed in "/build"

DEPENDS   :=   $(OFILES:.o=.d)
 
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).ds.gba   :    $(OUTPUT).nds

$(OUTPUT).nds   :    $(OUTPUT).bin

$(OUTPUT).bin   :   $(OUTPUT).elf
 
$(OUTPUT).elf   :   $(OFILES)
 
#---------------------------------------------------------------------------------
%.ds.gba: %.nds
   @echo built ... $(notdir $@)
   @dsbuild $<
   @cp $(CURDIR)/../$(notdir $@) ../$(notdir $(OUTPUT)).sc.nds

#---------------------------------------------------------------------------------
%.nds: %.bin
   
   @ndstool -c $@ -9 $(TARGET).bin $(ARM7BIN) $(LOGO) $(ICON) "$(TEXT1);$(TEXT2);$(TEXT3)"


#---------------------------------------------------------------------------------
%.bin: %.elf
   
   @$(OBJCOPY) -O binary $(TARGET).elf $(TARGET).bin
 
#---------------------------------------------------------------------------------
%.elf:
   @echo $(LD)  $(LDFLAGS) -specs=ds_arm9.specs $(OFILES) $(LIBPATHPA) $(LIBSPA) $(LIBPATHS) $(LIBS) -o $(TARGET).elf
   @$(LD)  $(LDFLAGS) -specs=ds_arm9.specs $(OFILES) $(LIBPATHPA) $(LIBSPA) $(LIBPATHS) $(LIBS) -o $(TARGET).elf
 
 
# your %.o: %.ext's here-include $(DEPENDS)

# ...

#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------


Basically, make enters the top part of the Makefile first (before all the #'s I made). However, the rule you're trying to get to isn't defined there; it's defined when the default rule ('all') calls make again, changing the current directory to build. It is then when your rules get defined.

You'd have to modify your Makefile (somehow) to redirect all unknown messages to be redirected to another call of make. I haven't a clue how one would do this.

#106314 - snowsquirrel - Tue Oct 17, 2006 8:48 pm

looks like I will have roll my own makefile, loosely based on the generated one.

Yuck...

#106323 - Cearn - Tue Oct 17, 2006 10:11 pm

The main purpose of makefiles it to make working with multiple sources manageable. Why do you need to compile individual files anyway?

#106335 - snowsquirrel - Wed Oct 18, 2006 12:00 am

If you have to ask that, you probably won't get the answer, but here it goes anyway.

Compiling is a nice quick syntax check for the file you are currently editing. Also, say you change a comment in a *.h file that is included everywhere. Now you go back to the .c/.cpp file you are editing, and make some changes. Now when you do a make, it has to compile 45 .c/.cpp files, that include the guilty .h, where as if you had just comiled that file, nothing would have changed.

Obviously linking has to be done, and can find other errors, but linking is generally a slow procedure, and most typos and mental slips cause compile errors, not link errors.

If you work on large projects (1000 plus .cpp/.c files), compiling a single file is essential IMHO. I compile-current-file (ctrl-f7) in visual studio all day. Now my homebrew project here is a meagre 8 .cpp files right now, I have just become accustomed to compiling a single file. My editor (vim) supports building single files with a button press, too.

I probably won't get to it until the weekend, but I will post my makefile, maybe give it a whirl, see what you think.

~S