M4 as a templating language (2020)
chrisman.github.io
chrisman.github.io
(compare HISTORY sections of BSD userland vs GNU coreutils ones as one simple example)
$ man gm4 |sed -ne 119,121p
AUTHOR
Written by Rene' Seindal.Of course, if you operate within a language ecosystem, you can probably find a nice templating system there. Python, for instance, has Jinja2. Or, if your needs are simple, you can use something more basic, like sed(1).
Quotes can be redefined to an arbitrary string
changequote(`[[[', `]]]')
And some editor give you syntax highlighting.That seems like an odd assertion given the existence of other templating systems which have friendlier syntax while being capable of generating arbitrary output. Is there a reason why you think on the M4 approach is valid?
Something like mustache for example, which has a C implementation that includes support for includes/partials: http://mustache.github.io/mustache.5.html
- https://github.com/M3t0r/tpl (mine)
tr translates letters, m4 translates words and simple expressions.I also have massive respect for those people. I only understood the point of autoconf when I ended up reimplementing a fraction of it in GNU Make macros.
[1]: https://github.com/TeddyDD/pp.awk [2]: https://www.mkws.sh/pp.html
I wrote something similar in my static collection of sysadmin tools - https://github.com/skx/sysbox - In my simple pre-processor I only allow two special things:
#include "file/goes/here" #execute ls -l | wc -l
Though there is a more complex version included, which supports all the syntax of the golang text/template library which is more powerful.
EOF
A Generation Lost in the Bazaar https://queue.acm.org/detail.cfm?id=2349257
(It's mostly a criticism of building tools, and MR is mentioned because of autoconf)
#!/usr/bin/env bash
declare SOMETHING="$(yq eval ".yaml.query" whatever.yml)"
cat <<EOF
Here is my template. It says ${SOMETHING}.
EOF
It's not pretty, but it works! You can obviously shell out to anything in the heredoc, so it's quite flexible. Imports that respect the variables might be a bit tricky; maybe just have them as separate scripts like the above and use environment variables to to pass information around would be easiest.So you get a giant c/c++ file with a parser implementation made of M4 definitions, C preprocessor definitions, includes of generated (lookup tables) or user-written (custom parsing actions) files, and it's absolute hell to debug :D
Weird comparison.
Of course what the author wrote, and what I understood needn't align, we're different, with different cultural references, but this stood out to me enough that I stopped reading to revisit HN to find out if anyone else observed the same casual use of what seems like inappropriately dismissive language.
https://web.archive.org/web/20070209223522/http://users.foot...
Then I discovered Lisp so I probably lost interest in MPP because of that.
One distguishing feature of MPP is that it preserves indentation when generating code. If you have a macro which generates multiple lines of code, and that macro call is indented, then its output gets indented. So in theory you can use this for Python and Yaml and their ilk.
Interestingly, without any prior Lisp knowledge, I based this project on nested list processing. It has programmable read-tables, like Common Lisp, and also lexically scoped local macros, like macrolet. Lisp showed me a vastly better designed architecture of all the infrastructure that I greenspunned inside MPP, which made it seem pointless to continue that project, and pour more effort into ramping up on Lisp.
Probably for the same reason, I never migrated that mpp.html page and its sub-content to my newer home page locations. I have all the code in version control and all. I'm always having to refer to it via archive.org.
I posted about MPP in the comp.lang.c newsgroup in 2008, when John Thingstad started a thread with my name in the subject line, asking:
I have noticed you have become dramatically better in Lisp in a relative short period of time. What is you "secret"?
https://groups.google.com/g/comp.lang.lisp/c/xvuivrEnQ9s/m/z...
There is a deleted article, which I think is my first response to the question, which I replaced using the Usenet supersede feature.
We used a bunch of shellscripts and m4 to manage a lot of linux servers and config-files in a similiar fashion to what ansible does (which was not really a thing at the time).
It worked ok, but I hate the m4 syntax to this day.
Then I read their makefile on github and they're still using pandoc...
https://github.com/chrisman/chrisman.github.io/blob/a2a949f3...
Actually, m4 is specified as part of the Single Unix Specification (IEEE Std 1003.1), GNU m4 being "only" one implementation of it, the original one supposedly being part of System V and published as part of OpenSolaris a couple years back (sadly, can't verify nor link to it as those resources seem to have vanished or placed behind paywalls/registrations).
m4 was heavily used (and I guess still is) for sendmail and DNS (BIND) configs. Don't know if it is actually usable as a grand unified mail config system over sendmail, postfix, and other SMTP servers, but in principal it could be.
For markup templating and static or dynamic site building, including HTML email templating, there are of course any number of much more specific tools as HNers will know. One that should appeal to m4 fans in that it's based on standards, and kindof is the least surprising giving HTML's history, is mighty SGML itself with full HTML-aware, injection-free templating.
Edit: and m4 is prominently used by autotools of course
If you have to rely on the downstream user installing additional dependencies, that substantially changes the equation. You can either have them install a better tool, or remove the external dependency altogether. I personally think m4 is elegant, but most programmers seem to struggle with recursive string interpolation, at least on a practical level if not a conceptual level. And complex m4 programming quickly devolves to dynamic code generation, which is even more hostile. So I've learned to avoid it.
Autotools was prescient in this regard (or perhaps usefully conformant m4 implementations were spotty) as ./configure scripts rely on sed instead of m4 for templating, including for Makefile generation. While heavily used by autotools, m4 is used to generate ./configure, Makefile.in, and similar inputs that are statically included in the release rather than generated downstream.
fib(X,Y+Z) :- fib(X-1,Y),fib(X-2,Z)If the unix CLI isn't going to slowly rot away, it needs to pick up improved versions of tools like this and start getting them into wide distribution.
IOW, m4 is really only suited for fairly straight-forward static input-output transformations, such as common templating tasks. These transformations can themselves become quite complex and even convenient to implement (put your functional programming hat on), but once you stray from recursive string interpolation on lists of simple tokens sourced from statically defined input the ergonomics break down immediately.
[0] http://www.ml1.org.uk/index.html
[1] http://www.ml1.org.uk/implementation.html
[2] https://github.com/crandylb/stage2-1
edit: It was quite impressive just how amazingly inefficient (in time and space) this approach can be (the combinator part, not the m4 part which worked pretty well).
With things like go get and nix you can be more or less independent of package managers or even OS to some extent.
> m4 is great for macros and includes. Not super fun for general programming. But, like immigrants, it gets the job done.
Only painful memories.
It's cool that you are comfortable with it (or at least for 90% of what you want it to do) but it is such a unwieldy tool that it gets painful very quickly.
As a curiosity for small projects it's okay. Seeing what's out there and extending one's view of the programming landscape is great.
But if you use it in a professional environment for heaven's sake please think of the maintainers that come after you and just don't use it.
M4 is similar. It's just a macro processor. If you try to make it work on a problem that requires more, it will backfire in uncomfortable ways.
Yes, M4 is a macro processor. A pretty decent one that is well-known and will not surprise you with incompatible changes or newly introduced bugs. Nobody suggested using it for more.
Hire twenty developers and ask how many know some M4 vs some Python.
So, I'd say the analogy still holds up pretty well.
I don't think it's proven if most of the people that had to work with it complain about the complexity of doing a simple loop. I also don't think it's built for reuse, considering so few people actually use it. If anything, hard to use software like m4 is exactly what pushes everyone to think "I can do better!".
https://chrome.google.com/webstore/detail/whatfont/jabopobgc...
https://addons.mozilla.org/en-CA/firefox/addon/zjm-whatfont/
Rather like this writer, I felt the need to make my blog entries markdown with minimum header and footer surrounding them. So I found a one-liner script that renders markdown in the browser. (Anyone using lynx gets the raw markdown instead, but that's probably no less friendly than what lynx could come up with, and also means that you can read it just as well with telnet (or I guess openssl s_client these days) if you don't have a browser around.
Care to share the one-liner?
Not exactly a one liner, but it looks simple to use.
m4 predates sendmail by 6 years (1977, 1983).
1. e.g. https://wolfram.schneider.org/bsd/7thEdManVol2/m4/m4.pdf
In 2021, I wouldn't bother.
I was new enough at the time that I guess those could have just been a front end to the actual config files without understanding that.
I just remember spending a lot of time fiddling with m4 files to get my fvwm and fvwm95 desktop just the way I wanted it.
It's nothing I chose, it's just the way it was already in the distribution.
edit... out of curiosity I've now googled "fvwm m4" and confirmed my memory. I was sort of mostly or half right. m4 is not strictly "the" config format, but it is a compile-time built-in feature that is generally always used, and old redhat in particular had a confusing setup.
However, in fvwm3, I've removed both those modules.
I didn't say "window manager", I named a specific piece of software by name, in a particular context.
It's a reasonable assumption that there is a significant connection of some sort between m4 and this window manager, or at least that my intention was to declare as much.
And what more should I have to say in this context than "fvwm uses it too"? Do you actually care about the details of exactly how fvwm uses m4? If you did, then googling "fvwm m4" gives you all that.
> But, like immigrants, it gets the job done.
What the hell?
Strongly disagree. Pandoc is the only solution I could find that outputs static HTML and supports maths. It's a really great solution. And it's pretty fast. I don't know in what way it could be overkill.
Using a hacky M4 script instead of Pandoc is completely insane. Find if you want to do insane things I guess but it's still insane.
> This arm64 system not only didn’t have pandoc installed, but pandoc wasn’t even in the software repository. I considered compiling it myself, but the language it is written in, Haskel, doesn’t even compile on arm64.
Then they justified it by explaining that their usecase didn't really need pandoc anyway.
And GHC support for ARM in general has been spotty. I know pandoc wouldn't build on Apple Silicon last time I tried to install it, but that was a few months ago.
That's a nice thing about C. It'll compile and run on basically anything.
https://github.com/jgm/pandoc/releases
But it looks like this was before that (didn't have the 2020 when I read it).