Wednesday, December 14, 2016

A MITM attack in the reign of Elizabeth I

This is what you end up w/ when you have an encryption but no message authentication code:

"Babington and his associates, having laid such a plan [of the assassination of Elizabeth], as, they thought, promised infallible success, were impatient to communicate the design to the queen of Scots [...]

For this service, they employed Gifford, who immediately applied to Walsingham [Sir Francis, the Secretary of State], that the interest of that minister might forward his secret correspondence with Mary. Walsingham proposed the matter to Paulet [...] The letters, by Paulet's connivance, were thrust through a chink in the wall; and answers were returned by the same conveyance.

Babington informed Mary of the design laid for a foreign invasion, the plan of an insurrection at home, the scheme for her deliverance, and the conspiracy for assassinating the usurper, by 6 noble gentlemen [...] Mary replied, that she approved highly of the design; [...]

These letters [...] were carried by Gifford to secretary Walsingham; were decyphered by the art of Philips, his clerk; and copies taken of them.

Walsingham employed another artifice, in order to obtain full insight into the plot: He subjoined to a letter of Mary's a postscript in the same cipher; in which he made her desire Babington to inform her of the names of the conspirators. The indiscretion of Babington furnished Walsingham with still another means of detection, as well as of defence. That gentleman had caused a picture to be drawn, where he himself was represented standing amidst the six assassins; and a motto was subjoined, expressing that their common perils were the band of their confederacy."

(From The History of England by David Hume.)

On her trial, Mary denied the charges of the insurrection & the assassination, stating that she personally did not write those letters in such a form, for all her correspondence was controlled by 2 secretaries, who did the tedious process of (de|en)cryption on her behalf.

Saturday, October 29, 2016

BOM & exec


Recently, I’ve stumbled upon a post about an accidental BOM in a shell script file. tl;dr for those who don’t read Ukrainian:

  1. A guy had a typical shell script that got corrupted by some Windows editor by prefixing the first line of the file (the shebang line) with the BOM.
  2. The shell was trying to execute the script.
  3. Everybody got upset.

I got curious why bash tries to run scripts w/ BOM in the first place. I’ve looked into the latest bash-4.3 & tcsh-6.19.00 on Fedora 24. Everywhere in the text below we draw the BOM w/ the replacement character (codepoint U+FFFD): �.

Some findings:

  • I was wrong about the bloody shebang lines for I thought that no shell ever reads them.
  • bash & tcsh don’t use libc properly & both invent their own rigmarole instead of using the provided routine.
  • bash is a mess! (Which is hardly a discovery.)

With shebang

If a file contains a valid shebang line, everything is easy: when you pass the file name to any of execv, execve, execlp, etc. functions, the kernel steps in, reads the shebang line and executes the interpreter, that was mentioned in the shebang, with the file in question as its argument.

This picture falls to pieces, when the file contains the petty BOM, for the kernel fails to recognize that �#!/omg/lol should be (in our naïve mind) an equivalent to #!/omg/lol.

Both tcsh & bash have a backup plan for systems w/o the shebang support in the kernel. Besides the obvious win32 candidate, tcsh lists 2 other systems: os390 & bs2000 (I wonder who on earth still have them). bash uses autoconf & therefore doesn’t have a pre hard-coded build configuration set. Unfortunately, I believe the autoconf test for the shebang line support is bogus:

$ cat ac_sys_interpreter
#! /bin/cat
exit 69

Presumably, the thinking was: if you run it on any modern system, the kernel will run /bin/cat ac_sys_interpreter which will just print the file, but on prehistoric time-sharing machines a simple-minded /bin/sh will execute it as a shell script & then you can test if the exit code == 69. (For why it would do so–read the next section.) The trouble is, that the old system may very well have /bin/sh that does its own shebang processing in case kernel doesn’t, alas rendering the test useless, & henceforth compiling bash w/o shebang support.

Without shebang

As long as the kernel flops at the invalid first line, the whole commotion becomes the case of a file w/o the shebang.

This is how we were all taught about interpreter files back in the day:

“the shell reads the command and tries to execlp the filename. Because the shell script is an executable file but isn’t a machine executable, an error is returned and execlp assumes that the file is a shell script (which it is). Then /bin/sh is executed with the pathname of the shell script as its argument.”

(from APUE, the 3rd ed)

E.g. suppose we have

$ cat
echo Діти, це їжачок!
ps -p $$                # print the shell the script is running under

If we run it, the shell

  1. checks if the script has executable bits (suppose it has)
  2. tries to exec the file
  3. which fails with ENOEXEC, for it’s not a ELF
  4. [a tcsh/bash dance]
  5. exec again but this time it’s /bin/sh with as an argument

The last item is important & may be not quite apparent, for if you have a csh-script

$ cp demo2.csh

you may expect that tcsh will not run it as sh-one:

$ tcsh -f
> ./demo2.csh
Діти, це їжачок!
   PID TTY          TIME CMD
102213 pts/21   00:00:00 sh

which is false, for tcsh follows the standards here.

Expectations vs. reality

APUE says a shell is ought to use execlp that in turn is supposed to do all the dirty work for us. As it happens execlp does exactly that, at least in Linux glibc. Of course, both bash/tcsh ignore the advice & use their own scheme.

tcsh does a plain execv then, after failure, peeks into the first 2 bytes to see (w/ the help of iswprint(3)) if they are “printable”. Here, if tcsh (a) finds the file “acceptable” & (b) tries to run the script with the shebang line in it on a system w/o kernel support for such a line, it processes that line by itself.

If we poison our script with the BOM:

$ uconv --add-signature >
$ chmod +x !$
$ head -c 37 !$ | hexdump -c
0000000 357 273 277   e   c   h   o     320 224 321 226 321 202 320 270
0000010   ,     321 206 320 265     321 227 320 266 320 260 321 207 320
0000020 276 320 272   !  \n                                            

tcsh doesn’t try to re-execv & aborts:

> ./
./ Exec format error. Wrong Architecture.

bash, on the other hand, tries to be more clever, failing spectacularly. After execve it goes into a journey of figuring out why the exec has failed. It:

  1. opens the file & analyses the shebang line! In the example above we didn’t have one, but if we did, bash would have produced a message:

    $ cat demo3.invalid.awk
    #!/usr/bin/awwwwwwwk -f
    BEGIN { print "this is awk" }
    $ ./demo3.invalid.awk
    sh: ./demo3.invalid.awk: /usr/bin/awwwwwwwk: bad interpreter: No such file or directory

    tcsh won’t do anything like that & will print ./demo3.invalid.awk: Command not found..

  2. checks if the file has an ELF header & tries to find out what is wrong w/ it;

  3. reports the “success” of the execution, if the file has the length of 0.

  4. checks if the file is “binary”. I use quotes here, for this is an example of how the good intentions don’t always turn into reality. Instead of a simple 2 bytes check, like it’s done in tcsh, bash reads 80 bytes & calls a certain check_binary_file() function that is a good example of why you should not blindly trust the comments in the code:

    /* Return non-zero if the characters from SAMPLE are not all valid
       characters to be found in the first line of a shell script.  We
       check up to the first newline, or SAMPLE_LEN, whichever comes first.
       All of the characters must be printable or whitespace. */
    check_binary_file (sample, sample_len)
         char *sample;
         int sample_len;
      register int i;
      unsigned char c;
      for (i = 0; i < sample_len; i++)
          c = sample[i];
          if (c == '\n')
            return (0);
          if (c == '\0')
            return (1);
      return (0);

    Despite of the resolution for all of the characters must be printable or whitespace, the function returns 1 only in case when sample contains the NULL character. Our BOM-example doesn’t have one, thus the script runs, albeit with a somewhat cryptic error if you have no idea about the existence of the BOM in the file:

    $ ./
    ./ line 1: �echo: command not found
       PID TTY          TIME CMD
    115569 pts/26   00:00:00 sh

    What if we do have the NULL character?

    $ hexdump -c
    0000000   e   c   h   o      \0  \n   e   c   h   o     320 224 321 226
    0000010 321 202 320 270   ,     321 206 320 265     321 227 320 266 320
    0000020 260 321 207 320 276 320 272   !  \n   p   s       -   p       $
    0000030   $  \n                                                        

    Here NULL is an argument to echo command, which should be totally legal, but not w/ bash!

    $ ./
    sh: ./ cannot execute binary file: Exec format error

    Which of course wouldn’t be an issue had the file had the shebang line.

  5. If bash finds the file “acceptable” on a system w/o kernel support for the shebang line when the file indeed contains one, it does the same thing tcsh does: tries to process it by itself.


The most popular shells are too bloated, bizarre & have many undocumented features.

Some hints:

  • The shebang line isn’t necessary if you target /bin/sh, but the shell does less work if you provide it.
  • To view BOMs, use less(1) or hexdump(1).
  • To test for the BOM, use file(1).
  • To remove the BOM manually, use M-x find-file-literally in Emacs.

Sunday, October 2, 2016

How GNU Make's patsubst Function Really Works


$(patsubst) is a GNU Make internal function that deals with text processing such as file names transformations. Despite of having a very simple idea behind it, the peculiar way of its implementation leads to confusion & uncertainty for novice Make users. The function doesn’t return any errors or signal any warnings. It uses its own wildcard mechanism that doesn’t have any resemblance with the usual glob or regexp patterns.

