Class: PreprocessinatorIncludesHandler

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

Overview

Ceedling - Test-Centered Build System for C
ThrowTheSwitch.org
Copyright (c) 2010-25 Mike Karlesky, Mark VanderVoord, & Greg Williams
SPDX-License-Identifier: MIT

Instance Method Summary collapse

Instance Method Details

#extract_includes(filepath:, test:, flags:, include_paths:, defines:, deep: false) ⇒ Object

Includes Extraction Overview

BACKGROUND


#include extraction is hard to do. In simple cases a regex approach suffices, but nested header files, clever macros, and conditional preprocessing statements easily introduce high complexity.

Unfortunately, there’s no readily available cross-platform C parsing tool that provides a simple means to extract the #include statements directly embedded in a given file. Even the gcc preprocessor itself only comes close to providing this information externally.

APPROACH


(Full details including fallback options are in the extensive code comments among the methods below.)

Sadly, we can’t preprocess a file with full search paths and defines and ask for the #include statements embedded in a file. We get far more #includes than we want with no way to discern which are at the depth of the file being processed.

Instead, we try our best to use some educated guessing to get as close as possible to the desired list.

 I. Try to extract shallow defines with no crawling out into other header files. This conservative approach
    gives us a reference point on possible directly included files. The results may be incomplete, though. 
    They also may mistakenly list #includes that should not be in the list--because of #ifndef defaults or
    because of system headers or #include <...> statements and differences among gcc implementations.

II. Extract a full list of #includes by spidering out into nested headers and processing all macros, etc.
    This is the greedy approach.

III. Find #includes common to (I) and (II). The results of (I) should limit the potentially lengthy

    results of (II). The complete and accurate list of (II) should cut out any mistaken entries in (I).

IV. I–III are not foolproof. A purely greedy approach or a purely conservative approach will cause symbol 
    conflicts, missing symbols, etc. The blended and balanced approach should come quite close to an 
    accurate list of shallow includes. Edge cases and gaps will cause trouble. Other Ceedling features 
    should provide the tools to intervene.


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/preprocessinator_includes_handler.rb', line 52

def extract_includes(filepath:, test:, flags:, include_paths:, defines:, deep: false)
  msg = @reportinator.generate_module_progress(
    operation: "Extracting #include statements via preprocessor from",
    module_name: test,
    filename: File.basename(filepath)
    )
  @loginator.log(msg, Verbosity::NORMAL)

  # Extract shallow includes with preprocessor and fallback regex
  shallow = extract_shallow_includes(
    test:     test,
    filepath: filepath,
    flags:    flags,
    defines:  defines
    )

  # Extract nested includes but optionally act in fallback mode
  nested = extract_nested_includes(
    filepath:      filepath,
    include_paths: include_paths,
    flags:         flags,
    defines:       defines,
    # If no shallow results, fall back to only depth 1 results of nested discovery
    shallow:       shallow.empty?
    )

  # Combine shallow and nested include knowledge of mocks
  mocks = combine_mocks(shallow, nested)

  # Redefine shallow and nested results without any mocks
  shallow = remove_mocks( shallow )
  nested  = remove_mocks( nested )

  # Return
  #  - Includes common to shallow and nested results, with paths from nested
  #  - Add mocks back in (may be empty if mocking not enabled)
  return common_includes(shallow:shallow, nested:nested, deep:deep) + mocks
end

#write_includes_list(filepath, list) ⇒ Object

Write to disk a yaml representation of a list of includes



92
93
94
# File 'lib/ceedling/preprocessinator_includes_handler.rb', line 92

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