# seastar_check_self_contained() checks if the headers listed as the source of # a target are self-contained. # # Header files should be self-contained. In general, the source files should # not have to adhere to special conditions to include them. For instance, # they don't need to include other header files for using a header file, or # to define certain macro(s) for using it. But the macros are allowed to be # used to its behavior though. # # seastar_check_self_contained() is created to perform a minimal check on the # specified set of header files by compiling each of them. # # Please note, there are chances that a symbol declaration could be included # indirectly by an (indirectly) included header file even if that symbol is not # a part of the public interface of that header file, so this dependency is # a little bit fragile. seastar_check_self_contained()" does not warn at seeing # the indirect dependency, it just check if the preprocessed header file # *contains* the declarations of the symbols so that any source file including # it can be compiled as well. The check performed by the CMake function allows # the indirect inclusion of the used symbols. For instance, if "juno.h" # references a symbol named "Jupiter", which is declared in "jupiter.h". So, # strictly speaking, "juno.h" should include "jupiter.h" for accessing this # symbol. But "juno.h" happens to include "solar.h", which in turn includes # "jupiter.h". So "seastar_check_self_contained()" accepts "juno.h", while a # tool like iwyu would complain at seeing it. # # You can also use CMAKE_CXX_INCLUDE_WHAT_YOU_USE for using an external tool # for performing a similar check. see # https://cmake.org/cmake/help/latest/prop_tgt/LANG_INCLUDE_WHAT_YOU_USE.html function (seastar_check_self_contained target library) cmake_parse_arguments ( parsed_args "" "" "EXCLUDE;INCLUDE" ${ARGN}) get_target_property (sources ${library} SOURCES) list (FILTER sources INCLUDE REGEX "${parsed_args_INCLUDE}") list (FILTER sources EXCLUDE REGEX "${parsed_args_EXCLUDE}") foreach (fn ${sources}) get_filename_component (file_ext ${fn} EXT) if (NOT file_ext STREQUAL ".hh") message (SEND_ERROR "Only headers are checked if they are self-contained, while ${fn} is not a header.") elseif (IS_ABSOLUTE ${fn}) # the header specified with absolute path is likely to be generated, this # is not our focus at this moment. continue () endif () get_filename_component (file_dir ${fn} DIRECTORY) list (APPEND includes "${file_dir}") set (src_dir "${CMAKE_BINARY_DIR}/${target}/${file_dir}") file (MAKE_DIRECTORY "${src_dir}") get_filename_component (file_name ${fn} NAME) set (src "${src_dir}/${file_name}.cc") # CMake refuses to compile .hh files, so we need to rename them first. add_custom_command ( OUTPUT ${src} DEPENDS ${fn} # silence "-Wpragma-once-outside-header" COMMAND sed -e "s/^#pragma once//" "${fn}" > "${src}" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" VERBATIM) list (APPEND srcs "${src}") endforeach () if (NOT srcs) # library's SOURCES does not contain any header return () endif () set (check_lib "${target}-${library}") add_library (${check_lib} EXCLUDE_FROM_ALL) target_sources (${check_lib} PRIVATE ${srcs}) # use ${library} as an interface library by consuming all of its # compile time options get_target_property (libraries ${library} LINK_LIBRARIES) if (libraries) target_link_libraries (${check_lib} PRIVATE ${libraries}) endif () # if header includes other header files with relative path, # we should satisfy it. list (REMOVE_DUPLICATES includes) target_include_directories (${check_lib} PRIVATE ${includes}) get_target_property (includes ${library} INCLUDE_DIRECTORIES) if (includes) target_include_directories (${check_lib} PRIVATE ${includes}) endif () get_target_property (compile_options ${library} COMPILE_OPTIONS) if (compile_options) target_compile_options (${check_lib} PRIVATE ${compile_options}) endif () # symbols in header file should always be referenced, but these # are just pure headers, so unused variables should be tolerated. target_compile_options (${check_lib} PRIVATE -Wno-unused-const-variable -Wno-unused-function -Wno-unused-variable) get_target_property (compile_definitions ${library} COMPILE_DEFINITIONS) if (compile_definitions) target_compile_definitions (${check_lib} PRIVATE ${compile_definitions}) endif () add_dependencies (${target} ${check_lib}) endfunction ()