Class: GeneratorPartials

Inherits:
Object show all
Defined in:
lib/ceedling/generators/generator_partials.rb

Instance Method Summary collapse

Instance Method Details

#generate_implementation(test:, name:, function_definitions:, source_includes:, header_includes:, c_module:, output_path:) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/ceedling/generators/generator_partials.rb', line 17

def generate_implementation(
    test:,
    name:,
    function_definitions:,
    source_includes:,
    header_includes:,
    c_module:,
    output_path:
  )
  source = @file_path_utils.form_partial_implementation_source_filename(name)
  header = @file_path_utils.form_partial_implementation_header_filename(name)

  header_filepath = File.join(output_path, header)
  source_filepath = File.join(output_path, source)

  # Binary mode: the function bodies written below may already contain their
  # own line endings verbatim. Windows text mode rewrites every "\n" on
  # write, which would alter any line ending already present in that
  # content instead of passing it through unchanged.
  @file_wrapper.open(header_filepath, 'wb') do |file|
    generate_header(file, header, header_includes, function_definitions, c_module, true)
  end

  @file_wrapper.open(source_filepath, 'wb') do |file|
    generate_source(file, source_includes, function_definitions, c_module)
  end

  return source_filepath
end

#generate_interface(test:, name:, function_declarations:, includes:, c_module:, output_path:) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
# File 'lib/ceedling/generators/generator_partials.rb', line 47

def generate_interface(test:, name:, function_declarations:, includes:, c_module:, output_path:)
  header = @file_path_utils.form_partial_interface_header_filename(name)
  filepath = File.join(output_path, header)

  # Binary mode: see generate_implementation above.
  @file_wrapper.open(filepath, 'wb') do |file|
    generate_header(file, header, includes, function_declarations, c_module, false)
  end

  return filepath
end

#generate_types(name:, c_module:, output_path:) ⇒ String?

A module's typedefs and aggregate (struct/enum/union) definitions are the same regardless of which functions a given test file chooses to test versus mock, so they're generated once here into their own header rather than by generate_header itself. Both the implementation and interface headers then simply #include this file, which means a module tested and mocked in the same test file -- each side producing its own generated header -- never ends up with two separate C definitions of the same type in one translation unit. Nothing is written and nil is returned when a module has no such content, since there's then nothing to share.

Parameters:

  • name (String)

    Partial module name (used to form the filename and include guard)

  • c_module (CExtractorTypes::CModule)

    Merged module with type_definitions/aggregate_definitions

  • output_path (String)

    Directory shared with the implementation and interface headers

Returns:

  • (String, nil)

    The bare filename (for use as a sibling #include), or nil if nothing was generated



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/ceedling/generators/generator_partials.rb', line 72

def generate_types(name:, c_module:, output_path:)
  return nil if c_module.type_definitions.empty? && c_module.aggregate_definitions.empty?

  header = @file_path_utils.form_partial_types_header_filename(name)
  filepath = File.join(output_path, header)

  # Binary mode: see generate_implementation above.
  @file_wrapper.open(filepath, 'wb') do |file|
    guard = FileWrapper.generate_include_guard(header)
    file << "#ifndef #{guard}\n"
    file << "#define #{guard}\n\n"

    anything_emitted = false
    pending_macros = []

    c_module.element_sequence.each do |item|
      next unless item.is_a?(CExtractorTypes::CStatement)

      if c_module.macro_definitions.include?(item)
        pending_macros << item
        next
      end

      next unless type_defining?(item, c_module)

      # A typedef/struct/enum moved here may depend on a macro (e.g. an array-size
      # constant) that preceded it in the original source -- this header is #included
      # before any macro generate_header later emits inline into the non-shared
      # header, so that macro would otherwise be undefined here. Carrying it forward
      # is safe: an identical #define may legally repeat, so generate_header's own
      # unmodified inline copy causes no redefinition conflict.
      pending_macros.each { |macro| file << macro.text << "\n" }
      pending_macros.clear

      file << item.text << "\n"
      anything_emitted = true
    end

    file << "\n" if anything_emitted
    file << "#endif // #{guard}\n\n"
  end

  return header
end