From 1a868f66412a54839546d518450c08b4a4fef67b Mon Sep 17 00:00:00 2001 From: Matthew Cross Date: Sat, 5 Feb 2022 16:18:14 -0500 Subject: [PATCH 1/4] Add logic to generate node size header file directly in CMake by scraping C++ compiler error messages. --- CMakeLists.txt | 1 + cmake/container_node_sizes_impl.hpp.in | 4 + cmake/get_align_of.cpp | 12 ++ cmake/get_container_node_sizes.cmake | 194 +++++++++++++++++++++++ cmake/get_node_size.cpp | 211 +++++++++++++++++++++++++ 5 files changed, 422 insertions(+) create mode 100644 cmake/container_node_sizes_impl.hpp.in create mode 100644 cmake/get_align_of.cpp create mode 100644 cmake/get_container_node_sizes.cmake create mode 100644 cmake/get_node_size.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 73de5ae..ed6d029 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,7 @@ endif() include(cmake/configuration.cmake) include(cmake/atomic.cmake) +include(cmake/get_container_node_sizes.cmake) # subdirectories add_subdirectory(src) diff --git a/cmake/container_node_sizes_impl.hpp.in b/cmake/container_node_sizes_impl.hpp.in new file mode 100644 index 0000000..8853ac6 --- /dev/null +++ b/cmake/container_node_sizes_impl.hpp.in @@ -0,0 +1,4 @@ +// The following section was autogenerated by get_container_node_sizes.cmake +//=== BEGIN AUTOGENERATED SECTION ===// +@NODE_SIZE_CONTENTS@ +//=== END AUTOGENERATED SECTION ===// diff --git a/cmake/get_align_of.cpp b/cmake/get_align_of.cpp new file mode 100644 index 0000000..236faac --- /dev/null +++ b/cmake/get_align_of.cpp @@ -0,0 +1,12 @@ +#include + +template +struct align_of +{ + static_assert(alignment == 0, "this should fail, the purpose of this is to generate a compile error on this type that contains the alignment value on this target"); +}; + +template +using get_align_of = align_of; + +get_align_of dummy; diff --git a/cmake/get_container_node_sizes.cmake b/cmake/get_container_node_sizes.cmake new file mode 100644 index 0000000..ee600fe --- /dev/null +++ b/cmake/get_container_node_sizes.cmake @@ -0,0 +1,194 @@ +# We need to capture this outside of a function as +# CMAKE_CURRENT_LIST_DIR reflects the current CMakeLists.txt file when +# a function is executed, but reflects this directory while this file +# is being processed. +set(_THIS_MODULE_DIR ${CMAKE_CURRENT_LIST_DIR}) + +# This function will return the alignment of the C++ type specified in +# 'type', the result will be in 'result_var'. +function(get_alignof_type type result_var) + # We expect this compilation to fail - the purpose of this is to + # generate a compile error on a generated tyoe + # "align_of" that is the alignment of the specified + # type. + # + # See the contents of get_align_of.cpp for more details. + execute_process( + COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} -c ${_THIS_MODULE_DIR}/get_align_of.cpp -o /dev/null "-DTEST_TYPE=${type}" + RESULT_VARIABLE align_result + OUTPUT_VARIABLE align_output + ERROR_VARIABLE align_output + ) + + # Look for the align_of<..., ##> in the compiler error output + string(REGEX MATCH "align_of<.*,[ ]*([0-9]+)>" align_of_matched ${align_output}) + + if(align_of_matched) + set(${result_var} ${CMAKE_MATCH_1} PARENT_SCOPE) + else() + message(FATAL_ERROR "Unable to determine alignment of C++ type ${type} - no error text matching align_of<..., ##> in compiler output |${align_output}|") + endif() +endfunction() + +# This function will return a list of C++ types with unique alignment +# values, covering all possible alignments supported by the currently +# configured C++ compiler. +# +# The variable named in 'result_types' will contain a list of types, +# and 'result_alignments' will contain a parallel list of the same +# size that is the aligment of each of the matching types. +function(unique_aligned_types result_types result_alignments) + # These two lists will contain a set of types with unique alignments. + set(alignments ) + set(types ) + + set(all_types char bool short int long "long long" float double "long double") + foreach(type IN LISTS all_types ) + get_alignof_type("${type}" alignment) + message("Alignment of '${type}' is '${alignment}'") + + if(NOT ${alignment} IN_LIST alignments) + list(APPEND alignments ${alignment}) + list(APPEND types ${type}) + endif() + endforeach() + + set(${result_types} ${types} PARENT_SCOPE) + set(${result_alignments} ${alignments} PARENT_SCOPE) +endfunction() + +# This function will return node sizes for the requested container +# when created with the specified set of types. +# +# 'container' must be one of the container types supported by +# get_node_size.cpp (see that file for details) +# +# 'types' is a list of C++ types to hold in the container to measure +# the node size +# +# 'align_result_var' will contain the list of alignments of contained +# types used. +# +# 'nodesize_result_var' will contain the list of node sizes, one entry +# for each alignment/type +function(get_node_sizes_of container types align_result_var nodesize_result_var) + # The argument 'types' is a CMake list, which is semicolon separated. Convert it to a comma separated list. + set(comma_types ) + foreach(type IN LISTS types) + if(comma_types) + string(APPEND comma_types ",${type}") + else() + set(comma_types "${type}") + endif() + endforeach() + + # We expect this to fail - the purpose of this is to generate a + # compile error on a generated type "node_size_of" that is + # the alignment of the specified type. + execute_process( + COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} -c ${_THIS_MODULE_DIR}/get_node_size.cpp -o /dev/null + "-D${container}=1" + "-DTEST_TYPES=${comma_types}" + RESULT_VARIABLE nodesize_result + OUTPUT_VARIABLE nodesize_output + ERROR_VARIABLE nodesize_output + ) + + if(NOT nodesize_output) + message(FATAL_ERROR "nodesize_output is empty") + endif() + + # Gather all node_size_of<..., ##> in the compiler error output + string(REGEX MATCHALL "node_size_of<[ ]*[0-9]+[ ]*,[ ]*[0-9]+[ ]*,[ ]*true[ ]*>" node_size_of_matches ${nodesize_output}) + + if(node_size_of_matches) + set(alignments ) + set(node_sizes ) + + foreach(node_size IN LISTS node_size_of_matches) + # Extract the alignment and node size + string(REGEX MATCH "([0-9]+)[ ]*,[ ]*([0-9]+)" match_result ${node_size}) + if(match_result AND NOT ${CMAKE_MATCH_1} IN_LIST alignments) + list(APPEND alignments ${CMAKE_MATCH_1}) + list(APPEND node_sizes ${CMAKE_MATCH_2}) + endif() + endforeach() + + set(${align_result_var} ${alignments} PARENT_SCOPE) + set(${nodesize_result_var} ${node_sizes} PARENT_SCOPE) + else() + message(FATAL_ERROR "Unable to determine node size of C++ container ${container} holding types ${types} - no error text matching node_size_of<##, ##, true> in compiler output |${nodesize_output}|") + endif() +endfunction() + +# This will write the container node sizes to an output header file +# that can be used to calculate the node size of a container holding +# the specified type. +function(get_container_node_sizes outfile) + + # Build up the file contents in the variable NODE_SIZE_CONTENTS, + # as requested in container_node_sizes_impl.hpp.in + set(NODE_SIZE_CONTENTS "") + + # Get the set of uniquely aligned types to work with + unique_aligned_types(types alignments) + message("=> alignments |${alignments}| types |${types}|") + + set(container_types + forward_list list + set multiset unordered_set unordered_multiset + map multimap unordered_map unordered_multimap + shared_ptr_stateless shared_ptr_stateful + ) + + foreach(container IN LISTS container_types) + string(TOUPPER "${container}_container" container_macro_name) + get_node_sizes_of("${container_macro_name}" "${types}" alignments node_sizes) + message("node size of |${container_macro_name}| holding types |${types}| : alignments |${alignments}| node sizes |${node_sizes}|") + + # Generate the contents for this container type + string(APPEND NODE_SIZE_CONTENTS "\ + +namespace detail +{ + template + struct ${container}_node_size; +") + + list(LENGTH alignments n_alignments) + math(EXPR last_alignment "${n_alignments}-1") + foreach(index RANGE ${last_alignment}) + list(GET alignments ${index} alignment) + list(GET node_sizes ${index} node_size) + + # Generate content for this alignment/node size in this container + string(APPEND NODE_SIZE_CONTENTS "\ + + template <> + struct ${container}_node_size<${alignment}> + : std::integral_constant + {}; +") + endforeach() + + # End contents for this container type + string(APPEND NODE_SIZE_CONTENTS "\ +} // namespace detail + +template +struct ${container}_node_size +: std::integral_constant::value + sizeof(T)> +{}; +") + endforeach() + + # Finally, write the file. As a reminder, configure_file() will + # substitute in any CMake variables wrapped in @VAR@ in the inpout + # file and write them to the output file; and will only rewrite + # the file and update its timestamp if the contents have changed. + # The only variable that will be substituted is NODE_SIZE_CONTENTS + configure_file("${_THIS_MODULE_DIR}/container_node_sizes_impl.hpp.in" ${outfile}) +endfunction() + +get_container_node_sizes("${CMAKE_CURRENT_BINARY_DIR}/cmake_container_node_sizes_impl.hpp") diff --git a/cmake/get_node_size.cpp b/cmake/get_node_size.cpp new file mode 100644 index 0000000..5de2c20 --- /dev/null +++ b/cmake/get_node_size.cpp @@ -0,0 +1,211 @@ +#include +#include + +#if FORWARD_LIST_CONTAINER +#include +#endif +#if LIST_CONTAINER +#include +#endif +#if MAP_CONTAINER || MULTIMAP_CONTAINER +#include +#endif +#if SHARED_PTR_STATELESS_CONTAINER || SHARED_PTR_STATEFUL_CONTAINER +#include +#endif +#if SET_CONTAINER || MULTISET_CONTAINER +#include +#endif +#if UNORDERED_MAP_CONTAINER || UNORDERED_MULTIMAP_CONTAINER +#include +#endif +#if UNORDERED_SET_CONTAINER || UNORDERED_MULTISET_CONTAINER +#include +#endif + +// This will fail to compile when is_node_size is true, which will +// cause the compiler to print this type with the calculated numbers +// in corresponding parameters. +template +struct node_size_of +{ + static_assert(!is_node_size, "Expected to fail"); +}; + +struct empty_state {}; + +template +struct is_same +{ + static constexpr bool value = false; +}; + +template +struct is_same +{ + static constexpr bool value = true; +}; + +// This is a partially implemented allocator type, whose whole purpose +// is to be derived from node_size_of to cause a compiler error when +// this allocator is rebound to the node type. +template +struct debug_allocator : + public node_size_of::value>, + private State +{ + template + struct rebind + { + using other = debug_allocator; + }; + + using value_type = T; + + T* allocate(size_t); + void deallocate(T*, size_t); +}; + +// Dummy hash implementation for containers that need it +struct dummy_hash +{ + // note: not noexcept! this leads to a cached hash value + template + std::size_t operator()(const T&) const + { + // quality doesn't matter + return 0; + } +}; + +// Functions to use the debug_allocator for the specified container +// and containee type. We use the preprocessor to select which one to +// compile to reduce the time this takes. + +#if FORWARD_LIST_CONTAINER +template +int test_container() +{ + std::forward_list> list = {T()}; + return 0; +} +#endif // FORWARD_LIST_CONTAINER + +#if LIST_CONTAINER +template +int test_container() +{ + std::list> list = {T()}; + return 0; +} +#endif // LIST_CONTAINER + +#if SET_CONTAINER +template +int test_container() +{ + std::set, debug_allocator> set = {T()}; + return 0; +} +#endif // SET_CONTAINER + +#if MULTISET_CONTAINER +template +int test_container() +{ + std::multiset, debug_allocator> set = {T()}; + return 0; +} +#endif // MULTISET_CONTAINER + +#if UNORDERED_SET_CONTAINER +template +int test_container() +{ + std::unordered_set, debug_allocator> set = {T()}; + return 0; +} +#endif // UNORDERED_SET_CONTAINER + +#if UNORDERED_MULTISET_CONTAINER +template +int test_container() +{ + std::unordered_multiset, debug_allocator> set = {T()}; + return 0; +} +#endif // UNORDERED_MULTISET_CONTAINER + +#if MAP_CONTAINER +template +int test_container() +{ + using type = std::pair; + std::map, debug_allocator> map = {{T(),T()}}; + return 0; +} +#endif // MAP_CONTAINER + +#if MULTIMAP_CONTAINER +template +int test_container() +{ + using type = std::pair; + std::multimap, debug_allocator> map = {{T(),T()}}; + return 0; +} +#endif // MULTIMAP_CONTAINER + +#if UNORDERED_MAP_CONTAINER +template +int test_container() +{ + using type = std::pair; + std::unordered_map, debug_allocator> map = {{T(),T()}}; + return 0; +} +#endif // UNORDERED_MAP_CONTAINER + +#if UNORDERED_MULTIMAP_CONTAINER +template +int test_container() +{ + using type = std::pair; + std::unordered_multimap, debug_allocator> map = {{T(),T()}}; + return 0; +} +#endif // UNORDERED_MULTIMAP_CONTAINER + +#if SHARED_PTR_STATELESS_CONTAINER +template +int test_container() +{ + auto ptr = std::allocate_shared(debug_allocator()); + return 0; +} +#endif // SHARED_PTR_STATELESS_CONTAINER + +#if SHARED_PTR_STATEFUL_CONTAINER +template +int test_container() +{ + struct allocator_reference_payload + { + void* ptr; + }; + + auto ptr = std::allocate_shared(debug_allocator()); + return 0; +} +#endif // SHARED_PTR_STATEFUL_CONTAINER + +template +int test_all(std::tuple) +{ + int dummy[] = {(test_container())...}; + return 0; +} + +int foo = test_all(std::tuple()); From 69002775d70876ff8791a12b72d867fc31b497d8 Mon Sep 17 00:00:00 2001 From: Matt Cross Date: Sat, 5 Feb 2022 21:14:36 +0000 Subject: [PATCH 2/4] Integrate cmake-based container node size detection logic. --- cmake/get_container_node_sizes.cmake | 17 ++++++++---- src/CMakeLists.txt | 39 +--------------------------- 2 files changed, 13 insertions(+), 43 deletions(-) diff --git a/cmake/get_container_node_sizes.cmake b/cmake/get_container_node_sizes.cmake index ee600fe..53bf44d 100644 --- a/cmake/get_container_node_sizes.cmake +++ b/cmake/get_container_node_sizes.cmake @@ -4,6 +4,14 @@ # is being processed. set(_THIS_MODULE_DIR ${CMAKE_CURRENT_LIST_DIR}) +set(_DEBUG_GET_CONTAINER_NODE_SIZES OFF) + +function(_gcns_debug_message) + if(_DEBUG_GET_CONTAINER_NODE_SIZES) + message(${ARGV}) + endif() +endfunction() + # This function will return the alignment of the C++ type specified in # 'type', the result will be in 'result_var'. function(get_alignof_type type result_var) @@ -45,7 +53,7 @@ function(unique_aligned_types result_types result_alignments) set(all_types char bool short int long "long long" float double "long double") foreach(type IN LISTS all_types ) get_alignof_type("${type}" alignment) - message("Alignment of '${type}' is '${alignment}'") + _gcns_debug_message("Alignment of '${type}' is '${alignment}'") if(NOT ${alignment} IN_LIST alignments) list(APPEND alignments ${alignment}) @@ -125,6 +133,7 @@ endfunction() # that can be used to calculate the node size of a container holding # the specified type. function(get_container_node_sizes outfile) + message(STATUS "Getting container node sizes") # Build up the file contents in the variable NODE_SIZE_CONTENTS, # as requested in container_node_sizes_impl.hpp.in @@ -132,7 +141,7 @@ function(get_container_node_sizes outfile) # Get the set of uniquely aligned types to work with unique_aligned_types(types alignments) - message("=> alignments |${alignments}| types |${types}|") + _gcns_debug_message("=> alignments |${alignments}| types |${types}|") set(container_types forward_list list @@ -144,7 +153,7 @@ function(get_container_node_sizes outfile) foreach(container IN LISTS container_types) string(TOUPPER "${container}_container" container_macro_name) get_node_sizes_of("${container_macro_name}" "${types}" alignments node_sizes) - message("node size of |${container_macro_name}| holding types |${types}| : alignments |${alignments}| node sizes |${node_sizes}|") + _gcns_debug_message("node size of |${container_macro_name}| holding types |${types}| : alignments |${alignments}| node sizes |${node_sizes}|") # Generate the contents for this container type string(APPEND NODE_SIZE_CONTENTS "\ @@ -190,5 +199,3 @@ struct ${container}_node_size # The only variable that will be substituted is NODE_SIZE_CONTENTS configure_file("${_THIS_MODULE_DIR}/container_node_sizes_impl.hpp.in" ${outfile}) endfunction() - -get_container_node_sizes("${CMAKE_CURRENT_BINARY_DIR}/cmake_container_node_sizes_impl.hpp") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5a512c9..2735c1e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -77,44 +77,7 @@ set(src configure_file("config.hpp.in" "${CMAKE_CURRENT_BINARY_DIR}/config_impl.hpp") # generate container_node_sizes.hpp -# don't run it while cross-compiling and CMAKE_CROSSCOMPILING_EMULATOR is not defined -if(FOONATHAN_MEMORY_BUILD_TOOLS) - if(NOT CMAKE_CROSSCOMPILING) - add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/container_node_sizes_impl.hpp - COMMAND $ --code ${CMAKE_CURRENT_BINARY_DIR}/container_node_sizes_impl.hpp - DEPENDS foonathan_memory_node_size_debugger - VERBATIM) - elseif(DEFINED CMAKE_CROSSCOMPILING_EMULATOR) - add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/container_node_sizes_impl.hpp - COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $ --code ${CMAKE_CURRENT_BINARY_DIR}/container_node_sizes_impl.hpp - DEPENDS foonathan_memory_node_size_debugger - VERBATIM) - elseif(QNX OR QNXNTO) - if(EXISTS "${FOONATHAN_MEMORY_CONTAINER_NODE_SIZES_IMPL}") - message("-- Using the pre-generated file: ${FOONATHAN_MEMORY_CONTAINER_NODE_SIZES_IMPL}") - add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/container_node_sizes_impl.hpp - COMMAND cp ${FOONATHAN_MEMORY_CONTAINER_NODE_SIZES_IMPL} ${CMAKE_CURRENT_BINARY_DIR}/container_node_sizes_impl.hpp ) - else() - message(FATAL_ERROR "\nError: Cannot find pre-generated file container_node_sizes_impl.hpp\n" - "Please pre-generate the header file container_node_sizes_impl.hpp by following the steps below:\n" - "- Build nodesize_dbg from source:\n" - " ${PROJECT_SOURCE_DIR}/tool/node_size_debugger.cpp \n" - "- Transfer nodesize_dbg to QNX target and execute:\n" - " nodesize_dbg --code container_node_sizes_impl.hpp \n" - "- Transfer generated header file back to your development system \n" - "- Set FOONATHAN_MEMORY_CONTAINER_NODE_SIZES_IMPL to the path of the pre-generated file and pass it to cmake as an argument\n") - endif() - else() - message(WARNING "cross-compiling, but emulator is not defined, " - "cannot generate container_node_sizes_impl.hpp, node size information will be unavailable") - file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/container_node_sizes_impl.hpp "#define FOONATHAN_MEMORY_NO_NODE_SIZE") - set(FOONATHAN_MEMORY_NO_NODE_SIZE 1 PARENT_SCOPE) - endif() -else() - message(WARNING "cannot generate container_node_sizes_impl.hpp, node size information will be unavailable") - file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/container_node_sizes_impl.hpp "#define FOONATHAN_MEMORY_NO_NODE_SIZE") - set(FOONATHAN_MEMORY_NO_NODE_SIZE 1 PARENT_SCOPE) -endif() +get_container_node_sizes(${CMAKE_CURRENT_BINARY_DIR}/container_node_sizes_impl.hpp) add_library(foonathan_memory ${detail_header} ${header} ${src}) target_include_directories(foonathan_memory PUBLIC $ # for client in subdirectory From cbcc25ef09979cc6ea57e603c004ef861da32e1d Mon Sep 17 00:00:00 2001 From: Matthew Cross Date: Tue, 8 Feb 2022 21:23:01 -0500 Subject: [PATCH 3/4] Modify get_node_sizes_of() CMake function to invoke compiler once per type, as some compilers (notably Microsoft) will not report multiple errors in this code. --- cmake/get_container_node_sizes.cmake | 72 +++++++++++++--------------- cmake/get_node_size.cpp | 6 +++ 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/cmake/get_container_node_sizes.cmake b/cmake/get_container_node_sizes.cmake index 53bf44d..1b55592 100644 --- a/cmake/get_container_node_sizes.cmake +++ b/cmake/get_container_node_sizes.cmake @@ -8,7 +8,7 @@ set(_DEBUG_GET_CONTAINER_NODE_SIZES OFF) function(_gcns_debug_message) if(_DEBUG_GET_CONTAINER_NODE_SIZES) - message(${ARGV}) + message("${ARGV}") endif() endfunction() @@ -80,53 +80,47 @@ endfunction() # 'nodesize_result_var' will contain the list of node sizes, one entry # for each alignment/type function(get_node_sizes_of container types align_result_var nodesize_result_var) - # The argument 'types' is a CMake list, which is semicolon separated. Convert it to a comma separated list. - set(comma_types ) - foreach(type IN LISTS types) - if(comma_types) - string(APPEND comma_types ",${type}") - else() - set(comma_types "${type}") - endif() - endforeach() - - # We expect this to fail - the purpose of this is to generate a - # compile error on a generated type "node_size_of" that is - # the alignment of the specified type. - execute_process( - COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} -c ${_THIS_MODULE_DIR}/get_node_size.cpp -o /dev/null - "-D${container}=1" - "-DTEST_TYPES=${comma_types}" - RESULT_VARIABLE nodesize_result - OUTPUT_VARIABLE nodesize_output - ERROR_VARIABLE nodesize_output - ) + set(alignments ) + set(node_sizes ) - if(NOT nodesize_output) - message(FATAL_ERROR "nodesize_output is empty") - endif() + foreach(type IN LISTS types) - # Gather all node_size_of<..., ##> in the compiler error output - string(REGEX MATCHALL "node_size_of<[ ]*[0-9]+[ ]*,[ ]*[0-9]+[ ]*,[ ]*true[ ]*>" node_size_of_matches ${nodesize_output}) + # We expect this to fail - the purpose of this is to generate + # a compile error on a generated type + # "node_size_of" that is the + # alignment of the specified type. + execute_process( + COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} -c ${_THIS_MODULE_DIR}/get_node_size.cpp -o /dev/null + "-D${container}=1" + "-DTEST_TYPE=${type}" + RESULT_VARIABLE nodesize_result + OUTPUT_VARIABLE nodesize_output + ERROR_VARIABLE nodesize_output + ) + + if(NOT nodesize_output) + message(FATAL_ERROR "Unable to determine node size of C++ container ${container} holding type ${type} - no error text matching node_size_of<##, ##, true> in compiler output |${nodesize_output}|") + endif() - if(node_size_of_matches) - set(alignments ) - set(node_sizes ) + # Find the instance of node_size_of<##, ##, true> in the + # compiler error output - the first number is the alignment, + # and the second is the node size. + string(REGEX MATCH "node_size_of<[ ]*([0-9]+)[ ]*,[ ]*([0-9]+)[ ]*,[ ]*true[ ]*>" node_size_of_match ${nodesize_output}) - foreach(node_size IN LISTS node_size_of_matches) + if(node_size_of_match) # Extract the alignment and node size - string(REGEX MATCH "([0-9]+)[ ]*,[ ]*([0-9]+)" match_result ${node_size}) - if(match_result AND NOT ${CMAKE_MATCH_1} IN_LIST alignments) + if(NOT ${CMAKE_MATCH_1} IN_LIST alignments) list(APPEND alignments ${CMAKE_MATCH_1}) list(APPEND node_sizes ${CMAKE_MATCH_2}) endif() - endforeach() + else() + message(FATAL_ERROR "Unable to determine node size of C++ container ${container} holding type ${type} - no error text matching node_size_of<##, ##, true> in compiler output |${nodesize_output}|") + endif() + endforeach() - set(${align_result_var} ${alignments} PARENT_SCOPE) - set(${nodesize_result_var} ${node_sizes} PARENT_SCOPE) - else() - message(FATAL_ERROR "Unable to determine node size of C++ container ${container} holding types ${types} - no error text matching node_size_of<##, ##, true> in compiler output |${nodesize_output}|") - endif() + # Return output to caller + set(${align_result_var} ${alignments} PARENT_SCOPE) + set(${nodesize_result_var} ${node_sizes} PARENT_SCOPE) endfunction() # This will write the container node sizes to an output header file diff --git a/cmake/get_node_size.cpp b/cmake/get_node_size.cpp index 5de2c20..dc6475c 100644 --- a/cmake/get_node_size.cpp +++ b/cmake/get_node_size.cpp @@ -201,6 +201,7 @@ int test_container() } #endif // SHARED_PTR_STATEFUL_CONTAINER +#ifdef TEST_TYPES template int test_all(std::tuple) { @@ -209,3 +210,8 @@ int test_all(std::tuple) } int foo = test_all(std::tuple()); +#endif + +#ifdef TEST_TYPE +int foo = test_container(); +#endif From 2c8f03e670668674988b45e72d2df8725b6748cd Mon Sep 17 00:00:00 2001 From: Matthew Cross Date: Wed, 9 Feb 2022 21:46:16 -0500 Subject: [PATCH 4/4] Switch node size checks to use more general "try_compile()" command, and update regex to handle "ul" suffixes on numbers. --- cmake/get_container_node_sizes.cmake | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/cmake/get_container_node_sizes.cmake b/cmake/get_container_node_sizes.cmake index 1b55592..772ca12 100644 --- a/cmake/get_container_node_sizes.cmake +++ b/cmake/get_container_node_sizes.cmake @@ -21,15 +21,15 @@ function(get_alignof_type type result_var) # type. # # See the contents of get_align_of.cpp for more details. - execute_process( - COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} -c ${_THIS_MODULE_DIR}/get_align_of.cpp -o /dev/null "-DTEST_TYPE=${type}" - RESULT_VARIABLE align_result + try_compile(align_result ${CMAKE_CURRENT_BINARY_DIR} ${_THIS_MODULE_DIR}/get_align_of.cpp + COMPILE_DEFINITIONS "-DTEST_TYPE=${type}" OUTPUT_VARIABLE align_output - ERROR_VARIABLE align_output + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED TRUE ) # Look for the align_of<..., ##> in the compiler error output - string(REGEX MATCH "align_of<.*,[ ]*([0-9]+)>" align_of_matched ${align_output}) + string(REGEX MATCH "align_of<.*,[ ]*([0-9]+)[ul ]*>" align_of_matched ${align_output}) if(align_of_matched) set(${result_var} ${CMAKE_MATCH_1} PARENT_SCOPE) @@ -89,13 +89,11 @@ function(get_node_sizes_of container types align_result_var nodesize_result_var) # a compile error on a generated type # "node_size_of" that is the # alignment of the specified type. - execute_process( - COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} -c ${_THIS_MODULE_DIR}/get_node_size.cpp -o /dev/null - "-D${container}=1" - "-DTEST_TYPE=${type}" - RESULT_VARIABLE nodesize_result + try_compile(nodesize_result ${CMAKE_CURRENT_BINARY_DIR} ${_THIS_MODULE_DIR}/get_node_size.cpp + COMPILE_DEFINITIONS "-D${container}=1" "-DTEST_TYPE=${type}" OUTPUT_VARIABLE nodesize_output - ERROR_VARIABLE nodesize_output + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED TRUE ) if(NOT nodesize_output) @@ -105,7 +103,7 @@ function(get_node_sizes_of container types align_result_var nodesize_result_var) # Find the instance of node_size_of<##, ##, true> in the # compiler error output - the first number is the alignment, # and the second is the node size. - string(REGEX MATCH "node_size_of<[ ]*([0-9]+)[ ]*,[ ]*([0-9]+)[ ]*,[ ]*true[ ]*>" node_size_of_match ${nodesize_output}) + string(REGEX MATCH "node_size_of<[ ]*([0-9]+)[ul ]*,[ ]*([0-9]+)[ul ]*,[ ]*true[ ]*>" node_size_of_match ${nodesize_output}) if(node_size_of_match) # Extract the alignment and node size