For example, why this transformation doesn’t work?

$(patsubst src/%.js, build/%.js, ./src/foo.js)

We expect ./src/foo.js to be converted to build/foo.js, but patsubst leaves the file name untouched.

Extract method

Before we begin, we need a quick way of inspecting the results of patsubst evaluations. GNU Make doesn’t have a REPL. There are primitive hacks around it like ims:

$ rlwrap -S 'ims> ' ./ims
ims> . $(words will cost ten thousand lives this day)

that allow you to play with Make functions interactively, but they won’t help you to examine Make’s internals, for there is no way to view the source code of a particular function like you do it in irb + method_source gem, for example.

I’ve extracted patsubst function from Make 4.2.90 into a separate command gmake-patsubst. After you compile it, just run it from the shell as:

$ ./gmake-patsubst src/%.js build/%.js ./src/foo.js

providing exactly 3 arguments as you would do in makefiles, only using the shell quoting/splitting rules instead of Make’s (i.e., use a space as an argument separator instead of a comma).

(A side note about the extract: it’s ≈ 520 lines of an imperative code! This is what you get when you program in C.)

If you want to read the algo itself, start from patsubst_expand_pat().

patsubst explained

Let’s recap first what patsubst does.


The majority of its use is to tranform a list of file names. It operates like a map() on an iterable in JavaScript:

    .map( (file) => magic_transform(PATTERN, REPLACEMENT, file) )
    .join(' '))

It’s a pure function that returns a new result, leaving its arguments untouched. It works with supplied file names in TEXT as strings–it doesn’t do any IO.

The first thing to remember is that it splits TEXT into chunks before doing any substantial work further. All transforming is being done by individually applying PATTERN to each chunk.

For example, we have a list of .jsx file that we want to tranform into the list of .js files. You may think that the simplest way of doing it with patsubst would look like this:

$ ./gmake-patsubst .jsx .js "foo.jsx bar.jsx"
foo.jsx bar.jsx

Well, that didn’t work!

The problem here is that in this case patsubst checks if each chunk matches PATTERN exacly as a full word byte-to-byte. In regex terms this would look as ^\.jsx$. To prove this, we modify our pattern to be exactly foo.jsx:

$ ./gmake-patsubst foo.jsx .js "foo.jsx bar.jsx"
.js bar.jsx

Which works as we described but isn’t much of a help in real makefiles.

Thus patsubst has a wildcard support. It is similar to the character % in Make pattern rules, that mathes any non-empty string. For example, % in %.jsx pattern could match foo against foo.jsx text. The substring that % matches (foo in the example) is called a stem1.

There could be only one % in a pattern. If you have several of them, only the first one would be the wildcard, all others would be treated as regular characters.

To return to our example with .jsx files, using % in both PATTERN & REPLACEMENT arguments yields to desired result:

$ ./gmake-patsubst %.jsx %.js "foo.jsx bar.jsx"
foo.js bar.js

When REPLACEMENT contains a % character, it is replaced by the stem that matched the % in PATTERN.

Using the character % only in patterns is rarely useful, unless you want to replicate Make’s $(filter-out) function:

$ ./gmake-patsubst %.jsx "" "foo.jsx bar.js"

Which is the equivalent of

$(filter-out %.jsx, foo.jsx bar.js)

If there is no % in PATTERN but there is % in REPLACEMENT, patsubst resorts to the case of a simple, exact substitution that we saw before.

$ ./gmake-patsubst foo.jsx % "foo.jsx bar.jsx"
% bar.jsx

Now, to return to our first example from Abstract:

$(patsubst src/%.js, build/%.js, ./src/foo.js)

Why didn’t it work out?

Putting together all we’ve learned so far, here is the high-level algorithm of what patsubst does:

  1. It searches for the % in PATTERN & REPLACEMENT. If found, it cuts off everything before %. Let’s call such a cut-out part pattern-prefix (src/) & replacement-prefix (build/). It leaves us with .js & (again) .js correspondingly. Let’s call those parts pattern-suffix & replacement-suffix.

  2. Splits TEXT into chunks. In our case there is nothing to split, for we have only 1 file name (a string w/o spaces): ./src/foo.js.

  3. If there is no % in PATTERN it does a simple substitution for each chunk & returns the result.

  4. If there indeed was % in PATTERN, it (for each chunk):

    4.1. (a) Makes sure that pattern-prefix is a substring of the chunk. In JavaScript it would look like:


    It’s false in our example, for src/ != ./src/.

    (b) Makes sure that pattern-suffix is a substring of the chunk. In JavaScript it would look like:


    It’s true in our example, for .js == .js.

    4.2. If the subitem #4.1 is false (our case!) it just returns an unmodified copy of the original chunk.

    4.3. Iff2 both (a) & (b) in the subitem #4.1 were indeed true, it cuts-out pattern-prefix & pattern-suffix from the chunk, transforming it to a stem.

    4.4. Concatenates replacement-prefix + stem + replacement-suffix.

  5. Joins all the chunks (modified of unmodified) with a space & returns the result.

As you see, the algo is simple enough, but probably is not exactly similar to what you may have imagined after reading the Make documentation.

In conclusion, hopefully now you can explain the result of patsubst evaluation below (why only src/baz.js was transformed correctly):

$ ./gmake-patsubst src/%.js build/%.js "./src/foo.js src/bar.jsx src/baz.js"
./src/foo.js src/bar.jsx build/baz.js

The nodejs version of the patsubst can be found here. Note that it’s a simple example & it must not be held as a reference.

PS. Here is an alternate version of this post that can be more readable on your phone.

  1. (For non-English speakers like yours trully) The noun stem means several things: 1) (in linguistics) a form of a word after all affixes are removed; 2) (in botany) a slender structure that supports a plant.

  2. A quote from the Emacs manual: ‘“Iff” means “if and only if”. […] Try to avoid using this term in documentation, since many are unfamiliar with it and mistake it for a typo.

Tuesday, September 20, 2016

Emacs 25.1 & hunspell

In Emacs 25 you don't ever need to modify ispell-dictionary-alist variable explicitly. Ispell package reads, during its initialization, the hunspell's .aff files & automatically fills the variable w/ parsed values.

If you have at least hunspell + hunspell-en-US dictionary installed, the minimum configuration, that works regardless of the underlying OS is:

(setenv "LANG" "en_US.UTF-8")
(setq ispell-program-name "hunspell")
(setq ispell-dictionary "en_US")

hunspell cuts out en_US part from LANG env variable and uses it as a default dictionary. To check it outside of Emacs, run:

$ hunspell -D

If it says


& waits for the user input from the stdin, then perhaps hunspell was configured properly.

ispell-dictionary on the other hand, is an Ispell-only setting. It uses it to start a hunspell session.

Iff the Ispell package has been initialized correctly, ispell-hunspell-dict-paths-alist variable should contain pairs like

("american" "/usr/share/myspell/en_US.aff")
("british" "/usr/share/myspell/en_GB.aff")

& ispell-dictionary-alist--the parsed values from the corresponding .aff files.

If ispell-hunspell-dict-paths-alist is nil, that means Ispell is either has failed to parse the output of a `hunspell -D` invocation or has failed to read the .aff files. The latter could occur if you use a native Windows version of Emacs w/ hunspell from Cygwin. If that is the case, you can always set the pairs manually:

(setq ispell-program-name "c:/cygwin64/bin/hunspell.exe")
(setq ispell-hunspell-dict-paths-alist
      '(("en_US" "C:/cygwin64/usr/share/myspell/en_US.aff")
        ("ru_RU" "C:/cygwin64/usr/share/myspell/ru_RU.aff")
        ("uk_UA" "C:/cygwin64/usr/share/myspell/uk_UA.aff")
        ("en_GB" "C:/cygwin64/usr/share/myspell/en_GB.aff")))

You'll need to restart Emacs after that.

The Apostrophe

If you can, try up update the hunspell dictionaries alongside the spell checker itself. The old versions lack the proper WORDCHARS setting inside the .aff files which results in wrong results (haha) for words that contain the ' sign. For example, if your dictionaries are up to date, the word isn't must not confuse the spell checker:

$ echo isn\'t | hunspell
Hunspell 1.3.3

If you get this instead:

$ echo isn\'t | hunspell
Hunspell 1.3.3
& isn 9 0: sin, ins, ism, is, in, inn, ion, isl, is n

the dictionaries are no good & no Emacs will fix that.

Switching Dictionaries On The Fly

If you find yourself switching dictionaries depending on the Emacs input mode, use the Mule hooks to set the right dictionary automatically:

(setq ispell-dictionary "en_GB")

