Class: PreprocessinatorIncludesHandler

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

Instance Method Summary collapse

Instance Method Details

#extract_bare_includes(test:, filepath:, search_paths:, flags:, defines:) ⇒ Object



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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
# File 'lib/ceedling/preprocess/preprocessinator_includes_handler.rb', line 33

def extract_bare_includes(test:, filepath:, search_paths:, flags:, defines:)
  filename = File.basename(filepath)

  msg = @reportinator.generate_module_progress(
    operation: "Extracting bare #includes via preprocessing from",
    module_name: test,
    filename: filename
  )
  @loginator.log( msg, Verbosity::OBNOXIOUS )

  # Creation:
  #  - This output is created with the -MM -MG -MP command line options.
  #  - Limited search paths are used towards shallow extracting of only the user #include statements of the file.
  #    This preprocessor mode assumes any includes discovered outside of a search path will be generated.
  #
  # Notes:
  #  - This approach can have gaps with advacnced user-level macros like `#include <MACRO>`.
  #    By including Ceedling's vendor search path, we support Partials macros of this sort.
  #  - Gaps can be minimized with proper defines in the project file. However, needed, complex macros 
  #    located in other header files could still gum up the works.
  #  - Many errors can occur but may not necessarily prevent usable results.
  command = 
    @tool_executor.build_command_line(
      @configurator.tools_test_bare_includes_preprocessor,
      # No additional arguments
      [],
      # Argument replacement
      filepath,
      defines,
      flags,
      search_paths
    )

  # Assume possible errors so we have best shot at extracting results from preprocessing.
  # Full code compilation will catch any breaking code errors
  command[:options][:boom] = false
  shell_result = @tool_executor.exec( command )

  make_rules = shell_result[:output]

  # Do not check exit code for success. In some error conditions we still get usable output.
  # Look for the first line of the make rule output.
  if not make_rules =~ PreprocessinatorBareIncludesExtractor::MAKE_RULE_MATCHER
    @loginator.lazy( Verbosity::DEBUG ) do
      "Preprocessor bare #include extraction failed: #{shell_result[:output]}"
    end
    return []
  end

  includes = PreprocessinatorBareIncludesExtractor.extract_includes( make_rules )
  includes = clean_self_reference(filepath, includes)

  header = "Extracted bare #includes from #{filepath}:"
  @loginator.log_list( includes, header, Verbosity::DEBUG )

  return includes
end

#extract_system_includes_from_text(name:, filepath:, defines: []) ⇒ Object



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/ceedling/preprocess/preprocessinator_includes_handler.rb', line 163

def extract_system_includes_from_text(name:, filepath:, defines: [])
  includes = []

  filename = File.basename(filepath)

  msg = @reportinator.generate_module_progress(
    operation: "Extracting system #includes from original file using fallback method",
    module_name: name,
    filename: filename
  )
  @loginator.log( msg, Verbosity::OBNOXIOUS, LogLabels::WARNING )

  cond_tracker = CPreprocessorConditionals.new( defines )

  # Open in binary mode: code_lines applies clean_encoding per-line, but each_line
  # itself can raise on invalid byte sequences before clean_encoding is reached.
  @file_wrapper.open(filepath, 'rb') do |input|
    @parsing_parcels.code_lines( input ) do |line|
      cond_tracker.process_directive( line )
      next unless cond_tracker.active?
      _include = @include_factory.system_include_from_directive( line )
      includes << _include if !_include.nil?
    end
  end

  return clean_self_reference( filepath, includes )
end

#extract_system_includes_preprocess(name:, filepath:, preprocessed_filepath:) ⇒ Object



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/ceedling/preprocess/preprocessinator_includes_handler.rb', line 141

def extract_system_includes_preprocess(name:, filepath:, preprocessed_filepath:)
  includes = []

  filename = File.basename(filepath)

  msg = @reportinator.generate_module_progress(
    operation: "Extracting system #includes from preprocessed output",
    module_name: name,
    filename: filename
  )
  @loginator.log(msg, Verbosity::OBNOXIOUS)

  includes = 
    @line_marker_includes_extractor.extract_includes_from_file(
      preprocessed_filepath,
      PreprocessinatorLineMarkerIncludesExtractor::SYSTEM,
      5 # Practical max depth limit for system headers (to avoid noisy length)
    )

  return clean_self_reference( filepath, includes )
end

#extract_user_includes_from_text(name:, filepath:, defines: []) ⇒ Object



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
# File 'lib/ceedling/preprocess/preprocessinator_includes_handler.rb', line 113

def extract_user_includes_from_text(name:, filepath:, defines: [])
  includes = []

  filename = File.basename(filepath)

  msg = @reportinator.generate_module_progress(
    operation: "Extracting user #includes from original file using fallback method",
    module_name: name,
    filename: filename
  )
  @loginator.log( msg, Verbosity::OBNOXIOUS, LogLabels::WARNING )

  cond_tracker = CPreprocessorConditionals.new( defines )

  # Open in binary mode: code_lines applies clean_encoding per-line, but each_line
  # itself can raise on invalid byte sequences before clean_encoding is reached.
  @file_wrapper.open(filepath, 'rb') do |input|
    @parsing_parcels.code_lines( input ) do |line|
      cond_tracker.process_directive( line )
      next unless cond_tracker.active?
      _include = @include_factory.user_include_from_directive( line )
      includes << _include if !_include.nil?
    end
  end

  return clean_self_reference( filepath, includes )
end

#extract_user_includes_preprocess(name:, filepath:, preprocessed_filepath:) ⇒ Object



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/ceedling/preprocess/preprocessinator_includes_handler.rb', line 91

def extract_user_includes_preprocess(name:, filepath:, preprocessed_filepath:)
  includes = []

  filename = File.basename(filepath)

  msg = @reportinator.generate_module_progress(
    operation: "Extracting user #includes from preprocessed output",
    module_name: name,
    filename: filename
  )
  @loginator.log(msg, Verbosity::OBNOXIOUS)

  includes = 
    @line_marker_includes_extractor.extract_includes_from_file(
      preprocessed_filepath,
      PreprocessinatorLineMarkerIncludesExtractor::USER
      # Note: No limit to max depth to search for user includes
    )

  return clean_self_reference( filepath, includes )
end

#load_includes_list(filepath) ⇒ Object



196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/ceedling/preprocess/preprocessinator_includes_handler.rb', line 196

def load_includes_list(filepath)
  loaded = begin
    @yaml_wrapper.load( filepath )
  rescue YamlLoadException => e
    raise YamlLoadException.new(
      reason: e.reason, source: e.source, original_error: e.original_error,
      message: "Cached #include list is corrupted or unreadable ⏩️ #{e.message}"
    )
  end

  # Note: It's possible empty YAML content returns nil so ensure empty list
  return Includes.from_hashes( loaded || [] )
end

#setupObject



28
29
30
31
# File 'lib/ceedling/preprocess/preprocessinator_includes_handler.rb', line 28

def setup()
  # Aliases
  @line_marker_includes_extractor = @preprocessinator_line_marker_includes_extractor
end

#write_includes_list(filepath, list) ⇒ Object

Write to disk a yaml representation of a list of includes



192
193
194
# File 'lib/ceedling/preprocess/preprocessinator_includes_handler.rb', line 192

def write_includes_list(filepath, list)
  @yaml_wrapper.dump(filepath, Includes.to_hashes(list))
end