Class: PreprocessinatorIncludesHandler

Inherits:
Object
  • Object
show all
Defined in:
lib/ceedling/preprocessinator_includes_handler.rb

Constant Summary collapse

@@makefile_cache =
{}

Instance Method Summary collapse

Instance Method Details

#extract_includes(filepath) ⇒ Object

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.



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# 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.has_key?(:project_auto_link_deep_dependencies) or
        !@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) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/ceedling/preprocessinator_includes_handler.rb', line 92

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(/.*#{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
  to_process = []

  if @configurator.project_config_hash.has_key?(:project_auto_link_deep_dependencies) && @configurator.project_config_hash[:project_auto_link_deep_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

    # 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!

    # 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

    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) ⇒ Object

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.



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# 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) ⇒ Object

shallow includes: only those headers a source file explicitly includes



10
11
12
# 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) ⇒ Object



159
160
161
# File 'lib/ceedling/preprocessinator_includes_handler.rb', line 159

def write_shallow_includes_list(filepath, list)
  @yaml_wrapper.dump(filepath, list)
end