
One line you should add to every makefile - jgrahamc
http://blog.jgc.org/2015/04/the-one-line-you-should-add-to-every.html
======
nathanb
I firmly believe that there is only one production-quality makefile that has
ever been written from scratch. Every other makefile has been copied from an
earlier makefile, dating back to the one Ur-makefile, and modified to suit the
author's purpose.

~~~
arcatek
To be honest, a simple Makefile is very simple to write and efficient once you
know the syntax fairly well. Then you add more and more things as the time
pass, and it starts to morph into a giant huge monster that eat puppies.

~~~
perdunov
> a giant huge monster that eat puppies

Not puppies, but brains of the poor programmer who is confronted with a
problem of building your bloatware on a non-supported platform (typically
Windows).

~~~
kd0amg
Most of the time I've blown on wrestling with other people's makefiles has
been on ostensibly supported platforms.

------
raimue
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

~~~
kazinator
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))             <--- typed by me
        Makefile.debug:8: bar
        ABC := xyz                    <---
        $(warning $(ABC))             <---
        Makefile.debug:8: xyz
    

:)

~~~
david-given
This is the kind of idea for which the phrase 'genius crazy' was invented.

I might actually _use_ this some time, god help me. I won't thank you, but I
will remember you and curse a little every time I do.

------
jderick
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](https://github.com/kgaughan/memoize.py)

~~~
beagle3
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/](http://gittup.org/tup/)

------
cperciva
Or, if you're using BSD Make:

# make -V SOURCE_FILES

~~~
mzs
Oh man I've missed -V! I've done something like this in gmake, basically using
the : in sh and -n of make to print whatever I wanted:

    
    
      $ foo() { echo 'foo: ; @ : ${'"$1"'}'; echo include Makefile; }
      $ foo SRCS
      foo: ; @ : ${SRCS}
      include Makefile
      $ foo OBJS | make -n -f- foo
      : foo.o bar.o baz.o

------
ottocoder
I think this article is a great reference for others wanting to write a small
informational or how-to post. It's concise and easy to follow for those who
are familiar with the subject while including enough details for beginners.

Back to the subject, I would also be interested to know a way to print out the
value of a variable every time it changed in the course of a make system's
execution.

------
ChuckMcM
Ohh, that is a great trick. I've added it.

I go back and forth on Make. It was where I started so there is some bias
there but generally it has always been possible to do what I want with it. The
places where it bites me were things that gmake added which added, to me,
features which could be cleverly exploited but made things much more
complicated and error prone. I flirted with SCons and other build systems, I
was amazed at how flexible Google's was (and had to be given the complexity
embodied in it) but for small projects (where small is perhaps a couple of
hundred source files, and a half dozen libraries) it still is my goto build
tool of choice.

------
falcolas

      print-%: ; @echo $*=$($*)
      .PHONY: print-%
    

This way the rule continues to work even if such a file suddenly exists in
your repo.

~~~
raimue
No, implicit rules cannot be marked as .PHONY this way. You need to declare an
explicit pseudo-target to achieve this.

    
    
      .PHONY: FORCE
      FORCE:
      print-%: FORCE ; @echo $*=$($*)

~~~
mannykannot
I touch make files rarely enough that whenever I do, I have to re-learn most
of what I need to know - and when I see phrases like 'explicit pseudo-target',
I ask myself if it really has to be this way (but never have the time to
answer myself.)

------
vladtaltos
I was copy pasting a lot myself and then stumbled into this guy's modular
setup - I built something similar from then on. it's pretty sufficient for
almost 90-95% of my needs...

[https://github.com/etola/makefile-heaven](https://github.com/etola/makefile-
heaven)

------
xvilka
There is a remake[1] project, allowing you to debug Makefile like a usual
script language.

