# DAPSS (Device Attachment Pipe Specification Source) preprocessing module # This module provides functionality to preprocess .dapss files to .daps files # using the C preprocessor, respecting include directories and target dependencies. # # Usage: # add_daps_target(target_name SOURCES file1.dapss file2.dapss ...) # register_daps_target(target_name) # In subdirectories # add_all_daps_dependencies() # In main CMakeLists.txt # # Examples: # add_daps_target(device_specs SOURCES devices/avia0.dapss devices/win0.dapss) # register_daps_target(device_specs) # add_all_daps_dependencies() # # The preprocessed .daps files will be placed in ${CMAKE_CURRENT_BINARY_DIR}/ # Function to add a DAPSS preprocessing target # Usage: add_daps_target(target_name SOURCES file1.dapss file2.dapss ...) function(add_daps_target target_name) set(options) set(oneValueArgs) set(multiValueArgs SOURCES) cmake_parse_arguments(DAPS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(NOT DAPS_SOURCES) message(FATAL_ERROR "add_daps_target: No SOURCES specified for target ${target_name}") endif() # Use binary directory directly for processed files # This ensures files are created in the same directory as the target set(output_dir "${CMAKE_CURRENT_BINARY_DIR}") # List to store all output files set(output_files) # Process each source file foreach(source_file ${DAPS_SOURCES}) # Get the base name without extension get_filename_component(base_name ${source_file} NAME_WE) get_filename_component(source_dir ${source_file} DIRECTORY) # Create output file path set(output_file "${output_dir}/${base_name}.daps") list(APPEND output_files ${output_file}) # Get include directories from current directory and target get_directory_property(include_dirs INCLUDE_DIRECTORIES) # Build include flags set(include_flags) foreach(include_dir ${include_dirs}) list(APPEND include_flags "-I${include_dir}") endforeach() # Add current source directory to includes if it's not already there if(source_dir) list(APPEND include_flags "-I${source_dir}") endif() # Convert list to space-separated string string(REPLACE ";" " " include_flags_str "${include_flags}") # Find C compiler if not already set if(NOT CMAKE_C_COMPILER) find_program(CMAKE_C_COMPILER gcc cc clang) if(NOT CMAKE_C_COMPILER) message(FATAL_ERROR "No C compiler found for DAPSS preprocessing") endif() endif() # Create custom command to preprocess the file add_custom_command( OUTPUT ${output_file} COMMAND sh -c "\"${CMAKE_C_COMPILER}\" -E -P -x c ${include_flags_str} \"${CMAKE_CURRENT_SOURCE_DIR}/${source_file}\" > \"${output_file}\"" DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${source_file} COMMENT "Preprocessing ${source_file} to ${base_name}.daps" VERBATIM ) endforeach() # Create custom target that depends on all output files add_custom_target(${target_name} DEPENDS ${output_files}) # Make the target part of the ALL target so it gets built by default # This ensures it gets built when building just this subdirectory set_target_properties(${target_name} PROPERTIES FOLDER "${CMAKE_CURRENT_SOURCE_DIR}" EXCLUDE_FROM_ALL FALSE ) # Set target properties set_target_properties(${target_name} PROPERTIES DAPS_OUTPUT_DIR ${output_dir} DAPS_OUTPUT_FILES "${output_files}" ) # Make the target available globally set(${target_name}_OUTPUT_DIR ${output_dir} PARENT_SCOPE) set(${target_name}_OUTPUT_FILES "${output_files}" PARENT_SCOPE) endfunction() # Function to register a DAPSS target for later dependency addition # Usage: register_daps_target(target_name) # This stores the target name in a global property for later use function(register_daps_target target_name) # Store the target name in a global property get_property(registered_targets GLOBAL PROPERTY DAPS_REGISTERED_TARGETS) list(APPEND registered_targets ${target_name}) set_property(GLOBAL PROPERTY DAPS_REGISTERED_TARGETS ${registered_targets}) message(STATUS "Registered DAPSS target ${target_name} for later dependency addition") endfunction() # Function to add all registered DAPSS targets as dependencies # Usage: add_all_daps_dependencies([TARGET main_target] [CONDITION condition_expression]) # This should be called from the main CMakeLists.txt after all subdirectories are processed function(add_all_daps_dependencies) set(options) set(oneValueArgs TARGET CONDITION) set(multiValueArgs) cmake_parse_arguments(DAPS_ALL "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) # Default target is PROJECT_NAME if(DAPS_ALL_TARGET) set(dep_target ${DAPS_ALL_TARGET}) else() set(dep_target ${PROJECT_NAME}) endif() # Get all registered targets get_property(registered_targets GLOBAL PROPERTY DAPS_REGISTERED_TARGETS) if(registered_targets) foreach(target_name ${registered_targets}) if(TARGET ${target_name}) if(DAPS_ALL_CONDITION) if(${DAPS_ALL_CONDITION}) add_dependencies(${dep_target} ${target_name}) message(STATUS "Added registered DAPSS target ${target_name} as dependency of ${dep_target} (condition: ${DAPS_ALL_CONDITION})") else() message(STATUS "Skipped registered DAPSS target ${target_name} (condition: ${DAPS_ALL_CONDITION} not met)") endif() else() add_dependencies(${dep_target} ${target_name}) message(STATUS "Added registered DAPSS target ${target_name} as dependency of ${dep_target}") endif() else() message(WARNING "Registered DAPSS target ${target_name} does not exist") endif() endforeach() else() message(STATUS "No DAPSS targets registered for dependency addition") endif() endfunction()