--- title: Make Tips toc: true published: 2019-04-16T11:23:06-05:00 modified: 2019-09-05T22:57:25-04:00 --- I tend to use make as a task runner, a purpose it is not expressly suited to, but works well enough. This own site's [[https://gitlab.com/doshitan/doshitan.com/blob/master/makefile][makefile]]. Note I almost always use and build for [[https://www.gnu.org/software/make/][GNU Make]], which is [[#gnu-vs-bsd-make][different in some ways than other makes]]. * Basics See the [[https://www.gnu.org/software/make/manual/make.html#Introduction][intro section]] of the GNU Make manual. And [[https://www.jfranken.de/homepages/johannes/vortraege/make.en.html][this page]] is a good intro and reference. Basic format: #+BEGIN_SRC makefile # v-- filename of the thing the recipe builds or an action/task name target: prerequisites ... # ^-- other targets to build before this one # v-- must start with a tab character, no spaces here recipe # <-- lines to execute ... #+END_SRC Each line execute in a separate shell, so you can not set variables inside a target. Chain commands together with ~&&~ or ~;~, e.g., #+BEGIN_SRC makefile thing: a_command && b_command # execute in same shell a_command; b_command # also executes in same shell #+END_SRC If you have a long line, use backslashes to break it up across lines. #+BEGIN_SRC makefile do-thing: command thing $(SOME_VAR) \ --a-flag \ --another-flag \ --output=$(SOME_DIR) #+END_SRC ~@~ at the beginning of a line suppresses make echoing the command. #+BEGIN_SRC makefile echo: echo "Hello, world" #+END_SRC #+BEGIN_SRC bash $ make echo echo "Hello, world" "Hello, world" #+END_SRC vs. #+BEGIN_SRC makefile echo: @echo "Hello, world" #+END_SRC #+BEGIN_SRC bash $ make echo "Hello, world" #+END_SRC ~-~ at the beginning of a line suppresses errors on that line from killing target build. #+BEGIN_SRC makefile clean: -rm *.o #+END_SRC Finishes successfully even if the ~rm~ errors (like if there are no ~.o~ files to clean, for this specific case you'd probably just use the ~-f~ on ~rm~ itself, but this is just an example). You can combine them: #+BEGIN_SRC makefile clean: @-rm *.o #+END_SRC Doesn't say what it's doing or care if it errors. If make is called without a target, it will run the first target listed in the makefile, unless the ~.DEFAULT_GOAL~ variable is set, then whatever that says gets run. * Capitalize ~makefile~ or not It [[https://www.gnu.org/software/make/manual/html_node/Makefile-Names.html][doesn't really matter]]. ~Makefile~ is conventional. Note that GNU make searches for ~makefile~ before ~Makefile~, so if both are present, the lowercase one wins. This can be an interesting feature in a shared project. For instance, if you have a version tracked/shared ~Makefile~, then a local ~makefile~ that does an ~include Makefile~ to pull in the shared one, you can then add personal targets to your ~makefile~, things that are only useful for you or that you are giving a trial run for a while. This is also potentially dangerous, mixing local modifications in the same interface, safer to have a differently named, like a ~make.local~ that you have to ~make -f make.local ~, but sometimes it's nice to have your tweaks presented in the same interface. I prefer lowercase ~makefile~ as it's ever so slightly easier to type and it's usually surrounded by other lowercased names so it looks better to me to match. * Make as a task runner Often in projects you have a number of commands that you may wish to run on occasion. There are many existing task runner solutions out there[fn::The JavaScript world in particular seems to love to create them.]. I shy away from these as I think often they are overcomplicated for the task at hand. If a project has a JavaScript dependency, often it will use the ~scripts~ section in it's ~package.json~ file, which can easily be run with ~npm run