Let us start from the root CMakeLists.txt. This file puts together the whole superbuild process:
- We declare a C99 project:
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(recipe-03 LANGUAGES C)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_EXTENSIONS OFF)
set(CMAKE_C_STANDARD_REQUIRED ON)
- As in the previous recipe, we set the EP_BASE directory property and the staging installation prefix:
set_property(DIRECTORY PROPERTY EP_BASE ${CMAKE_BINARY_DIR}/subprojects)
set(STAGED_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/stage)
message(STATUS "${PROJECT_NAME} staged install: ${STAGED_INSTALL_PREFIX}")
- The dependency on FFTW is checked in the external/upstream subdirectory and we proceed to add this subdirectory to the build system:
add_subdirectory(external/upstream)
- We include the ExternalProject.cmake module:
include(ExternalProject)
- We declare the recipe-03_core external project. The sources for this project are in the ${CMAKE_CURRENT_LIST_DIR}/src folder. The project is set up to pick the correct FFTW library using the FFTW3_DIR option:
ExternalProject_Add(${PROJECT_NAME}_core
DEPENDS
fftw3_external
SOURCE_DIR
${CMAKE_CURRENT_LIST_DIR}/src
CMAKE_ARGS
-DFFTW3_DIR=${FFTW3_DIR}
-DCMAKE_C_STANDARD=${CMAKE_C_STANDARD}
-DCMAKE_C_EXTENSIONS=${CMAKE_C_EXTENSIONS}
-DCMAKE_C_STANDARD_REQUIRED=${CMAKE_C_STANDARD_REQUIRED}
CMAKE_CACHE_ARGS
-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS}
-DCMAKE_PREFIX_PATH:PATH=${CMAKE_PREFIX_PATH}
BUILD_ALWAYS
1
INSTALL_COMMAND
""
)
The external/upstream subdirectory also contains a CMakeLists.txt:
- In this file, we add the fftw3 folder as another subdirectory in the build system:
add_subdirectory(fftw3)
The CMakeLists.txt in external/upstream/fftw3 takes care of our dependencies:
- First, we attempt to find the FFTW3 library on the system. Note that we used the CONFIG argument to find_package:
find_package(FFTW3 CONFIG QUIET)
- If the library was found we can use the imported target, FFTW3::fftw3, to link against it. We print a message to our users showing where the library is located. We add a dummy INTERFACE library, fftw3_external. This is needed to properly fix dependency trees between subprojects in the superbuild:
find_package(FFTW3 CONFIG QUIET)
if(FFTW3_FOUND)
get_property(_loc TARGET FFTW3::fftw3 PROPERTY LOCATION)
message(STATUS "Found FFTW3: ${_loc} (found version ${FFTW3_VERSION})")
add_library(fftw3_external INTERFACE) # dummy
else()
# this branch will be discussed below
endif()
- If CMake was unable to locate a pre-installed version of FFTW, we enter the else-branch of the conditional, in which we download, build, and install it using ExternalProject_Add. The name of the external project is fftw3_external. The fftw3_external project will be downloaded from the official online archive. The integrity of the download will be checked using the MD5 checksum:
message(STATUS "Suitable FFTW3 could not be located. Downloading and building!")
include(ExternalProject)
ExternalProject_Add(fftw3_external
URL
http://www.fftw.org/fftw-3.3.8.tar.gz
URL_HASH
MD5=8aac833c943d8e90d51b697b27d4384d
- We disable progress printing for the download and define the update command to be empty:
DOWNLOAD_NO_PROGRESS
1
UPDATE_COMMAND
""
- Configuration, building, and installation output will be logged to a file:
LOG_CONFIGURE
1
LOG_BUILD
1
LOG_INSTALL
1
- We set the installation prefix for the fftw3_external project to the STAGED_INSTALL_PREFIX directory previously defined and turn off building the test suite for FFTW3:
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX=${STAGED_INSTALL_PREFIX}
-DBUILD_TESTS=OFF
- If we are building on Windows, we set the WITH_OUR_MALLOC preprocessor option by means of a generator expression and close the ExternalProject_Add command:
CMAKE_CACHE_ARGS
-DCMAKE_C_FLAGS:STRING=$<$<BOOL:WIN32>:-DWITH_OUR_MALLOC>
)
- Finally, we define the FFTW3_DIR variable and cache it. This variable will be used by CMake as a search directory for the exported FFTW3::fftw3 target:
include(GNUInstallDirs)
set(
FFTW3_DIR ${STAGED_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/cmake/fftw3
CACHE PATH "Path to internally built FFTW3Config.cmake"
FORCE
)
The CMakeLists.txt in the src folder is fairly compact:
- Also in this file, we declare a C project:
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(recipe-03_core LANGUAGES C)
- We call find_package to detect the FFTW library. Once again, we are using the CONFIG detection mode:
find_package(FFTW3 CONFIG REQUIRED)
get_property(_loc TARGET FFTW3::fftw3 PROPERTY LOCATION)
message(STATUS "Found FFTW3: ${_loc} (found version ${FFTW3_VERSION})")
- We add the fftw_example.c source file to the executable target fftw_example:
add_executable(fftw_example fftw_example.c)
- We set link libraries for our executable target:
target_link_libraries(fftw_example
PRIVATE
FFTW3::fftw3
)