[1] [https://github.com/rocky/remake](https://github.com/rocky/remake)

------
rjuyal
This heading looked like some buzzfeed type headline.

~~~
AceJohnny2
So I'm not the only one...

------
lukaslalinsky
I'd say that most people should not write makefiles by hand. You should use
some higher level build system, that knows how to deal with source files in
your language, track their dependencies, etc. A "hello world" makefile with
one source file looks simple, but once the project gets more complicated, you
quickly end up building such a high level build system yourself, with the
additional disadvantage of restricting your build system to only work on
systems with GNU make, even though there might be other native build systems
available for the platform.

~~~
falcolas
Makefiles, once you have learned the syntax, are very simple to write, as they
can be naturally decomposed into individual steps, and rules are easily
generalized for similar file types.

Their reputation has been tarnished by autotools, but in that case you're
using autotools as your build system, not make.

~~~
lukaslalinsky
The problem is that C/C++ files have internal depenedencies which make needs
to know about. Yes, for gcc you can use a simple trick to extract the
dependencies to makefile rules, but in case you use a different compiler, you
need to do it yourself. If you are compiling a different language, you need to
do it yourself again. Using something like CMake or even automake, which can
automatically track the dependencies, saves you a lot of work.

~~~
xjia
How do they track the dependencies automatically?

~~~
evmar
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](http://martine.github.io/ninja/manual.html#ref_headers)

~~~
xjia
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.

~~~
lukaslalinsky
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".

------
gbog
Everyone seems to talk about make files for generating complex c projects.
What about make files used to store bash commands of medium complexity. In my
python projects I have make clean-pyc, make test, for example. In my music
folder I can make find-big-dirs, make find-non-mp3, etc

Advantages are it is easy to edit, cat, and the locality of the commands: I
don't want to pollute my bashrc with commands that are useful only in a given
context.

~~~
girvo
I often use make as a task-runner too, which is super useful. In fact, I
currently have a makefile that will build and test both the backend (PHP/Hack)
and the front end (Browserify, less, etc.). The best part about make is that
it handles new languages without issues: if it outputs files, make can handle
it.

------
emmelaich
It seems Make is a popular topic on HN lately, so it's timely to mention "How
to write vaguely acceptable makefiles"

    
    
        http://www.cl.cam.ac.uk/~srk31/blog/2014/11/19#writing-makefiles

------
oso2k
jgc is a great resource when you got a sticky issue to resolve. For my money,
the suckless guys are the guys to emulate when you start fresh with a Makefile
[0][1].

[0]
[http://git.suckless.org/sbase/tree/Makefile](http://git.suckless.org/sbase/tree/Makefile)

[1]
[http://git.suckless.org/ubase/tree/Makefile](http://git.suckless.org/ubase/tree/Makefile)

------
forgottenpass
Better article from years ago, that this blogger is probably rehashing anyway:
[http://blog.melski.net/2010/11/30/makefile-hacks-print-
the-v...](http://blog.melski.net/2010/11/30/makefile-hacks-print-the-value-of-
any-variable/)

~~~
jgrahamc
_that this blogger is probably rehashing anyway_

Nope.

Eric (who wrote that blog you are referrring to is a friend), but I wrote this
little trick up years before him:
[http://www.cmcrossroads.com/article/printing-value-
makefile-...](http://www.cmcrossroads.com/article/printing-value-makefile-
variable) and now I'm rehashing my own writing 10 years later.

~~~
emelski
I shouldn't be surprised that you published that before I did -- to be fair,
it's quite a challenge to find _any_ topic related to make that you _haven't_
written about. :)

~~~
jgrahamc
The real question is who wrote the original line? My bet's on it being Usman.

~~~
emelski
I'll take any excuse for a little code spelunking -- according to Perforce it
was Scott, in October 2002.

~~~
jgrahamc
Nice. Thanks for looking that up.

------
rzw
Aww..Happily RIP $(warning)

~~~
paulw0
Debuggers won't like you :)

------
jheriko
never use makefiles. its not 1975 and we have learned a lot since then

~~~
__d
examples?

~~~
jheriko
(not to mention the shameful use of timestamps to detect modifcation in make -
leading to years and years of wasted time as people get confused by it when
working with others)

------
amelius
The mere fact that such a thing is necessary disqualifies make as a build tool
for me.

That being said, this trick could be handy for existing projects.

~~~
falcolas
> The mere fact that such a thing is necessary disqualifies make as a build
> tool for me.

It's a very simple debugging addition. Hardly necessary, just convenient. The
"built-in" echo works just fine as well.

------
herge
That's one huge advantage with Rake, just add `p VARIABLE_NAME` anywhere in
your Rakefile, and you'll see the textual value of it at that point.

~~~
ska
That misses the point; you can already echo a variable wherever you want in a
makefile similarly. This gives you a way to do it without editing the
makefile, without knowing before hand you want to see that variable.

~~~
herge
Echo and p aren't exactly the same, there's a difference during debugging
between:

    
    
        1 2 3 4 (echo)
    

and

    
    
        ["1", "2 3", "4"] (p)

~~~
ta0967
that's a strawman though. what about

    
    
      printf ' "%s"' $(numbers)
    

to output

    
    
      "1" "2 3" "4"

------
jdlyga
The best quality of life change I ever made was turning off email
notifications. I just have have the numeric counter on, and check it every so
often like I always did anyway. I only have notifications for things that
people expect quicker replies to like texts, calls, voicemails, etc.

