Class: PreprocessinatorIncludesHandler
- 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
-
#extract_includes(filepath:, test:, flags:, include_paths:, defines:, deep: false) ⇒ Object
Includes Extraction Overview ============================.
-
#write_includes_list(filepath, list) ⇒ Object
Write to disk a yaml representation of a list of includes.
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 |