How We Use Make
segment.com
segment.com
Makefiles are far too difficult to read and write compared to alternatives in my opinion when you're automating anything beyond a few simple tasks. You'll inevitably have tasks that require several lines of code, complex logic, different settings for production, staging and development environments, common code that has to be shared between build steps etc. I find it difficult to make shell scripts robust and maintainable.
I'd much rather use JavaScript's Gulp (especially if my project was using Node like in the post) or Python's Fabric if possible.
Corrected for accuracy.
> when you're automating anything beyond a few simple tasks.
This is why, historically, so few projects of any scale or complexity have used Make.
BIN := ./node_modules/.bin
UGLIFY ?= $(BIN)/uglify-js
UGLIFY_FLAGS ?= --screw-ie8
build/%.min.js: build/%.js
@$(UGLIFY) $(UGLIFY_FLAGS) $< > $@
I find all Makefiles end up containing code like this where it makes sense when you write it but when returning to it a few weeks later you don't understand what it does anymore.I'm also intrigued by their claim they used @ in the recipes, yet they never did.
I think what he means is that their Makefiles effectively start having a common API across projects, by having similar target names.
No need to use "all" if you put the default target first (see `default` subsection in the post).
> I'm also intrigued by their claim they used @ in the recipes, yet they never did.
Yea seems that got stripped out.
Still, this is a good practical example for using a Makefile. I'm a fan of this too.
As long as running `make` does the Right Thing, does it matter if it does it via an `all` target or by defaulting to a different first target?
I do agree that generally `all` is a common convention, though.
I usually structure my targets so that I can run `make test` immediately without having to know what all the random commands are to build/install.
> No need to use "all" if you put the default target first (see `default` subsection in the post).
That's obviously the reason they're doing that, but it's an odd decision. Especially since "all" is a common name for a Makefile target and .DEFAULT_GOAL can be used to override the "first target" convention of Makefiles.
firsttarget: mysource.txt
cp $< $@
.DEFAULT_GOAL=all # no need to put it first
.PHONY: all
all: firsttarget secondtarget
secondtarget:
touch $@ $ man make | grep -A2 silent
-s, --silent, --quiet
Silent operation; do not print the commands as they are executed.Yes, 70's era Unix tools are not the most friendly, but there's still a lot of uses to Make (as opposed to Autotools)
You can actually build a Make file to solve any DAG, written as dependencies, or use its tools to not rebuilt your whole project when only one file has changed
(here http://mosermichael.github.io/cstuff/all/projects/2011/06/17... )
this saves you from repeating the same make constructs many times over, in the following example you do a static library and executable.
1: TOPDIR=../..
2:
3: # - declare build targets. (built with make)
4: TARGETS:=shlib slibuser
5:
6: # - slib target is a static library -
7: shlib_TYPE=lib
8: shlib_SRC=slib.c
9:
10:
11: # - slibuser target is a executable using slib -
12: slibuser_TYPE=exe
13: slibuser_SRC=slibuser.c slibuser2.c slibuser3.c
14: slibuser_LIBS=shlib
15:
16: include $(TOPDIR)/rules.makeA) It is a 2-phase build system (read DAG, traverse DAG) whereas code generation requires an N-phase build system (build some files, detect more dependencies, build more files, ...)
B) It has no way to express dependencies on the inexistence of files (#include "foo.h" will behave differently if the first search directory in the include path starts also featuring a "foo.h", but this cannot be specified), necessarily meaning that incremental build become incorrect in various circumstances
C) It does mtime-newer check, rather than mtime-equal check. This has numerous problems with various file systems.
D) It does not check the mtime did not change during a build, effectively allowing the build tree to be poisoned with an incorrect build result. For example, edit foo.c while foo.o is being compiled from it. foo.o can be correct w.r.t old foo.c, but its mtime suggests it is newer than the current foo.c. All incremental builds thus become incorrect.
In short, make doesn't try hard enough to be a correct build system, and it is also inflexible.
This is why I wrote `buildsome`[1], where I resolve all these issues and more.
buildsome is only tailored for our needs at the moment, so can only build on Linux, and not on OS X or Windows.