400 lines
17 KiB
CMake
400 lines
17 KiB
CMake
# cmake/PostBuild.cmake
|
|
# Configures optional post-build targets like tests and analysis tools.
|
|
|
|
# ============================================================================
|
|
# HELPER FUNCTION: Write file only if content changed (preserves mtime for PCH)
|
|
# This prevents PCH invalidation during builds when config.h content is identical
|
|
# ============================================================================
|
|
function(_postbuild_write_if_different filepath content)
|
|
set(should_write TRUE)
|
|
|
|
# Check if file already exists
|
|
if(EXISTS "${filepath}")
|
|
# Read existing content
|
|
file(READ "${filepath}" existing_content)
|
|
|
|
# Compare content
|
|
if("${existing_content}" STREQUAL "${content}")
|
|
set(should_write FALSE)
|
|
endif()
|
|
endif()
|
|
|
|
# Only write if content changed or file doesn't exist
|
|
if(should_write)
|
|
file(WRITE "${filepath}" "${content}")
|
|
endif()
|
|
endfunction()
|
|
|
|
# --- Configuration file ---
|
|
# Build TYPE_DEFINES string from current type configuration
|
|
# This ensures JavaCPP sees the same type availability as the CMake build
|
|
set(TYPE_DEFINES "")
|
|
|
|
# Check if we're in selective types mode
|
|
if(DEFINED SD_TYPES_LIST AND NOT SD_TYPES_LIST STREQUAL "")
|
|
# Selective types mode - export only enabled types
|
|
# The HAS_* macros were already set by apply_type_definitions_to_target
|
|
# We need to capture them and add to TYPE_DEFINES
|
|
|
|
# Get all HAS_* definitions that were set
|
|
get_directory_property(COMPILE_DEFS COMPILE_DEFINITIONS)
|
|
foreach(def IN LISTS COMPILE_DEFS)
|
|
if(def MATCHES "^HAS_")
|
|
string(APPEND TYPE_DEFINES "#define ${def}\n")
|
|
endif()
|
|
endforeach()
|
|
else()
|
|
# All types mode - define all HAS_* macros
|
|
string(APPEND TYPE_DEFINES "#define HAS_BOOL 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_FLOAT 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_FLOAT32 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_DOUBLE 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_FLOAT64 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_FLOAT16 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_HALF 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_BFLOAT16 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_BFLOAT 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_FLOAT8 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_HALF2 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_INT8 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_INT8_T 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_INT16 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_INT16_T 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_INT32 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_INT32_T 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_INT 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_INT64 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_INT64_T 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_LONG 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_UINT8 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_UINT8_T 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_UINT16 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_UINT16_T 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_UINT32 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_UINT32_T 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_UINT64 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_UINT64_T 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_UNSIGNEDLONG 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_UTF8 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_STD_STRING 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_UTF16 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_STD_U16STRING 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_UTF32 1\n")
|
|
string(APPEND TYPE_DEFINES "#define HAS_STD_U32STRING 1\n")
|
|
endif()
|
|
|
|
# Generate config.h with write-if-different to preserve PCH
|
|
# This prevents PCH invalidation during the build when content hasn't changed
|
|
set(CONFIG_H_IN "${CMAKE_CURRENT_SOURCE_DIR}/include/config.h.in")
|
|
set(CONFIG_H_OUT "${CMAKE_CURRENT_BINARY_DIR}/include/config.h")
|
|
|
|
# Read the template
|
|
file(READ "${CONFIG_H_IN}" CONFIG_H_CONTENT)
|
|
|
|
# Perform variable substitutions (mimics configure_file behavior)
|
|
# Handle cmakedefine01 directives
|
|
if(HAVE_ONEDNN)
|
|
string(REPLACE "#cmakedefine01 HAVE_ONEDNN" "#define HAVE_ONEDNN 1" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
else()
|
|
string(REPLACE "#cmakedefine01 HAVE_ONEDNN" "#define HAVE_ONEDNN 0" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
endif()
|
|
|
|
if(HAVE_ARMCOMPUTE)
|
|
string(REPLACE "#cmakedefine01 HAVE_ARMCOMPUTE" "#define HAVE_ARMCOMPUTE 1" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
else()
|
|
string(REPLACE "#cmakedefine01 HAVE_ARMCOMPUTE" "#define HAVE_ARMCOMPUTE 0" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
endif()
|
|
|
|
if(HAVE_CUDNN)
|
|
string(REPLACE "#cmakedefine01 HAVE_CUDNN" "#define HAVE_CUDNN 1" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
else()
|
|
string(REPLACE "#cmakedefine01 HAVE_CUDNN" "#define HAVE_CUDNN 0" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
endif()
|
|
|
|
if(HAVE_OPENBLAS)
|
|
string(REPLACE "#cmakedefine01 HAVE_OPENBLAS" "#define HAVE_OPENBLAS 1" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
else()
|
|
string(REPLACE "#cmakedefine01 HAVE_OPENBLAS" "#define HAVE_OPENBLAS 0" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
endif()
|
|
|
|
if(HAVE_FLATBUFFERS)
|
|
string(REPLACE "#cmakedefine01 HAVE_FLATBUFFERS" "#define HAVE_FLATBUFFERS 1" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
else()
|
|
string(REPLACE "#cmakedefine01 HAVE_FLATBUFFERS" "#define HAVE_FLATBUFFERS 0" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
endif()
|
|
|
|
if(SD_SELECTIVE_TYPES)
|
|
string(REPLACE "#cmakedefine01 SD_SELECTIVE_TYPES" "#define SD_SELECTIVE_TYPES 1" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
else()
|
|
string(REPLACE "#cmakedefine01 SD_SELECTIVE_TYPES" "#define SD_SELECTIVE_TYPES 0" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
endif()
|
|
|
|
# Handle @VAR@ substitutions
|
|
if(DEFINED SD_LIBRARY_NAME)
|
|
string(REPLACE "@SD_LIBRARY_NAME@" "${SD_LIBRARY_NAME}" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
else()
|
|
# Remove the line if variable not defined
|
|
string(REGEX REPLACE "#cmakedefine SD_LIBRARY_NAME[^\n]*\n" "" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
endif()
|
|
|
|
if(DEFINED ONEDNN_PATH)
|
|
string(REPLACE "@ONEDNN_PATH@" "${ONEDNN_PATH}" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
else()
|
|
string(REGEX REPLACE "#cmakedefine ONEDNN_PATH[^\n]*\n" "" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
endif()
|
|
|
|
if(DEFINED OPENBLAS_PATH)
|
|
string(REPLACE "@OPENBLAS_PATH@" "${OPENBLAS_PATH}" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
else()
|
|
string(REGEX REPLACE "#cmakedefine OPENBLAS_PATH[^\n]*\n" "" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
endif()
|
|
|
|
if(DEFINED FLATBUFFERS_PATH)
|
|
string(REPLACE "@FLATBUFFERS_PATH@" "${FLATBUFFERS_PATH}" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
else()
|
|
string(REGEX REPLACE "#cmakedefine FLATBUFFERS_PATH[^\n]*\n" "" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
endif()
|
|
|
|
if(DEFINED DEFAULT_ENGINE)
|
|
string(REPLACE "@DEFAULT_ENGINE@" "${DEFAULT_ENGINE}" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
else()
|
|
string(REGEX REPLACE "#cmakedefine DEFAULT_ENGINE[^\n]*\n" "" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
endif()
|
|
|
|
# Substitute TYPE_DEFINES
|
|
string(REPLACE "@TYPE_DEFINES@" "${TYPE_DEFINES}" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
|
|
|
# Write config.h only if content changed (preserves mtime for PCH)
|
|
_postbuild_write_if_different("${CONFIG_H_OUT}" "${CONFIG_H_CONTENT}")
|
|
|
|
include_directories(${CMAKE_CURRENT_BINARY_DIR}/include)
|
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
|
|
|
# --- Flatbuffers Header and Java Generation ---
|
|
if(DEFINED ENV{GENERATE_FLATC} OR DEFINED GENERATE_FLATC)
|
|
set(FLATC_EXECUTABLE "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-build/flatc")
|
|
set(MAIN_GENERATED_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/include/graph/generated.h")
|
|
add_custom_command(
|
|
OUTPUT ${MAIN_GENERATED_HEADER}
|
|
COMMAND ${CMAKE_COMMAND} -E env "FLATC_PATH=${FLATC_EXECUTABLE}" bash ${CMAKE_CURRENT_SOURCE_DIR}/flatc-generate.sh
|
|
DEPENDS flatbuffers_external
|
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
|
COMMENT "Running flatc to generate C++ headers"
|
|
VERBATIM
|
|
)
|
|
add_custom_target(generate_flatbuffers_headers DEPENDS ${MAIN_GENERATED_HEADER})
|
|
add_custom_command(
|
|
TARGET generate_flatbuffers_headers POST_BUILD
|
|
COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/copy-flatc-java.sh
|
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
|
COMMENT "Copying generated Java files"
|
|
VERBATIM
|
|
)
|
|
endif()
|
|
|
|
if(SD_EXTRACT_INSTANTIATIONS)
|
|
include(ExtractInstantiations)
|
|
|
|
endif()
|
|
|
|
# --- Self-Contained Preprocessing Target ---
|
|
if(SD_PREPROCESS)
|
|
message("Preprocessing enabled: ${CMAKE_BINARY_DIR}")
|
|
message("Setting up self-contained preprocessing with FlatBuffers...")
|
|
|
|
include(ExternalProject)
|
|
|
|
# Build FlatBuffers for preprocessing (minimal build, just need headers)
|
|
set(PREPROCESS_FLATBUFFERS_VERSION "25.2.10")
|
|
set(PREPROCESS_FLATBUFFERS_URL "https://github.com/google/flatbuffers/archive/v${PREPROCESS_FLATBUFFERS_VERSION}.tar.gz")
|
|
set(PREPROCESS_FB_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/preprocess-flatbuffers-src")
|
|
set(PREPROCESS_FB_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/preprocess-flatbuffers-build")
|
|
|
|
# Check if we already have FlatBuffers headers
|
|
set(PREPROCESS_FB_HEADER "${PREPROCESS_FB_SOURCE_DIR}/include/flatbuffers/flatbuffers.h")
|
|
if(NOT EXISTS ${PREPROCESS_FB_HEADER})
|
|
message("Downloading and extracting FlatBuffers for preprocessing...")
|
|
|
|
# Download and extract FlatBuffers
|
|
file(DOWNLOAD ${PREPROCESS_FLATBUFFERS_URL}
|
|
"${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-${PREPROCESS_FLATBUFFERS_VERSION}.tar.gz"
|
|
SHOW_PROGRESS
|
|
STATUS download_status)
|
|
|
|
list(GET download_status 0 download_result)
|
|
if(NOT download_result EQUAL 0)
|
|
message(FATAL_ERROR "Failed to download FlatBuffers for preprocessing")
|
|
endif()
|
|
|
|
# Extract the archive
|
|
execute_process(
|
|
COMMAND ${CMAKE_COMMAND} -E tar xzf "flatbuffers-${PREPROCESS_FLATBUFFERS_VERSION}.tar.gz"
|
|
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
|
RESULT_VARIABLE extract_result
|
|
)
|
|
|
|
if(NOT extract_result EQUAL 0)
|
|
message(FATAL_ERROR "Failed to extract FlatBuffers for preprocessing")
|
|
endif()
|
|
|
|
# Move the extracted directory to our expected location
|
|
file(RENAME "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-${PREPROCESS_FLATBUFFERS_VERSION}"
|
|
"${PREPROCESS_FB_SOURCE_DIR}")
|
|
endif()
|
|
|
|
# Verify FlatBuffers headers are now available
|
|
if(NOT EXISTS ${PREPROCESS_FB_HEADER})
|
|
message(FATAL_ERROR "FlatBuffers headers not found for preprocessing: ${PREPROCESS_FB_HEADER}")
|
|
endif()
|
|
|
|
message("✅ FlatBuffers headers available for preprocessing: ${PREPROCESS_FB_SOURCE_DIR}/include")
|
|
|
|
# Get ALL subdirectories under include/ and add the root include directory first
|
|
set(all_includes "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
|
file(GLOB_RECURSE all_dirs LIST_DIRECTORIES true "${CMAKE_CURRENT_SOURCE_DIR}/include/*")
|
|
foreach(item ${all_dirs})
|
|
if(IS_DIRECTORY ${item})
|
|
list(APPEND all_includes ${item})
|
|
endif()
|
|
endforeach()
|
|
|
|
# Add binary include directory
|
|
list(APPEND all_includes "${CMAKE_CURRENT_BINARY_DIR}/include")
|
|
|
|
# Also add build directories
|
|
list(APPEND all_includes
|
|
"${CMAKE_SOURCE_DIR}/include/"
|
|
"${CMAKE_SOURCE_DIR}/include/system"
|
|
"${CMAKE_BINARY_DIR}/compilation_units"
|
|
"${CMAKE_BINARY_DIR}/cpu_instantiations"
|
|
"${CMAKE_BINARY_DIR}/cuda_instantiations"
|
|
"${CMAKE_BINARY_DIR}/include"
|
|
)
|
|
|
|
# Add our self-contained FlatBuffers include directory
|
|
list(APPEND all_includes "${PREPROCESS_FB_SOURCE_DIR}/include")
|
|
|
|
# Build include flags
|
|
set(include_flags "")
|
|
foreach(dir IN LISTS all_includes)
|
|
if(EXISTS ${dir})
|
|
string(APPEND include_flags " -I${dir}")
|
|
endif()
|
|
endforeach()
|
|
|
|
set(defs_flags "")
|
|
|
|
# Add basic platform definitions
|
|
string(APPEND defs_flags " -D__CPUBLAS__=true")
|
|
if(SD_CUDA)
|
|
string(APPEND defs_flags " -D__CUDABLAS__=true -DHAVE_CUDA=1")
|
|
endif()
|
|
if(HAVE_OPENBLAS)
|
|
string(APPEND defs_flags " -DHAVE_OPENBLAS=1")
|
|
endif()
|
|
|
|
if(SD_ALL_OPS OR "${SD_OPS_LIST}" STREQUAL "")
|
|
string(APPEND defs_flags " -DSD_ALL_OPS=1")
|
|
# When SD_ALL_OPS=1, NOT_EXCLUDED should evaluate to 1 for all ops
|
|
string(APPEND defs_flags " -DNOT_EXCLUDED(x)=1")
|
|
else()
|
|
# Add specific operation definitions
|
|
foreach(OP ${SD_OPS_LIST})
|
|
string(APPEND defs_flags " -DOP_${OP}=1")
|
|
endforeach()
|
|
# Define NOT_EXCLUDED macro for selective ops
|
|
string(APPEND defs_flags " -DNOT_EXCLUDED(x)=\\(defined\\(x\\)\\)")
|
|
endif()
|
|
|
|
# Add build type definitions
|
|
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
|
string(APPEND defs_flags " -DDEBUG=1 -D_DEBUG=1")
|
|
else()
|
|
string(APPEND defs_flags " -DNDEBUG=1")
|
|
endif()
|
|
|
|
# Add any additional compile definitions from the main build
|
|
if(compile_defs AND NOT compile_defs STREQUAL "compile_defs-NOTFOUND")
|
|
foreach(def IN LISTS compile_defs)
|
|
string(APPEND defs_flags " -D${def}")
|
|
endforeach()
|
|
endif()
|
|
|
|
set(PREPROCESSED_DIR "${CMAKE_SOURCE_DIR}/preprocessed")
|
|
file(MAKE_DIRECTORY ${PREPROCESSED_DIR})
|
|
|
|
set(PREPROCESSED_FILES)
|
|
set(PROCESSED_SOURCES "")
|
|
|
|
# Use ALL_SOURCES from global scope
|
|
if(DEFINED ALL_SOURCES AND ALL_SOURCES)
|
|
set(SOURCE_LIST ${ALL_SOURCES})
|
|
elseif(DEFINED ALL_SOURCES_LIST AND ALL_SOURCES_LIST)
|
|
set(SOURCE_LIST ${ALL_SOURCES_LIST})
|
|
else()
|
|
message(WARNING "No source list available for preprocessing. Skipping.")
|
|
add_custom_target(preprocess_sources ALL
|
|
COMMAND ${CMAKE_COMMAND} -E echo "Preprocessing skipped - no source files available")
|
|
return()
|
|
endif()
|
|
|
|
list(LENGTH SOURCE_LIST source_count)
|
|
message("Starting preprocessing of ${source_count} source files...")
|
|
message("Operation definitions: SD_ALL_OPS=${SD_ALL_OPS}, SD_OPS_LIST=${SD_OPS_LIST}")
|
|
|
|
foreach(src IN LISTS SOURCE_LIST)
|
|
if(NOT EXISTS ${src} OR NOT src MATCHES "\\.(c|cpp|cxx|cc|cu)$")
|
|
continue()
|
|
endif()
|
|
|
|
if(NOT src IN_LIST PROCESSED_SOURCES)
|
|
get_filename_component(src_name ${src} NAME_WE)
|
|
get_filename_component(src_path ${src} PATH)
|
|
file(RELATIVE_PATH rel_path ${CMAKE_SOURCE_DIR} ${src_path})
|
|
string(REPLACE "/" "_" src_dir_ "${rel_path}")
|
|
set(preprocessed_file "${PREPROCESSED_DIR}/${src_dir_}_${src_name}.i")
|
|
|
|
if(NOT EXISTS "${preprocessed_file}")
|
|
if(src MATCHES "\\.cu$")
|
|
set(compiler "${CMAKE_CUDA_COMPILER}")
|
|
set(lang_flags "${CMAKE_CUDA_FLAGS} ${CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE}}")
|
|
elseif(src MATCHES "\\.c$")
|
|
set(compiler "${CMAKE_C_COMPILER}")
|
|
set(lang_flags "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE}}")
|
|
else()
|
|
set(compiler "${CMAKE_CXX_COMPILER}")
|
|
set(lang_flags "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}}")
|
|
endif()
|
|
|
|
# Split the flags properly for execute_process
|
|
separate_arguments(lang_flags_list UNIX_COMMAND "${lang_flags}")
|
|
separate_arguments(defs_flags_list UNIX_COMMAND "${defs_flags}")
|
|
separate_arguments(include_flags_list UNIX_COMMAND "${include_flags}")
|
|
|
|
execute_process(
|
|
COMMAND ${compiler} -E -P -C ${lang_flags_list} ${defs_flags_list} ${include_flags_list} "${src}" -o "${preprocessed_file}"
|
|
RESULT_VARIABLE result
|
|
ERROR_VARIABLE error_output
|
|
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
|
)
|
|
if(result EQUAL 0)
|
|
list(APPEND PREPROCESSED_FILES ${preprocessed_file})
|
|
message(STATUS "✅ Preprocessed: ${src}")
|
|
else()
|
|
message(WARNING "❌ Failed to preprocess ${src}")
|
|
message(WARNING " Error: ${error_output}")
|
|
endif()
|
|
else()
|
|
list(APPEND PREPROCESSED_FILES ${preprocessed_file})
|
|
message(STATUS "✓ Already preprocessed: ${src}")
|
|
endif()
|
|
list(APPEND PROCESSED_SOURCES ${src})
|
|
endif()
|
|
endforeach()
|
|
|
|
list(LENGTH PREPROCESSED_FILES processed_count)
|
|
message("✅ Preprocessing complete. Generated ${processed_count} preprocessed files in ${PREPROCESSED_DIR}")
|
|
add_custom_target(preprocess_sources ALL DEPENDS ${PREPROCESSED_FILES})
|
|
endif()
|
|
|