(defun my-hunspell-hook()
  "Set a local hunspell dictionary based on the current input method."
  (setq ispell-local-dictionary
         ((null current-input-method)
         ((string-match-p "ukrainian" current-input-method)
         ((string-match-p "russian" current-input-method)
          (user-error "input method %s is not supported"

(defun my-hunspell-hook-reset()
  (setq ispell-local-dictionary ispell-dictionary))

(add-hook 'input-method-activate-hook 'my-hunspell-hook)
(add-hook 'input-method-deactivate-hook 'my-hunspell-hook-reset)

Saturday, September 3, 2016

inn 2.6.0, Injection-Info & .POSTED

I usually refrain myself from writing anything in the style of "How to setup foo", for it's quite silly, but my recent adventures in gmane forced me to break my rule for there is practically 0 info about the inn+newsstar "stack".

The setup is:

  1. Fedora 24.
  2. We create newsgroup gmane.test in an INN installed on a localhost (this INN is lonely & isn't connected to any other NNTP servers out there).
  3. We use newsstar (grab the .spec file from here) to connect to machine, download articles from remote gmane.test group & post them to local gmane.test newsgroup.
  4. We use our favourite newsreader (Mutt + nntp patch) to read local gmane.test newsgroup.
  5. We post our message to local gmane.test newsgroup. Then we run newsstar again & it uses INN's spool of messages prepared to be sent away. newsstar grabs our message, connects to machine & posts it.

In reality, the last step could be the hardest one, for after running newsstar we get the response that out article was rejected by w/ the cryptic reason:

441 Can't set system Injection-Info: header

Let's begin w/ the

Step 1, creating the local newsgroup

After dnf install inn, run:

# systemctl enable innd
# systemctl start !$
# /usr/libexec/news/ctlinnd newgroup gmane.test

Step 2, configure newsstar

If you have built an rpm from the .spec above, copy a sample config

# mkdir /etc/newsstar
# cp /usr/share/doc/newsstar/sample_config/ !$/

& uncomment the lines corresponding to the default INN paths:

spool_dir       /var/spool/news
active_file     /var/lib/news/active
outgoing_dir    /var/spool/news/outgoing
articles_dir    /var/spool/news/articles

Next, create /var/lib/newsstar/ file, add the desired remote newsgroup name & set the proper file ownership:

# echo 'gmane.test -1' > /var/lib/newsstar/
# chown news:news !$

Run newsstar under news user:

$ sudo -u news newsstar

It should download the last article from remote gmane.test group & post it to local gmane.test newsgroup.

In case of errors, look into journalctl & run newsstar w/ -vv CL options.

Steps 3-4, posting

Open /etc/news/newsfeeds & add the following lines to it:\

Restart INN (systemctl restart innd).

Open your newsreader, post an article to gmane.test. It obviously immidiately appears in the local INN installation. Now we need to push it to the remote gmane server.

$ sudo -u news newsstar

& boom--newsstar says it moved the "bad" article to its graveyard, for gmane didn't like it. You may open the buried article & examine its contents. There is 2 things in it that forbid us from pushing it upstream.

  1. Injection-Info header.
  2. Path header that has something like .POSTED.localhost in the middle of it.

To make life more enjoyable, INN doesn't provide any obvious way to either not to set Injection-Info header nor to edit Path properly. The only way I found is to use INN perl (yes, it's that bad) filters. It's a little more challenging to do it under Fedora, for the maintainer of inn package had simultaneously decided (a) to compile INN w/ perl support & (b) to turn it off by not including a sample ( filter in the package (this is why INN cries in the logs that perl filters are disabled).

Grab the INN tarball, extract file to /usr/libexec/news/filter/ (just creating an empty file won't do) & mark it executable. Then open (be careful, this is not the same file we've extracted from the tarball) & add to filter_post subroutine:

$hdr{'Injection-Info'} = undef;
$modify_headers = 1;

return $rval;

Restart INN. At this point, this change to the article generation is enough for such servers as, but if you post another article to gmane.test & run newsstar, the reply from gmane still fails to comfort:

441 Path: header shows a previous injection of the article

To satisfy gmane, we need to change Path header from:




There is a setting for /etc/news/inn.conf, called addinjectionpostinghost that reduces .POSTED.localhost to .POSTED but it's still not enough. Again, edit filter_post subroutine in /usr/libexec/news/filter/ to add:

$hdr{'Path'} = 'not-for-mail';

Restart INN, repost the message, rerun newsstar & go jogging in the park, because, congratulations, dude! you've wasted an hour of your life for nothing.

Sunday, July 31, 2016

Sexp navigation in `js-mode`

The sexp navigation in js-mode that comes w/ Emacs 25.1.1 is broken, so there is a quite popular smartparens minor mode. All I need from it is (sp-up-sexp) w/ which it's possible to write "move me to the beginning of the current expression", like

(define-key js-mode-map [(meta up)] (lambda () (interactive) (sp-up-sexp -1)))

or even

(defun my-js-expr-start ()
  "Requires smartparens."
    (while (sp-up-sexp -1)))

You don't have to turn smartparens-mode on to use that.

Being curious of the internals of smartparens, I was "severely shocked" at its size. The main part the mode 327KB or, according to Github, 7133 SCLO.

7133 lines for a facility of auto-closing quotes, parens & whatnot!

This world is doomed for it'll collapse of its own bloat.

Monday, July 18, 2016

Generating Dependencies Automatically with GNU Make & Browserify


For any one to be required to use more force than is absolutely necessary for the job in hand is waste.
— Henry Ford

In the previous post about the example of a build system for JavaScript SPAs, we didn’t cover the topic of auto-discovering dependencies. While not being the most complex one, it oftentimes leads to a rather frustrating expirience for the novice user.

In this post we’ll examine several ways of dependency management to aid Make to properly construct its dependency trees.

We’ll use a simple “app” consisting of 3 .js files:

├── bar.js
├── foo.js
└── main.js

where we’ll compile them from ES2015 to ES5 w/ Babel & will combine them in 1 bundle w/ Browserify. The dependency tree for main.js looks very simple:

i.e., foo.js & bar.js are commonjs modules, main.js requires bar that in turn requres foo.

The makefile that we’ll write will do 2 things:

  1. compile all .js files into a separate tree directory;
  2. create a bundle from the files in the separate tree directory.

The dependency problem arises when we modify, say, foo.js. Our build system should automatically recognize that the bundle from the step 2 became outdated & needs to be recreated.

The compilation

As usual we want to support a single source three with multiple builds (development & production). Thus it’s inconvinient to put the results of the compilation in the source directory. The simplest way of achieving this is to run Make from the output directory that != source directory. For example:

├── foobar/
│   ├── bar.js
│   ├── foo.js
│   ├── main.js
│   └──
└── _out/
    └── development/
        ├── .ccache/
        │   ├── bar.js
        │   ├── foo.js
        │   └── main.js
        └── main.js

where foobar is out source directory, _out is the output directory where we run Make, _out/development/main.js is the bundle.

Let’s start with compiling .js files first. For simplicity we’ll assume that all the npm packages we need are installed in the global mode.

# npm -g i babel-cli babel-preset-es2015 browserify
$ cat ../foobar/

src := $(dir $(lastword $(MAKEFILE_LIST)))
NODE_ENV ?= development
out := $(NODE_ENV)

.PHONY: compile

js.src := $(shell find $(src) -name '*.js' -type f)
js.dest := $(patsubst $(src)%.js, $(out)/.ccache/%.js, $(js.src))

ifeq ($(NODE_ENV), development)
BABEL_OPT := -s inline
_BABEL_OPT := --presets $(shell npm -g root)/babel-preset-es2015 $(BABEL_OPT)

$(js.dest): $(out)/.ccache/%.js: $(src)/%.js
»   @mkdir -p $(dir $@)
»   babel $(_BABEL_OPT) $< -o $@

compile: $(js.dest)

If we run it in _out directory:

$ make -f ../foobar/
babel --presets /opt/lib/node_modules/babel-preset-es2015 -s inline ../foobar//bar.js -o development/.ccache/bar.js
babel --presets /opt/lib/node_modules/babel-preset-es2015 -s inline ../foobar//foo.js -o development/.ccache/foo.js
babel --presets /opt/lib/node_modules/babel-preset-es2015 -s inline ../foobar//main.js -o development/.ccache/main.js

$ make -f ../foobar/
make: Nothing to be done for 'compile'.

To recap what we wrote here:

  • The empty .DELETE_ON_ERROR: target tells Make to remove the produced target, for example, development/.ccache/foo.js in case of the compilation failure. You should always include this line into your makefiles, otherwise, in our case, it’s possible to end up with invalid development/.ccache/foo.js if Babel terminates unexpectedly due to a bug, user signal, etc. Recall that Make thinks about the success in terms of the exit status of a shell command.

  • We collected the names of our source files in js.src; js.dest contains the transformed paths so that



  • Notice how we wrote the header of the patter rule:

      $(js.dest): $(out)/.ccache/%.js: $(src)/%.js

    by prepending it with $(js.dest) we limited the scope of it.

  • The default output build is ‘development’. We make sure that in the development mode we include source maps for the output .js files. I do not discuss here the command line options for Babel (& the kludge to force Babel pick up a globaly installed preset), for they are irrelevant to the topic.


As we transpile the .js files into a mundane ES5, the bundle should be created from the results of the compilation, not from the original files.

$ awk '/bundle/,0' ../foobar/
bundles.src := $(filter %/main.js, $(js.dest))
bundles.dest := $(patsubst $(out)/.ccache/%.js, $(out)/%.js, $(bundles.src))

ifeq ($(NODE_ENV), development)
$(bundles.dest): $(out)/%.js: $(out)/.ccache/%.js
»   @mkdir -p $(dir $@)
»   browserify $(BROWSERIFY_OPT) $< -o $@

compile: $(bundles.dest)

Again, if we run it in the output directory, the expected development/main.js appears:

$ make -f ../foobar/
browserify -d development/.ccache/main.js -o development/main.js

but the makefile falls short of detecting whether the bundle needs to be updated:

$ touch ../foobar/foo.js

$ make -f ../foobar/
babel --presets /opt/lib/node_modules/babel-preset-es2015 -s inline ../foobar//foo.js -o development/.ccache/foo.js

Despite of the fact that foo.js was indeed recompiled, our bundle remained intact because we didn’t specify any additional dependency relationships except a forlorn $(out)/main.js$(out)/.cache/main.js in the pattern rule.

There are several ways to ameliorate this. We’ll start with

Method 1: The Manual

The addition of a single line to

$(out)/main.js: $(js.src)

seems to be able to solve the problem. If you run Make again it sees that one of the prerequisites (foo.js) is newer than the bundle target.

Pros Cons
Easy to maintain in small projects Unmanageable in projects w/ a lot of small modules
No dependencies on external tools

The biggest impediment here is that the method doesn’t scale. Essentially you resort yourself to doubling the amount of work of the dependency management: the 1st time you do it when you write your code, the 2nd time–during the reconstruction of the same dependency graph in the Makefile. This is waste.

It’s also prone to errors. For example, if you have several bundles:

├── one/
│   └── main.js
├── two/
│   └── main.js
├── bar.js
├── foo.js

then adding the same naïve lines:

$(out)/one/main.js: $(js.src)
$(out)/two/main.js: $(js.src)

to will lead you to the recompilation of 2 bundles even if you make a change only to 1 of them:

$ make -f ../many-foobars/

$ make -f ../many-foobars/ -W ../many-foobars/one/main.js -tn
touch development/one/main.js
touch development/two/main.js

(-W options means “pretend that the target has been modified”.)

Method 2: Automatic make depend

Instead of specifying prerequisites manually we can use an external tool that returns the dependency list, in the Make-compatible format, for each file. One of such tools is make-commonjs-depend.

# npm -g i make-commonjs-depend
$ make-commonjs-depend development/.ccache/main.js
development/.ccache/main.js: \
development/.ccache/bar.js: \
Pros Cons
Could be slow
Easy to maintain
Requires an external tool
May rebuilt already up to date targets

We can write a phony target “depend” & run make depend every time after we add/remove/rename any .js file & include the generated file into our Makefile.

We can also write a special target $(out)/.ccache/, the recipe of which creates its target by running make-commonjs-depend command. In this case, if we include $(out)/.ccache/ & Make sees that the target is out of date, it remakes $(out)/.ccache/ & then immidiately restarts itself.

$ awk '/depend/,0' ../foobar/
$(out)/.ccache/ $(js.dest)
»   make-commonjs-depend $^ > $@
»   @echo ========== RESTARTING MAKE ==========

include $(out)/.ccache/

Here file has all compiled .js files as prerequisites thus when any of them needs to be updated Make recompiles such .js files & reruns make-commonjs-depend.

$ rm -rf development
$ make -f ../foobar/
../foobar/ development/.ccache/ No such file or directory
babel --presets /opt/lib/node_modules/babel-preset-es2015 -s inline ../foobar//bar.js -o development/.ccache/bar.js
babel --presets /opt/lib/node_modules/babel-preset-es2015 -s inline ../foobar//foo.js -o development/.ccache/foo.js
babel --presets /opt/lib/node_modules/babel-preset-es2015 -s inline ../foobar//main.js -o development/.ccache/main.js
make-commonjs-depend development/.ccache/bar.js development/.ccache/foo.js development/.ccache/main.js > development/.ccache/
========== RESTARTING MAKE ==========
babel --presets /opt/lib/node_modules/babel-preset-es2015 -s inline ../foobar//bar.js -o development/.ccache/bar.js
babel --presets /opt/lib/node_modules/babel-preset-es2015 -s inline ../foobar//main.js -o development/.ccache/main.js
make-commonjs-depend development/.ccache/bar.js development/.ccache/foo.js development/.ccache/main.js > development/.ccache/
========== RESTARTING MAKE ==========
browserify -d development/.ccache/main.js -o development/main.js

Although it works fine the unnecessary rebuilds could be a pain in big projects. For example, Make doesn’t understand that transpiling main.js in not needed in case of bar.js update, but because make-commonjs-depend gives Make a preconfigured graph which states that main.jsbar.js, it dutifully rebuilds main.js.

$ touch ../foobar/bar.js

$ make -f ../foobar/
babel --presets /opt/lib/node_modules/babel-preset-es2015 -s inline ../foobar//bar.js -o development/.ccache/bar.js
babel --presets /opt/lib/node_modules/babel-preset-es2015 -s inline ../foobar//main.js -o development/.ccache/main.js
make-commonjs-depend development/.ccache/bar.js development/.ccache/foo.js development/.ccache/main.js > development/.ccache/
========== RESTARTING MAKE ==========
browserify -d development/.ccache/main.js -o development/main.js

On the other hand, if you don’t mind such remakes you may think it’s a small price to pay for having a fully automated dependency graph available after adding only 5 lines of code to the makefile.

Method 3: Variation of Tromey’s Way

The invention of another, more clever way of auto-discovering dependencies is generally attributed to Tom Tromey, who invented it while working on automake project in the second half of the 90s.

Instead of having targets that Make uses to restart itself, every file that needs dependency traction writes its dependency tree after the compilation step, as a side effect of it.

Pros Cons
Easy to maintain
No dependencies on external tools (it uses Browserify)

For example,

$(out)/%.js: $(out)/.ccache/%.js
»   mkdir -p $(dir $@)
»   browserify $< -o $@
»   a-magic-command-to-generate-a-dependency-list > $(basename $<).d

The key here is to generate the prerequisite lists only for the bundles, not for every .js file & keep those prerequisite lists in .d files alongside the main.js file in $(out)/.ccache directory. (.d extension means nothing special, it’s just a name convention.)

During the 1st run when there is no .d files, Make knows nothing about them so it compiles .js files, then compiles bundles. The rule that creates a bundle also produces a corresponding .d file with the list of all the dependencies the bundle depends on.

At this stage we’re as at the point as if we didn’t have any dependencies for the bundles at all, but we can instruct Make to read those .d files at startup later on. In the next run, Make scans .d files, looks into the provided dependency lists & sees if any of the bundles needs to be updated. After each update the corresponding .d file updates as well.

The beauty of the method is that it doesn’t care if we reshuffle our code into a completely different set of .js files as long as we don’t remove any files in $(out)/.ccache directory & if we do remove that directory completely–it still doesn’t matter, for it’ll be the same as doing the clean build from the scratch.

$ awk '/bundle/,0' ../foobar/
bundles.src := $(filter %/main.js, $(js.dest))
bundles.dest := $(patsubst $(out)/.ccache/%.js, $(out)/%.js, $(bundles.src))

define make-depend
@echo Generating $(basename $<).d
@printf '%s: ' $@ > $(basename $<).d
@browserify --no-bundle-external --list $< \
»   | sed s%.\*$<%% | sed s%$(CURDIR)/%% | tr '\n' ' ' \
»   >> $(basename $<).d

ifeq ($(NODE_ENV), development)
$(bundles.dest): $(out)/%.js: $(out)/.ccache/%.js
»   @mkdir -p $(dir $@)
»   browserify $(BROWSERIFY_OPT) $< -o $@
»   $(make-depend)

compile: $(bundles.dest)

-include $(bundles.src:.js=.d)

Before explaining the new code, let’s see it in action. We clean up $(out) & run make:

$ rm -rf development
$ make -f ../foobar/
babel --presets /opt/lib/node_modules/babel-preset-es2015 -s inline ../foobar//bar.js -o development/.ccache/bar.js
babel --presets /opt/lib/node_modules/babel-preset-es2015 -s inline ../foobar//foo.js -o development/.ccache/foo.js
babel --presets /opt/lib/node_modules/babel-preset-es2015 -s inline ../foobar//main.js -o development/.ccache/main.js
browserify -d development/.ccache/main.js -o development/main.js
Generating development/.ccache/main.d

The generated file development/.ccache/main.d should contain a new rule (a oneliner, w/o a recipe):

$ cat development/.ccache/main.d
development/main.js: development/.ccache/foo.js development/.ccache/bar.js  

Now if we update bar.js:

$ touch ../foobar/bar.js
$ make -f ../foobar/
babel --presets /opt/lib/node_modules/babel-preset-es2015 -s inline ../foobar//bar.js -o development/.ccache/bar.js
browserify -d development/.ccache/main.js -o development/main.js
Generating development/.ccache/main.d

Volia! Make accurately recompiles only those files that needs to be recompiled: bar.js & the bundle.

Looking into the body of the pattern rule we see a line that contains $(make-depend) string. It looks like we’re injecting a value of the variable make-depend into the recipe. This trick is called a canned recipe. make-depend is a multi-line REV (recursively expanded variable) which means that Make expands it value every time it has a need to. You may think of make-depend variable as a macro or a function with a dynamic scope.

The purpose of the make-depend REV is to write a .d file that should contain a valid Make syntax.

If we run Browserify by hand on a compiled main.js file with --list command line option, Browserify prints a newline-separated list of main.js dependencies:

$ browserify --no-bundle-external --list development/.ccache/main.js

This is obviously not a valid Make syntax. We ought to:

  1. remove main.js from the list, otherwise we get a circular dependency problem;

  2. transform absolute paths to relative ones, for our pattern rules expect the latter.

This is what make-depend macro does, not counting a pattern rule header generation.

Of course nothing prevents you from writing a small script that runs Browserify by internally & formats the output accordingly. You can even take make-commonjs-depend & write a custom printer for it if you’re feeling brave.

Finally, as we’re generating .d files we should give Make a chance to read them in the next run. This is what

-include $(bundles.src:.js=.d)

line does. :.js=.d suffix means “in every file name substitute .js extension with .d”, e.g. the expanded result looks like

-include development/.ccache/main.d

A minus sign prevents Make from printing a warning if development/.ccache/main.d is not found.

What if we rename foo.js into fool.js (& do the corresponding changes in the code)? In a poorly written build system it could break the build & could require users manually remove .d files.

$ mv ../foobar/foo.js ../foobar/fool.js
$ sed -i "s,'./foo','./fool'," ../foobar/bar.js
$ tree ../foobar/ --noreport
├── bar.js
├── fool.js
├── main.js

$ make -f ../foobar/
babel --presets /opt/lib/node_modules/babel-preset-es2015 -s inline ../foobar//bar.js -o development/.ccache/bar.js
babel --presets /opt/lib/node_modules/babel-preset-es2015 -s inline ../foobar//fool.js -o development/.ccache/fool.js
browserify -d development/.ccache/main.js -o development/main.js
Generating development/.ccache/main.d

There was no errors of any kind because foo.js leftover happily resides in $(out)/.ccache directory.

PS. Here is an alternate version of this post that can be more readable on your phone.

Sunday, June 26, 2016


npm eats inodes for breakfast. A brand-new Angular2 project downloads > 40K files in node_modules just to get started (this includes babel).

Nobody counts inodes unless for some reason they use a previous generation filesystem (ext4) where inodes may suddenly become a scarce resource. The symptoms are rather common: there is a plenty of free space but you cannot create a new file.

So I decided to outwit myself via dump(8)ing /home to a network drive, reformating /home using a smaller inode_ratio value to make sure inodes would be abundant, then restore(8)ing from the dump file.

It went fine, except for 1 strange thing. The 1st time I launched Chromium it complained that “Your preference file is corrupted or invalid”. Was it because I was dumping a live fs? It seems that everything else has been restored correctly.

Wednesday, June 8, 2016

An unhealthy tweaking

Being in a state of horror because of discovering that perhaps in the next version of FVWM there will be no FvwmWharf module any more, I did something long overdue: switched to FvwmButtons.

Being more or less satisfied w/ the result,

I nevertheless feel that such an activity is a primary example of wasting time for nothing.

Thursday, May 26, 2016


Hey, look what I've found in the archives of comp.sources.misc!

Enquire: Everything you wanted to know about your C Compiler and Machine, but didn't know who to ask

One day Richard Stallman passed by, and mentioned that they needed such a program for GCC.

Saturday, May 21, 2016

Creative Marketing

From Stevens' Portals in 4.4BSD paper:

"Ideas similar to portals have appeared in numerous operating systems over the past decade.

The 4.2BSD manual [Joy et al. 1983] defined the portal system call, with seven arguments, and a footnote that it was not implemented in 4.2BSD."

On a side note: what a beautiful idea Portals was. It's a shame that Linux has never caught up with BSD on it.

Thursday, April 7, 2016

Sunrise/Sunset Algo

If you need to implement sunrise/sunset calculations having only a latitude/longitude (& a particular date), go here.

If found that w/ zenith = 90.79 it gives the same rise/set numbers as googling for "<location> sunrise".

Also be careful w/ defining your sin/asin et al. that should take degrees & return degrees. For example:

let sin = (d) => Math.sin(d * (Math.PI / 180))
let asin = (d) => Math.asin(d) * (180/Math.PI)

I had to do the same while reviving an old timezone viewer tktz to force it to work again on Fedora 23. Of course I forgot that asin() returns radians & was scratching my head over why I was getting phoney baloney numbers.

Monday, March 28, 2016

A State of Tcl

If you write a generator that gives a user several choices, like 'npm init', would you chose a GUI based approach instead? Judging by the amount & the state of lightweight gui libs for such a task, GUI was popular in 1990s & since then everyone has been sticking to cli mytool --opt1 --foo=bar solutions, for they are easy to write & support.

I thought that today, maybe, it's better to spin off a tiny node server & xdg-open a browser, where user would click, clack & submit the form. If you think about GUI--do exactly that.

But then I remembered that once upon a time (many years ago) I loved Tcl!

Well. After playing w/ 8.6.4 for a day I say it's a complete disaster. I don't get why I ever thought of it as a nice language.

The idea was very simple: draw a dialog, user clicks, presses OK, the dialog spits some json & quits. Then another tool reads that json & does all the work that the generator should do.

I won't write about Ttk widgets, they are practically the same & have not been changed a bit through all this years. 8.6.4 has fixed an annoying issue w/ HiDPI screens but X11 version of it contains a scaling bug, when everything scales properly except the fonts--they stay tiny, as if you have 75dpi monitor. The only remedy I've found it to inject this manual trigger:

if {[tk windowingsystem] == "x11"} {
    # force all fonts to have a platform-dependent default size
    # according to the DPI
    foreach idx [font names] { font configure $idx -size 0 }

The main problem w/ modern Tcl is (please don't laugh) its innate inability to properly deal w/ JSON. If you have a checkbox that sets its binded variable to 0 or 1, how would you represent that value in json? As a number? A string? How do you know that it's indeed a number? It says 1--I say it's a digit! But to Tcl it's a string. If you have an entry widget where user can enter "1" would you leave it in json as a string or would you auto-convert it to an integer? If user have entered "no" would you auto-convert it to false? What about nulls?

The sub-problem of a JSON representation nightmare is a total absence of any standard lib for converting Tcl dicts into JSON. There is tcllib [json::dict2json] that is undocumented & it's undocumented for a good reason for it doesn't work at all. Tcl wiki contains a handful of inadequate snippets that are tied to a particular dataset & are not useful as general converters. The only one half-working solution I've found is DKF's [tcl2json]. Try to get null w/ it, though.

tl;dr: forget about Tcl.

Friday, February 26, 2016

Run Debian Chromium on Fedora

Just a quickie. If you have a bunch of Fedora 32bit VMs, then starting from March there won't be any new Chrome for them. Instead of ditching all those precious VMs, I thought of using a pre-compiled Chromium provided by Debian.

It actually works if you're willing to put up w/ a regular rigmarole of (a) finding out "what's the curren version of Chromium?" & (b) proper deb → rpm conversions. Here is a makefile that automates all that.

Tuesday, February 23, 2016

JavaScript Tools with GNU Make

In the beginning

I speak what appears to me the general opinion; and where an opinion is general, it is usually correct.
— Mansfield Park

… there was no transcompiling in JavaScript world whatsoever & everyone who was programming back then for the front-side portion of the web was greatly admiring the fact of an instant gratification.

One day Sass appeared from the direction of Rails campfire site, where folks were having a good time singing Kumbaya. Many looked closely at Sass & thought that adding a new level of abstraction was never a bad thing & quickly joined the movement. Humble designers tried to held a convention but their feeble voices were swamped by the music.

Shortly after, CoffeeScript came along. Although compiling it in the browser on-the-fly was possible, rarely somebody did that for it was considered uncivil & rude. The sites were lean & jQuery was still a King.

Then a guy who was competing with TJ for a number of pushed packages to the npm registry, wrote Browserify. It became possible to write isomorphic code before everyone realized that such a word exists.

Starting a project started to mean a process of thinking of a build system.

$ mkdir ~/projects/money-printer
$ cd !$
$ touch █

Some transferred their Rake skills to their brave new SPA world, some tried to employ tiny shell scripts, the majority, though, was unsure what to do & how to behave properly.

Something had to happen because however it used to be, it used to be somehow, it never happened yet that is was no-how, thus several nice tools materialized. Although most of them work fine, occasionally I catch myself thinking that, perhaps, those tools are a little unnecessary for my needs.

Theories of galaxies

It turns out, people in different industries had similar problems for years. For instance, sometime during the end of the Middle Ages, Bell Labs engineers were bitterly complaining to each other how they kept making the classic mistake of debugging an incorrect program because they would forget to compile the change.

One day Steve Johnson (the author of yacc) came storming into the office of his colleague. The colleague name was Stuart Feldman. After they pitied each other on the miscompilation misfortune, they sketched up on the board a general idea of how to prevent this kind of errors in the future. The result of the sketching & the vigorous one-night coding is know by a program called Make.

Many years later Feldman will say “One of the reasons Make was so simple was that it was only supposed to solve my problem, and help Steve too.”

Why use Make today? Or more importantly, why use Make as a build tool for writing SPAs?

I remember the first time I was forced to read a makefile. It was circa 2003, when the FreeBSD port I was installing failed to compile properly. While trying to resolve the problem, I’ve discovered, to my surprise, that the whole FreeBSD ports system was written in a dialect of Make language. I didn’t like its syntax & the whole construction seemed overly complex, unintuitive, weird.

A modern JavaScript developer meets Make only if he tries to install some peace of software that is absent in a collection of packages for his favourite OS. Such software is usually written in old languages like C & uses autoconf system to generate a bunch of makefiles. The process looks foreign, too exotic, ancient, outdated, uninteresting, not relevant.

Despite its alien nature, Make has managed to become a happy witness to the first mass-produced personal computers, to the eradication of Smallpox, to the invention of WWW, to the collapse of USSR, to the end of apartheid in South Africa, to the introduction of €, to DHH’s “blog in 15 minutes” video, to the end of Great Recession & to SpaceX drone ship landing.

Make today is typically twice old then a typical web developer. If you learned Make, say, in 1986 (when the first edition of O’Reilly’s Managing Projects with GNU Make came out), you can still employ that knowledge to this very day, usually being the only 1 person in the whole building who can fix some random broken makefile.

“This rubbish doesn’t compile, man.”
“What does it say?”
“Something about a missing rule for a target.”
(covers his face with hands)
“Call Jane.”

The only communities that rejected Make completely were Java & Go. For the former you could use Make in theory but in practice no one except you then could parse & maintain your makefile. For the latter, Rob Pike’s idea of build conditions so rigorously constrained that no external tool is necessary, proved to be a winner. Unfortunately, this is not the case for JavaScript world.

Over the years, there were many attempts to “fix” Make via either enhancing it syntax, introducing incompatible features, or rethinking the whole idea. The majority of this this attempts if not failed, withal didn’t acquire much advocacy. Even such cosy tools as Rake have never gained popularity beyond the language domain they are written in & belong to.

JavaScript community is not unique. It follows the same waves of “it’s own way”, where the introduction of new revolutionary tools every 6 months inevitably leads to the psychological state called “tools fatigue”.

A dull speaker always talks long

Instead of a yet another reintroduction to a particulars of some Make implementation, I’ll try to show how to use GNU Make in a small but a real web application. There will be some shotrcuts & simplifications along the way; I did them not because of Make limitations but to keep this text short.

A small notice: the text implies that a reader is very comfortable with the command line. If it’s not you to a t (for example, you come from a designer’s background), please stop reading now, go read The Unix Programming Environment book, practice for a month, then return. It’s the only book you will ever need to read to become a jolly good Unix user.

Our example is a web-based RSS feeds filter. Suppose you want to subscribe to Back to Work podcast but only listen to episodes where hosts do not talk about Apple (or vice versa, Apple is your only interest). Or to find all the great shows where the guest was John Roderick? The b2w feed contains > 250 episodes; each episode contains extensive metadata. It’s not hard to programatically search through the XML & generate a smaller feed for the RSS reader of your choice.

The app consists of 2 parts: (a) a web component, where a user specifies a URI for the feed alongside a couple of filtering patterns & (b) a small server proxy, required mainly because of a same-origin policy.

The app source tree looks like this:

├── cli/
│   └── grepfeed*
├── client/
│   ├── index.html
│   ├── main.jsx
│   ├── moomintroll.svg
│   └── style.sass
├── lib/
│   ├── dom.js
│   ├── feed.js
│   └── u.js
├── mk/
│   ├──*
│   └── watchman.json
├── server/
│   └── index.js*
├── test/
│   ├── data/
│   │   ├── back2work.xml
│   │   ├── irishhistorypodcast.xml
│   │   └── simple.xml
│   └── test_feed.js
├── Makefile
├── package.json

lib directory contains a shared code, used both by a server component & a “client” side. The HTTP server doesn’t require any additional build step to function, but the web app is all about transcompiling:

  • it is written in a subset of ES2015 & we use Babel to transform the code to ES5;

  • instead of CSS we use a mix of hand-written Sass & plain CSS from NProgress npm package. The result will be in 1 style.css file.

  • the browser-facing part of the code is written in JSX thus requires both an additional compilation step to ES5 before ES2015 (i.e., ES5 → ES2015 → JSX) and React libraries at runtime.

  • to employ some Node.js libraries in the browser & to automatically manage the dependencies we use Browserify. The resulting app will be squeezed in 1 file main.js.

  • to be able to focus on the coding, instead of typing over & over again the same commands in the terminal, we use Watchman to automatically run Make for us whenever any of our files that needs recompiling change.

In real life you always have at least 2 different builds: one is for a development phase only, another for a production deployment. In the ‘devel’ version we use source maps, for the production version–the code minification.

It is not enough to have an ability to produce 2 builds, the goal is to have those 2 build at the same time.

For example, depending on the value of NODE_ENV environment variable we can decide how to compile & where to put the output files. There is a whole separate history of having a single source tree but multiple builds per “platform”, in which I won’t get into here. We are going to separate the source tree with the compiled output to a point that you may mark the source three as a read-only & don’t worry of ever accumulating random junk there over time. As an additional bonus this eliminates the need of any ‘clean’ operations that never work properly anyway.

This is how the result looks like:

├── development/
│   ├── client/
│   │   ├── index.html
│   │   ├── main.browserify.js
│   │   ├── moomintroll.svg
│   │   ├── style.css
│   │   └──
│   └── lib/
│       ├── dom.js
│       ├── feed.js
│       └── u.js
├── node_modules/ [438 entries exceeds filelimit, not opening dir]
├── production/
│   ├── client/
│   │   ├── index.html
│   │   ├── main.browserify.js
│   │   ├── moomintroll.svg
│   │   └── style.css
│   └── lib/
│       ├── dom.js
│       ├── feed.js
│       └── u.js
└── package.json

The contents of development/client directory is what our server uses to serve to the end-user. Files in development/lib can be safely ignored; they are temporal & placed there for Browserify, that uses them for producing development/client/main.browserify.js bundle. You may notice that the contents of development/client & production/client directories is different. As a matter of fact, the size is quite different too:

$ du -h --max-depth=1
3.3M ./development
444K ./production
62M ./node_modules
65M .

This is what you get after leaving out embedded source maps from main.browserify.js & an aggressive JavaScript minification.

You can read the app source code at It won’t hurt if, before carrying on, you clone it & try to reproduce one of the builds by yourself.

Static assets

We have files in our app that don’t require any transformation. It’s an .svg image of a rather happy Moomintroll & index.html. If we were living in the past & were compiling non-static assets in the same directory where their sources were, our .svg & .html files would have required no attention from a build system. But we chose the different route–to move everything outside of the source tree directory.

Our first steps are:

  1. Grab a list of files in the source tree.
  2. Chose a destination for selected files.
  3. Write a rule that specifies how to copy data.
  4. Invoke the rule.

In the root of our source tree we create a file named Makefile. When you run Make, it searches the current directory for a file with that name & starts parsing it.

NODE_ENV ?= development
out := $(NODE_ENV)
src.mkf := $(lastword $(MAKEFILE_LIST))
src := $(dir $(src.mkf))

We defined 4 variables. If you have NODE_ENV variable already defined in your environment, Make grabs it value, otherwise we set it to development string. out variable gets the value of NODE_ENV. We will use $(out) everywhere in our Makefile later on where we will need to prefix the file destination.

src.mkf gets the (relative) path to the Makefile itself. Ignore for now how it manages to do that. During the definition of src variable, we invoke Make internal $(dir) function to cut of the file name portion of src.mkf value. $(dir) is very similar to dirname(1) or Node path.dirname().

Steps 1-2: grab source & destination
static.src := $(wildcard $(src)/client/*.html $(src)/client/*.svg)
static.dest := $(subst $(src), $(out), $(static.src))

Here we define another 2 variables: the source of our static assets & its destination.

$(wildcard glob1 glob2 ...) is a Make function that internally uses fnmatch(2) to get a list of files. If it doesn’t match anything it returns an empty string. Think of $(wildcard) as primitive analogue of ls(1); it’s not recursive and uses glob patterns instead of regexps.

$(subst FROM, TO, TEXT) returns a new string with all matches of FROM replaced by TO. E.g. the next line in Make language

$(subst lamb,lambda,Mary had a little lamb)

is equivalent to JavaScript

"Mary had a little lamb".replace(/lamb/g, "lambda")

The only difference that $(subst) doesn’t support any regexp.

What we did in static.dest is got /foo/bar/grepfeed/client/index.html replaced with development/client/index.html.

Step 3: a rule

Now we can write a custom pattern rule that copies source files to their destination:

$(out)/%: $(src)/%
» mkdir -p $(dir $@)
» cp -a $< $@

Make language is all about rules. You may think of rules as functions (or rather, procedures) that take 2 parameters: target & source. A body of a “function” is any number of shell commands prefixed by a TAB character (marked by » above and everywhere below in this text).

target: source1 source2 ...
» body

Terms “source” & “body” are non-standard. I use them in this section only for clarity. The official GNU Make terms are “prerequisites” (also “dependency”) & “recipe”, e.g.

target: prerequisite1 prerequisite2 ...
» recipe

% character in the target & in the source is a wildcard. Cryptic $@ & $< inside of the body (recipe) of the rule are automatic variables. When (& only when) Make invokes the rule, it substitutes $@ with a target name & $< with a source name. There could be several sources (prerequisites, dependencies); $< means the first one, thus Make have another autovar $^ that means “the whole list”.

The exact meaning of $@, $<, $^ often escapes from newcomers. Here is the picture to help you to remember which autovar corresponds to what

The problem with our rule that it’s too broad. % in $(src)/% can match anything, not only client/index.html but client/main.jsx too. It’s possible to limit severely the applicability of a pattern rule by prefixing it with an explicit list of targets:

$(static.dest): $(out)/%: $(src)/%
» mkdir -p $(dir $@)
» cp -a $< $@
Step 4: invoking the rule

There is no way to explicitly invoke a pattern rule. But if we ask Make to create a target that match some rule, Make checks for the match & internally transforms the pattern rule to several simple file-based rules.

If we run in some temporal directory

$ make -f ../grepfeed/Makefile development/client/index.html

(-f CLO tells Make what file to read instead of Makefile in the current directory.)

Make automatically creates this rule on-the-fly:

development/client/index.html: /foo/bar/grepfeed/client/index.html
»  mkdir -p development/client
»  cp -a /foo/bar/grepfeed/client/index.html development/client/index.html

Or in an action:

$ make -f ../grepfeed/Makefile development/client/index.html development/client/moomintroll.svg
mkdir -p development/client/
cp -a ../grepfeed//client/index.html development/client/index.html
mkdir -p development/client/
cp -a ../grepfeed//client/moomintroll.svg development/client/moomintroll.svg

but it we provide a file name that do not match any pattern, Make aborts:

$ make -f ../grepfeed/Makefile foo/index.html bar/moomintroll.svg
make: *** No rule to make target 'foo/index.html'.  Stop.

It’s a little inconvenient to pass a list of file names to Make directly, for the list can be huge. We can write another rule that has a target with an arbitrary name but in sources has an actual list of the desired targets.

compile: development/client/index.html development/client/moomintroll.svg

or even better:

compile: $(static.dest)

This rule doesn’t have to have any recipe (body). Then we can execute Make as

$ make -f ../grepfeed/Makefile compile

One of the most lucrative Make features is that if you write your rules with caution, prudence & tact, it won’t rebuild targets that are up-to-date.

$ rm -rf development
$ make -f ../grepfeed/Makefile compile
mkdir -p development/client/
cp -a ../grepfeed//client/index.html development/client/index.html
mkdir -p development/client/
cp -a ../grepfeed//client/moomintroll.svg development/client/moomintroll.svg

$ make -f ../grepfeed/Makefile compile
make: Nothing to be done for 'compile'.

$ touch ../grepfeed/client/moomintroll.svg
$ make -f ../grepfeed/Makefile compile
mkdir -p development/client/
cp -a ../grepfeed//client/moomintroll.svg development/client/moomintroll.svg

How Make decides which target is up-to-date? By the simplest possible way: via checking last modification time for a target & its source. Over the years there were multiple attempts to enhance this algo by looking, for example, into a message digest of a file, but nobody had bothered to actually implement them efficiently enough to be included in GNU Make.

The next Make appeal comes from realization that by writing makefiles you’re constructing an acyclic graph of targets & their dependencies. So far we wrote 1 node with 2 leaves, each of which is generated via a pattern rule.

The arrow means “depends on.”


Debug facilities is where the original GNU Make distribution falls short. Partially it comes from the dynamic Make nature, for it is impossible to fully answer what would happen without doing it.

There is no REPL of any kind. Some primitive hacks exists, for example,, that could help mainly to experience internal Make functions like $(filter) or $(patsubst) without manually creating a makefile & running it.

ims> .pwd
ims> src = ../grepfeed/
ims> out = development
ims> static.src = $(wildcard $(src)/client/*.html $(src)/client/*.svg)
ims> . $(static.src)
../grepfeed//client/index.html ../grepfeed//client/moomintroll.svg
ims> . $(subst $(src), $(out), $(static.src))
  development/client/index.html  development/client/moomintroll.svg

There is also a forked version of GNU Make called remake, that can show an additional information about targets, plus it contains a real debugger.


If you don’t want to install any additional tools, prepare to grieve.

The most annoying GNU Make misconduct is inability to print the variable value without modifying makefiles. A clever trick, popularized by John Graham-Cumming, comprises of adding a special patter rule to a makefile. A modified version of the rule splits a variable value into separate lines for I find the trick most useful for displaying a list of files:

» @echo "$(strip $($*))" | tr ' ' \\n

Then, we can print the value of static.dest

$ make -f ../grepfeed/Makefile pp-static.dest

When you want to print what targets will be remade, try -n & -t options together:

$ make -f ../grepfeed/Makefile -tn compile
touch development/client/index.html
touch development/client/moomintroll.svg


Before transforming any of sass/js/jsx files we need to make sure we have all the installed tools. In package.json, among other things, we have:

  • node-sass
  • babel-cli
  • babel-preset-es2015
  • babel-preset-react
  • browserify
  • uglify-js

We can switch the responsibility to the user by asking in a readme to “install those in global mode” or we can be more polite & write a simple rule that checks if our packages are installed after each change in package.json.

export NODE_PATH = $(realpath node_modules)

node_modules: package.json
»   npm install --loglevel=error --depth=0 $(NPM_OPT)
»   touch $@

package.json: $(src)/package.json
»   cp -a $< $@

We have here 2 new simple file-based rules.

We need to copy package.json from the source code directory because if our output directory isn’t a descendant of the $(src), npm fails to find package.json at all, or picks up a wrong one.

Explicitly setting NODE_PATH is required for Babel because when the source code is in a different subtree, Babel searches for packages in node_modules directory downwards starting from a particular .js file.

Notice that we are telling Make to export NODE_PATH to child processes, such as for a CLI wrapper of Babel & that it’s not a regular variable, but a macro.

Regular Make variables, distinguished in their definition by := (as in foo := bar) have nothing interesting about them; they work exactly as you expect, by setting the value of a left-hand side immediately. Macros on the other hand, create only a stub, that is not evaluated until macro is accessed.

When we run Make for the first time, the directory node_modules may not exist yet, thus had we defined NODE_PATH as a regular variable, its value would have been an empty string & Babel would have failed to find any Node.js modules. But when it’s a macro, Make evaluates it when somebody (a child process) tries to read it. At that point node_modules definitely exists, & Make expands it to a full path with the help of its internal $(realpath) function.

To test all this, run Make in the $(out) directory:

$ make -f ../grepfeed/Makefile node_modules
cp -a ../grepfeed//package.json package.json
npm install --loglevel=error --depth=0 --cache-min 99999999

> node-sass@3.4.2 install /home/alex/lib/writing/articles/javascript-tools-with-gnu-make/_out.blogger/s06/grepfeed/_out/node_modules/node-sass
> node scripts/install.js

Binary downloaded and installed at /home/alex/lib/writing/articles/javascript-tools-with-gnu-make/_out.blogger/s06/grepfeed/_out/node_modules/node-sass/vendor/linux-ia32-47/binding.node

> spawn-sync@1.0.15 postinstall /home/alex/lib/writing/articles/javascript-tools-with-gnu-make/_out.blogger/s06/grepfeed/_out/node_modules/spawn-sync
> node postinstall

> node-sass@3.4.2 postinstall /home/alex/lib/writing/articles/javascript-tools-with-gnu-make/_out.blogger/s06/grepfeed/_out/node_modules/node-sass
> node scripts/build.js

` /home/alex/lib/writing/articles/javascript-tools-with-gnu-make/_out.blogger/s06/grepfeed/_out/node_modules/node-sass/vendor/linux-ia32-47/binding.node ` exists. 
 testing binary.
Binary is fine; exiting.
grepfeed@0.0.1 /home/alex/lib/writing/articles/javascript-tools-with-gnu-make/_out.blogger/s06/grepfeed/_out
├── babel-cli@6.5.1 
├── babel-polyfill@6.5.0 
├── babel-preset-es2015@6.5.0 
├── babel-preset-react@6.5.0 
├── browserify@13.0.0 
├── node-sass@3.4.2 
└── uglify-js@2.6.2 

touch node_modules

and again, to check if we indeed wrote 2 rules properly:

$ make -f ../grepfeed/Makefile node_modules
make: 'node_modules' is up to date.

Npm gets slower & slower with every release so this could take a while. There is NPM_OPT in the node_modules recipe; use it to pass any additional options to npm, for example:

$ make -f ../grepfeed/Makefile node_modules NPM_OPT="--cache-min 99999999"


To compile .sass files to .css we employ the same algo we have used for static assets.

node-sass := node_modules/.bin/node-sass
SASS_OPT := -q --output-style compressed
ifeq ($(NODE_ENV), development)
SASS_OPT := -q --source-map true
sass.src := $(wildcard $(src)/client/*.sass)
sass.dest := $(patsubst $(src)/%.sass, $(out)/%.css, $(sass.src))

$(out)/client/%.css: $(src)/client/%.sass
»   @mkdir -p $(dir $@)
»   $(node-sass) $(SASS_OPT) --include-path node_modules -o $(dir $@) $<

$(sass.dest): node_modules

compile: $(sass.dest)

Here we use NODE_ENV for the first time to modify the compiler behaviour: to include source maps when we are in a developer mode & to turn on the minification for a production mode.

Output .css files depend on node_module target, which depends on package.json which means if we modify the latter, Make considers our .css files outdated & remakes them.

You may not like a useless rebuilding every time you fix a typo in package.json, but it ensures that after updating a version string of a css package (like Nprogress), you won’t end up with an old code in $(out).

$ grep import ../grepfeed/client/style.sass
@import "nprogress/nprogress"

The usage of NODE_ENV for turning on/off minification through modifying node-sass command line options seems easy & convenient, but it’s inherently un-Unix: the minification step should be done by a separate command.

A more civilized way to do conversions would be to use chains of implicit rules. In a production mode

.css → .uncompressed_css → .sass

& in a development mode

.css → .sass

I’ll live this to you as a homework. For tips of how to achieve that, read the section about .js files transformation below.

ES2015 & Browserify

As our app is written in a subset of ES2015 we need another pattern rule to convert .js files to a ES5. lib directory is the location of the ES2015 code.

babel := node_modules/.bin/babel
ifeq ($(NODE_ENV), development)
BABEL_OPT := -s inline
js.src := $(wildcard $(src)/lib/*.js)
js.dest := $(patsubst $(src)/%.js, $(out)/%.js, $(js.src))

$(js.dest): node_modules

$(out)/%.js: $(src)/%.js
»   @mkdir -p $(dir $@)
»   $(babel) --presets es2015 $(BABEL_OPT) $< -o $@

There is no sign of minification because the destination files in $(out)/lib are for temporal purposes.

The same goes for .jsx files (of which we have only 1) in client directory.

jsx.src := $(wildcard $(src)/client/*.jsx)
jsx.dest := $(patsubst $(src)/%.jsx, $(out)/%.js, $(jsx.src))

$(jsx.dest): node_modules
# we use .jsx files only as input for browserify
.INTERMEDIATE: $(jsx.dest)

$(out)/client/%.js: $(src)/client/%.jsx
»   @mkdir -p $(dir $@)
»   $(babel) --presets es2015,react $(BABEL_OPT) $< -o $@

One thing is different here: the temporal output is placed in $(out)/client, that is the directory that our server uses for its root for static files. After all compilation steps are finished there should be no temporal files. Make doesn’t know that the result of .jsx transcompiling is a temporal link in the chain thus we mark such targets as intermediates, by adding them as dependencies to a special .INTERMEDIATE target. You’ll see shortly what happens to such targets.

This rule contains another shortcut: the transformation from JSX to ES5 is done in 1 step. Ideologically this is Not Right because after JSX conversion we should get plain ES6 which we could then convert to ES5 code.

To get a final bundle with the name $(out)/client/main.browserify.js we write a simple file-based rule:

browserify := node_modules/.bin/browserify
browserify.dest.sfx := .es5
ifeq ($(NODE_ENV), development)
browserify.dest.sfx := .js

bundle1 := $(out)/client/main.browserify$(browserify.dest.sfx)
$(bundle1): $(out)/client/main.js $(js.dest)
»   @mkdir -p $(dir $@)
»   $(browserify) $(BROWSERIFY_OPT) $< -o $@


Notice how we manually add to bundle dependencies a list of files in $(out)/lib & that our modest js target is empty for now.

This rules contains a catch: if it’s a development mode, the chain is simple

main.browserify.js → .js deps

where everything is compiled with source maps. For a production mode, there is an additional link:

main.browserify.js → main.browserify.es5 → .js deps

where main.browserify.js, despite its name, is created not by browserify but by a separate uglifyjs program.

# will be empty in development mode
es5.dest := $(patsubst %.es5, %.js, $(bundle1))

UGLIFYJS_OPT := --screw-ie8 -m -c
%.js: %.es5
»   node_modules/.bin/uglifyjs $(UGLIFYJS_OPT) -o $@ -- $<

ifneq ($(browserify.dest.sfx), .js)
js: $(es5.dest)
# we don't need .es5 files around
.INTERMEDIATE: $(bundle1)
js: $(bundle1)

compile: js

js target gets its prerequisites depending on NODE_ENV value.

The whole dependency graph of JavaScript files look like this (ellipse-shaped nodes are intermediates; dashed are production-mode only):

Now we can test the production mode:

$ NODE_ENV=production make -f ../grepfeed/Makefile js
node_modules/.bin/babel --presets es2015  ../grepfeed//lib/feed.js -o production/lib/feed.js
node_modules/.bin/babel --presets es2015  ../grepfeed//lib/dom.js -o production/lib/dom.js
node_modules/.bin/babel --presets es2015  ../grepfeed//lib/u.js -o production/lib/u.js
node_modules/.bin/babel --presets es2015,react  ../grepfeed//client/main.jsx -o production/client/main.js
node_modules/.bin/browserify  production/client/main.js -o production/client/main.browserify.es5
node_modules/.bin/uglifyjs --screw-ie8 -m -c -o production/client/main.browserify.js -- production/client/main.browserify.es5
rm production/client/main.browserify.es5 production/client/main.js

$ NODE_ENV=production make -f ../grepfeed/Makefile js
make: Nothing to be done for 'js'.
$ touch ../grepfeed/lib/u.js
$ NODE_ENV=production make -f ../grepfeed/Makefile js
node_modules/.bin/babel --presets es2015  ../grepfeed//lib/u.js -o production/lib/u.js
node_modules/.bin/babel --presets es2015,react  ../grepfeed//client/main.jsx -o production/client/main.js
node_modules/.bin/browserify  production/client/main.js -o production/client/main.browserify.es5
node_modules/.bin/uglifyjs --screw-ie8 -m -c -o production/client/main.browserify.js -- production/client/main.browserify.es5
rm production/client/main.browserify.es5 production/client/main.js

Albeit we didn’t explicitly put in any of the recipes a rm command, Make automatically removes targets that were prerequisites in .INTERMEDIATE target.

A watched pot never boils

2 of 4 stand-alone utils we use in our makefile have a built-in “watch” feature & browserify has a separate (& quite popular) watchify wrapper. It’s hard to imagine a project that needs to recompile only those files that watchify watches or the project that only uses node-sass. It’s also hard to imagine a reason why would you include the “watch” feature into your CLI program in the first place, knowing very well that your tool will never be the only one third-party tool in a project.

The only valid reason I can think of is a conscientious endeavour to set a world benchmark for software bloat, but we won’t get into that.

Instead of running 3 separate processes in parallel we will use watchman. It will look out for files we specify & run Make on every change automatically. If we have wrote Makefile properly, only files that are outdated (in $(out) directory) will be recompiled.

To make this more developer-friendly we can play a confirmation sound when Make finishes without errors; run a separate terminal window for watchman output & raise the window in case of a compilation error.

watchman configuration is not exactly the easiest one for it has 2 modes for reading it: from stdin in a json format or via command line options. The latter is more limited & the former is too verbose. We’ll use the json only to escape from the shell quoting issues.

We add another target to the makefile:

»   watchman trigger-del $(src) assets
»   @mkdir -p $(out)
»   m4 -D_SRC="$(src)" -D_TTY=`tty` \
»   »   -D_OUT_PARENT=`pwd` \
»   »   -D_MAKE="$(MAKE)" -D_MK="$(src.mkf)" \
»   »   $(src)/mk/watchman.json | watchman -n -j

m4 macro processor is absolutely not required, you can replace it with any other you like; we use it only to transform $(src)/mk/watchman.json file:

        "expression": [
            ["pcre", "^(client|lib)/[^#]+$", "wholename"],
            ["pcre", "^package.json$", "wholename"]
        "name": "assets",
        "command": [
            "_MAKE", "-C", "_OUT_PARENT", "-f", "_MK", "compile"
        "append_files": false,
        "stderr": ">_TTY",
        "stdout": ">_TTY"

I won’t describe what all this means, please refer to watchman manual for the particulars. What we need to note is that on each file change, watchman will run $(src)/mk/ script that in turn will run Make as

make -C $(src) -f $(src)/Makefile compile

where -C instruct Make to chdir before parsing a makefile provided in the -f CLO.

$(src)/mk/ is closely tied to my Fedora installation, so you will need to modify it for your machine:


# See `watch` target in Makefile.

# clear xterm history
printf "\033c"
# what is to be done
printf "\033[0;33m%s\033[0;m\n" "$*"

# run make


if [ $ec -eq 0 ]; then
    play $media/message.oga 2> /dev/null
    play $media/bell.oga 2> /dev/null
    # raise xterm window
    printf "\033[05t"

exit $ec

If everything works fine, you open a new xterm window, run make -f ../grepfeed/Makefile watch there & forget about it. On any compilation error, that xterm window pops up, alerting us that build has failed.


As we see, with a little help of shell scripting & a little knowledge of Make language it is possible to construct a build system for a SPA that uses all the latest JavaScript tools under the hood. There is 0 magic in it & no dependencies on any “plugins”. For why would you need a “plugin” to use a program that is already capable of transforming input?

Much more could be said about the Make language itself. We wrote our build system in 1 big makefile only to stay simple. You don’t have to be such a simpleton in your projects. There were no talks about what is a list in terms of Make, nothing about scoping rules, user-defined functions, canned recipes, etc.

I didn’t cover giant topics like auto-discovering dependencies for .js files (we have cheated by explicitly stating the dependencies for the output browserify bundle) or parallel jobs.

If you’re interested in GNU Make & want to know more, start with its official manual that covers most of the Make language details. After that, read Robert Mecklenburg’s Managing Projects with GNU Make book that will feed you with many ideas that you might otherwise be missing out. If that will be not enough, read The GNU Make Book by John Graham-Cumming. There is nothing to read about Make beyond that book for it contains maximum hardcore staff you will ever extract about the topic.

I want only to remind you that it doesn’t matter what toolchain you chose for a project (based on Make or not). If you fail to deliver a working app, no build system in the world will save you. Nobody cares about your polished infrastructure, for it’s the app that is important to the end user.


PS. Here is an alternate version of this post that can be more readable on your phone.