Strengths, weaknesses, opportunities, and threats facing the GNU Autotools
owlfolio.org
owlfolio.org
1. autoconf is awful to learn.
2. autoconf can be useful in determining the platform, dealing with a few quirks, and ensuring that system dependencies/libraries are satisfied.
3. autoconf's usefulness here is completely undermined by automake, as changing Makefile.am requires rerunning autoreconf, which then requires rerunning configure. So, developers must constantly rerun the configure script, even though nothing about their system environment has materially changed. For example, this happens when a new source file is created and added to Makefile.am.
4. Perhaps the most egregious missing weakness from TFA is acknowledgement that configure scripts are horrifically slow. It's 2022 and developers have their time wasted by configure checking whether printf() exists.
5. automake documentation discourages developers from globbing source files in source directories, and insists they list them individually. It's silly and just results in needless running of configure.
6. The complex interdependencies between generated files is nigh-impossible to understand and reason about. It's cruft.
7. libtool is completely braindead, the absolute worst of it all. It serves absolutely no purpose on contemporary systems, but the docs continue to admonish developers that they must use it to stand a chance of creating a shared library (no, just learn to specify -fPIC). Instead of analyzing a project once, as part of autoconf, libtool determines what to do on the fly for every source file--and all in bash. It doubles a project's compilation time.
8. Creating alternatives to libtool with new autoconf macros, deprecating libtool, and cleansing all traces of it from the planet should absolutely be the highest priority of the autotools project.
I'd say on some platforms "horrifically slow" is an understatement. At my day job we were building software in Cygwin on Windows machines infected with Symantec's virus scanner which adds hundreds of milliseconds to every process launch. The configure script for Protocol Buffers took something like half an hour to run.
We eventually switched to CMake but not without a lot of pain first. For what it's worth, CMake fixes the speed issue but not much else. It still has its own totally esoteric custom language, it still discourages globbing source files and requires re-running upon adding any file or changing anything, and it has even more insane default settings than autotools (for example file(DOWNLOAD) from an https:// URL by default ignores certificates!)
There is something wrong with all of these buildsystems. I don't know what the solution is but I feel we are very far from it.
We use cmake, with Windows as our main (but not the only) target platform. We found that not globbing is slow and impractical for us.
1. We generate VS project files, which then guides the build process. When you add source files using the IDE, the generated project(s) will be updated, no regenerate is triggered, the build system will do the correct thing: only the added file, not everything is (re-)built.
2. If we didn't glob, then given the nice local workflow above, people would often forget to update the cmake files and get CI failures.
3. When injecting cmake regeneration into the build process, then for some strange reason we found a bad serialization of build steps, which slows everything down.
4. The slow part on Windows seems to be that cmake has to use some system call to figure out if source file name casing is correct, which is very slow (for us the slowest part of the generation process by far). I don't recall the details here, but I think globbing somewhat reduces this issue.
All in all, I can say: figure out what works best for you and don't trust experts that discourage globbing altogether.
And the solution to all build systems being bad is imho not to use C/C++. It's model for platform independence is fundamentally broken. It's not like snafu doesn't exist elsewhere too (Python), but other systems are clearly less troublesome (Go, NPM, Cargo).
Globbing is discouraged exactly for the reason that then cmake can't discover when files should be added or removed from the build process, or build options have changed. But if globbing isn't used there's no reason why manually re-running cmake would be required (there have been some problems in the past with Visual Studio not automatically reloading a modified project, but I haven't seen those problems in a long time).
No it's not silly, realistically you can't actually do that anywhere without re-running configure. Any build system based on directory trees will have this limitation. See meson's docs for more on this: https://mesonbuild.com/FAQ.html#why-cant-i-specify-target-fi...
I also came here to comment that libtool is totally useless on modern systems and I hope it gets removed or made optional, but you beat me to it :)
Perhaps the error printing during a parallel build could also be improved somehow.
Especially since configure doesn't actually make anything any faster even in most cases where it _does_ detect errors. It aborts at the first error. So when I'm missing packages for example, I will wait half a minute while `./configure` runs, then it errors with a single missing package, then I will install that package and re-run `./configure`, wait another half a minute until it prints another single missing package, etc. Repeat until I have all packages.
I hate autotools so much. Configure scripts should either run in parallel, or cache its results, or both (ideally both), and they should report as many errors as it can before aborting.
I do agree that m4 is rather unpleasant to write, and that the resulting tests are too slow (often because user defined macros do a poor job of cacheing) but I also think that these things could be addressed (newer macro languages, bundled or threaded micro-tests) while still preserving the good bits of autoconf.
These days I use meson mostly, but I would love to see a complete build system really get into parallelizing platform checking and merge it into the normal build process.
I then replaced automake and libtool with tup, and the Tupfile would just source these variables from configure. It worked great! It's a pity that tup hasn't caught on.
And in this space, it's often a lot easier to get something autotools-based to build than something cmake or meson, at least in my experience. With autotools more often than not all I need to do is to specify the right target hosttriple and be done. With cmake and meson, it's often a fight to figure out how to cross-compile something like that.
This approach of cross-compiling for windows with mingw-w64, sometimes on "proper" linux, sometimes on WSL2, sometimes even on cygwin, seems to be still somewhat common in C/C++ land and in open source in particular, especially for projects that pull in a fair amount of dependencies (such as the aforementioned ffmpeg) - you will find a lot of Windows build guides that say only mingw cross-compilation from linux is supported and tested.
There are some projects that try to be partial dependency "package" managers for mingw, but for whatever reason I never really used them, so I cannot comment on how well they work and how up-to-date they are kept.
I guess, I just like fighting with the interwoven mess of build-systems and dependencies sometimes (and really, I don't spend more than maybe 1 or 2 hours a month on that)... a bit like people doing linux-from-scratch, except probably less time consuming than building an entire kernel and userland step-by-step.
They're the most popular targets today. They certainly weren't yesterday, and very probably won't be tomorrow. I've seen a lot of changes over the decades and the attitude that "nobody will ever need more than 640 k" has always been popular. I also say this from the point of view of someone who makes a living with porting software to a reasonably popular platform "today" that is not one of those listed. Also someone who has spent many years doing "maintenance programming" as opposed new development on the leading edge. "Maintenance" accounts for something like 80% of revenue in the software industry, and the old machines in maintenance mode are not always identical to the new sleek affairs on developer's desks.
> 1. autoconf is awful to learn.
Yes. Like vim, it has a learning curve. It's not actually that bad, and the internet is chock full of documentation and examples. It's about on a par with alternatives like CMake and meson in terms of learning difficulty.
> 3. autoconf's usefulness here is completely undermined by automake, as changing Makefile.am requires rerunning autoreconf, which then requires rerunning configure. So, developers must constantly rerun the configure script, even though nothing about their system environment has materially changed. For example, this happens when a new source file is created and added to Makefile.am.
Ah, you got stuck at point 1. You don't have to re-run autoconf after re-running automate (autoreconf knows this), so you don't have to re-run configure. The makefiles generated by automake know this. That's why when you just type "make" after modifying a Makefile.am it will do the right thing automatically, and that is to re-run the config.status script which contains all the autodetected configuration already cached. It's seriously faster than running configure although the printed output is identical (because configure itself generates and runs that script).
> 4. Perhaps the most egregious missing weakness from TFA is acknowledgement that configure scripts are horrifically slow. It's 2022 and developers have their time wasted by configure checking whether printf() exists.
Yes. You pay the price for portability. You have argued "but I don't port my software why should I pay the price? That only helps other people and there's nothing in it for me". OK, fair enough.
> 5. automake documentation discourages developers from globbing source files in source directories, and insists they list them individually.
The documentation also says why. It's a well-reasoned argument. Also, despite it being a pain in the butt it turns out that explicitly showing your work is a benefit in the long run.
> 6. The complex interdependencies between generated files is nigh-impossible to understand and reason about.
They're a DAG; they should be straightforward for someone with a background in programming to grasp. The relationships are there a priori but the autotools document them and make them explicit.
> 7. libtool is completely braindead
OK. Agree with you there. Libtool was a godsend in its time. It's improved massively (yes, I see the complaints about frustrations with it over a decade ago) but it's largely superfluous today.
Portability to what, though?
It's 2022, not 1982. Most of the commercial UNIXes that autotools was written to handle are long dead now. When was the last time anyone saw a (non-embedded) system with CHAR_BITS ≠ 8, for example?
You are not supposed to understand it. Stop wasting your time and blaming autotools instead of your process.
./configure && make && make install
And I like that I can very easily see all the various build options: ./configure --help
I don't like that configure takes a long time and checks things that don't seem like they really need to be checked. Nor do I like how difficult autotools is to use as a developer (I have some, but not much experience working on a project using autotools, over a decade ago).I've yet to see a competing build system that makes the end user usage and option discovery as simple.
Edit: I've not necessarily used and explored all the various build systems, but the few I have used have generally not been as simple, or at least weren't to me obviously as simple.
The end user experience is in every aspect superior to autotools. There is a small downside for cmake compared to autotools: while you have to install the bits for autotools it runs on a shell. There is a bigger downside for meson: you need a minimal python infrastructure up and working. Over time you need that python infrastructure to keep working. Sometimes it doesn't.
I still vastly prefer meson over cmake and much more so autotools. If I have to fix cmake or meson builds, well, really, if you know their languages, it's just no comparison to debugging the 1000s of lines of shell code autotools generates.
Here are a couple issues I have run into (one being fixed, though too late for some key versions of Ubuntu; and the other just languishing, as I guess "working" is asking for too much).
Thanks for the report!
When I care to look how to fix it, it's almost always some error on the autotools configuration and I can edit the Makefile to run things correctly. Also, when it breaks, there are normally more broken things on the project. But autotools are always among the first things to break.
It's usually not broken on my own code because I will write a DAG builder in bare C before I use them personally, so I don't know the breakage timing.
We have a fairly customized integration(https://github.com/buildroot/buildroot/blob/master/package/p...) which we've iterated on for a while that works quite well these days. The cross compilation support with upstream meson has improved a lot over the years and while it's quite mature now IMO it still takes a bit of env setup to work correctly(but once it works it tends to not break much).
I forget what I do in meson. Which means I just read the meson.build and meson_options.txt. They are quite straightforward, and very concise, if you're not Doing It Wrong.
cmake -S source_folder -B build_folder
cmake --build build_folder
cmake --install build_folder
You don't need to run a GUI at all for this, I don't see how you could infer this from the previous messages less CMakeCache.txt
Listing the options cannot be done by just introspecting a CMakeLists: what would it show for: if(FOO)
option(ENABLE_BAMBOOZLE_${FOO} "Enable Bamboozle - ${FOO}-specific version" OFF)
else()
option(ENABLE_BAMBOOZLE "Enable Bamboozle" ON)
endif()
(and if your meta-build system does not allow to do that, I'm sorry but I'll have to build a meta-meta-build-system on top of it which implements it and no one will like it)If you find yourself debugging generated scripts, you have done something wrong.
IMO there needs to be a replacement for Autotools that from a user's perspective behaves exactly like Autotools (following the same GNU standards that specify how the configure script, etc is to be used, what parameters it accepts, etc) but provides a better experience for the developer.
If you're a user, familiar
./configure && make && sudo make install
will do the trick for you.If you're a package maintainer, ./configure supports all the --libdir flags that packaging system sets, (handwritten) Makefile respects CFLAGS, DESTDIR, etc. All of it is extremely hackable since there are no silly layers of preprocessors between you and make.
I guess the secret sauce here is having only OpenSSL as a dependency and the project being a fairly small library.
cmake .. && cmake --build . && cmake --install .
...and discovering/changing the build options can be done interactively:
ccmake .
...not that much different (and it usually works on Windows too). IMHO cmake for 'end users' (who just want to build a project into an executable) is mostly fine, it's just not great for the project maintainers because the cmake scripting language is a PITA.
You just said that half of the procedure is simple enough. And then, I don't get your claim that nothing is comparable. For example, how is `cargo install` more complex than that? Or less discoverable?
(Oh, and notice that there is no distinction between distribution and development packages for any other system, it's autotools only. Also, you may say "cargo is Rust-only", what is true, but autotools are C-only while pretending all over the docs that they are cross language.)
This is not specific to Autotools, but I like learning from well-structured books written by experts in its fields. The book provides a good path on how to handle this rather complex collection of tools without searching and jumping from one obscure internet resource to the other. And after a few hours of reading and experimentation, Autotools are not so unapproachable any more as the common preconception suggests. I agree with others that, once understood and the entry barrier removed, Autotools can be used quite pragmatically and are probably not harder to grasp as competitors in the field.
Unfortunately the defaults are what they are and many people don't care to fine tune their builds.
It took years for the GNU maintainers to publish a libtool that fixed this bug, and then years for libtool users to upgrade to the new version.
I hate GNU so much.
But here's the thing: AFAIK lua builds from just a Makefile. libopencm3 also builds from just a Makefile, and it will build multiple examples for multiple microcontrollers. The BSD guys seem to do just fine with Makefiles.
So, could we not just add a few features to Makefiles so that we can do away with all this other infrastructure?
Personally, I just try to use Makefiles wherever possible. My heart sinks when someone comes out with a new build tool. If you must have a build tool, use either autotools or cmake. Please please please don't introduce some new shiny toy that is "autotools done right" but in practise is at least as much pain. And, for the love of all that is holy, don't write your build tool in Python. There's nothing wrong with Python. It just doesn't belong in build systems. Build systems should be written in C or C++, and nothing else. Not Rust, not Haskell, not anything else.
No-one loves such tools but they are not used without a reason.
As an end user and for writing build stuff it both seems to be more complicated than its competitors.
We switched to waf, which is customarily embedded within the source tree, and that just ends this problem forever.
Later it dawned on me that autotools did actually make sense at one time, when there have been dozens of competing UNIX implementations which hadn't been standardized yet. But that time is long gone, autotools no longer has a purpose, just let it rest.
What we need is a converter from Autotools to cmake, or some other system and then take Autotools to a farm upstate for retirement
- faster builds
- progress indicator
A maintain dozens of mixed autotools, cmake and some header-only/makefile-only projects. The cmake build recipes are constantly behind and fragile. The makefile-only projects are a dirty hack, and very limited. autotools is easily the best, with support for everything. And if it's not in autoconf, then it's in autoconf-archive. meson and ninja are cool, but overkill mostly. We had dozens of such build tools before, and they all died.
I even have to teach GNU maintainers how to use autotools/automake properly, as they cannot deal with recursive subdirs, rather have their own configure.in in each subdir. Of course this doesn't scale well.
No, another hack on top of the auto-* ecosystem won't make things better. CMake's problems are cmakes's problems, but it doesn't make autostuff better in any way
But please tell me again why do I need a buildsystem that needs to check if I have Fortran or if I'm running AIX under MIPS again?
Makefile only is crude but it can work fine if your target is the usual distros and your project is small (read: less trouble than autotools)
If you need Fortran support you need to check for it. Ditto for AIX. Hardcoding assumptions is fragile.