Since sdcc have some limitations, like compiling one file at a time, I've tried hard to write a Makefile to perfect the automation of MCS-51 development, which have some requirements:
- Source file (.c) expect main.c are stored in
ProjectFolder/Sources/, whilemain.care stored at the root of project folder. - Headers are stored in
ProjectFolder/Includes/. - Outputs through compiling, linking and locating should be stored at
ProjectFolder/Builds/ - Makefile should be smart enough to find all source files, instead of type their file name by hand.
- Makefile should be smart enough to if there are some files in
Sources/, or there's onlymain.cin the project.
The file structure can be depicted like:
Project Folder
|
|- Sources
| |
| |(some source files, but OPTIONAL)
|
|- Includes
| |
| |(some headers, but OPTIONAL)
|
|- Builds
| |
| |(some .rel .o .hex files. OUTPUT here)
|
|- main.c
|
|- Makefile
Here's my solution but still have a problem. It cannot be used for project only have one file main.c which means no source file in Sources/.
INCLUDES = Includes/
SOURCES = Sources/
BUILDS = Builds/
CC = sdcc
CFLAGS = -o $(BUILDS)
LOADER = stcgal
LOADER_FLAGS = -P stc89
$(BUILDS)main.ihx: main.c $(BUILDS)main.rel
# Link
@$(CC) main.c $(shell find $(BUILDS) -name "*.rel" -not -name "main.rel" -maxdepth 1) $(CFLAGS)
@echo Link & Locate Succeeded
$(BUILDS)main.rel: $(SOURCES) $(BUILDS)
# Compile
@for f in $(shell ls $(SOURCES)*.c) ; do \
$(CC) -c $${f} $(CFLAGS) ; \
done
@echo Compile Succeeded
$(SOURCES):
@mkdir $(SOURCES)
$(BUILDS):
@mkdir $(BUILDS)
clean:
# Remove all files in build folder
@rm $(BUILDS)*
@echo Build Folder Cleaned
load: $(BUILDS)main.ihx
# Load data to MCU via USB port
@$(LOADER) $(LOADER_FLAGS) -p $(shell ls /dev/tty.usbserial*) $(BUILDS)main.ihx
Let's try something. First note that I've not looked at the
loadtarget.Let's start with the same definition as you:
We need a variable with the source files from Sources. GNU Make has a
wildcardfunctions which does the same thing as yourfind. See that I'm using:=to have an immediate expansion of the value, so the wildcard will not be executed several times.Now a variable with the
.relfiles. It is build from main.rel and the SRCFILES value:Let's define another variable with the flag to pass so the Includes directory is searched:
Now we can define pattern rules to describe how to build
.relfiles from.cfiles. I'm using an order-only prerequisite for the build directory:Let's define some usability targets:
And finally define how to build the targets which aren't handled by the pattern rules:
I've used a few variables (
CC,CPPFLAGS,CFLAGS,LDFLAGS,LOADLIBES,LDLIBS) in the same way as they are used by the built-in rules of GNU Make.I've kept your makefile behavior. There are good reasons to have
Makefiles targeting to build in the current directory. Explaining them and modifying theMakefilefor that is out of scope for this answer, you may look at MadScientist's GNU Make White Papers and the GNU Make Manual.