A Tutorial on Portable Makefiles
More nifty portable Make facts:<p>- For portable recursive make(1) calls, use $(MAKE). This has the added advantage of BSD systems which can electively install GNU Make as gmake being able to pass in the path to gmake to run GNU Makefiles [1]<p>- BSD&#x27;s don&#x27;t include GNU Make in base system. BSD&#x27;s port and build system uses Make extensively, and has a different dialect [2]<p>- In addition to that, you will likely choose to invoke system commands in your Makefile. These also have the same GNU-specific features that won&#x27;t work on BSD&#x27;s. So keep your commands like find, ls, etc. POSIX-compliant [3]<p>- Part of the reasons tools like CMake exist is to abstract not only library&#x2F;header paths and compiler extensions, but also the fact POSIX shell scripting and Makefile&#x27;s are quite limited.<p>- Not only is there a necessity to use POSIX commands and POSIX compatible Make language, but the shell scripting must also not use Bash-isms and such, since there&#x27;s no guarantee the system will have Bash.<p>- POSIX Makefiles have no conditionals as of 2017. Here&#x27;s a ticket from the issue tracker suggesting it in 2013: <a href="http:&#x2F;&#x2F;austingroupbugs.net&#x2F;view.php?id=805" rel="nofollow">http:&#x2F;&#x2F;austingroupbugs.net&#x2F;view.php?id=805</a>.<p>- You can do nifty tricks with portable Makefile&#x27;s to get around limitations. For instance, major dialects can still use commands to grab piped information and put it into a variable. For instance, you may not have double globs across all systems, but you can use POSIX find(1) to store them in a variable:<p><pre><code>    FILES= find . -type f -not -path &#x27;*&#x2F;\.*&#x27; | grep -i &#x27;.*[.]go$$&#x27; 2&gt; &#x2F;dev&#x2F;null
</code></pre>
Then access the variable:<p><pre><code>    if command -v entr &gt; &#x2F;dev&#x2F;null; then ${WATCH_FILES} | entr -c $(MAKE) test; else $(MAKE) test entr_warn; fi
</code></pre>
I cover this in detail in my book <i>The Tao of tmux</i>, available for free to read online. [4]<p>- MacOS comes with Bash, and if I remember correctly, GNU Make comes with the developer CLI tools as make.<p>- For file watching across platforms (including with respect for kqueue), I use entr(1) [5]. This can plop right into a Makefile. I use it to automatically rerun testsuites and rebuild docs&#x2F;projeocts. For instance <a href="https:&#x2F;&#x2F;github.com&#x2F;cihai&#x2F;cihai&#x2F;blob&#x2F;cebc197&#x2F;Makefile#L16" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;cihai&#x2F;cihai&#x2F;blob&#x2F;cebc197&#x2F;Makefile#L16</a> (feel free to copy&#x2F;paste, it&#x27;s permissively licensed).<p>[1] <a href="https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;make&#x2F;manual&#x2F;html_node&#x2F;MAKE-Variable.html#MAKE-Variable" rel="nofollow">https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;make&#x2F;manual&#x2F;html_node&#x2F;MAKE-Vari...</a><p>[2]  <a href="https:&#x2F;&#x2F;www.freebsd.org&#x2F;cgi&#x2F;man.cgi?query=make&amp;apropos=0&amp;sektion=1&amp;manpath=FreeBSD+11.0-RELEASE+and+Ports&amp;arch=default&amp;format=html#end" rel="nofollow">https:&#x2F;&#x2F;www.freebsd.org&#x2F;cgi&#x2F;man.cgi?query=make&amp;apropos=0&amp;sek...</a><p>[3] <a href="http:&#x2F;&#x2F;pubs.opengroup.org&#x2F;onlinepubs&#x2F;9699919799&#x2F;utilities&#x2F;find.html" rel="nofollow">http:&#x2F;&#x2F;pubs.opengroup.org&#x2F;onlinepubs&#x2F;9699919799&#x2F;utilities&#x2F;fi...</a><p>[4] <a href="https:&#x2F;&#x2F;leanpub.com&#x2F;the-tao-of-tmux&#x2F;read#tips-and-tricks" rel="nofollow">https:&#x2F;&#x2F;leanpub.com&#x2F;the-tao-of-tmux&#x2F;read#tips-and-tricks</a><p>[5] <a href="http:&#x2F;&#x2F;entrproject.org" rel="nofollow">http:&#x2F;&#x2F;entrproject.org</a>