espressif_tinyusb/test/vendor/ceedling/lib/ceedling/preprocessinator_includes_h...

97 lines
4.0 KiB
Ruby

class PreprocessinatorIncludesHandler
constructor :configurator, :tool_executor, :task_invoker, :file_path_utils, :yaml_wrapper, :file_wrapper
# shallow includes: only those headers a source file explicitly includes
def invoke_shallow_includes_list(filepath)
@task_invoker.invoke_test_shallow_include_lists( [@file_path_utils.form_preprocessed_includes_list_filepath(filepath)] )
end
##
# Ask the preprocessor for a make-style dependency rule of only the headers
# the source file immediately includes.
#
# === Arguments
# +filepath+ _String_:: Path to the test file to process.
#
# === Return
# _String_:: The text of the dependency rule generated by the preprocessor.
def form_shallow_dependencies_rule(filepath)
# change filename (prefix of '_') to prevent preprocessor from finding
# include files in temp directory containing file it's scanning
temp_filepath = @file_path_utils.form_temp_path(filepath, '_')
# read the file and replace all include statements with a decorated version
# (decorating the names creates file names that don't exist, thus preventing
# the preprocessor from snaking out and discovering the entire include path
# that winds through the code). The decorated filenames indicate files that
# are included directly by the test file.
contents = @file_wrapper.read(filepath)
if !contents.valid_encoding?
contents = contents.encode("UTF-16be", :invalid=>:replace, :replace=>"?").encode('UTF-8')
end
contents.gsub!( /^\s*#include\s+[\"<]\s*(\S+)\s*[\">]/, "#include \"\\1\"\n#include \"@@@@\\1\"" )
contents.gsub!( /^\s*TEST_FILE\(\s*\"\s*(\S+)\s*\"\s*\)/, "#include \"\\1\"\n#include \"@@@@\\1\"")
@file_wrapper.write( temp_filepath, contents )
# extract the make-style dependency rule telling the preprocessor to
# ignore the fact that it can't find the included files
command = @tool_executor.build_command_line(@configurator.tools_test_includes_preprocessor, [], temp_filepath)
shell_result = @tool_executor.exec(command[:line], command[:options])
return shell_result[:output]
end
##
# Extract the headers that are directly included by a source file using the
# provided, annotated Make dependency rule.
#
# === Arguments
# +make_rule+ _String_:: Annotated Make dependency rule.
#
# === Return
# _Array_ of _String_:: Array of the direct dependencies for the source file.
def extract_shallow_includes(make_rule)
# Extract the dependencies from the make rule
hdr_ext = @configurator.extension_header
dependencies = make_rule.split.find_all {|path| path.end_with?(hdr_ext) }.uniq
dependencies.map! {|hdr| hdr.gsub('\\','/') }
# Separate the real files form the annotated ones and remove the '@@@@'
annotated_headers, real_headers = dependencies.partition {|hdr| hdr =~ /^@@@@/ }
annotated_headers.map! {|hdr| hdr.gsub('@@@@','') }
# Find which of our annotated headers are "real" dependencies. This is
# intended to weed out dependencies that have been removed due to build
# options defined in the project yaml and/or in the headers themselves.
list = annotated_headers.find_all do |annotated_header|
# find the index of the "real" include that matches the annotated one.
idx = real_headers.find_index do |real_header|
real_header =~ /^(.*\/)?#{Regexp.escape(annotated_header)}$/
end
# If we found a real include, delete it from the array and return it,
# otherwise return nil. Since nil is falsy this has the effect of making
# find_all return only the annotated headers for which a real include was
# found/deleted
idx ? real_headers.delete_at(idx) : nil
end.compact
# Extract direct dependencies that were also added
src_ext = @configurator.extension_source
sdependencies = make_rule.split.find_all {|path| path.end_with?(src_ext) }.uniq
sdependencies.map! {|hdr| hdr.gsub('\\','/') }
list += sdependencies
list
end
def write_shallow_includes_list(filepath, list)
@yaml_wrapper.dump(filepath, list)
end
end