
A simple makefile is a unicorn - kiyanwang
http://nibblestew.blogspot.com/2017/12/a-simple-makefile-is-unicorn.html
======
__david__
The Makefile shown in the article is simultaneously not complicated and also
over-complicated. I feel like most Make users don't understand Make very well
(especially the ones that complain really loudly about it).

Here's a couple examples:

1\. The "%.o: %.c" line is a huge code smell for Makefiles. You shouldn't ever
write that line—it's built in!

2\. Mentioning .h files in the Makefile. Don't. Go look up the `-MMD` flag in
your C compiler. Clang, gcc and many other C compilers support it. Add that
and a "-include *.d" line in the Makefile and you'll have great dependency
support.

Everything else in that makefile is just setting variables. It's made overly
complicated by the directory junk, but I'm failing to see the problem.

~~~
skohan
> I feel like most Make users don't understand Make very well (especially the
> ones that complain really loudly about it).

But the question is whether this is Make's fault for being incomprehensible,
or the User's fault for being lazy.

The thing is virtually _any_ system or tool can be understood with enough
practice, but just because there is someone out there who can use it well does
not mean it's not poorly designed.

Both C and Make are decades-old technologies, but most people can read a C
file without much experience and intuitively understand what is going on. The
same is not true for Makefiles.

~~~
mschaef
> Both C and Make are decades-old technologies, but most people can read a C
> file without much experience and intuitively understand what is going on.

While they might think they know what's going on, I'm not convinced they
actually do. C can be an incredibly subtle language to get right...

[http://blog.llvm.org/2011/05/what-every-c-programmer-
should-...](http://blog.llvm.org/2011/05/what-every-c-programmer-should-
know.html)

Regarding make, the thing to realize there is that it's just a DSL for
specifying a dependency graph (and the way for satisfying dependencies). It's
not a hard concept, but unless you come to the field with a bit of computer
science background, it's not likely something you've been directly exposed to
at the level required to understand make. But I don't know that this means
make's choice of abstraction is necessarily a bad thing for its intended use
cases. I also think this tends to put the lie to the notion that the
difficulty is mainly around tabs... tabs may obscure the details, but
switching to a clearer syntax won't solve the more fundamental gaps in
understanding the mechanics of make.

I'll also argue that this is a potential problem with DSL's in general...
because DSL's often don't use traditional imperative language semantics,
there's always a bit of a learning curve that needs to be ascended. However,
for make at least, there are a useful debugging tools to help understand what
it's actually doing.

For me, at least, 'make -n' is great in that it instructs make to resolve the
dependency graph based on the current state, and then just print the commands
it'll run without executing them. If you know what the commands do, and know
what needs to run, this can be a huge help understanding what's going on. (And
there are other more powerful debugging capabilities as well for dumping
variables, etc.)

~~~
crdoconnor
DSLs are most suited to constrained execution spaces - where you know that
there are relatively hard limits on what it is that the resultant program will
have to do. The problem is that build systems are not really a constrained
execution space - there's too often a _lot_ more required than just specifying
a dependency tree and just saying 'make it happen'.

As with many 'simplified' DSLs that are often unsuited to the task at hand
(e.g. C++ templating), make (or versions of it, anyway), evolved to
accommodate these use cases and then morphed into something that accidentally
became turing complete: [https://stackoverflow.com/questions/3480950/are-
makefiles-tu...](https://stackoverflow.com/questions/3480950/are-makefiles-
turing-complete)

~~~
mschaef
> As with many 'simplified' DSLs that are often unsuited to the task at hand
> (e.g. C++ templating)

Isn't a C++ template the exact opposite of 'Domain Specific'?

------
bigmanwalter
I use makefile to build my javascript and css. It works brilliantly. I
initially used Gulp, but started running into problems when there were build
errors that would crash Gulp so I had to use a plugin called Gulp-plumber just
to keep the watcher going. Then when I started having a somewhat more complex
chain of dependencies I didn't enjoy having to manually specify the build
order. The final nail in the coffin for Gulp is when I wanted to dynamically
alter flags based on certain conditions, whether it was a debug or prod build
for example, it just started getting messier and messier.

I am completely satisfied with Make as a replacement. Took me a couple days of
hacking to figure out how to set it up and it's been problem-free ever since.

By far, my favourite aspect is that I no longer need to depend on flimsy gulp-
specific wrappers. I just call my build tools natively.

