What is the function of add_custom_target in CMake?

From the CMake Cookbook, I see that we can use the command add_custom_command and add_custom_target to run a custom command at build time. There is a toy example that I want to extract compressed files in subdirectory and link it to the final executable files. We have two CMakeLists.txt files and the following one is in the subdirectory.

find_package(BLAS REQUIRED)
find_package(LAPACK REQUIRED)

set(MATH_SRCS
  ${CMAKE_CURRENT_BINARY_DIR}/wrap_BLAS_LAPACK/CxxBLAS.cpp
  ${CMAKE_CURRENT_BINARY_DIR}/wrap_BLAS_LAPACK/CxxLAPACK.cpp
  ${CMAKE_CURRENT_BINARY_DIR}/wrap_BLAS_LAPACK/CxxBLAS.hpp
  ${CMAKE_CURRENT_BINARY_DIR}/wrap_BLAS_LAPACK/CxxLAPACK.hpp
  )

add_custom_target(BLAS_LAPACK_wrappers
  WORKING_DIRECTORY
    ${CMAKE_CURRENT_BINARY_DIR}
  DEPENDS
    ${MATH_SRCS}
  COMMENT
    "Intermediate BLAS_LAPACK_wrappers target"
  VERBATIM
  )

add_custom_command(
  OUTPUT
    ${MATH_SRCS}
  COMMAND
    ${CMAKE_COMMAND} -E tar xzf ${CMAKE_CURRENT_SOURCE_DIR}/wrap_BLAS_LAPACK.tar.gz
  WORKING_DIRECTORY
    ${CMAKE_CURRENT_BINARY_DIR}
  DEPENDS
    ${CMAKE_CURRENT_SOURCE_DIR}/wrap_BLAS_LAPACK.tar.gz
  COMMENT
    "Unpacking C++ wrappers for BLAS/LAPACK"
  )

add_library(math "")

target_sources(math
  PRIVATE
    ${MATH_SRCS}
  )

target_include_directories(math
  INTERFACE
    ${CMAKE_CURRENT_BINARY_DIR}/wrap_BLAS_LAPACK
  )

# BLAS_LIBRARIES are included in LAPACK_LIBRARIES
target_link_libraries(math
  PUBLIC
    ${LAPACK_LIBRARIES}
  )

The following CMakeLists.txt is in the main directory.

cmake_minimum_required(VERSION 3.5 FATAL_ERROR)

# Fortran needed to discover LAPACK with some compilers
project(recipe-04 LANGUAGES CXX Fortran)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_subdirectory(deps)

add_executable(linear-algebra linear-algebra.cpp)

target_link_libraries(linear-algebra
  PRIVATE
    math
  )

I do not know why we need the add_custom_target in this example.

You can see a target as a goal that you want to achieve with your build. As you can see your command does not have any target, therefore any work done on it is meaningless.

You can test this by yourself by removing the target, the command is not executed.

I am still confused about what you say what any work done on it is meaningless. Because according to the CMake documentation, the first signature of add_custom_target is generating files. Please check this link https://cmake.org/cmake/help/latest/command/add_custom_command.html.

What’s more, this code can still extract the compressed file to the specific target even after I remove the command add_custom_target.

That’s because the files generated by the add_custom_command() are also added as sources to the target_sources(math ...) command. The add_custom_target(BLAS_LAPACK_wrappers) call is not necessary in this particular example unless you explicitly wanted to be able to generate the sources as a standalone step at build time (e.g. by doing make BLAS_LAPACK_wrappers).

Thank you so much!