Live data from Hacker News

One line you should add to every makefile

blog.jgc.org

71–80 of 99 posts

Re: One line you should add to every makefile

#71
post #52

I prefer to use memoize.py whenever possible instead of Make. I think it is much simpler to let it manage the dependencies rather than having to code them explicitly. Almost every other make system I have ever used eventually devolves to the point where 'make clean; make' is the only reliable way to use it. https://github.com/kgaughan/memoize.py

Very nice.

tup[0] is a another implementation of the same idea, that does work on Windows (unlike memoize) and has a few other goodies.

I would also recommend having a look at djb's "redo", implemented by apenwarr - it is much easier than to do right than a makefile, but unfortunately you still have to get the dependencies right yourself (which tup and memoize do for you automatically).

[0] http://gittup.org/tup/

Re: One line you should add to every makefile

#72

Earlier quoted context omitted.

When I started with make, I copied working files to a safe place, copied from the safe place to a scratch place, tweaked the scratch, got it working, etc., etc. Managing the make file was itself part of managing the project. Then I read and thoroughly grokked the O'Reilly book on make (which some douche stole from my desk; twenty plus years on, I am still bitter about that one... ...don't miss the Tannenbaum OS book…

git rebase I pretty much understand. Make will forever be a mystery to me. Mostly just how after the third or fourth version of it they didn't take a step back and think, "Hey, wait, maybe we should just make a language that spits out a shell file and ditch having it sort of kind of look like a shell file itself."

Because a shell file would be an inefficient and imprecise way of describing the state and logic that Make uses.

Re: One line you should add to every makefile

#73

Earlier quoted context omitted.

git rebase I pretty much understand. Make will forever be a mystery to me. Mostly just how after the third or fourth version of it they didn't take a step back and think, "Hey, wait, maybe we should just make a language that spits out a shell file and ditch having it sort of kind of look like a shell file itself."

Because a shell file would be an inefficient and imprecise way of describing the state and logic that Make uses.

Really? I mean, it pretty much just runs commands in sequence and/or parallel, right?

Sorry, like I said, I don't think I really understand make.

I mean, I can understand that it's doing some checks to determine what commands to emit, but doesn't it all end up falling out as pretty much a straight "Yes? Do this. No? Do that. Do this and then this and then this. Do all these at the same time."

That's my mental model at the moment anyway.

Re: One line you should add to every makefile

#75
post #50

Earlier quoted context omitted.

I wrote a god-awful Perl script to gen (and update) Makefiles for me: https://github.com/wspeirs/makemake

It seems every competent programmer makes that mistake at least once in their carreer :)

The mistake of writing your own makefile generator or using perl? My first experience with perl read in all of the files in its directory and output to another file also in the directory, it managed to read in both itself and the output. I accidentally implemented `rm *`.

Re: One line you should add to every makefile

#76

Earlier quoted context omitted.

Because a shell file would be an inefficient and imprecise way of describing the state and logic that Make uses.

Really? I mean, it pretty much just runs commands in sequence and/or parallel, right? Sorry, like I said, I don't think I really understand make. I mean, I can understand that it's doing some checks to determine what commands to emit, but doesn't it all end up falling out as pretty much a straight "Yes? Do this. No? Do that. Do this and then this and then this. Do all these at the same time." That's my mental model a…

Ultimately, make represents a dependency graph; Something that a shell language is not well prepared to represent. Yes, it's doing X, Y, and Z at the same time, but when X is done it can launch A and B, when Z finishes then C can also be started, but you don't want to run them all at the same time because of a max subprocesses limit. You don't know if X or Z will finish first, so you can't just launch C as soon as Z is done, nor do you want to waste time waiting for A and B to finish to launch C if Z is done. How do you express that in pure shell?

Re: One line you should add to every makefile

#77
post #69
post #42

Earlier quoted context omitted.

With gcc/clang it's a set of flags starting with -M, and with MSVC it's /showIncludes. They're discussed a bit here: http://martine.github.io/ninja/manual.html#ref_headers

What if we're using a different compiler, then? The comment that I was replying to sounds like CMake or something has more magic thus power for a future unknown compiler.

The point I was trying to make is that when you use CMake on any not-completely-unknown compiler, it will do this for you. If you are writing your own makefile, you either need to take the different compilers into account or implement it just for gcc ("screw the other guys") or simply resolve to "make clean && make".

Re: One line you should add to every makefile

#78
post #28

You can avoid editing the Makefile to add the rule with GNU make 3.81 or older, which does not support --eval. Create a new file in your home named ~/Makefile.debug with the contents: print-%: ; @echo $*=$($*) include Makefile Now you can use it the following way from any source directory: $ make -f ~/Makefile.debug print-SOURCE_FILES

You're missing the final tail call which includes Makefile.debug again. With this, we can make a REPL:

    $ cat Makefile
    FOO := bar

    target:
Next:

    $ cat Makefile.debug
    ifeq ($(MAKEFILE_INCLUDED),)
    -include Makefile
    MAKEFILE_INCLUDED := y
    endif

    REPL_COMMAND := $(shell read line; printf "%s\n" $$line)

    $(eval $(REPL_COMMAND))

    -include Makefile.debug
Now, here we go:

    $ make -f Makefile.debug
    $(warning $(FOO))             
:)

Re: One line you should add to every makefile

#79

Earlier quoted context omitted.

Because a shell file would be an inefficient and imprecise way of describing the state and logic that Make uses.

Really? I mean, it pretty much just runs commands in sequence and/or parallel, right? Sorry, like I said, I don't think I really understand make. I mean, I can understand that it's doing some checks to determine what commands to emit, but doesn't it all end up falling out as pretty much a straight "Yes? Do this. No? Do that. Do this and then this and then this. Do all these at the same time." That's my mental model a…

    x: y
        z
x depends on y (meaning, if x is missing, or is a file that is older than y where y is also a file, it needs to be recreated).

z is how to recreate x.

Makefiles are programs that construct a dependency graph.

The rest of makefile syntax is mostly about ways of generating variants of the above without being overly verbose, or reducing gruntwork when e.g. adding new header includes to existing source files. But this is the heart of it.

Root the dependency graph somewhere, and as long as the dependencies are complete and correct, the minimal set of commands, and potential parallelism, can be calculated.

Post reply on HN