Live data from Hacker News

The Language Agnostic, All-Purpose, Incredible, Makefile

blog.mindlessness.life

11–20 of 124 posts

Re: The Language Agnostic, All-Purpose, Incredible, Makefile

#11
post #9

Make is great as a dependency resolution engine. For everything else, it is absolutely horrible. What I typically do is use make only for what it is good: as a dependency resolution back-end. All the build logic for my projects is written in Python, in an executable file stored in the project root directory and called "make" (I have "." in my PATH). The Python script, when it runs, generates on the fly a clean, lean,…

There's at least one more usecase IMO: definition of common development lifecycle steps in a shared Makefile across services. At my current workplace, instead of having a bunch of bash scripts in every service, I just give every service repo a Makefile that usually is a oneliner where common.mk is included. this just wraps docker-compose and gives us commands like make, make run, make stop, make lint, make test, make help etc.

This way we can e.g. have repos using completely different technology stacks but the interface to them is the same - whether it's our database, a node.js webservice, a python data analytics tool etc. and the definition of these lifecycle commands in common.mk are totally trivial, they're just .phony. one-liner rules.

Re: The Language Agnostic, All-Purpose, Incredible, Makefile

#12
post #9

Make is great as a dependency resolution engine. For everything else, it is absolutely horrible. What I typically do is use make only for what it is good: as a dependency resolution back-end. All the build logic for my projects is written in Python, in an executable file stored in the project root directory and called "make" (I have "." in my PATH). The Python script, when it runs, generates on the fly a clean, lean,…

There's at least one more usecase IMO: definition of common development lifecycle steps in a shared Makefile across services. At my current workplace, instead of having a bunch of bash scripts in every service, I just give every service repo a Makefile that usually is a oneliner where common.mk is included. this just wraps docker-compose and gives us commands like make, make run, make stop, make lint, make test, make…

That works, but isn't particularly a Make feature. That'd be just as easy to do in bash, python, ruby, JS...

Re: The Language Agnostic, All-Purpose, Incredible, Makefile

#13

Earlier quoted context omitted.

There's at least one more usecase IMO: definition of common development lifecycle steps in a shared Makefile across services. At my current workplace, instead of having a bunch of bash scripts in every service, I just give every service repo a Makefile that usually is a oneliner where common.mk is included. this just wraps docker-compose and gives us commands like make, make run, make stop, make lint, make test, make…

That works, but isn't particularly a Make feature. That'd be just as easy to do in bash, python, ruby, JS...

Yes, but a Makefile is a sensible place for documentation on how to build and run everything (that happens to be executable). If there's a bunch of scripts all over, I'm not going to know which one I'm supposed to run. And it's probably not going to resolve dependencies for me.

Re: The Language Agnostic, All-Purpose, Incredible, Makefile

#14
post #9

Make is great as a dependency resolution engine. For everything else, it is absolutely horrible. What I typically do is use make only for what it is good: as a dependency resolution back-end. All the build logic for my projects is written in Python, in an executable file stored in the project root directory and called "make" (I have "." in my PATH). The Python script, when it runs, generates on the fly a clean, lean,…

i like make primarily as an 'entry point'. there are better tools for dependency management and building, usually language-specific, but as the OP notes, that also requires remembering each tool's invocation details, and documenting them in the README for anyone else wanting to build your project. it's easier to capture the tool invocation in a Makefile and let that serve as your primary interface.

Re: The Language Agnostic, All-Purpose, Incredible, Makefile

#15
post #3

I like make, but I had a lot more luck with just/justfile, which is similar to make conceptually but with less idiosyncratic syntax/execution.

I'd also add https://github.com/go-task/task and https://github.com/magefile/mage (both written in Go) for people who are looking for alternatives to Make.

Re: The Language Agnostic, All-Purpose, Incredible, Makefile

#16
I sometimes use GNU Make to fire off custom code generators, before the files are handed off to other parts of the toolchain which can have their own complicated dependency management. This works quite well. The one annoying problem that I often encounter is that Make does not handle multiple targets (i.e. the code generator generates multiple files, e.g. 'file1.h', 'file1.cpp', 'file2.h', 'file2.cpp', 'test.cpp'). I usually end up inserting a bunch of .PHONY targets, which causes unnecessary evaluation of the dependency graph, but at least it works, instead of breaking in seemingly random ways.

My other use of Makefiles is to capture small (< ~5 lines) of bash, python or such scripts for doing certain things within a directory. I find that to be more efficient than documenting that sort of info in a README.md file.

Re: The Language Agnostic, All-Purpose, Incredible, Makefile

#17
post #16

I sometimes use GNU Make to fire off custom code generators, before the files are handed off to other parts of the toolchain which can have their own complicated dependency management. This works quite well. The one annoying problem that I often encounter is that Make does not handle multiple targets (i.e. the code generator generates multiple files, e.g. 'file1.h', 'file1.cpp', 'file2.h', 'file2.cpp', 'test.cpp'). I…

Not sure what you mean by "Make does not handle multiple targets".

You can definitely do `make foo bar` and it will run the recipes for both foo and bar. You can also write a recipe with multiple prerequisites (which could be the result of a variable expansion).

Curious about the limitation; could be there's a way around it or that I never ran into it.

Re: The Language Agnostic, All-Purpose, Incredible, Makefile

#18
post #17
post #16

I sometimes use GNU Make to fire off custom code generators, before the files are handed off to other parts of the toolchain which can have their own complicated dependency management. This works quite well. The one annoying problem that I often encounter is that Make does not handle multiple targets (i.e. the code generator generates multiple files, e.g. 'file1.h', 'file1.cpp', 'file2.h', 'file2.cpp', 'test.cpp'). I…

Not sure what you mean by "Make does not handle multiple targets". You can definitely do `make foo bar` and it will run the recipes for both foo and bar. You can also write a recipe with multiple prerequisites (which could be the result of a variable expansion). Curious about the limitation; could be there's a way around it or that I never ran into it.

The poster is talking about a single command that generates multiple outputs. e.g. a codegen tool that generates "foo.c" and "foo.h"

Re: The Language Agnostic, All-Purpose, Incredible, Makefile

#19
Make is very programmable; here's something from our code base:

  # Yes I am aware that this looks like TECO and Prolog had a baby.
  
  $(foreach prog,${3P-nonboost-packages},$(patsubst %,3P-build-%/${prog},${MAKE_CONFIGURATIONS})): 3P-src/$${@F} $(patsubst %,toolchain-%/_env,${CONFIGURATIONS})
   @echo Building ${@F} for $(subst 3P-build-,,${@D})
   @mkdir -p $@
   @if [ -f "$
This is after extensive simplification.

Re: The Language Agnostic, All-Purpose, Incredible, Makefile

#20
post #18
post #17

Earlier quoted context omitted.

Not sure what you mean by "Make does not handle multiple targets". You can definitely do `make foo bar` and it will run the recipes for both foo and bar. You can also write a recipe with multiple prerequisites (which could be the result of a variable expansion). Curious about the limitation; could be there's a way around it or that I never ran into it.

The poster is talking about a single command that generates multiple outputs. e.g. a codegen tool that generates "foo.c" and "foo.h"

I'm still not understanding the problem (sorry for being obtuse).

If you have a program called `makes-two-files` you could have a recipe:

foo.c foo.h: predecessor_of_foo @makes-two=files foo

There are other ways to do this in Make as well. I use Make extensively to drive CMake which makes all sorts of products, so my confusion comes from thinking this works fine (works for my purpose, obviously, but I'm interested in other possibilities).

Post reply on HN