~~~
andreareina
I used Make for my javascript for a while, but having to update the makefile
everytime dependencies changed got annoying. Now I just `webpack --watch`; the
startup time isn't great, but it's a one-time cost and the recompile happens
faster than I can switch to the browser.

~~~
bigmanwalter
I write my makefile once at the beginning of a project and never touch it
again. If you need to update yours with every new dependency, you might have
your makefile set up sub-optimally. I make sure to have something like the
following to include all my js/css dependencies.

    
    
        JS  = $(shell find . -name "*.js" -o -name "*.json")
        CSS = $(shell find . -name "*.scss" -o -name "*.css")
    

I use a small program called watch
[https://github.com/tj/watch](https://github.com/tj/watch) written by TJ
Holowaychuck (the inventor of the Express framework) which automatically re-
runs my makefile every second. As make is smart enough look for modified files
and rebuild only what is necessary, it works quite well.

~~~
andreareina
I'm writing for the browser so imports have to be bundled into the final
product; I'm not seeing how that will rebuild a.js (depends on b.js) when b.js
changes.

~~~
bigmanwalter
You could do something as follows assuming all source files are in src/, your
entry point is src/a.js and your output is build/scripts.js. I use browserify
for my compilation but this would work similarly with webpack.

    
    
       JS_FILES = $(shell find ./src -name "*.js")
       JS_ENTRY = ./src/a.js
       JS_OUT   = ./build/scripts.js
    
       $(JS_OUT): $(JS_FILES)
           browserify $(JS_ENTRY) > $(JS_OUT)
    

Now anytime any js files within the src/ directory are modified, make will
rebuild scripts.js

------
bandrami
Meh. The author uses a silly example of Makefiles. People get the wrong idea
about make. They think it's a program for compiling things; it's not, it's a
very early, slim, clean version of chef or ansible. Personally I only got to
know how cool make really is when I started to use it for stuff other than
compilation, like file transfers or service run control (at one point my toy
distro's rc system was "/bin/make -f /etc/rc.mk", where /bin/make was a static
version.)

Even for the example he uses, since he seems to be on GNU Make, it's a pretty
perfect case to use Guile integration to handle that metaprogramming he's
trying to do by hand.

~~~
banachtarski
Early yes, slim no, clean debatable.

I certainly think whatever incarnation of make that you would summon to do
some sort of multi-machine configuration management (per your chef/ansible
comparison) is something I would do everything in my power to avoid.

~~~
ratboy666
Love me some make -- here is a session:

    
    
      : fred@dejah ~ $; cat >hello.c
      #include <stdio.h>
      int main() {printf("hello\n"); return 0;}
      ^D
      : fred@dejah ~ $; make hello
      gcc     hello.c   -o hello
      : fred@dejah ~ $; 
    

How about that? make with no Makefile. The unicorn doesn't even exist. Which
is as clean as it can get. make only resolves dependencies. Which is as slim
as it can get. Early we agree on.

~~~
banachtarski
I've programmed in the early heyday when Make was my ONLY option and I'm
primarily a C++ developer. These days? No thanks. I don't want to return to
that hell. Any technology is "slim" if you cherry-pick just one feature. By
any reasonable definition, make is filled with warts and all sorts of tricks
that are REQUIRED for any non-trivial project that supports multiple platforms
to work. It is old crufty technology and I'll take my chances with other
options thanks.

You're free to love make all you want, but I've been there, was effectively
held hostage by it for lack of better options, and hate it. Automake and
asociated tools was the first attempt at getting us out of that hell, and it
didn't succeed but cmake/premake/bazel are doing a whole lot better.

------
josteink
The author presents some non-trivial makefiles meant for C/C++ as proof that
there are no simple makefiles. That's a bit disingenuous.

I think the problem here is the complexity of C, C++ and the building of such,
not the makefile itself. Make can make simple things simple, but it can't take
away genuine, real complexity as if it never existed.

I have lots of makefiles I use and am super-happy with. But none of them are
for C-based projects. When you take away the complexity that C/C++ brings, you
no longer need to bring that along to your makefile.

And you know what you have then? Apparently what the author refers to as a
"unicorn": A nice and super-simple makefile. The unicorn is suddenly real.

~~~
hzhou321
Make sense. Then, it is because of the complexity we want to use the makefile.
The include files is a mess for c/c++ because it poses no restrictions and
people do abuse it. In my practice, I never put header files in the makefile.
They are either stable or I need deliberately ponder on its design. When
necessary, I simply touch the c source to trigger rebuild. So my makefile
remain simple and I always need know roughly how my header files are used,
which is a necessary responsibility.

------
RX14
I agree with the author - for C/C++ projects. The module system in C and C++
is pushed out of the compiler and into the build tool. This means make (which
is simple) is insufficient to easily correctly implement the logic to build
C/C++ projects of more than a few files.

However, a lot of other commenters in this thread have mentioned using make to
manage their JS builds. JS build tools tend to work on whole directories of
files together, and as such its fairly easy to compose these tools without a
lot of logic in the build tool, and here make excells because its ubiquitous
and simple. We use a makefile for building crystal and its simple and works
great.

Make isnt useless, its just useless in the world it was created in.

~~~
sureaboutthis
Then why does your Linux/BSD/Unix operating system use it, including every
piece of software installed on it?

~~~
Jyaif
> Then why does your Linux/BSD/Unix operating system use it

Because many old programmers don't want to change their habit.

> including every piece of software installed on it?

Look up ninja.

~~~
Annatar
That’s right, I don’t want to change something powerful which works really
well because someone finds it hard to understand (lacking the prerequisite
knowledge) or even worse, wants instant gratification and isn’t willing to
master it. That’s like wanting to design a CPU accelerator without wanting to
learn how to design electrical circuits. Of course I’m going to say no!, I
don’t want to change the tool! If learning this stuff is too hard or not
interesting to one, then one ought to consider doing something else for a
living.

We have tools like Maven and Ant and Scons and CMake because someone didn’t
get Make and shell but they thought they did. Now I’m stuck with toy build
tools which use unnecessary dependencies (like Java and .NET and Python) and
only do as much as their programmer could imagine, limited by that
programmer’s imagination (and experience). You bet your patootie I’m going to
say NO! I don’t want to be stuck with a toy, someone’s misunderstanding of
Make.

------
khedoros1
There are any number of technologies that I've seen described as "simple" that
I'm inexperienced in...and they look overly complex to me. When I learn to use
them, they don't.

I've used make for a long time. I've never considered it difficult to learn or
use. It has a limited number of things that it does for you, and leaves the
rest _to_ you. I like that paradigm a lot more than systems that seem to
operate magically.

------
mmphosis
I think the simplest makefile is not to create one.

    
    
      echo 'int main(){}' > a.c && make a
    

_The only winning move is not to play. How about a nice game of chess?_

------
beefhash
If you're interested in build systems, you may find djb's redo concept
interesting, as implemented in
[https://github.com/apenwarr/redo/](https://github.com/apenwarr/redo/) for
example.

------
crdoconnor
The more build scripts I write the more convinced I become that an ideal build
system needs to be:

* Using declarative code as much as possible but still written in a good _general purpose_ turing complete language (maybe python - _not_ make).

* Built upon a foundation of well designed libraries, installable from a package manager that abstract common build workflows.

Make meets neither of these standards.

~~~
devonkim
Sounds like you may want something like Scons with better support for common
build patterns.

~~~
crdoconnor
Something more along those lines, yes, although I'm really not that convinced
about some of their design decisions and though the documentation is at least
very detailed, it's rather obtuse.

I think it's possible to do better.

------
INTPenis
I'd be inclined to agree if the author offered some alternative. Grunt is
mentioned in the comments of course, but I have no experience with that.

In a simple C project packaged for Linux, FreeBSD anc Mac OS I seriously think
a simple Makefile is possible.

And will continue to think that until I see an alternative that is easy to get
going with on those systems.

~~~
jbfoo
For a simple project cmake is also very easy to write. Much easier than plain
make IMO, as you have only a single layer of abstraction (cmake).

~~~
jcelerier
and when using cmake it will also work for android, windows, haiku, etc

------
hwh
When seeing "simple" as an absolute measure, the author surely has a point. As
for a relative measure - I think the argument is unjust, as you can easily
come across much more complex makefiles. So my take on this is this: explain
the width of the scale you're using when you measure in terms relative to it.

------
vletrmx
The example Makefile in this article is contrived, here's an example of a
simple Makefile:
[https://git.suckless.org/dmenu/tree/Makefile](https://git.suckless.org/dmenu/tree/Makefile).
I can find plenty of other such examples.

------
andreareina
Make is good at traversing and resolving a dependency graph; the problem is
that we are forced to write said dependency graph. It's no hardship for small
projects, but as projects grow and the dependency graph becomes annoying
and/or difficult to manage by hand, we turn to automatic solutions -- and we
should. Except that pattern substitution doesn't cut it, we really need a way
to programmatically generate dependencies given a source file.

~~~
pja
Fortunately, compiler writers have noticed this problem, and C/C++ compilers
will spit out makefile snippets which define the dependencies for a given
file. See the sample makefile above by danaliv.

~~~
JdeBP
They are, however, insufficient for the whole task.

* [https://news.ycombinator.com/item?id=15060146](https://news.ycombinator.com/item?id=15060146)

------
kbart
Yeah, let's better create another abstraction layer and release several
frameworks each year to make things simpler. /s

Make has its use. It's a great tool for building small/medium projects that
don't have many dependencies. You can setup a new project in minutes with
nothing more than a text editor and compiler. If you know *sh scripting, it's
not really complicated. For bigger projects I prefer Bitbake to avoid
"dependency hell".

------
haspok
I think the author would get a heart attack immediately if he heard about
[https://github.com/ninenines/erlang.mk](https://github.com/ninenines/erlang.mk)
... :)

~~~
maze-le
I for one find erlang.mk abhorrent as well. I usually write my own makefiles
(~ less than 20 lines) to utilize eunit, edoc and rebar3.

~~~
dozzie
My own makefiles are less than 20 lines, too, but they use erlang.mk instead
of rebar3.

You don't get to claim simplicity if you use rebar.

~~~
maze-le
>> You don't get to claim simplicity if you use rebar.

Yea, thats true. But good to see that I am not the only one who creates
simplified makefiles to utilize other build tools.

My critique on erlang.mk is, that its far simpler to remember the 10-20ish
commands of the rebar toolchain than thousands (or hundreds, but that it what
it feels like) of erlang.mk options for every erlang tool that has ever been
invented.

~~~
dozzie
The reverse is also true: it's far simpler to remember the 10-20ish options of
the erlang.mk plugins you use than hundreds options of various rebar plugins.

There is no significant difference between the two.

------
RVuRnvbM2e
This is simple vs magic.

Makefiles are simple in that you can see every directive and very little is
hidden from you. There is no magic - just dependency ordering using mtime as a
very simple heuristic.

~~~
palotasb
Except that there is a lot of magic [1] and it does cause bugs. For example
the implicit `%: %.o` rule has to be cancelled if you have a rule like
`$(SPECIFIC_OBJ_FILES): %.c.o: %.c`

[1]:
[https://www.gnu.org/software/make/manual/html_node/Catalogue...](https://www.gnu.org/software/make/manual/html_node/Catalogue-
of-Rules.html#Catalogue-of-Rules)

~~~
meribold
I like to put `MAKEFLAGS += --no-builtin-rules` near the top of my makefiles.
This way, all predefined rules are cancelled and I won't be caught off guard
by a rule that I didn't specify explicitly being a match.

I also usually put `.SUFFIXES:`, but I guess that's redundant: "The `-r` or
`--no-builtin-rules` flag causes the default list of suffixes to be empty."
[1]

[1]: [https://www.gnu.org/software/make/manual/make.html#Suffix-
Ru...](https://www.gnu.org/software/make/manual/make.html#Suffix-Rules)

------
pif
Make shares a fundamental property with C and C++: they are not meant to be
simple; they are meant to be powerful!

In the purest Unix tradition, Make was designed to be tool-agnostic: you can
choose which editor to code in, which (if any) preprocessor to use, which
compiler and which linker to invoke and with which arguments, and what else to
do aside.

And, all of this is controlled by a bunch of text files, which means grep and
sed are your friends when you want to change a linker option for several
projects.

Make comes from a philosophy which is the opposite of the IDE's ground. Not
that the IDE concept is wrong per se, but if you are only used to have the
same monolithic behemoth from code typing to binary output, your critics of
make sound the same as an industrial fast food cook complaining that artisan
patisserie is too complex.

------
doxcf434
Is this not a simple Makefile?

[https://github.com/apex/apex/blob/master/Makefile](https://github.com/apex/apex/blob/master/Makefile)

~~~
jhasse
I wouldn't expect `make clean` to delete stuff it didn't create itself. This
does though as it just executes `git clean -f`!

------
cturner
People in this thread might be able to offer me advice on a project I have
open.

I know C but am not experienced working on large C codebases. Below I will
describe its rough build structure. I hope for strong tool or re-framing
advice.

I have an existing python codebase. I want to make it easy to create native-
code plugins. The method I have worked out: I compile shared-libraries. Python
then calls into these via python-ctypes.

Each plugin is a directory project/ext/plugin,

* Python code: __init__.py and ext.py

* C code, api.c

* A rough build script, build.py. This accesses global config (e.g. path information) held outside this directory. It compiles api.c into a .so or .dll. It does this by generating a shell script or batch file, and then shelling out to it.

A python script in the root directory walks through this structure and forks a
process for each plugin build.py. It is multiplatform (currently linux gcc and
windows mingw32). So I have if statements saying "if windows, generate this
big string, otherwise generate that big string."

The shared-object is compiled to a separate directory, res/ext/plugin. I did
this to create separation between my source and build artifacts separate. (Is
this sensible?)

This naive build structure was easy to create, and allowed me to spend my
focus elsewhere while I was bootstrapping. Now that is done, I am interested
in how I could improve the build so that it could scale to a large number of
plugins.

Would I be well-served to use Make or Cmake or something else? Can they access
configuration from outside of their own directory? Maybe I should communicate
configuration via environment variables?

~~~
bjourne
It sounds like your build process is not well designed. Why would a build
script need to generate a shell script to call? And why would a python script
fork a process for each plugin?

I think waf, which I've plugged before, would be a good choice for your
project. Without knowing the details, your build script would look something
like:

    
    
        def configure(ctx):
            # Load C compiler support
            ctx.load('compiler_c compiler_cxx')
            if ctx.env.DEST_OS == 'win32':
                # Special thing for Windows
        def build(ctx):
            for plugin in ['a', 'b', ...]:
                ctx.shlib(source=ctx.path.ant_glob('ext/'+plugin+'/*.c'), target=plugin)
    

You get cross-platform support for free. The code will create an 'a.dll' on
Windows, 'a.so' on Linux and something else on OS X. Note that while the build
function above looks like imperative code, it actually is not. Instead it is
Python code to create a dependency graph which waf rebuilds for you when it is
needed.

------
Annatar
If the author of the article believes that the example Makefile isn’t simple,
he needs to learn Make, for that example is TRIVIAL.

Learn UNIX tools people, they’re excellent tools developed by masters with the
amount of knowledge, experience and insight very few of you will ever amass
(don’t think “ah! But I’m better!” for that way lie pain, misery and a build
process of nightmares), and they work the way they do for multiple reasons.
When it comes to build engines, Make is the real deal: sufficiently simple to
get started right away, infinitely flexible to do whatever one needs when it
comes to automated / intelligent building, with lots of useful built-in rules
“out of the box”. In this case the problem isn’t in the tool, but in one’s own
capabilities as a programmer.

------
donatj
Lol, I just made the argument that ‘a simple makefile can do most of what
people use grunt for’ on Twitter like 6 days ago. Worth nothing however
everything in our makefile is a PHONY which makes things a ton simpler, though
arguably we’re not using make to it’s full potential.

~~~
ganonm
You may want to consider using 'stamp files'. These are just empty files
created via 'touch' to serve as a timestamp that Make can use to determine if
a target needs to be rebuilt if the target doesn't correspond to an actual
file in the build directory. This is useful for build targets such as running
docker-compose build.

See [https://www.technovelty.org/tips/the-stamp-idiom-with-
make.h...](https://www.technovelty.org/tips/the-stamp-idiom-with-make.html)

~~~
TickleSteve
I have to disagree with this, I consider stamp files a Makefile anti-pattern.

Stamp files are an often an indication that someone is trying to turn a
Makefile into a shell script.

Rules should be generated that generate a target from its dependencies. The
intermediate steps should be encapsulated as the rule commands.

~~~
gbuk2013
Sometimes it is necessary though. I have had to use this pattern in 2
scenarios:

Building a static website where the targets are wildly different from the
source files. I could probably make it explicit but it will be overly verbose
and brittle.

Check for and remove trailing whitespace. Because the dependency is actually
the target, a stamp file is necessary.

~~~
Sean1708
Specifically in the second case: How do you get the timestamp on these stamp
files to update, or do you just do it manually? And if you are doing it
manually, why not just run a shell script instead?

~~~
gbuk2013
The timestamp on the source files is updated by sed, when it strips the
whitespace. The stamp file is then updated with touch. The advantage of using
Make is that only modified files will be fed to sed and, consequently, only
they will be caught by the rsync command, that I use to push the code out to
the server(s).

------
exDM69
Here's my "simple" makefile for C. It's for building a simple executable and a
static library. I don't use Make for more complex projects.

It has a bunch of extra features, like coverage and profiling and tags files.
They are pretty easy to remove if you don't want them.

If you want to put object files to another directory, it's much better to run
make in the output directory than to hack your Makefile to output objects to
another directory. Make can look for source files elsewhere but not search for
object files outside of $PWD.

[https://github.com/rikusalminen/makefile-
for-c](https://github.com/rikusalminen/makefile-for-c)

------
bjourne
If you are fed up with make, like I was, then just use WAF. It is an amazing
build tool. Arguing with make fanatics is a waste of time. They are set in
their ways and unwilling to accept that make is crap.

~~~
Qwertious
Problem is, you're forced to use it if the project devs are using it.

------
C0d3r
My Makefiles usually have one line per directive, can I still call my
Makefiles simple?

I mainly use them to replace scripts to run
tests/linters/formatters/containers/etc

------
JepZ
Well, while I agree that it is nearly impossible to write a useful Makefile
for a more than minimal C project, I found that if you are willing to
structure your project according to the best practices of CMake you can write
fairly simple and _useful_ CMake file.

But be aware, that as soon as you want to structure your project in any other
way than it is the CMake default you are starting to write your own Makefile
again ;-)

------
seertaak
Can't upvote this enough; I to create a Makefile for my app
([https://zenaud.io](https://zenaud.io)) and came to the exact same
conclusion. Once you're using the -MD clang option to generate makefile
directives for include dependencies, your Makefile is no longer simple -- in
fact it starts looking horrible. It's best to avoid IMHO.

------
gumby
Gosh, programming is hard! Complaining about the syntax of make, or that it’s
possible to write bad makefiles (and using bad examples to boot) is not, in
and of itself, convincing. Almost the same text could be used to complain
about C++, Java, HTML, Chinese, or any other subject.

And doesn’t work with visual studio??? Whose problem is that (hint: not
make’s).

------
vortico
Compiling projects is inherently complicated, so the solution must also be
complicated. You can solve the problem on a spectrum of easy but lack of
configurability, or complex/verbose but very flexible. Make is the latter.

The author has shown that he does not understand the Make language very well
since half of his final bullet points are wrong.

------
johannes1234321
In the C++ space modules would have been an option to clean this up and
enforce more of an project structure, which in turn would allow smart tools to
rely on that. Unfortunately the C++ committee can't agree to anything outside
a compilation unit to exist and the abstract machine it's built upon to be
quite limited ...

------
rileytg
i find it always starts simple, and usually one maintainer; after a year, it’s
a nightmare of hack on hack on hack with three+ contributors each knowing a
slice. makefiles on projects that are active for two+ years, a year+ later
might as well be chinese. (if it was chinese i could at least ask someone
fluent to translate.)

------
reacweb
gnumake is a scripting language based on rules. It is not a simple language
(bash is not simple either), but it allows to write simple scripts that work
fine to perform simple tasks. It works reasonably well for project compilation
which is not a so simple task. It becomes a excessively complex when it tries
to become overly generic. On one of my projects, gnumake handles double
compilation of sources for shared and static libraries, compilation of test
programs written in C++/java/Ada often using corba. It handles dependencies in
the whole source tree and works perfectly fine. The single limitation I have
encountered is the handling of spaces in file or directory names. It is very
difficult in bash scripts. It is almost impossible in complex makefiles.

------
cntlzw
Isn't the main problem with build tools that no one spends much time learning
them? You set them up, they work, then forget about them. Skip forward six
months and waste hours on SO figuring out how your build works.

~~~
falsedan
I think that means, the cognitive complexity is not in scale with the business
requirements. If I had a service I needed to set up once and maybe update a
couple of times a year, but took multiple days to sucessfully update, I'd
spend some effort on making iteasier to make changes (either by better
understanding, simplifying the system, or rewriting it to remove overhead).

------
Davidbrcz
Just use cmake or scons. In 2018, you should not hand write a single makefile
!

A simple cmake/sconcs build file will be as simple as the one shown (or even
simpler !) and it will definitively will be easier to integrate external
dependencies if you have to.

~~~
tonyedgecombe
CMake has to be one of the worst documented projects I've come across.

------
hungerstrike
I can't stand when people use a makefile for JavaScript projects. I mean, here
we have this beautiful cross-platform engine and then you go and ruin it with
your shitty non-cross-platform makefile. Yuck!

------
gcb0
the only bad sin I've seen with makefiles is when organizations distribute
complex ones that every project must use.

make should be simple, custom, and predictable for each piece of a project. I
sometimes have a file for each dir. having a central invisible one is awful.

------
nikanj
Based on the headline, I expected this to be a rant about unicorn valuations.
Was very pleasantly surprised!

