edit: This little project eventually went nowhere as I kept understanding Make better and better. In the end I deemed it good enough for my purposes and decided writing my own replacement wasn't worth the time.
Realizing that I didn't want xmk to miss Make's core feature made me feel a bit silly for trying to reinvent it. Thus I ended up spending a good couple hours trying to come up with a Makefile that could make me feel satisfied. Pretending I was only ever building for one platform without any separate debug buils led me to this:
001 PRJNAME = my_app # name of bin to build
002 SRCD = src # root dir of src files
003 LIBD = lib # root dir of vendor src files
004 SRC := $(shell find $(SRCD) -name '*.c') # recursively get all src files from src dir
005 SRC += $(shell find $(LIBD) -name '*.c') # append those from vendor dir
006 OBJ = $(patsubst %.c, xmk.d/obj/linux/%.o, $(SRC)) # get obj filenames for all src files
007 DEP = $(patsubst %.o, %.d, $(OBJ)) # filenames to save header dependencies to
008 BIN = xmk.d/bin/linux/$(PRJNAME) # where to save the binary...
009
010 CC = gcc
011 CFLAGS = -Isrc/include
012 LDFLAGS =
013
014
015 all: linux win64 # we omit the win64 build for brevity
016
017
018 $(BIN): $(OBJ) # this is run last in the chain, after compiling objects
019 $(CC) $(OBJ) -o $@
020
021 xmk.d/obj/linux/$(SRCD)/%.o: $(SRCD)/%.c # ugly and unwieldy copy/paste
022 mkdir -p $(@D) # however could be remedied by placing lib/ in src/
023 $(CC) $(CFLAGS) -MMD -MP -c $< -o $@
024 xmk.d/obj/linux/$(LIBD)/%.o: $(LIBD)/%.c
025 mkdir -p $(@D) # these create the necessary dirs to hold obj and dep files
026 $(CC) $(CFLAGS) -MMD -MP -c $< -o $@
027
028 .PHONY: clean linux
029 clean: $(OBJ) $(DEP) # getting rid of all the build files
030 rm $(OBJ) $(DEP)
031
032 linux: $(BIN) # so the user can run the target by specifying the platform
033
034 -include $(DEP) # include dependency files
035
Still this isn't a Makefile one would use in a real project. There's not even an option to create a debug build. I played around with a phony rule debug
that would use ($eval....)
to modify variables before running the build process, but it unfortunately didn't work out. The possible solutions I've come across to solve the remaining issues all don't sit well with me and are the main reason I was trying to develop my own build tool. That said, at this point it appears best to redevelop xmk as a build assistant around Make that either adds preprocessing to Makefiles or build Makefiles from config files that describe all the required rules and targets in a hierarchical way.
Right now I'm gravitating towards the latter option, especially since it would allow me to have one build tool for all sorts of programming environments.
So my conclusion remains that Make gets uncomfortable to deal with the moment you plan on using more than one or two simple target binaries in a Makefile.