I’ve never enjoyed gnu make. Most people I know don’t, but it’s a necessary evil. So I took some time out to finally get it into some shape. So, now I have a new SW structure. Here is my new directory structure:

And here are my makefiles and includes:

SW/Makefile:

 1 SW_DIR= $(shell pwd | sed 's/\/cygdrive\/c\//C:\\\\/' | sed 's/\//\\\\/g')
 2 SW_DIR_CYG= $(shell pwd)
 3 CFLAGS_Z80=-mz80
 4 CFLAGS_GENERIC=-c -DNDEBUG
 5 AFLAGS=-o
 6 LFLAGS= -mz80 --no-std-crt0 --nostdlib --code-loc 0x100 --data-loc 0x8000
 7 INCLUDES=-I${SW_DIR}/include -I${SW_DIR}/app/include
 8 INCLUDES_CYG=-I${SW_DIR_CYG}/include -I${SW_DIR_CYG}/app/include
 9 TOOLDIR=/cygdrive/c/Program\ Files/SDCC/bin
10 LIBDIR=lib
11 
12 MAKEARGS="CFLAGS_Z80=${CFLAGS_Z80}" "CFLAGS_GENERIC=${CFLAGS_GENERIC}" "INCLUDES=${INCLUDES}" "AFLAGS=${AFLAGS}" "TOOLDIR=${TOOLDIR}" "LIBDIR=../${LIBDIR}" "BASEDIR=.." "LFLAGS=${LFLAGS}" "INCLUDES_CYG=${INCLUDES_CYG}"
13 
14 
15 # This makefile is the top level makefile that calls down to all the submakes
16 # It will get the current directory, basic flags, and then drill down
17 # includes are 
18 #
19 
20 #
21 
22 .PHONY: all c bsp clean depends clean_bsp clean_app clean_c clean_lib
23 
24 all:
25  cd app ; ${MAKE} all ${MAKEARGS} "DIRS=test" "PROG=mainRW"
26 # cd app ; ${MAKE} all ${MAKEARGS} "DIRS=menu" "PROG=menu"
27 
28 c:
29  cd c_src ; ${MAKE} all ${MAKEARGS}
30 
31 bsp:
32  cd bsp ; ${MAKE} all ${MAKEARGS} "DIRS=crt0  diag  flash  gpio  interrupt  membank  spi  tick  uart" "LIB=bsp"
33  cd app ; ${MAKE} all ${MAKEARGS} "DIRS=idle intelHex ringBuffer timer" "LIB=bsp"
34 
35 clean: clean_bsp clean_app clean_c clean_lib
36 
37 clean_bsp:
38  cd bsp ; ${MAKE} clean ${MAKEARGS} "DIRS=crt0  diag  flash  gpio  interrupt  membank  spi  tick  uart" "LIB=bsp"
39 
40 clean_app:
41  cd app ; ${MAKE} clean ${MAKEARGS} "DIRS=idle intelHex ringBuffer  test  timer menu test" "LIB=bsp"
42 
43 clean_c:
44  cd c_src; ${MAKE} clean ${MAKEARGS}
45 
46 clean_lib:
47  cd lib ; rm -f *.lib; rm -f *.rel
48  
49 depends:
50  cd app ; ${MAKE} depends ${MAKEARGS}
51 
52 test:
53  cd bsp; pwd; make test ${MAKEARGS}

SW/common.inc:

1 COMMON=INCUDED
2 
3 MAKEARGS="CFLAGS_Z80=${CFLAGS_Z80}" "CFLAGS_GENERIC=${CFLAGS_GENERIC}" "INCLUDES=${INCLUDES}" "AFLAGS=${AFLAGS}" "TOOLDIR=${TOOLDIR}" "LIBDIR=../${LIBDIR}" "BASEDIR=../${BASEDIR}"

SW/subdirs.inc:

 1 SUBDIRS=INCUDED
 2 
 3 .PHONY: all clean
 4 
 5 all:
 6  echo ${DIRS}
 7  @for i in ${DIRS} ; do \
 8         cd $$i; \
 9   make all ${MAKEARGS}; \
