Build autotools as CMake ExternalProject

Building an autotools project as a CMake ExternalProject saves the time of converting that other project to CMake. This technique makes it easy to automatically build that other project when it’s not easily installable otherwise, or you wish to build it optimized. This technique has project-specific aspects, but here is a high-level overview. One of the key issues this technique overcomes is the ExternalProject rebuilding each time the main CMake project is rebuilt.

When building autotools project via CMake ExternalProject, it is useful to first check that autotools is available to avoid emitting errors at build time. The goal is to emit errors about missing packages during build system configuration instead of during the build. We do this by including the file FindAutotools.cmake

This example is simplified from the p4est-cmake project.

Main CMakeLists.txt

if(NOT p4est_external)
  find_package(p4est)
endif()

if(p4est_external OR NOT p4est_FOUND)
  include(cmake/p4est.cmake)
endif()

cmake/p4est.cmake

set(p4est_external true CACHE BOOL "build p4est library")

include(ExternalProject)

set(_ld ${PROJECT_BINARY_DIR}/lib)

set(p4est_LIBRARY ${_ld}/${CMAKE_STATIC_LIBRARY_PREFIX}p4est${CMAKE_STATIC_LIBRARY_SUFFIX} CACHE FILEPATH "p4est library" FORCE)
set(sc_LIBRARY ${_ld}/${CMAKE_STATIC_LIBRARY_PREFIX}sc${CMAKE_STATIC_LIBRARY_SUFFIX} CACHE FILEPATH "sc library" FORCE)

ExternalProject_Add(p4est
GIT_REPOSITORY https://github.com/cburstedde/p4est.git
GIT_TAG prev3-develop
UPDATE_DISCONNECTED true  # need this to avoid constant rebuild
CONFIGURE_HANDLED_BY_BUILD ON  # avoid constant reconfigure
CONFIGURE_COMMAND ${PROJECT_BINARY_DIR}/p4est-prefix/src/p4est/configure ${p4est_flags} ${p4est_mpi}
BUILD_COMMAND make -j${Ncpu}
INSTALL_COMMAND make -j${Ncpu} install
TEST_COMMAND ""
BUILD_BYPRODUCTS ${p4est_LIBRARY} ${sc_LIBRARY}
)

ExternalProject_Get_Property(p4est SOURCE_DIR)

ExternalProject_Add_Step(p4est
  bootstrap
  COMMAND ./bootstrap
  DEPENDEES download
  DEPENDERS configure
  WORKING_DIRECTORY ${SOURCE_DIR})

set(p4est_LIBRARIES ${p4est_LIBRARY} ${sc_LIBRARY} PARENT_SCOPE)

file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/include)  # avoid race condition

add_library(p4est::p4est INTERFACE IMPORTED GLOBAL)
target_include_directories(p4est::p4est INTERFACE ${PROJECT_BINARY_DIR}/include)
target_link_libraries(p4est::p4est INTERFACE "${p4est_LIBRARIES}")  # need the quotes to expand list
# set_target_properties didn't work, but target_link_libraries did work

add_dependencies(p4est::p4est p4est)