in check_headers.cmake, we verify the self containness of a header file by replicating it and remove `#pragma once` directive in this header. but this approach failed to compile headers which include a header file with the same name in the root source directory, as we add `-I<directory-of-original-header>` in the cflags when building the generated source file, so that it can include the headers in the same directory. but this confuses the compiler, as, assuming we have "log.hh" in current directory, and under the root source directory, the compiler would always include the "log.hh" in the current directory even it should have included "log.hh" under the root source directory. in this change, instead of adding `-I<directory-of-original-header>` to cflags, we just include the header under test in a new .cc file solely generated for testing. this should address this problem. Signed-off-by: Kefu Chai <kefu.chai@scylladb.com> Closes scylladb/scylladb#21216
107 lines
3.4 KiB
CMake
107 lines
3.4 KiB
CMake
function (check_headers check_headers_target target)
|
|
if(NOT TARGET ${check_headers_target})
|
|
return()
|
|
endif()
|
|
|
|
# "target" is required, so we can get the compiling options for compiling
|
|
# the headers.
|
|
cmake_parse_arguments (
|
|
parsed_args
|
|
""
|
|
"GLOB;GLOB_RECURSE;EXCLUDE;INCLUDE"
|
|
""
|
|
${ARGN})
|
|
|
|
set(sources "")
|
|
if(DEFINED parsed_args_GLOB)
|
|
file(GLOB sources
|
|
LIST_DIRECTORIES false
|
|
RELATIVE ${CMAKE_SOURCE_DIR}
|
|
"${parsed_args_GLOB}")
|
|
elseif(DEFINED parsed_args_GLOB_RECURSE)
|
|
file(GLOB_RECURSE sources
|
|
LIST_DIRECTORIES false
|
|
RELATIVE ${CMAKE_SOURCE_DIR}
|
|
"${parsed_args_GLOB_RECURSE}")
|
|
else()
|
|
message(FATAL_ERROR "Please specify GLOB or GLOB_RECURSE.")
|
|
endif()
|
|
if(DEFINED parsed_args_INCLUDE)
|
|
list(FILTER sources INCLUDE REGEX "${parsed_args_INCLUDE}")
|
|
endif()
|
|
if(DEFINED parsed_args_EXCLUDE)
|
|
list(FILTER sources EXCLUDE REGEX "${parsed_args_EXCLUDE}")
|
|
endif()
|
|
|
|
foreach(fn ${sources})
|
|
get_filename_component(file_dir ${fn} DIRECTORY)
|
|
set(src_dir "${CMAKE_BINARY_DIR}/check-headers/${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 ${CMAKE_SOURCE_DIR}/${fn}
|
|
COMMAND ${CMAKE_COMMAND} -E echo "#include \"${fn}\"" > "${src}"
|
|
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
|
VERBATIM)
|
|
list(APPEND srcs "${src}")
|
|
endforeach()
|
|
|
|
if(NOT srcs)
|
|
# not headers to checks
|
|
return()
|
|
endif()
|
|
|
|
set(check_lib "${check_headers_target}-${target}")
|
|
add_library(${check_lib} EXCLUDE_FROM_ALL)
|
|
target_sources(${check_lib}
|
|
PRIVATE ${srcs})
|
|
# use ${target} as an interface library by consuming all of its
|
|
# compile time options
|
|
get_target_property(libraries ${target} LINK_LIBRARIES)
|
|
if (libraries)
|
|
# as a side effect, the libraries linked by the ${target} are also built as
|
|
# the dependencies of ${check_lib}. some of the libraries are scylla
|
|
# libraries. we could tell them from the 3rd party libraries, but we would
|
|
# have to recursively pull in their compiling options. so, since that
|
|
# we always build "check-headers" target along with "scylla", this does
|
|
# not incur overhead.
|
|
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 ${target} INCLUDE_DIRECTORIES)
|
|
if(includes)
|
|
target_include_directories(${check_lib}
|
|
PRIVATE ${includes})
|
|
endif()
|
|
|
|
get_target_property(compile_options ${target} 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 ${target} COMPILE_DEFINITIONS)
|
|
if(compile_definitions)
|
|
target_compile_definitions(${check_lib}
|
|
PRIVATE ${compile_definitions})
|
|
endif()
|
|
|
|
add_dependencies(${check_headers_target} ${check_lib})
|
|
endfunction ()
|