CMAKE: generalize the 64-bit suffixed-source generator

SUFFIX is now a required argument and an optional SYMBOL_ALLOWLIST
restricts the renaming to the listed symbols (needed by the upcoming
LAPACKE test suite). All 3523 generated _64 sources stay byte-identical.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Simon Maertens
2026-08-05 16:19:11 +01:00
co-authored by Claude Fable 5
parent f0f3e5f9a8
commit 3705542eac
2 changed files with 86 additions and 18 deletions
+54 -15
View File
@@ -1,22 +1,34 @@
include_guard(GLOBAL)
set(EXTENDED_API_GENERATOR
"${CMAKE_CURRENT_LIST_DIR}/Generate64BitSuffixedSource.cmake" CACHE INTERNAL
"Script that generates 64-bit suffixed sources for the extended API")
"${CMAKE_CURRENT_LIST_DIR}/GenerateSuffixedSource.cmake" CACHE INTERNAL
"Script that generates suffixed sources for extended APIs")
if(BUILD_INDEX64_EXT_API)
add_custom_target(64bit_codegen ALL
COMMENT "Generating 64-bit suffixed sources for extended API")
endif()
# Generate 64-bit suffixed sources for the extended API. The generation happens
# at build time in the Generate64BitSuffixedSource.cmake script.
function(generate_64bit_suffixed_sources target source_list generated_sources)
# Generate suffixed sources for an extended API. The generation happens at
# build time in the GenerateSuffixedSource.cmake script. Arguments:
# SUFFIX <suffix> -- suffix appended to symbols and file names
# (required)
# SYMBOL_ALLOWLIST <sym>... -- only rename the listed symbols
# (case-insensitive); by default every symbol
# defined in the sources is renamed
# NO_STRING_REPLACEMENTS -- do not rename symbols inside string literals
function(generate_suffixed_sources target source_list generated_sources)
set(options NO_STRING_REPLACEMENTS)
cmake_parse_arguments(PARSE_ARGV 3 extended_api "${options}" "" "")
set(oneValueArgs SUFFIX)
set(multiValueArgs SYMBOL_ALLOWLIST)
cmake_parse_arguments(PARSE_ARGV 3 extended_api "${options}" "${oneValueArgs}" "${multiValueArgs}")
get_filename_component(destination "${target}_64_sources" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
get_property(_generated_64bit_source_files GLOBAL PROPERTY EXTENDED_API_GENERATED_SOURCE_FILES)
if(NOT DEFINED extended_api_SUFFIX)
message(FATAL_ERROR "generate_suffixed_sources: SUFFIX is required")
endif()
get_filename_component(destination "${target}${extended_api_SUFFIX}_sources" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
get_property(_generated_suffixed_source_files GLOBAL PROPERTY EXTENDED_API_GENERATED_SOURCE_FILES)
set(new_generated_source_files)
set(generated_source_files)
@@ -24,7 +36,7 @@ function(generate_64bit_suffixed_sources target source_list generated_sources)
get_filename_component(source_abs "${_source}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
get_filename_component(source_name "${_source}" NAME_WLE)
get_filename_component(source_ext "${_source}" EXT)
set(output_file "${destination}/${source_name}_64${source_ext}")
set(output_file "${destination}/${source_name}${extended_api_SUFFIX}${source_ext}")
set(_fortran_extensions ".f" ".F" ".f90" ".F90")
if(NOT source_ext IN_LIST _fortran_extensions)
@@ -33,13 +45,21 @@ function(generate_64bit_suffixed_sources target source_list generated_sources)
endif()
# Make sure we only have one custom command generating a given output file
if(NOT "${output_file}" IN_LIST _generated_64bit_source_files)
if(NOT "${output_file}" IN_LIST _generated_suffixed_source_files)
set(generator_args
"-DINPUT_FILE=${source_abs}"
"-DOUTPUT_FILE=${output_file}")
"-DOUTPUT_FILE=${output_file}"
"-DSUFFIX=${extended_api_SUFFIX}")
if(extended_api_NO_STRING_REPLACEMENTS)
list(APPEND generator_args "-DREPLACE_IN_STRINGS=OFF")
endif()
if(DEFINED extended_api_SYMBOL_ALLOWLIST)
# Join with $<SEMICOLON> so that the allowlist stays one -D argument
# on the command line but still reaches the script as a CMake list.
# An allowlist change re-runs the generation (the command changes).
list(JOIN extended_api_SYMBOL_ALLOWLIST "$<SEMICOLON>" _symbol_allowlist)
list(APPEND generator_args "-DSYMBOL_ALLOWLIST=${_symbol_allowlist}")
endif()
add_custom_command(
OUTPUT "${output_file}"
@@ -50,7 +70,7 @@ function(generate_64bit_suffixed_sources target source_list generated_sources)
DEPENDS
"${source_abs}"
"${EXTENDED_API_GENERATOR}"
COMMENT "Generating 64-bit extended API source for ${_source}"
COMMENT "Generating ${extended_api_SUFFIX} extended API source for ${_source}"
VERBATIM)
list(APPEND new_generated_source_files "${output_file}")
@@ -62,13 +82,32 @@ function(generate_64bit_suffixed_sources target source_list generated_sources)
# Make sure each generated source file is only part of one target to
# avoid multiple targets trying to generate the same file
if(new_generated_source_files)
add_custom_target("${target}_64bit_codegen" ALL
add_custom_target("${target}${extended_api_SUFFIX}_codegen" ALL
DEPENDS ${new_generated_source_files}
COMMENT "Generating 64-bit suffixed sources for target ${target}")
add_dependencies(64bit_codegen "${target}_64bit_codegen")
COMMENT "Generating ${extended_api_SUFFIX} suffixed sources for target ${target}")
if(extended_api_SUFFIX STREQUAL "_64" AND TARGET 64bit_codegen)
add_dependencies(64bit_codegen "${target}${extended_api_SUFFIX}_codegen")
endif()
set_property(GLOBAL APPEND PROPERTY EXTENDED_API_GENERATED_SOURCE_FILES ${new_generated_source_files})
endif()
set(${generated_sources} ${generated_source_files} PARENT_SCOPE)
endfunction()
# Generate 64-bit suffixed sources for the extended API. Kept as a thin
# wrapper around generate_suffixed_sources for the Index-64 extended API.
function(generate_64bit_suffixed_sources target source_list generated_sources)
set(options NO_STRING_REPLACEMENTS)
cmake_parse_arguments(PARSE_ARGV 3 extended_api "${options}" "" "")
set(_forwarded_options)
if(extended_api_NO_STRING_REPLACEMENTS)
list(APPEND _forwarded_options NO_STRING_REPLACEMENTS)
endif()
generate_suffixed_sources("${target}" "${source_list}" _generated_source_files
SUFFIX "_64" ${_forwarded_options})
set(${generated_sources} ${_generated_source_files} PARENT_SCOPE)
endfunction()
@@ -10,6 +10,22 @@ if(NOT DEFINED REPLACE_IN_STRINGS)
set(REPLACE_IN_STRINGS ON)
endif()
if(NOT DEFINED SUFFIX)
message(FATAL_ERROR "SUFFIX must be set")
endif()
# Optional allowlist: if given, only the listed symbols (case-insensitive)
# are suffixed. Used to route a subset of the routines to alternative
# implementations (e.g. LAPACKE test wrappers) while all other references
# keep resolving to their default implementation.
if(DEFINED SYMBOL_ALLOWLIST)
set(_symbol_allowlist)
foreach(_allowlist_entry IN LISTS SYMBOL_ALLOWLIST)
string(TOLOWER "${_allowlist_entry}" _allowlist_entry)
list(APPEND _symbol_allowlist "${_allowlist_entry}")
endforeach()
endif()
# Check whether the input file is fixed or free form based on its extension.
get_filename_component(input_extension "${INPUT_FILE}" LAST_EXT)
string(TOLOWER "${input_extension}" input_extension_lower)
@@ -279,7 +295,7 @@ function(_protect_fortran_string_literals input_text result count_result)
string(REGEX MATCHALL "${string_literal_regex}" string_literals
"${current_line}")
foreach(string_literal IN LISTS string_literals)
set(placeholder "@@LAPACK_64_STRING_LITERAL_${literal_count}@@")
set(placeholder "@@LAPACK_SUFFIX_STRING_LITERAL_${literal_count}@@")
string(REPLACE "${string_literal}" "${placeholder}" current_line
"${current_line}")
set(protected_string_literal_${literal_count} "${string_literal}"
@@ -304,7 +320,7 @@ function(_restore_fortran_string_literals input_text literal_count result)
if(literal_count GREATER 0)
math(EXPR last_literal_index "${literal_count} - 1")
foreach(index RANGE 0 ${last_literal_index})
set(placeholder "@@LAPACK_64_STRING_LITERAL_${index}@@")
set(placeholder "@@LAPACK_SUFFIX_STRING_LITERAL_${index}@@")
string(REPLACE "${placeholder}" "${protected_string_literal_${index}}"
output_text "${output_text}")
endforeach()
@@ -382,6 +398,19 @@ endwhile()
list(REMOVE_DUPLICATES symbol_names)
list(REMOVE_ITEM symbol_names ETIME etime ETIME_ etime_)
# Restrict the renaming to allowlisted symbols if an allowlist was given
if(DEFINED SYMBOL_ALLOWLIST)
set(_filtered_symbol_names)
foreach(symbol_name IN LISTS symbol_names)
string(TOLOWER "${symbol_name}" _symbol_name_lower)
list(FIND _symbol_allowlist "${_symbol_name_lower}" _symbol_allowlist_index)
if(NOT _symbol_allowlist_index EQUAL -1)
list(APPEND _filtered_symbol_names "${symbol_name}")
endif()
endforeach()
set(symbol_names ${_filtered_symbol_names})
endif()
# If string literals should not be modified, protect them before performing replacements
if(NOT REPLACE_IN_STRINGS)
_protect_fortran_string_literals(
@@ -394,7 +423,7 @@ foreach(symbol_name IN LISTS symbol_names)
string(TOUPPER "${symbol_name}" symbol_upper)
foreach(symbol_variant "${symbol_name}" "${symbol_lower}" "${symbol_upper}")
set(match_regex "(^|[^A-Za-z0-9_])${symbol_variant}([^A-Za-z0-9_]|$)")
set(replacement "\\1${symbol_variant}_64\\2")
set(replacement "\\1${symbol_variant}${SUFFIX}\\2")
string(REGEX REPLACE
"${match_regex}" "${replacement}"
rewritten_content "${rewritten_content}")