533 lines
21 KiB
CMake
533 lines
21 KiB
CMake
# FileConcatenation.cmake
|
|
# Clean template concatenation with duplicate import elimination
|
|
|
|
# Global variables to track includes and content
|
|
set(GLOBAL_INCLUDES_SET "" CACHE INTERNAL "Set of unique includes")
|
|
set(GLOBAL_INCLUDES_LIST "" CACHE INTERNAL "Ordered list of unique includes")
|
|
|
|
# Function to extract and deduplicate includes from content
|
|
function(extract_and_deduplicate_includes content includes_var content_without_includes_var)
|
|
# Handle empty content
|
|
if(content STREQUAL "")
|
|
set(${includes_var} "" PARENT_SCOPE)
|
|
set(${content_without_includes_var} "" PARENT_SCOPE)
|
|
return()
|
|
endif()
|
|
|
|
# Split content into lines
|
|
string(REPLACE "\n" ";" content_lines "${content}")
|
|
|
|
set(extracted_includes "")
|
|
set(content_without_includes "")
|
|
set(in_multiline_comment FALSE)
|
|
|
|
foreach(line ${content_lines})
|
|
# Handle empty lines
|
|
if(NOT DEFINED line OR line STREQUAL "")
|
|
string(APPEND content_without_includes "\n")
|
|
continue()
|
|
endif()
|
|
|
|
# Handle multi-line comments
|
|
if(line MATCHES "/\\*")
|
|
set(in_multiline_comment TRUE)
|
|
endif()
|
|
if(line MATCHES "\\*/")
|
|
set(in_multiline_comment FALSE)
|
|
string(APPEND content_without_includes "${line}\n")
|
|
continue()
|
|
endif()
|
|
if(in_multiline_comment)
|
|
string(APPEND content_without_includes "${line}\n")
|
|
continue()
|
|
endif()
|
|
|
|
# Skip single-line comments unless they contain includes
|
|
if(line MATCHES "^[ \t]*//.*#include")
|
|
# This is a commented include, treat as regular content
|
|
string(APPEND content_without_includes "${line}\n")
|
|
elseif(line MATCHES "^[ \t]*//")
|
|
# Regular comment, keep as content
|
|
string(APPEND content_without_includes "${line}\n")
|
|
elseif(line MATCHES "^[ \t]*#include")
|
|
# Extract include statement - use STRIP instead of REGEX REPLACE to avoid empty match issues
|
|
string(STRIP "${line}" cleaned_include)
|
|
if(NOT cleaned_include STREQUAL "")
|
|
list(APPEND extracted_includes "${cleaned_include}")
|
|
endif()
|
|
else()
|
|
# Regular content line
|
|
string(APPEND content_without_includes "${line}\n")
|
|
endif()
|
|
endforeach()
|
|
|
|
set(${includes_var} "${extracted_includes}" PARENT_SCOPE)
|
|
set(${content_without_includes_var} "${content_without_includes}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Function to add includes to global set maintaining order
|
|
function(add_includes_to_global_set new_includes)
|
|
foreach(include_stmt ${new_includes})
|
|
# Normalize the include statement
|
|
string(STRIP "${include_stmt}" include_stmt)
|
|
|
|
# Check if this include is already in our global set
|
|
list(FIND GLOBAL_INCLUDES_SET "${include_stmt}" found_index)
|
|
if(found_index EQUAL -1)
|
|
# New include, add to both set and ordered list
|
|
list(APPEND GLOBAL_INCLUDES_SET "${include_stmt}")
|
|
list(APPEND GLOBAL_INCLUDES_LIST "${include_stmt}")
|
|
|
|
# Update cache
|
|
set(GLOBAL_INCLUDES_SET "${GLOBAL_INCLUDES_SET}" CACHE INTERNAL "Set of unique includes")
|
|
set(GLOBAL_INCLUDES_LIST "${GLOBAL_INCLUDES_LIST}" CACHE INTERNAL "Ordered list of unique includes")
|
|
endif()
|
|
endforeach()
|
|
endfunction()
|
|
|
|
# Function to generate the final includes section
|
|
function(generate_includes_section result_var)
|
|
set(includes_section "")
|
|
|
|
if(GLOBAL_INCLUDES_LIST)
|
|
string(APPEND includes_section "/*\n * Consolidated Include Section\n * All unique includes from processed templates\n */\n")
|
|
|
|
# Group includes by type for better organization
|
|
set(system_includes "")
|
|
set(local_includes "")
|
|
set(other_includes "")
|
|
|
|
foreach(include_stmt ${GLOBAL_INCLUDES_LIST})
|
|
if(include_stmt MATCHES "#include[ \t]*<.*>")
|
|
list(APPEND system_includes "${include_stmt}")
|
|
elseif(include_stmt MATCHES "#include[ \t]*\".*\"")
|
|
list(APPEND local_includes "${include_stmt}")
|
|
else()
|
|
list(APPEND other_includes "${include_stmt}")
|
|
endif()
|
|
endforeach()
|
|
|
|
# Output system includes first
|
|
if(system_includes)
|
|
string(APPEND includes_section "\n// System includes\n")
|
|
foreach(include_stmt ${system_includes})
|
|
string(APPEND includes_section "${include_stmt}\n")
|
|
endforeach()
|
|
endif()
|
|
|
|
# Then local includes
|
|
if(local_includes)
|
|
string(APPEND includes_section "\n// Local includes\n")
|
|
foreach(include_stmt ${local_includes})
|
|
string(APPEND includes_section "${include_stmt}\n")
|
|
endforeach()
|
|
endif()
|
|
|
|
# Finally other includes
|
|
if(other_includes)
|
|
string(APPEND includes_section "\n// Other includes\n")
|
|
foreach(include_stmt ${other_includes})
|
|
string(APPEND includes_section "${include_stmt}\n")
|
|
endforeach()
|
|
endif()
|
|
|
|
string(APPEND includes_section "\n")
|
|
endif()
|
|
|
|
set(${result_var} "${includes_section}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Process a single template instance with specific type indices
|
|
function(process_single_template_instance template_file comb1 comb2 comb3 result_var)
|
|
file(READ "${template_file}" original_content)
|
|
|
|
# Set template variables
|
|
set(FL_TYPE_INDEX ${comb1})
|
|
set(TYPE_INDEX_1 ${comb1})
|
|
set(TYPE_INDEX_2 ${comb2})
|
|
set(TYPE_INDEX_3 ${comb3})
|
|
|
|
# Determine what #cmakedefine flags to enable based on template content
|
|
set(SD_COMMON_TYPES_GEN 0)
|
|
set(SD_FLOAT_TYPES_GEN 0)
|
|
set(SD_INTEGER_TYPES_GEN 0)
|
|
set(SD_PAIRWISE_TYPES_GEN 0)
|
|
set(SD_SEMANTIC_TYPES_GEN 0)
|
|
|
|
if(original_content MATCHES "#cmakedefine[ \t]+SD_COMMON_TYPES_GEN")
|
|
set(SD_COMMON_TYPES_GEN 1)
|
|
endif()
|
|
if(original_content MATCHES "#cmakedefine[ \t]+SD_FLOAT_TYPES_GEN")
|
|
set(SD_FLOAT_TYPES_GEN 1)
|
|
endif()
|
|
if(original_content MATCHES "#cmakedefine[ \t]+SD_INTEGER_TYPES_GEN")
|
|
set(SD_INTEGER_TYPES_GEN 1)
|
|
endif()
|
|
if(original_content MATCHES "#cmakedefine[ \t]+SD_PAIRWISE_TYPES_GEN")
|
|
set(SD_PAIRWISE_TYPES_GEN 1)
|
|
endif()
|
|
if(original_content MATCHES "#cmakedefine[ \t]+SD_SEMANTIC_TYPES_GEN")
|
|
set(SD_SEMANTIC_TYPES_GEN 1)
|
|
endif()
|
|
|
|
# Manual string replacement instead of configure_file
|
|
set(processed_content "${original_content}")
|
|
|
|
# Replace @variable@ patterns
|
|
string(REPLACE "@FL_TYPE_INDEX@" "${FL_TYPE_INDEX}" processed_content "${processed_content}")
|
|
string(REPLACE "@TYPE_INDEX_1@" "${TYPE_INDEX_1}" processed_content "${processed_content}")
|
|
string(REPLACE "@TYPE_INDEX_2@" "${TYPE_INDEX_2}" processed_content "${processed_content}")
|
|
string(REPLACE "@TYPE_INDEX_3@" "${TYPE_INDEX_3}" processed_content "${processed_content}")
|
|
|
|
# Process #cmakedefine directives
|
|
if(SD_COMMON_TYPES_GEN)
|
|
string(REPLACE "#cmakedefine SD_COMMON_TYPES_GEN" "#define SD_COMMON_TYPES_GEN" processed_content "${processed_content}")
|
|
else()
|
|
string(REPLACE "#cmakedefine SD_COMMON_TYPES_GEN" "/* #undef SD_COMMON_TYPES_GEN */" processed_content "${processed_content}")
|
|
endif()
|
|
|
|
if(SD_FLOAT_TYPES_GEN)
|
|
string(REPLACE "#cmakedefine SD_FLOAT_TYPES_GEN" "#define SD_FLOAT_TYPES_GEN" processed_content "${processed_content}")
|
|
else()
|
|
string(REPLACE "#cmakedefine SD_FLOAT_TYPES_GEN" "/* #undef SD_FLOAT_TYPES_GEN */" processed_content "${processed_content}")
|
|
endif()
|
|
|
|
if(SD_INTEGER_TYPES_GEN)
|
|
string(REPLACE "#cmakedefine SD_INTEGER_TYPES_GEN" "#define SD_INTEGER_TYPES_GEN" processed_content "${processed_content}")
|
|
else()
|
|
string(REPLACE "#cmakedefine SD_INTEGER_TYPES_GEN" "/* #undef SD_INTEGER_TYPES_GEN */" processed_content "${processed_content}")
|
|
endif()
|
|
|
|
if(SD_PAIRWISE_TYPES_GEN)
|
|
string(REPLACE "#cmakedefine SD_PAIRWISE_TYPES_GEN" "#define SD_PAIRWISE_TYPES_GEN" processed_content "${processed_content}")
|
|
else()
|
|
string(REPLACE "#cmakedefine SD_PAIRWISE_TYPES_GEN" "/* #undef SD_PAIRWISE_TYPES_GEN */" processed_content "${processed_content}")
|
|
endif()
|
|
|
|
if(SD_SEMANTIC_TYPES_GEN)
|
|
string(REPLACE "#cmakedefine SD_SEMANTIC_TYPES_GEN" "#define SD_SEMANTIC_TYPES_GEN" processed_content "${processed_content}")
|
|
else()
|
|
string(REPLACE "#cmakedefine SD_SEMANTIC_TYPES_GEN" "/* #undef SD_SEMANTIC_TYPES_GEN */" processed_content "${processed_content}")
|
|
endif()
|
|
|
|
# Validation - check that processing worked
|
|
if(processed_content MATCHES "@[A-Za-z_]+@")
|
|
message(WARNING "Template processing failed for ${template_file} with indices ${comb1},${comb2},${comb3} - unresolved variables remain")
|
|
set(${result_var} "" PARENT_SCOPE)
|
|
return()
|
|
endif()
|
|
|
|
if(processed_content MATCHES "#cmakedefine[ \t]+[A-Za-z_]+")
|
|
message(WARNING "CMakeDefine processing failed for ${template_file} with indices ${comb1},${comb2},${comb3} - unresolved directives remain")
|
|
set(${result_var} "" PARENT_SCOPE)
|
|
return()
|
|
endif()
|
|
|
|
set(${result_var} "${processed_content}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Process template with type combinations and include deduplication
|
|
function(process_template_with_combinations template_file combination_type combinations result_var)
|
|
if(NOT EXISTS "${template_file}")
|
|
set(${result_var} "" PARENT_SCOPE)
|
|
return()
|
|
endif()
|
|
|
|
set(all_content "")
|
|
get_filename_component(template_name ${template_file} NAME_WE)
|
|
|
|
# Detect if this is a single-type template
|
|
file(READ "${template_file}" template_content)
|
|
set(is_single_type_template FALSE)
|
|
|
|
if(template_content MATCHES "@FL_TYPE_INDEX@" AND
|
|
NOT template_content MATCHES "@TYPE_INDEX_[23]@|@COMB[23]@")
|
|
set(is_single_type_template TRUE)
|
|
message(STATUS "📋 Detected single-type template: ${template_name}")
|
|
endif()
|
|
|
|
if(is_single_type_template)
|
|
# Single-type processing: Extract all unique type indices and process each individually
|
|
set(unique_indices "")
|
|
|
|
foreach(combination ${combinations})
|
|
string(REPLACE "," ";" comb_list "${combination}")
|
|
foreach(index ${comb_list})
|
|
list(FIND unique_indices ${index} found_pos)
|
|
if(found_pos EQUAL -1)
|
|
list(APPEND unique_indices ${index})
|
|
endif()
|
|
endforeach()
|
|
endforeach()
|
|
|
|
list(SORT unique_indices COMPARE NATURAL)
|
|
message(STATUS "🔢 Processing ${template_name} with individual indices: ${unique_indices}")
|
|
|
|
# Process each unique index individually
|
|
foreach(index ${unique_indices})
|
|
# For single-type templates, use the index for all three parameters
|
|
process_single_template_instance("${template_file}" ${index} ${index} ${index} instance_content)
|
|
|
|
if(NOT instance_content STREQUAL "")
|
|
# Extract includes and content separately
|
|
extract_and_deduplicate_includes("${instance_content}" extracted_includes content_only)
|
|
|
|
# Add includes to global set
|
|
add_includes_to_global_set("${extracted_includes}")
|
|
|
|
# Only append the content without includes
|
|
string(APPEND all_content "// === ${template_name}_${index}.cpp ===\n")
|
|
string(APPEND all_content "${content_only}")
|
|
string(APPEND all_content "// === End ${template_name}_${index}.cpp ===\n\n")
|
|
|
|
# Verify float16 instantiation
|
|
if(index EQUAL 3)
|
|
if(instance_content MATCHES "SD_COMMON_TYPES_3")
|
|
message(STATUS "✅ Float16 ${template_name} instantiation generated (index ${index})")
|
|
else()
|
|
message(WARNING "⚠️ Float16 ${template_name} instantiation incomplete")
|
|
endif()
|
|
endif()
|
|
endif()
|
|
endforeach()
|
|
|
|
else()
|
|
# Multi-type processing: Original logic for templates that actually use multiple types
|
|
message(STATUS "📋 Processing multi-type template: ${template_name}")
|
|
|
|
foreach(combination ${combinations})
|
|
string(REPLACE "," ";" comb_list "${combination}")
|
|
list(LENGTH comb_list comb_count)
|
|
|
|
# Validate combination format
|
|
if(NOT ((combination_type EQUAL 3 AND comb_count EQUAL 3) OR
|
|
(combination_type EQUAL 2 AND comb_count EQUAL 2)))
|
|
continue()
|
|
endif()
|
|
|
|
# Extract combination indices
|
|
if(combination_type EQUAL 3)
|
|
list(GET comb_list 0 comb1)
|
|
list(GET comb_list 1 comb2)
|
|
list(GET comb_list 2 comb3)
|
|
set(file_suffix "${comb1}_${comb2}_${comb3}")
|
|
else()
|
|
list(GET comb_list 0 comb1)
|
|
list(GET comb_list 1 comb2)
|
|
set(comb3 ${comb1})
|
|
set(file_suffix "${comb1}_${comb2}")
|
|
endif()
|
|
|
|
# Validate indices
|
|
if(DEFINED SD_COMMON_TYPES_COUNT)
|
|
math(EXPR max_index "${SD_COMMON_TYPES_COUNT} - 1")
|
|
if(comb1 GREATER max_index OR comb2 GREATER max_index OR comb3 GREATER max_index)
|
|
continue()
|
|
endif()
|
|
endif()
|
|
|
|
# Process the multi-type template
|
|
process_single_template_instance("${template_file}" ${comb1} ${comb2} ${comb3} instance_content)
|
|
|
|
if(NOT instance_content STREQUAL "")
|
|
# Extract includes and content separately
|
|
extract_and_deduplicate_includes("${instance_content}" extracted_includes content_only)
|
|
|
|
# Add includes to global set
|
|
add_includes_to_global_set("${extracted_includes}")
|
|
|
|
# Only append the content without includes
|
|
string(APPEND all_content "// === ${template_name}_${file_suffix}.cpp ===\n")
|
|
string(APPEND all_content "${content_only}")
|
|
string(APPEND all_content "// === End ${template_name}_${file_suffix}.cpp ===\n\n")
|
|
endif()
|
|
endforeach()
|
|
endif()
|
|
|
|
set(${result_var} "${all_content}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Detect template requirements
|
|
function(detect_template_requirements template_file needs_2_type_var needs_3_type_var)
|
|
file(READ "${template_file}" template_content)
|
|
|
|
set(needs_2_type FALSE)
|
|
set(needs_3_type FALSE)
|
|
|
|
if(template_content MATCHES "TYPE_INDEX_3|COMB3|_template_3")
|
|
set(needs_3_type TRUE)
|
|
endif()
|
|
|
|
if(template_content MATCHES "TYPE_INDEX_2|COMB2|_template_2")
|
|
set(needs_2_type TRUE)
|
|
endif()
|
|
|
|
if(NOT needs_2_type AND NOT needs_3_type)
|
|
get_filename_component(template_name "${template_file}" NAME)
|
|
if(template_name MATCHES "_3\\.")
|
|
set(needs_3_type TRUE)
|
|
elseif(template_name MATCHES "_2\\.")
|
|
set(needs_2_type TRUE)
|
|
else()
|
|
set(needs_2_type TRUE)
|
|
set(needs_3_type TRUE)
|
|
endif()
|
|
endif()
|
|
|
|
set(${needs_2_type_var} ${needs_2_type} PARENT_SCOPE)
|
|
set(${needs_3_type_var} ${needs_3_type} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Process a batch of templates into one concatenated unit
|
|
function(process_concatenated_unit unit_index template_files)
|
|
# Clear global includes for this unit
|
|
set(GLOBAL_INCLUDES_SET "" CACHE INTERNAL "Set of unique includes")
|
|
set(GLOBAL_INCLUDES_LIST "" CACHE INTERNAL "Ordered list of unique includes")
|
|
|
|
set(output_dir "${CMAKE_BINARY_DIR}")
|
|
set(final_unit_file "${output_dir}/concatenated_unit_${unit_index}.cpp")
|
|
|
|
string(TIMESTAMP current_time "%Y-%m-%d %H:%M:%S")
|
|
set(unit_content_body "")
|
|
|
|
foreach(template_file ${template_files})
|
|
get_filename_component(template_name ${template_file} NAME_WE)
|
|
message(STATUS " Processing template: ${template_name}")
|
|
|
|
# Detect template requirements
|
|
detect_template_requirements("${template_file}" needs_2_type needs_3_type)
|
|
|
|
# Process with 3-type combinations if needed
|
|
if(needs_3_type AND COMBINATIONS_3)
|
|
process_template_with_combinations("${template_file}" 3 "${COMBINATIONS_3}" template_content)
|
|
string(APPEND unit_content_body "${template_content}")
|
|
endif()
|
|
|
|
# Process with 2-type combinations if needed
|
|
if(needs_2_type AND COMBINATIONS_2)
|
|
process_template_with_combinations("${template_file}" 2 "${COMBINATIONS_2}" template_content)
|
|
string(APPEND unit_content_body "${template_content}")
|
|
endif()
|
|
endforeach()
|
|
|
|
# Generate the consolidated includes section
|
|
generate_includes_section(includes_section)
|
|
|
|
# Combine everything with proper structure
|
|
set(final_content "/*\n * Concatenated Compilation Unit ${unit_index}\n * Generated: ${current_time}\n */\n\n")
|
|
string(APPEND final_content "${includes_section}")
|
|
string(APPEND final_content "/*\n * Template Implementations\n */\n\n")
|
|
string(APPEND final_content "${unit_content_body}")
|
|
|
|
file(WRITE "${final_unit_file}" "${final_content}")
|
|
list(APPEND CONCATENATED_SOURCES "${final_unit_file}")
|
|
set(CONCATENATED_SOURCES ${CONCATENATED_SOURCES} PARENT_SCOPE)
|
|
|
|
# Report deduplication statistics
|
|
list(LENGTH GLOBAL_INCLUDES_LIST total_unique_includes)
|
|
message(STATUS "✅ Created concatenated_unit_${unit_index}.cpp with ${total_unique_includes} unique includes")
|
|
endfunction()
|
|
|
|
# Main function to concatenate and process compilation units
|
|
function(concatenate_and_process_compilation_units target_count)
|
|
message(STATUS "=== CONCATENATING AND PROCESSING COMPILATION UNITS ===")
|
|
|
|
# Find all template files
|
|
file(GLOB_RECURSE ALL_TEMPLATE_FILES
|
|
"${CMAKE_SOURCE_DIR}/include/ops/declarable/helpers/cpu/compilation_units/*.cpp.in"
|
|
"${CMAKE_SOURCE_DIR}/include/loops/cpu/compilation_units/*.cpp.in"
|
|
"${CMAKE_SOURCE_DIR}/include/loops/cpu/comb_compilation_units/*.cpp.in"
|
|
"${CMAKE_SOURCE_DIR}/include/helpers/cpu/loops/*.cpp.in"
|
|
)
|
|
|
|
list(LENGTH ALL_TEMPLATE_FILES total_files)
|
|
if(total_files EQUAL 0)
|
|
message(FATAL_ERROR "❌ No template files found to process!")
|
|
endif()
|
|
|
|
math(EXPR files_per_unit "(${total_files} + ${target_count} - 1) / ${target_count}")
|
|
message(STATUS "📊 Processing ${total_files} templates into ${target_count} units with include deduplication")
|
|
|
|
# Ensure we have combinations
|
|
if(NOT DEFINED COMBINATIONS_2 OR NOT DEFINED COMBINATIONS_3)
|
|
message(FATAL_ERROR "❌ Type combinations not initialized!")
|
|
endif()
|
|
|
|
list(LENGTH COMBINATIONS_2 combo2_count)
|
|
list(LENGTH COMBINATIONS_3 combo3_count)
|
|
message(STATUS "Using ${combo2_count} 2-type and ${combo3_count} 3-type combinations")
|
|
|
|
# Create concatenated units
|
|
set(unit_index 0)
|
|
set(files_in_current_unit 0)
|
|
set(current_unit_files "")
|
|
|
|
foreach(template_file ${ALL_TEMPLATE_FILES})
|
|
list(APPEND current_unit_files ${template_file})
|
|
math(EXPR files_in_current_unit "${files_in_current_unit} + 1")
|
|
|
|
if(files_in_current_unit GREATER_EQUAL files_per_unit)
|
|
process_concatenated_unit(${unit_index} "${current_unit_files}")
|
|
set(current_unit_files "")
|
|
set(files_in_current_unit 0)
|
|
math(EXPR unit_index "${unit_index} + 1")
|
|
endif()
|
|
endforeach()
|
|
|
|
# Handle remaining files
|
|
if(NOT current_unit_files STREQUAL "")
|
|
process_concatenated_unit(${unit_index} "${current_unit_files}")
|
|
endif()
|
|
|
|
message(STATUS "✅ Created concatenated compilation units with deduplicated includes")
|
|
set(CONCATENATED_SOURCES ${CONCATENATED_SOURCES} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
|
|
|
|
# Main entry point
|
|
function(create_4gb_safe_concatenated_units)
|
|
message(STATUS "🔧 Creating concatenated compilation units with include deduplication...")
|
|
|
|
set(TARGET_UNITS 4)
|
|
|
|
if(NOT DEFINED COMBINATIONS_2 OR NOT DEFINED COMBINATIONS_3)
|
|
message(STATUS "Initializing dynamic combinations...")
|
|
initialize_dynamic_combinations()
|
|
endif()
|
|
|
|
# Debug output
|
|
list(LENGTH COMBINATIONS_2 combo2_count)
|
|
list(LENGTH COMBINATIONS_3 combo3_count)
|
|
if(combo2_count GREATER 0)
|
|
list(GET COMBINATIONS_2 0 first_combo2)
|
|
message(STATUS "Debug: First 2-type combination: ${first_combo2}")
|
|
endif()
|
|
if(combo3_count GREATER 0)
|
|
list(GET COMBINATIONS_3 0 first_combo3)
|
|
message(STATUS "Debug: First 3-type combination: ${first_combo3}")
|
|
endif()
|
|
|
|
concatenate_and_process_compilation_units(${TARGET_UNITS})
|
|
|
|
if(DEFINED CONCATENATED_SOURCES)
|
|
list(LENGTH CONCATENATED_SOURCES unit_count)
|
|
message(STATUS "📊 Created ${unit_count} concatenated units with deduplicated includes")
|
|
endif()
|
|
endfunction()
|
|
|
|
# Clean up existing units
|
|
function(clean_concatenated_units)
|
|
file(GLOB existing_units "${CMAKE_BINARY_DIR}/concatenated_unit_*.cpp")
|
|
if(existing_units)
|
|
file(REMOVE ${existing_units})
|
|
list(LENGTH existing_units removed_count)
|
|
message(STATUS "🗑️ Cleaned up ${removed_count} existing concatenated units")
|
|
endif()
|
|
|
|
# Clean up any temp processing files
|
|
file(GLOB temp_files "${CMAKE_BINARY_DIR}/temp_*.cpp*")
|
|
if(temp_files)
|
|
file(REMOVE ${temp_files})
|
|
endif()
|
|
endfunction() |