Calling Make Inside of Make

A discussion of how to call make recursively.

Calling Make Inside of Make

Introduction

Make is a wonderful tool for building executables, libraries, and packages from source. If you have worked with open-source projects written in C or C++ for a Unix based platform, you have undoubtedly run the make and sudo make install commands to build and install a package from source. Problems can arise when you try to call make within another parent Makefile.

The Problem

The issue I ran into recently was using Make to automate the patching of a Linux kernel package. Specifically, I created a Makefile which would call the Arch Linux command makepkg to build a custom version of the official Raspberry PI Arch Linux kernel package. The problem I ran into was that the parent Makefile I created would implicitly set environment variables that the makepkg command would inherit. This is a known and correct method of passing arguments and configuration of the parent make call to child make calls.

The problem I found with this inheritance was that my parent build would export the environment variable MAKELEVEL which makepkg would inherit. This is normally fine but in the linux-raspberrypi PKGBUILD, which I was patching, a kernel version string is retrieved by executing make kernelrelease. Let us look at how the output of the command changes as we set the MAKELEVEL environment variable manually:

$ make kernelrelease                                                            
4.4.19-1-ARCH

With MAKELEVEL set to 1:

$ MAKELEVEL=1 make kernelrelease
 make[1]: Entering directory '/home/patrick/work/PKGBUILDs/core/linux-raspberrypi/src/linux-5ba1281cbd7f1d8db419f41919a51dedc4d5afa3'
 4.4.19-1-ARCH
 make[1]: Leaving directory '/home/patrick/work/PKGBUILDs/core/linux-raspberrypi/src/linux-5ba1281cbd7f1d8db419f41919a51dedc4d5afa3'

As you can see, the output is changed when manually setting MAKELEVEL to 1 since GNU Make is printing additional information. The problem is that the _kernver variable in the linux-raspberrypi PKGBUILD is expected to be in the first format and having MAKELEVEL set to 1 would mangle the call to sed later in the build process. This will cause the build to fail.

The Solution

The solution for me was to simply set MAKELEVEL=0 when calling makepkg in my parent Makefile (for example: MAKELEVEL=0 makepkg). But who is at fault here?

  • makepkg internally squashes the MAKEFLAGS environment variable which can be set by parent Make builds. It may not be apparent to PKGBUILD maintainers that makepkg does not handle other inherited variables, such as MAKELEVEL.
  • If a PKGBUILD relies on a command to output in a certain way, it may be necessary to be as explicit as possible to make sure that the command outputs the way you expect it.
  • It may be necessary to unexport the environment variables set in a parent Makefile to appease child Make builds.

It was easy enough to fix this issue in my build process but the issue was cryptic and hard to diagnosis. Also, I did not find any information about this issue. Personally, I would like to see additional safety upstream to make sure the build will handle all cases correctly.