10   cd ..; \
11     done
12 
13 clean:
14  echo ${DIRS}
15  @for i in ${DIRS} ; do \
16         cd $$i; \
17   make clean ${MAKEARGS}; \
18   cd ..; \
19     done

SW/generate.inc:

 1 CC=${TOOLDIR}/sdcc.exe
 2 AS=${TOOLDIR}/sdasz80.exe
 3 AR=${TOOLDIR}/sdcclib.exe
 4 
 5 C_SOURCES=$(wildcard *.c)
 6 S_SOURCES=$(wildcard *.s)
 7 REL_C=$(patsubst %.c,%.rel, ${C_SOURCES})
 8 REL_S=$(patsubst %.s,%.rel ,${S_SOURCES})
 9 
10 all: ${REL_C} ${REL_S}
11 
12 # - keeps it from crashing out if no *.d file
13 -include *.d
14 
15 clean:
16  rm -f *.d
17  rm -f *.lib
18  rm -f *.rel
19  rm -f *.asm
20  rm -f *.lst
21  rm -f *.sym
22 
23 %.rel : %.s
24  ${AS} -g ${AFLAGS} $<
25  ${AR} r ${LIBDIR}/${LIB}.lib $@
26 
27 %.rel : %.c
28  ${CC} ${CFLAGS_Z80} ${CFLAGS_GENERIC} ${INCLUDES} $<
29  ${AR} r ${LIBDIR}/${LIB}.lib $@
30 
31 %.d : %.c
32  gcc ${CFLAGS_GENERIC} ${INCLUDES_CYG} -MM $< > $*.d

The Makefiles found in directories with no code:

1 include ${BASEDIR}/common.inc
2 include ${BASEDIR}/subdirs.inc

The Makefiles found in directories with code:

1 include ${BASEDIR}/common.inc
2 include ${BASEDIR}/generate.inc

SW/bsp/crt0 has a special makefile since crt0 isn’t archived but copied to SW/lib:

 1 include ${BASEDIR}/common.inc
 2 
 3 # This makefile is unique because the crt0 isn't archived. Rather it must be the first item in the list of rel/ar given to the linker
 4 CC=${TOOLDIR}/sdcc.exe
 5 AS=${TOOLDIR}/sdasz80.exe
 6 AR=${TOOLDIR}/sdcclib.exe
 7 
 8 C_SOURCES=$(wildcard *.c)
 9 S_SOURCES=$(wildcard *.s)
10 REL_C=$(patsubst %.c,%.rel, ${C_SOURCES})
11 REL_S=$(patsubst %.s,%.rel ,${S_SOURCES})
12 
13 all: ${REL_C} ${REL_S}
14 
15 clean:
16  rm -f *.d
17  rm -f *.lib
18  rm -f *.rel
19  rm -f *.asm
20  rm -f *.lst
21  rm -f *.sym
22 
23 %.rel : %.s
24  ${AS} -g ${AFLAGS} $<
25 # ${AR} rc ${LIBDIR}/${LIB} $@
26  cp crt0.rel ${LIBDIR}/
27 
28 %.rel : %.c
29  ${CC} ${CFLAGS_Z80} ${CFLAGS_GENERIC} ${INCLUDES} $<
30 # ${AR} rc ${LIBDIR}/${LIB}.ar $@

