class PreprocessinatorIncludesHandler

Public Instance Methods

extract_includes(filepath) click to toggle source

Extract the headers that are directly included by a source file using the provided, annotated Make dependency rule.

Arguments

filepath String

C source or header file to extract includes for.

Return

Array of String

Array of the direct dependencies for the source file.

# File lib/ceedling/preprocessinator_includes_handler.rb, line 64
def extract_includes(filepath)
  to_process = [filepath]
  ignore_list = []
  list = []
  all_mocks = []

  include_paths = @configurator.project_config_hash[:collection_paths_include]
  include_paths = [] if include_paths.nil?
  include_paths.map! {|path| File.expand_path(path)}

  while to_process.length > 0
    target = to_process.shift()
    ignore_list << target
    new_deps, new_to_process, all_mocks = extract_includes_helper(target, include_paths, ignore_list, all_mocks)
    list += new_deps
    to_process += new_to_process
    if !@configurator.project_config_hash[:project_auto_link_deep_dependencies]
      break
    else
      list = list.uniq()
      to_process = to_process.uniq()
    end
  end

  return list
end
extract_includes_helper(filepath, include_paths, ignore_list, mocks) click to toggle source
# File lib/ceedling/preprocessinator_includes_handler.rb, line 91
def extract_includes_helper(filepath, include_paths, ignore_list, mocks)
  # Extract the dependencies from the make rule
  make_rule = self.form_shallow_dependencies_rule(filepath)
  target_file = make_rule.split[0].gsub(':', '').gsub('\\','/')
  base = File.basename(target_file, File.extname(target_file))
  make_rule_dependencies = make_rule.gsub(/.*\b#{Regexp.escape(base)}\S*/, '').gsub(/\\$/, '')
  
  # Extract the headers dependencies from the make rule
  hdr_ext = @configurator.extension_header
  headers_dependencies = make_rule_dependencies.split.find_all {|path| path.end_with?(hdr_ext) }.uniq
  headers_dependencies.map! {|hdr| hdr.gsub('\\','/') }
  full_path_headers_dependencies = extract_full_path_dependencies(headers_dependencies)

  # Extract the sources dependencies from the make rule
  src_ext = @configurator.extension_source
  sources_dependencies = make_rule_dependencies.split.find_all {|path| path.end_with?(src_ext) }.uniq
  sources_dependencies.map! {|src| src.gsub('\\','/') }
  full_path_sources_dependencies = extract_full_path_dependencies(sources_dependencies)

  list = full_path_headers_dependencies + full_path_sources_dependencies

  mock_prefix = @configurator.project_config_hash[:cmock_mock_prefix]
  # Creating list of mocks
  mocks += full_path_headers_dependencies.find_all do |header|
    File.basename(header) =~ /^#{mock_prefix}.*$/
  end.compact

  # ignore real file when both mock and real file exist
  mocks.each do |mock|
    list.each do |filename|
      if File.basename(filename) == File.basename(mock).sub(mock_prefix, '')
        ignore_list << filename
      end
    end
  end.compact

  # Filtering list of final includes to only include mocks and anything that is NOT in the ignore_list
  list = list.select do |item|
    mocks.include? item or !(ignore_list.any? { |ignore_item| !item.match(/^(.*\/)?#{Regexp.escape(ignore_item)}$/).nil? })
  end

  to_process = []

  if @configurator.project_config_hash[:project_auto_link_deep_dependencies]
    # Creating list of headers that should be recursively pre-processed
    # Skipping mocks and vendor headers
    headers_to_deep_link = full_path_headers_dependencies.select do |hdr|
      !(mocks.include? hdr) and (hdr.match(/^(.*\/)(#{VENDORS_FILES.join('|')}) + #{Regexp.escape(hdr_ext)}$/).nil?)
    end
    headers_to_deep_link.map! {|hdr| File.expand_path(hdr) }
    headers_to_deep_link.compact!

    headers_to_deep_link.each do |hdr|
      if (ignore_list.none? {|ignore_header| hdr.match(/^(.*\/)?#{Regexp.escape(ignore_header)}$/)} and
          include_paths.none? {|include_path| hdr =~ /^#{include_path}\.*/})
        if File.exist?(hdr)
          to_process << hdr
          src = @file_finder.find_compilation_input_file(hdr, :ignore)
          to_process << src if src
        end
      end
    end
  end

  return list, to_process, mocks

end
form_shallow_dependencies_rule(filepath) click to toggle source

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.

# File lib/ceedling/preprocessinator_includes_handler.rb, line 23
def form_shallow_dependencies_rule(filepath)
  if @@makefile_cache.has_key?(filepath)
    return @@makefile_cache[filepath]
  end
  # 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])

  @@makefile_cache[filepath] = shell_result[:output]
  return shell_result[:output]
end
invoke_shallow_includes_list(filepath) click to toggle source

shallow includes: only those headers a source file explicitly includes

# File lib/ceedling/preprocessinator_includes_handler.rb, line 10
def invoke_shallow_includes_list(filepath)
  @task_invoker.invoke_test_shallow_include_lists( [@file_path_utils.form_preprocessed_includes_list_filepath(filepath)] )
end
write_shallow_includes_list(filepath, list) click to toggle source
# File lib/ceedling/preprocessinator_includes_handler.rb, line 159
def write_shallow_includes_list(filepath, list)
  @yaml_wrapper.dump(filepath, list)
end

Private Instance Methods

extract_full_path_dependencies(dependencies) click to toggle source
# File lib/ceedling/preprocessinator_includes_handler.rb, line 165
def extract_full_path_dependencies(dependencies)
  # Separate the real files form the annotated ones and remove the '@@@@'
  annotated_files, real_files = dependencies.partition {|file| file =~ /^@@@@/}
  annotated_files.map! {|file| file.gsub('@@@@','') }
  # Matching annotated_files values against real_files to ensure that
  # annotated_files contain full path entries (as returned by make rule)
  annotated_files.map! {|file| real_files.find {|real| !real.match(/^(.*\/)?#{Regexp.escape(file)}$/).nil?}}
  annotated_files = annotated_files.compact

  # Find which of our annotated files 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 files themselves.
  return annotated_files.find_all do |annotated_file|
    # find the index of the "real" file that matches the annotated one.
    idx = real_files.find_index do |real_file|
      real_file =~ /^(.*\/)?#{Regexp.escape(annotated_file)}$/
    end
    # If we found a real file, 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 filess for which a real file was
    # found/deleted
    idx ? real_files.delete_at(idx) : nil
  end.compact
end