Makefile Generators

A common and peculiar theme in human nature is the impulse to add something to solve every problem, rather than eliminate the root cause of the problem. Many people apparently find this easier than thinking through the problem to understand what's really going on. The result is increasing and needless complexity. In the software world, this translates to added layers of software that compensate for, rather than fix, the original problems.

There are lots of tools that attempt to automatically generate makefiles specific to the user's environment, or even automate the download and installation of dependent projects (a task that should be left to package managers, which do this much better). It really isn't necessary to add this extra complexity, and is generally not a good idea in the modern world of package managers. The results of trying to be overly clever are usually disastrous. K.I.S.S. ( Keep It Simple, Stupid )

cleverness * wisdom = constant

Most such tools, including the most popular, GNU configure and cmake, attempt to locate libraries and other dependencies installed via completely unknown and often incorrect methods. They may have been installed using multiple different package managers, or willy-nilly via caveman installs performed by unqualified users. Worse yet, there may be multiple installations of the same library waiting to be discovered, and the build system may use the first one it finds, rather than the correct one. Attempts to compensate for the thousands of variables that might be encountered in the chaotic environments created by thousands of different users generally results in an absurdly complex build system that works some of the time and is a nightmare to debug when it doesn't.

In addition to the common problems with build scripts, generator tools such as GNU configure and cmake also have bugs of their own. When you or a user of your software runs into one, it can be a real challenge to solve, and many people will just give up.

Attempts to build and install software this way are partly responsible for the false notion that compiled languages are difficult to use. In fact, the languages are not the problem: the problem is poorly designed and overly complicated build systems that don't work outside the developers' specific environment. When such build systems fail, they are a nightmare to debug.

My advice is to create a simple makefile that looks for dependencies only where the user (or package manager) tells it to look. This is easy to do using standard make variables such as CFLAGS and LDFLAGS, which virtually all package managers already provide via make command-line arguments or environment variables. This way, we can be sure that the build is using only the dependencies that we want it to use, which were hopefully installed by a trusted procedure, such as the same package manager building the package at hand.

Ideally, the makefile should build and install only this project and leave the installation of dependencies to the package manager. If a program and all of its dependencies are installed independently by the same package manager, then all of the individual makefiles they use can be simple and reliable, and very few problems will occur. This means users won't waste their time struggling to haphazardly install your software, and you won't waste your time trying to help them with self-inflicted problems.

Practice

Note

Be sure to thoroughly review the instructions in Section 2, “Practice Problem Instructions” before doing the practice problems below.
  1. What is the intended purpose of makefile generators? Are they necessary? Do they always work? Why or why not? What might be a more reliable approach to building and installing software?

  2. How do overly complicated build systems contribute to the notion that compiled languages are difficult to use?