WCDH: Make it possible to generate multiple files.

Extend the write_compiler_detection_header interface to allow
specifying a location for supplementary files, and getting the
list of resulting files as a variable.
This commit is contained in:
Stephen Kelly 2014-10-31 00:41:53 +01:00
parent 2ed0088b2a
commit 4cf5179c77
15 changed files with 212 additions and 27 deletions

View File

@ -11,6 +11,7 @@
# write_compiler_detection_header( # write_compiler_detection_header(
# FILE <file> # FILE <file>
# PREFIX <prefix> # PREFIX <prefix>
# [OUTPUT_FILES_VAR <output_files_var> OUTPUT_DIR <output_dir>]
# COMPILERS <compiler> [...] # COMPILERS <compiler> [...]
# FEATURES <feature> [...] # FEATURES <feature> [...]
# [VERSION <version>] # [VERSION <version>]
@ -21,6 +22,33 @@
# The ``write_compiler_detection_header`` function generates the # The ``write_compiler_detection_header`` function generates the
# file ``<file>`` with macros which all have the prefix ``<prefix>``. # file ``<file>`` with macros which all have the prefix ``<prefix>``.
# #
# By default, all content is written directly to the ``<file>``. The
# ``OUTPUT_FILES_VAR`` may be specified to cause the compiler-specific
# content to be written to separate files. The separate files are then
# available in the ``<output_files_var>`` and may be consumed by the caller
# for installation for example. The ``OUTPUT_DIR`` specifies a relative
# path from the main ``<file>`` to the compiler-specific files. For example:
#
# .. code-block:: cmake
#
# write_compiler_detection_header(
# FILE climbingstats_compiler_detection.h
# PREFIX ClimbingStats
# OUTPUT_FILES_VAR support_files
# OUTPUT_DIR compilers
# COMPILERS GNU Clang
# FEATURES cxx_variadic_templates
# )
# install(FILES
# ${CMAKE_CURRENT_BINARY_DIR}/climbingstats_compiler_detection.h
# DESTINATION include
# )
# install(FILES
# ${support_files}
# DESTINATION include/compilers
# )
#
#
# ``VERSION`` may be used to specify the API version to be generated. # ``VERSION`` may be used to specify the API version to be generated.
# Future versions of CMake may introduce alternative APIs. A given # Future versions of CMake may introduce alternative APIs. A given
# API is selected by any ``<version>`` value greater than or equal # API is selected by any ``<version>`` value greater than or equal
@ -220,7 +248,7 @@ function(write_compiler_detection_header
message(FATAL_ERROR "write_compiler_detection_header: PREFIX parameter missing.") message(FATAL_ERROR "write_compiler_detection_header: PREFIX parameter missing.")
endif() endif()
set(options) set(options)
set(oneValueArgs VERSION EPILOG PROLOG) set(oneValueArgs VERSION EPILOG PROLOG OUTPUT_FILES_VAR OUTPUT_DIR)
set(multiValueArgs COMPILERS FEATURES) set(multiValueArgs COMPILERS FEATURES)
cmake_parse_arguments(_WCD "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) cmake_parse_arguments(_WCD "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
@ -255,6 +283,35 @@ function(write_compiler_detection_header
message(FATAL_ERROR "${err}") message(FATAL_ERROR "${err}")
endif() endif()
if(_WCD_OUTPUT_FILES_VAR)
if(NOT _WCD_OUTPUT_DIR)
message(FATAL_ERROR "If OUTPUT_FILES_VAR is specified, then OUTPUT_DIR must also be specified.")
endif()
endif()
if(_WCD_OUTPUT_DIR)
if(NOT _WCD_OUTPUT_FILES_VAR)
message(FATAL_ERROR "If OUTPUT_DIR is specified, then OUTPUT_FILES_VAR must also be specified.")
endif()
get_filename_component(main_file_dir ${file_arg} DIRECTORY)
if (NOT IS_ABSOLUTE ${main_file_dir})
set(main_file_dir "${CMAKE_CURRENT_BINARY_DIR}/${main_file_dir}")
endif()
if (NOT IS_ABSOLUTE ${_WCD_OUTPUT_DIR})
set(_WCD_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/${_WCD_OUTPUT_DIR}")
endif()
get_filename_component(out_file_dir ${_WCD_OUTPUT_DIR} ABSOLUTE)
string(FIND ${out_file_dir} ${main_file_dir} idx)
if (NOT idx EQUAL 0)
message(FATAL_ERROR "The compiler-specific output directory must be within the same directory as the main file.")
endif()
if (main_file_dir STREQUAL out_file_dir)
unset(_WCD_OUTPUT_DIR)
else()
string(REPLACE "${main_file_dir}/" "" _WCD_OUTPUT_DIR "${out_file_dir}/")
endif()
endif()
set(compilers set(compilers
GNU GNU
Clang Clang
@ -314,6 +371,14 @@ function(write_compiler_detection_header
endforeach() endforeach()
list(REMOVE_DUPLICATES _langs) list(REMOVE_DUPLICATES _langs)
if(_WCD_OUTPUT_FILES_VAR)
get_filename_component(main_file_name ${file_arg} NAME)
set(compiler_file_content_
"#ifndef ${prefix_arg}_COMPILER_DETECTION_H
# error This file may only be included from ${main_file_name}
#endif\n")
endif()
foreach(_lang ${_langs}) foreach(_lang ${_langs})
get_property(known_features GLOBAL PROPERTY CMAKE_${_lang}_KNOWN_FEATURES) get_property(known_features GLOBAL PROPERTY CMAKE_${_lang}_KNOWN_FEATURES)
@ -340,7 +405,19 @@ function(write_compiler_detection_header
foreach(compiler ${_WCD_COMPILERS}) foreach(compiler ${_WCD_COMPILERS})
_load_compiler_variables(${compiler} ${_lang} ${${_lang}_features}) _load_compiler_variables(${compiler} ${_lang} ${${_lang}_features})
set(file_content "${file_content}\n# ${pp_if} ${prefix_arg}_COMPILER_IS_${compiler}\n") set(file_content "${file_content}\n# ${pp_if} ${prefix_arg}_COMPILER_IS_${compiler}\n")
set(file_content "${file_content}
if(_WCD_OUTPUT_FILES_VAR)
set(compile_file_name "${_WCD_OUTPUT_DIR}${prefix_arg}_COMPILER_INFO_${compiler}.h")
set(file_content "${file_content}\n# include \"${compile_file_name}\"\n")
endif()
if(_WCD_OUTPUT_FILES_VAR)
set(compiler_file_content compiler_file_content_${compiler})
else()
set(compiler_file_content file_content)
endif()
set(${compiler_file_content} "${${compiler_file_content}}
# if !(${_cmake_oldestSupported_${compiler}}) # if !(${_cmake_oldestSupported_${compiler}})
# error Unsupported compiler version # error Unsupported compiler version
# endif\n") # endif\n")
@ -354,7 +431,7 @@ function(write_compiler_detection_header
set(MACRO_HEX) set(MACRO_HEX)
endif() endif()
string(CONFIGURE "${_compiler_id_version_compute_${compiler}}" VERSION_BLOCK @ONLY) string(CONFIGURE "${_compiler_id_version_compute_${compiler}}" VERSION_BLOCK @ONLY)
set(file_content "${file_content}${VERSION_BLOCK}\n") set(${compiler_file_content} "${${compiler_file_content}}${VERSION_BLOCK}\n")
set(PREFIX) set(PREFIX)
set(MACRO_DEC) set(MACRO_DEC)
set(MACRO_HEX) set(MACRO_HEX)
@ -370,7 +447,7 @@ function(write_compiler_detection_header
set(_define_item "\n# define ${prefix_arg}_${feature_PP} 0\n") set(_define_item "\n# define ${prefix_arg}_${feature_PP} 0\n")
set(_define_item "\n# if ${_cmake_feature_test_${compiler}_${feature}}\n# define ${prefix_arg}_${feature_PP} 1\n# else${_define_item}# endif\n") set(_define_item "\n# if ${_cmake_feature_test_${compiler}_${feature}}\n# define ${prefix_arg}_${feature_PP} 1\n# else${_define_item}# endif\n")
endif() endif()
set(file_content "${file_content}${_define_item}") set(${compiler_file_content} "${${compiler_file_content}}${_define_item}")
endforeach() endforeach()
endforeach() endforeach()
if(pp_if STREQUAL "elif") if(pp_if STREQUAL "elif")
@ -522,6 +599,22 @@ function(write_compiler_detection_header
endforeach() endforeach()
if(_WCD_OUTPUT_FILES_VAR)
foreach(compiler ${_WCD_COMPILERS})
set(CMAKE_CONFIGURABLE_FILE_CONTENT "${compiler_file_content_}")
set(CMAKE_CONFIGURABLE_FILE_CONTENT "${CMAKE_CONFIGURABLE_FILE_CONTENT}${compiler_file_content_${compiler}}")
set(compile_file_name "${_WCD_OUTPUT_DIR}${prefix_arg}_COMPILER_INFO_${compiler}.h")
set(full_path "${main_file_dir}/${compile_file_name}")
list(APPEND ${_WCD_OUTPUT_FILES_VAR} ${full_path})
configure_file("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
"${full_path}"
@ONLY
)
endforeach()
set(${_WCD_OUTPUT_FILES_VAR} ${${_WCD_OUTPUT_FILES_VAR}} PARENT_SCOPE)
endif()
if (_WCD_EPILOG) if (_WCD_EPILOG)
set(file_content "${file_content}\n${_WCD_EPILOG}\n") set(file_content "${file_content}\n${_WCD_EPILOG}\n")
endif() endif()

View File

@ -67,6 +67,22 @@ add_executable(WriteCompilerDetectionHeader main.cpp)
set_property(TARGET WriteCompilerDetectionHeader PROPERTY CXX_STANDARD 98) set_property(TARGET WriteCompilerDetectionHeader PROPERTY CXX_STANDARD 98)
set_defines(WriteCompilerDetectionHeader "${true_defs}" "${false_defs}") set_defines(WriteCompilerDetectionHeader "${true_defs}" "${false_defs}")
write_compiler_detection_header(
FILE "${CMAKE_CURRENT_BINARY_DIR}/compiler_multi_files/multi_file_compiler_detection.h"
PREFIX MULTI
OUTPUT_FILES_VAR multi_files
OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/compiler_multi_files/compiler_support"
COMPILERS GNU Clang
VERSION 3.1
FEATURES
${cxx_known_features} ${c_known_features}
)
add_executable(multi_files multi_files.cpp)
set_property(TARGET multi_files PROPERTY CXX_STANDARD 98)
target_include_directories(multi_files PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/compiler_multi_files)
set_defines(multi_files "${true_defs}" "${false_defs}")
if(MSVC) if(MSVC)
return() # MSVC has only one mode. return() # MSVC has only one mode.
endif() endif()
@ -86,3 +102,8 @@ endif()
add_executable(WriteCompilerDetectionHeader_11 main.cpp) add_executable(WriteCompilerDetectionHeader_11 main.cpp)
set_property(TARGET WriteCompilerDetectionHeader_11 PROPERTY CXX_STANDARD 11) set_property(TARGET WriteCompilerDetectionHeader_11 PROPERTY CXX_STANDARD 11)
set_defines(WriteCompilerDetectionHeader_11 "${true_defs}" "${false_defs}") set_defines(WriteCompilerDetectionHeader_11 "${true_defs}" "${false_defs}")
add_executable(multi_files_11 multi_files.cpp)
set_property(TARGET multi_files_11 PROPERTY CXX_STANDARD 11)
target_include_directories(multi_files_11 PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/compiler_multi_files)
set_defines(multi_files_11 "${true_defs}" "${false_defs}")

View File

@ -0,0 +1,25 @@
#define JOIN_IMPL(A, B) A ## B
#define JOIN(A, B) JOIN_IMPL(A, B)
#define CHECK(FEATURE) (JOIN(PREFIX, JOIN(_COMPILER_, FEATURE)) == JOIN(EXPECTED_COMPILER_, FEATURE))
#if !CHECK(CXX_DELEGATING_CONSTRUCTORS)
#error cxx_delegating_constructors expected availability did not match.
#endif
#if !CHECK(CXX_VARIADIC_TEMPLATES)
#error cxx_variadic_templates expected availability did not match.
#endif
#if !CHECK(VERSION_MAJOR)
#error Compiler major version did not match.
#endif
#if !CHECK(VERSION_MINOR)
#error Compiler minor version did not match.
#endif
#if !CHECK(VERSION_PATCH)
#error Compiler patch version did not match.
#endif

View File

@ -1,29 +1,8 @@
#include "test_compiler_detection.h" #include "test_compiler_detection.h"
#define JOIN_IMPL(A, B) A ## B #define PREFIX TEST
#define JOIN(A, B) JOIN_IMPL(A, B) #include "compile_tests.h"
#define CHECK(FEATURE) (JOIN(TEST_COMPILER_, FEATURE) == JOIN(EXPECTED_COMPILER_, FEATURE))
#if !CHECK(CXX_DELEGATING_CONSTRUCTORS)
#error cxx_delegating_constructors expected availability did not match.
#endif
#if !CHECK(CXX_VARIADIC_TEMPLATES)
#error cxx_variadic_templates expected availability did not match.
#endif
#if !CHECK(VERSION_MAJOR)
#error Compiler major version did not match.
#endif
#if !CHECK(VERSION_MINOR)
#error Compiler minor version did not match.
#endif
#if !CHECK(VERSION_PATCH)
#error Compiler patch version did not match.
#endif
int main() int main()
{ {

View File

@ -0,0 +1,10 @@
#include "multi_file_compiler_detection.h"
#define PREFIX MULTI
#include "compile_tests.h"
int main()
{
return 0;
}

View File

@ -0,0 +1,6 @@
CMake Error at .*Modules/WriteCompilerDetectionHeader.cmake:[0-9]+ \(message\):
The compiler-specific output directory must be within the same directory as
the main file.
Call Stack \(most recent call first\):
MultiBadOutDir.cmake:4 \(write_compiler_detection_header\)
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,12 @@
include(WriteCompilerDetectionHeader)
write_compiler_detection_header(
FILE "${CMAKE_CURRENT_BINARY_DIR}/dir/somefile"
PREFIX Pref
OUTPUT_FILES_VAR outfiles
OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}"
COMPILERS GNU
VERSION 3.1
FEATURES cxx_auto_type
)

View File

@ -0,0 +1,5 @@
CMake Error at .*Modules/WriteCompilerDetectionHeader.cmake:[0-9]+ \(message\):
If OUTPUT_DIR is specified, then OUTPUT_FILES_VAR must also be specified.
Call Stack \(most recent call first\):
MultiNoOutFileVar.cmake:4 \(write_compiler_detection_header\)
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,11 @@
include(WriteCompilerDetectionHeader)
write_compiler_detection_header(
FILE "${CMAKE_CURRENT_BINARY_DIR}/somefile"
PREFIX Pref
OUTPUT_DIR outfiles
COMPILERS GNU
VERSION 3.1
FEATURES cxx_auto_type
)

View File

@ -0,0 +1,5 @@
CMake Error at .*Modules/WriteCompilerDetectionHeader.cmake:[0-9]+ \(message\):
If OUTPUT_FILES_VAR is specified, then OUTPUT_DIR must also be specified.
Call Stack \(most recent call first\):
MultiNoOutdir.cmake:4 \(write_compiler_detection_header\)
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,11 @@
include(WriteCompilerDetectionHeader)
write_compiler_detection_header(
FILE "${CMAKE_CURRENT_BINARY_DIR}/somefile"
PREFIX Pref
OUTPUT_FILES_VAR outfiles
COMPILERS GNU
VERSION 3.1
FEATURES cxx_auto_type
)

View File

@ -12,3 +12,7 @@ run_cmake(InvalidFeature)
run_cmake(InvalidCXXFeature) run_cmake(InvalidCXXFeature)
run_cmake(EmptyPrefix) run_cmake(EmptyPrefix)
run_cmake(InvalidPrefix) run_cmake(InvalidPrefix)
run_cmake(MultiNoOutdir)
run_cmake(MultiNoOutFileVar)
set(NO_CACHE TRUE)
run_cmake(MultiBadOutDir)