And the common C directory also has a special Makefile:

 1 include ${BASEDIR}/common.inc
 2 
 3 CC=${TOOLDIR}/sdcc.exe
 4 AS=${TOOLDIR}/sdasz80.exe
 5 AR=${TOOLDIR}/sdcclib.exe
 6 
 7 
 8 C_SOURCES= _calloc.c _divslong.c _divulong.c _free.c _heap.c _itoa.c _ltoa.c _malloc.c _memchr.c _memcmp.c _memcpy.c _memset.c _modslong.c _modulong.c _mullong.c _realloc.c _startup.c _strcat.c _strchr.c _strcmp.c _strcspn.c _strncat.c _strncmp.c _strncpy.c _strpbrk.c _strrchr.c _strspn.c _strstr.c _strtok.c assert.c atoi.c atol.c errno.c gets.c isalnum.c isalpha.c isblank.c iscntrl.c isdigit.c isgraph.c islower.c isprint.c ispunct.c isspace.c isupper.c isxdigit.c labs.c puts.c rand.c sprintf.c strxfrm.c time.c tolower.c toupper.c vprintf.c 
 9 
10 # _divschar.c _modschar.c _mulschar.c _setjmp.c _strcpy.c abs.c _memmove.c _strlen.c _modsint.c _moduint.c _mulint.c _divsint.c _divuint.c
11 
12 C_LONG_LONG_SOURCES= _divslonglong.c _divulonglong.c _modslonglong.c _modulonglong.c _mullonglong.c _rlslonglong.c _rlulonglong.c _rrslonglong.c _rrulonglong.c atoll.c
13 
14 C_FLOAT_SOURCES= _atof.c _fs2schar.c _fs2sint.c _fs2slong.c _fs2uchar.c _fs2uint.c _fs2ulong.c _fsadd.c _fscmp.c _fsdiv.c _fseq.c _fsget1arg.c _fsget2args.c _fsgt.c _fslt.c _fsmul.c _fsneq.c _fsnormalize.c _fsreturnval.c _fsrshift.c _fssub.c _fsswapargs.c _logexpf.c _schar2fs.c _sint2fs.c _slong2fs.c _uchar2fs.c _uint2fs.c _ulong2fs.c acosf.c asincosf.c asinf.c atan2f.c atanf.c ceilf.c cosf.c coshf.c cotf.c expf.c fabsf.c floorf.c frexpf.c ldexpf.c log10f.c logf.c modff.c powf.c sincosf.c sincoshf.c sinf.c sinhf.c sqrtf.c tancotf.c tanf.c tanhf.c
15 
16 REL_C_SOURCES=$(patsubst %.c,%.rel, ${C_SOURCES})
17 REL_C_LONG_LONG_SOURCES=$(patsubst %.c,%.rel, ${C_LONG_LONG_SOURCES})
18 REL_C_FLOAT_SOURCES=$(patsubst %.c,%.rel, ${C_FLOAT_SOURCES})
19 REL_S=$(patsubst %.s,%.rel ,${S_SOURCES})
20 
21 .PHONY: all z80
22 
23 all: c_lib float_lib longlong_lib z80
24 
25 z80:
26  cd z80; make all ${MAKEARGS} "LIB=c"
27 
28 c_lib: ${REL_C_SOURCES} ${REL_S}
29  ${AR} r ${LIBDIR}/c.lib ${REL_C_SOURCES} ${REL_S}
30  
31 float_lib: ${REL_C_FLOAT_SOURCES}
32  ${AR} r ${LIBDIR}/float.lib ${REL_C_FLOAT_SOURCES}
33  
34 longlong_lib: ${REL_C_LONG_LONG_SOURCES}
35  ${AR} r ${LIBDIR}/longlong.lib ${REL_C_LONG_LONG_SOURCES}
36  
37 %.rel : %.s
38  ${AS} -g ${AFLAGS} $<
39 
40 %.rel : %.c
41  ${CC} ${CFLAGS_Z80} ${CFLAGS_GENERIC} ${INCLUDES} $<
42 
43 clean:
44  rm -f *.d
45  rm -f *.lib
46  rm -f *.rel
47  rm -f *.asm
48  rm -f *.lst
49  rm -f *.sym
50  cd z80; make clean ${MAKEARGS}

And this is how I make a clean build of the program I’m working with:

$> make clean
$> make all

It’s not perfect. It’s probably not even good. But it’s better than the ad hoc Makefiles I had before because it’s more scalable and extensible.