Build Make external projects from CMake
CMake ExternalProject allows building a wide variety of subprojects isolated from the main CMake project.
For GNU Make Makefile projects, it is necessary to invoke the make
command.
However, there are several programs named “make” across operating systems.
To help ensure the correct GNU Make is selected, we do:
find_program(MAKE_EXECUTABLE
NAMES gmake mingw32-make make
NAMES_PER_DIR
DOC "GNU Make")
A real-life example of CMake with Makefile ExternalProject has multiple Make invocations to build separate Make target groups, where later Make targets depend on the other Make targets being built first. We just show a snippet here for clarity, omitting definition of some of the obvious variables used.
CONFIGURE_COMMAND ""
- since Make doesn’t have a configure step, so we must define this blank, as otherwise CMake will try to find a CMakeLists.txt in the external project code.
BUILD_COMMAND
- builds the first target(s) that are required by targets in subsequent steps. If there’s no subsequent targets, this is the only build step.
INSTALL_COMMAND
- Note that “-j” option is NOT used to avoid race conditions in install scripts that might intermittently fail.
BUILD_BYPRODUCTS
- In general we point this at the “installed” files, as otherwise “ninja: error: “lib” needed by “target”, missing and no known rule to make it”. Ninja is stricter than Make about the target to source graph.
include(GNUInstallDirs)
set_property(DIRECTORY PROPERTY EP_UPDATE_DISCONNECTED true)
# don't recheck for updates to the Git repo at subsequent CMake reconfigure
find_program(MAKE_EXECUTABLE NAMES gmake make mingw32-make REQUIRED)
set(my_LIBRARY ${CMAKE_INSTALL_FULL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}my${CMAKE_STATIC_LIBRARY_SUFFIX})
ExternalProject_Add(my
URL https://github.invalid/username/archive.tar.bz2
CONFIGURE_COMMAND ""
BUILD_COMMAND ${MAKE_EXECUTABLE} -j -C <SOURCE_DIR>
INSTALL_COMMAND ${MAKE_EXECUTABLE} -C <SOURCE_DIR> install prefix=${CMAKE_INSTALL_PREFIX}
BUILD_BYPRODUCTS ${my_LIBRARY}
)