Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Makefiles are an eerily lisplike turing tarpit. I hand wrote the makefiles for my projects, they generate wonderfully organized build trees. Hell I use makefiles to manage my dotfiles repository, even blogged about it.

https://www.matheusmoreira.com/articles/managing-dotfiles-wi...

The sanest way I've found to write makefiles is to think of it as a tool that maps input paths to output paths.

When compiling a program, I want to map source/program.c to build/$(config)/objects/program.o so I write pattern rules that do just that.

  $(directories.build.objects)/%.o: $(directories.source)/%.c | directories
          $(strip $(CC) $(CFLAGS) -o $@ -c $<)
Then I write make functions to convert paths in some tree to paths in another tree, which makes it easy to create lists of files which then match the pattern rules.

  source_to_object = $(patsubst $(directories.source)/%.c,$(directories.build.objects)/%.o,$(1))
These functions are then augmented by lots and lots of project specific variables to organize things...

  directories.source := source

  directories.build.root := build
  directories.build := $(directories.build.root)/$(config)
  directories.build.objects := $(directories.build)/objects

  sources.program := $(shell find $(directories.source) -type f)
  objects.program := $(call source_to_object,$(sources.program))
Then I add a real target which is supposed to get the makefile going.

  targets.program := $(directories.build)/program

  $(targets.program): $(objects.program) | directories
          $(strip $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^)
Then I add a phony target for it.

  targets.phony += program
  program: $(targets.program)

  .PHONY: $(targets.phony)
Then typing "make program" triggers the rule to make build/$(config)/program which depends on all the object files which will be linked into it which in turn is derived from a dynamically computed list of source files, and making those object files triggers the pattern rule which builds the entire thing.

Using make without phony targets is insane. Without phony targets, I'd need to type things like "make build/aarch64/program" in order to get a build started. So I use phony targets for everything. Much easier to type "make program".

It got to the point I created a phony-targets shell script which parses make's database output and processes it into a sort of help text for any given makefile's phony targets interface:

https://github.com/matheusmoreira/.files/blob/master/~/.loca...



Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: