rubycc 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +56 -0
  3. data/LICENSE.txt +21 -0
  4. data/NOTICE +52 -0
  5. data/README.md +208 -0
  6. data/data/README.md +117 -0
  7. data/data/r10_corpus_scan.json +4082 -0
  8. data/data/r10_manual_classification.json +5342 -0
  9. data/data/r10_verification_m4a.json +1531 -0
  10. data/data/r10_verification_m4b.json +1818 -0
  11. data/data/r10_verification_m4c.json +1489 -0
  12. data/data/r10_verification_m4d.json +318 -0
  13. data/data/r10_verification_rbs.json +192 -0
  14. data/data/verified_gems.json +397 -0
  15. data/exe/rmake +16 -0
  16. data/exe/rubycc +9 -0
  17. data/exe/rubycc-ar +114 -0
  18. data/exe/rubycc-doctor +14 -0
  19. data/exe/rubycc-pkgconf +8 -0
  20. data/include/float.h +87 -0
  21. data/include/iso646.h +18 -0
  22. data/include/libc/alloca.h +18 -0
  23. data/include/libc/arpa/inet.h +61 -0
  24. data/include/libc/assert.h +43 -0
  25. data/include/libc/dirent.h +72 -0
  26. data/include/libc/dlfcn.h +58 -0
  27. data/include/libc/features.h +205 -0
  28. data/include/libc/glibc/aarch64/ctype.h +108 -0
  29. data/include/libc/glibc/aarch64/endian.h +54 -0
  30. data/include/libc/glibc/aarch64/errno.h +154 -0
  31. data/include/libc/glibc/aarch64/fcntl.h +144 -0
  32. data/include/libc/glibc/aarch64/inttypes.h +182 -0
  33. data/include/libc/glibc/aarch64/limits.h +63 -0
  34. data/include/libc/glibc/aarch64/pthread.h +131 -0
  35. data/include/libc/glibc/aarch64/setjmp.h +84 -0
  36. data/include/libc/glibc/aarch64/stdint.h +174 -0
  37. data/include/libc/glibc/aarch64/sys/epoll.h +88 -0
  38. data/include/libc/glibc/aarch64/sys/fcntl.h +19 -0
  39. data/include/libc/glibc/aarch64/sys/select.h +75 -0
  40. data/include/libc/glibc/aarch64/sys/stat.h +136 -0
  41. data/include/libc/glibc/aarch64/sys/syscall.h +167 -0
  42. data/include/libc/glibc/aarch64/sys/time.h +74 -0
  43. data/include/libc/glibc/aarch64/sys/types.h +127 -0
  44. data/include/libc/glibc/aarch64/time.h +113 -0
  45. data/include/libc/glibc/x86_64/ctype.h +108 -0
  46. data/include/libc/glibc/x86_64/endian.h +54 -0
  47. data/include/libc/glibc/x86_64/errno.h +154 -0
  48. data/include/libc/glibc/x86_64/fcntl.h +134 -0
  49. data/include/libc/glibc/x86_64/inttypes.h +182 -0
  50. data/include/libc/glibc/x86_64/limits.h +61 -0
  51. data/include/libc/glibc/x86_64/pthread.h +111 -0
  52. data/include/libc/glibc/x86_64/setjmp.h +82 -0
  53. data/include/libc/glibc/x86_64/stdint.h +163 -0
  54. data/include/libc/glibc/x86_64/sys/epoll.h +91 -0
  55. data/include/libc/glibc/x86_64/sys/fcntl.h +19 -0
  56. data/include/libc/glibc/x86_64/sys/select.h +75 -0
  57. data/include/libc/glibc/x86_64/sys/stat.h +130 -0
  58. data/include/libc/glibc/x86_64/sys/syscall.h +188 -0
  59. data/include/libc/glibc/x86_64/sys/time.h +74 -0
  60. data/include/libc/glibc/x86_64/sys/types.h +123 -0
  61. data/include/libc/glibc/x86_64/time.h +113 -0
  62. data/include/libc/grp.h +50 -0
  63. data/include/libc/langinfo.h +126 -0
  64. data/include/libc/link.h +18 -0
  65. data/include/libc/locale.h +83 -0
  66. data/include/libc/math.h +191 -0
  67. data/include/libc/netinet/in.h +126 -0
  68. data/include/libc/netinet/tcp.h +44 -0
  69. data/include/libc/poll.h +46 -0
  70. data/include/libc/pwd.h +58 -0
  71. data/include/libc/regex.h +53 -0
  72. data/include/libc/sched.h +35 -0
  73. data/include/libc/signal.h +204 -0
  74. data/include/libc/stdio.h +157 -0
  75. data/include/libc/stdlib.h +92 -0
  76. data/include/libc/string.h +74 -0
  77. data/include/libc/strings.h +25 -0
  78. data/include/libc/sys/cdefs.h +126 -0
  79. data/include/libc/sys/inotify.h +111 -0
  80. data/include/libc/sys/ioctl.h +36 -0
  81. data/include/libc/sys/mman.h +65 -0
  82. data/include/libc/sys/param.h +41 -0
  83. data/include/libc/sys/resource.h +109 -0
  84. data/include/libc/sys/socket.h +167 -0
  85. data/include/libc/sys/statfs.h +82 -0
  86. data/include/libc/sys/timerfd.h +55 -0
  87. data/include/libc/sys/uio.h +40 -0
  88. data/include/libc/sys/un.h +25 -0
  89. data/include/libc/sys/utsname.h +35 -0
  90. data/include/libc/sys/wait.h +135 -0
  91. data/include/libc/termios.h +179 -0
  92. data/include/libc/unistd.h +194 -0
  93. data/include/stdalign.h +16 -0
  94. data/include/stdarg.h +31 -0
  95. data/include/stdatomic.h +158 -0
  96. data/include/stdbool.h +15 -0
  97. data/include/stdckdint.h +28 -0
  98. data/include/stddef.h +60 -0
  99. data/include/stdnoreturn.h +18 -0
  100. data/include/x86intrin.h +16 -0
  101. data/lib/rubycc/backend/aarch64.rb +1724 -0
  102. data/lib/rubycc/backend/x86_64.rb +1369 -0
  103. data/lib/rubycc/compile_error.rb +36 -0
  104. data/lib/rubycc/compiler.rb +305 -0
  105. data/lib/rubycc/doctor/builder.rb +151 -0
  106. data/lib/rubycc/doctor/cli.rb +190 -0
  107. data/lib/rubycc/doctor/fetcher.rb +84 -0
  108. data/lib/rubycc/doctor/gemfile.rb +115 -0
  109. data/lib/rubycc/doctor/verified_gems.rb +114 -0
  110. data/lib/rubycc/doctor.rb +16 -0
  111. data/lib/rubycc/driver.rb +463 -0
  112. data/lib/rubycc/front/ast.rb +528 -0
  113. data/lib/rubycc/front/constant_evaluator.rb +631 -0
  114. data/lib/rubycc/front/initializer_resolver.rb +592 -0
  115. data/lib/rubycc/front/lexeme_reader.rb +460 -0
  116. data/lib/rubycc/front/lexer.rb +232 -0
  117. data/lib/rubycc/front/parser.rb +4122 -0
  118. data/lib/rubycc/front/token.rb +49 -0
  119. data/lib/rubycc/ir/call_convention.rb +486 -0
  120. data/lib/rubycc/ir/generator.rb +6036 -0
  121. data/lib/rubycc/ir/ir.rb +417 -0
  122. data/lib/rubycc/link/compat_runtime.rb +89 -0
  123. data/lib/rubycc/link/errors.rb +13 -0
  124. data/lib/rubycc/link/executable_linker.rb +405 -0
  125. data/lib/rubycc/link/library_resolver.rb +437 -0
  126. data/lib/rubycc/link/partial_linker.rb +546 -0
  127. data/lib/rubycc/link/shared_linker.rb +1732 -0
  128. data/lib/rubycc/mkmf_shim.rb +83 -0
  129. data/lib/rubycc/objfile/ar_archive.rb +437 -0
  130. data/lib/rubycc/objfile/elf_reader.rb +646 -0
  131. data/lib/rubycc/objfile/elf_writer.rb +891 -0
  132. data/lib/rubycc/objfile/relocatable_writer.rb +376 -0
  133. data/lib/rubycc/pkgconf/cli.rb +139 -0
  134. data/lib/rubycc/pkgconf/errors.rb +39 -0
  135. data/lib/rubycc/pkgconf/model.rb +28 -0
  136. data/lib/rubycc/pkgconf/parser.rb +109 -0
  137. data/lib/rubycc/pkgconf/pkgconf.rb +15 -0
  138. data/lib/rubycc/pkgconf/resolver.rb +70 -0
  139. data/lib/rubycc/pkgconf/search_path.rb +38 -0
  140. data/lib/rubycc/pkgconf/system_path_filter.rb +131 -0
  141. data/lib/rubycc/preprocess/constant_expression.rb +219 -0
  142. data/lib/rubycc/preprocess/glibc_version.rb +124 -0
  143. data/lib/rubycc/preprocess/pp_token.rb +62 -0
  144. data/lib/rubycc/preprocess/preprocessor.rb +2020 -0
  145. data/lib/rubycc/preprocess/scanner.rb +290 -0
  146. data/lib/rubycc/preprocess/token_converter.rb +157 -0
  147. data/lib/rubycc/rmake/cli.rb +143 -0
  148. data/lib/rubycc/rmake/errors.rb +71 -0
  149. data/lib/rubycc/rmake/executor.rb +818 -0
  150. data/lib/rubycc/rmake/expander.rb +251 -0
  151. data/lib/rubycc/rmake/makefile.rb +352 -0
  152. data/lib/rubycc/rmake/model.rb +137 -0
  153. data/lib/rubycc/rmake/parser.rb +226 -0
  154. data/lib/rubycc/rmake/rmake.rb +15 -0
  155. data/lib/rubycc/type.rb +1236 -0
  156. data/lib/rubycc/version.rb +5 -0
  157. data/lib/rubycc.rb +36 -0
  158. data/lib/rubygems_plugin.rb +102 -0
  159. metadata +219 -0
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rubycc
4
+ module Rmake
5
+ # A make variable. The flavor decides *when* the right-hand side is expanded:
6
+ # a recursive (`=`) variable keeps its text verbatim and is expanded afresh
7
+ # on every reference, so it can see values defined later; a simple (`:=`)
8
+ # variable is expanded once at definition and thereafter holds a plain
9
+ # string. `?=` produces a recursive variable (only when the name is unset)
10
+ # and `+=` appends in whichever flavor the variable already has.
11
+ class Variable
12
+ attr_reader :flavor, :value
13
+
14
+ def initialize(flavor, value)
15
+ @flavor = flavor
16
+ @value = value
17
+ end
18
+
19
+ def simple?
20
+ @flavor == :simple
21
+ end
22
+
23
+ def recursive?
24
+ @flavor == :recursive
25
+ end
26
+ end
27
+
28
+ # An explicit rule as written: its target and prerequisite words and recipe
29
+ # lines are stored unexpanded, because make expands them against the final
30
+ # variable table (all mkmf assignments precede the rules that use them). A
31
+ # `::` rule sets +double_colon+; +order+ is the read order, used only to pick
32
+ # the default goal (the first non-special target seen).
33
+ class ExplicitRule
34
+ attr_reader :targets, :prerequisites, :recipe, :order
35
+
36
+ def initialize(targets:, prerequisites:, recipe:, double_colon:, order:)
37
+ @targets = targets
38
+ @prerequisites = prerequisites
39
+ @recipe = recipe
40
+ @double_colon = double_colon
41
+ @order = order
42
+ end
43
+
44
+ def double_colon?
45
+ @double_colon
46
+ end
47
+ end
48
+
49
+ # A double-suffix inference rule such as `.c.o:` — build a `to_suffix` file
50
+ # from a same-stem `from_suffix` file using +recipe+.
51
+ class SuffixRule
52
+ attr_reader :from_suffix, :to_suffix, :recipe
53
+
54
+ def initialize(from_suffix:, to_suffix:, recipe:)
55
+ @from_suffix = from_suffix
56
+ @to_suffix = to_suffix
57
+ @recipe = recipe
58
+ end
59
+ end
60
+
61
+ # One shell command in an execution step: its expanded text with the
62
+ # recipe-line prefixes already interpreted. +silent+ (`@`), +ignore_error+
63
+ # (`-`) and +force+ (`+`) are retained as attributes so a dumper can show
64
+ # them; B1 only plans, it does not run anything.
65
+ class Command
66
+ attr_reader :text, :silent, :ignore_error, :force
67
+
68
+ def initialize(text:, silent:, ignore_error:, force:)
69
+ @text = text
70
+ @silent = silent
71
+ @ignore_error = ignore_error
72
+ @force = force
73
+ end
74
+
75
+ def silent?
76
+ @silent
77
+ end
78
+
79
+ def ignore_error?
80
+ @ignore_error
81
+ end
82
+
83
+ def force?
84
+ @force
85
+ end
86
+ end
87
+
88
+ # A single node of the execution plan: the target that would be (re)built and
89
+ # the ordered, fully-expanded commands that would build it. +prereqs+ names
90
+ # the other steps that must complete before this one may start — the edges a
91
+ # parallel scheduler (B3 `-j`) needs. It is empty for a step with no stale
92
+ # step among its prerequisites, and the sequential runner ignores it entirely
93
+ # (the plan is already emitted in a valid dependency order).
94
+ class Step
95
+ attr_reader :target, :commands
96
+ attr_accessor :prereqs
97
+
98
+ def initialize(target:, commands:, prereqs: [])
99
+ @target = target
100
+ @commands = commands
101
+ @prereqs = prereqs
102
+ end
103
+ end
104
+
105
+ # The result of Makefile#plan: the steps in the order make would run them
106
+ # (prerequisites before dependents). It carries no execution logic — the
107
+ # recipe runner is B2.
108
+ class Plan
109
+ attr_reader :steps
110
+
111
+ def initialize(steps)
112
+ @steps = steps
113
+ end
114
+
115
+ # The command texts in execution order, one per line — the shape a
116
+ # `make -n` transcript takes, used by the golden tests.
117
+ def command_lines
118
+ @steps.flat_map { |step| step.commands.map(&:text) }
119
+ end
120
+
121
+ # A human-readable dump that, unlike #command_lines, keeps the target
122
+ # boundaries and the +@+/+-+/+++ prefix attributes visible.
123
+ def dump
124
+ @steps.map do |step|
125
+ lines = step.commands.map do |cmd|
126
+ flags = +""
127
+ flags << "@" if cmd.silent?
128
+ flags << "-" if cmd.ignore_error?
129
+ flags << "+" if cmd.force?
130
+ " #{flags.empty? ? '' : "#{flags} "}#{cmd.text}"
131
+ end
132
+ (["#{step.target}:"] + lines).join("\n")
133
+ end.join("\n")
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,226 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "errors"
4
+ require_relative "model"
5
+ require_relative "expander"
6
+
7
+ module Rubycc
8
+ module Rmake
9
+ # Turns Makefile text into the raw model — variables plus explicit rules with
10
+ # their recipes — that Makefile then resolves into suffix rules, phony
11
+ # targets, the suffix list and a dependency graph. The parser accepts only
12
+ # the constructs the mkmf corpus (test/fixtures/mkmf) actually emits:
13
+ # variable assignments in all four flavours, backslash line continuation,
14
+ # `#` comments, explicit rules (single and double colon, with tab recipes)
15
+ # and the `.c.o:`-style two-suffix inference rules. Anything it cannot place
16
+ # is a ParseError rather than a silent skip, so an unsupported Makefile fails
17
+ # loudly instead of mis-building.
18
+ class Parser
19
+ # A variable name: letters, digits and underscore, not starting with a
20
+ # digit. mkmf never uses dotted or otherwise exotic names, so keeping this
21
+ # narrow is what lets a leading-dot line (`.PHONY:`, `.c.o:`) fall through
22
+ # to rule handling instead of being mistaken for an assignment.
23
+ NAME = /[A-Za-z_][A-Za-z0-9_]*/
24
+
25
+ # An assignment is a name, optional spaces, then an operator anchored right
26
+ # after the name. `+=`/`?=`/`::=`/`:=` are tried before bare `=`, and all
27
+ # of them before a rule's `:` can match, so `all: dep` (colon then space)
28
+ # is never read as `:=`.
29
+ ASSIGN = /\A[ \t]*(#{NAME})[ \t]*(\+=|\?=|::=|:=|=)(.*)\z/
30
+
31
+ # +overrides+ are command-line variable definitions (make's `VAR=value`
32
+ # operands): they are seeded before parsing and win over any assignment the
33
+ # Makefile makes to the same name, which is make's rule that a command-line
34
+ # variable overrides a makefile variable. They are stored as simple
35
+ # (already-expanded) variables so a `:=` assignment referencing one during
36
+ # the parse sees the command-line value.
37
+ #
38
+ # +defaults+ are POSIX's built-in variables (currently just `MAKE`): unlike
39
+ # +overrides+ they are ordinary variables once seeded, so a Makefile
40
+ # assignment to the same name replaces them exactly as it would replace any
41
+ # other pre-existing value. They are seeded first so an override (or a
42
+ # Makefile assignment) to the same name still wins.
43
+ def initialize(overrides: {}, defaults: {})
44
+ @variables = {}
45
+ @rules = []
46
+ @order = 0
47
+ @current_rule = nil
48
+ @expander = Expander.new(@variables)
49
+ @overrides = overrides || {}
50
+ (defaults || {}).each { |name, value| @variables[name] = Variable.new(:simple, value.to_s) }
51
+ @overrides.each { |name, value| @variables[name] = Variable.new(:simple, value.to_s) }
52
+ end
53
+
54
+ attr_reader :variables, :rules
55
+
56
+ def self.parse(text, overrides: {}, defaults: {})
57
+ new(overrides: overrides, defaults: defaults).tap { |p| p.run(text) }
58
+ end
59
+
60
+ def run(text)
61
+ logical_lines(text).each do |content, kind, line_no|
62
+ if kind == :recipe
63
+ handle_recipe(content, line_no)
64
+ else
65
+ handle_normal(content, line_no)
66
+ end
67
+ end
68
+ self
69
+ end
70
+
71
+ private
72
+
73
+ # --- physical -> logical lines (continuation handling) ---------------
74
+
75
+ # Fold backslash-continued physical lines into logical lines, tagging each
76
+ # as a recipe (started with a tab) or a normal line. A continuation and the
77
+ # following line's leading whitespace collapse to a single space, matching
78
+ # make; this is exercised by the unit tests since the corpus itself has no
79
+ # continuations.
80
+ def logical_lines(text)
81
+ physical = text.split("\n", -1)
82
+ result = []
83
+ i = 0
84
+ while i < physical.length
85
+ raw = physical[i]
86
+ start_line = i + 1
87
+ recipe = raw.start_with?("\t")
88
+ buf = raw
89
+ while continuation?(buf)
90
+ buf = drop_trailing_backslash(buf)
91
+ i += 1
92
+ nxt = (physical[i] || "")
93
+ nxt = nxt.sub(/\A\t/, "") if recipe
94
+ buf = "#{buf.rstrip} #{nxt.lstrip}"
95
+ end
96
+ result << [buf, recipe ? :recipe : :normal, start_line]
97
+ i += 1
98
+ end
99
+ result
100
+ end
101
+
102
+ # A line continues when it ends with an odd number of backslashes (an even
103
+ # number is that many escaped literal backslashes with no continuation).
104
+ def continuation?(line)
105
+ m = line.match(/(\\+)\z/)
106
+ m && m[1].length.odd?
107
+ end
108
+
109
+ def drop_trailing_backslash(line)
110
+ line.sub(/\\\z/, "")
111
+ end
112
+
113
+ # --- normal (non-recipe) lines ---------------------------------------
114
+
115
+ def handle_normal(content, line_no)
116
+ stripped = strip_comment(content)
117
+ return if stripped.strip.empty?
118
+
119
+ if (m = ASSIGN.match(stripped))
120
+ @current_rule = nil
121
+ apply_assignment(m[1], m[2], m[3])
122
+ elsif stripped.include?(":")
123
+ parse_rule(stripped, line_no)
124
+ else
125
+ raise ParseError.new("cannot parse line: #{content.strip.inspect}", line_number: line_no)
126
+ end
127
+ end
128
+
129
+ # Strip a `#` comment. `\#` is an escaped literal hash. Recipe lines are
130
+ # never passed here, so `#` inside a recipe stays intact for the shell.
131
+ def strip_comment(line)
132
+ out = +""
133
+ i = 0
134
+ while i < line.length
135
+ c = line[i]
136
+ if c == "\\" && line[i + 1] == "#"
137
+ out << "#"
138
+ i += 2
139
+ elsif c == "#"
140
+ break
141
+ else
142
+ out << c
143
+ i += 1
144
+ end
145
+ end
146
+ out
147
+ end
148
+
149
+ def apply_assignment(name, op, rhs)
150
+ # A command-line override wins over every makefile assignment to the same
151
+ # name (make's precedence rule), so ignore the assignment entirely.
152
+ return if @overrides.key?(name)
153
+
154
+ # make strips leading whitespace after the operator but keeps trailing
155
+ # whitespace in the value (a documented make behaviour the golden tests
156
+ # depend on, e.g. `dldflags = ... zlib ` contributes its trailing space).
157
+ value = rhs.sub(/\A[ \t]+/, "")
158
+ case op
159
+ when "="
160
+ @variables[name] = Variable.new(:recursive, value)
161
+ when ":=", "::="
162
+ @variables[name] = Variable.new(:simple, @expander.expand(value))
163
+ when "?="
164
+ @variables[name] ||= Variable.new(:recursive, value)
165
+ when "+="
166
+ append_assignment(name, value)
167
+ end
168
+ end
169
+
170
+ def append_assignment(name, value)
171
+ existing = @variables[name]
172
+ if existing.nil?
173
+ @variables[name] = Variable.new(:recursive, value)
174
+ elsif existing.simple?
175
+ joined = existing.value.empty? ? @expander.expand(value) : "#{existing.value} #{@expander.expand(value)}"
176
+ @variables[name] = Variable.new(:simple, joined)
177
+ else
178
+ joined = existing.value.empty? ? value : "#{existing.value} #{value}"
179
+ @variables[name] = Variable.new(:recursive, joined)
180
+ end
181
+ end
182
+
183
+ # --- rules -----------------------------------------------------------
184
+
185
+ def parse_rule(line, _line_no)
186
+ idx = line.index(":")
187
+ target_part = line[0...idx]
188
+ rest = line[(idx + 1)..]
189
+ double_colon = rest.start_with?(":")
190
+ rest = rest[1..] if double_colon
191
+
192
+ # An inline recipe after `;` (target: dep ; cmd). Absent from the corpus
193
+ # but cheap and part of the grammar.
194
+ inline = nil
195
+ if (semi = rest.index(";"))
196
+ inline = rest[(semi + 1)..].sub(/\A[ \t]+/, "")
197
+ rest = rest[0...semi]
198
+ end
199
+
200
+ @order += 1
201
+ rule = ExplicitRule.new(
202
+ targets: split_words(target_part),
203
+ prerequisites: split_words(rest),
204
+ recipe: [],
205
+ double_colon: double_colon,
206
+ order: @order
207
+ )
208
+ rule.recipe << inline if inline
209
+ @rules << rule
210
+ @current_rule = rule
211
+ end
212
+
213
+ def handle_recipe(content, line_no)
214
+ raise ParseError.new("recipe line has no preceding rule", line_number: line_no) if @current_rule.nil?
215
+
216
+ # Drop only the leading recipe-marker tab; any further indentation is
217
+ # part of the command text (the prefix scanner ignores leading blanks).
218
+ @current_rule.recipe << content.sub(/\A\t/, "")
219
+ end
220
+
221
+ def split_words(text)
222
+ text.split(/[ \t]+/).reject(&:empty?)
223
+ end
224
+ end
225
+ end
226
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rmake — the mkmf-Makefile subset (M3 / DESIGN R5). It ships the parser, the
4
+ # variable expander, the dependency-graph planner, the shell-less runner and the
5
+ # CLI (exe/rmake, B6) that RubyGems drives as `$(MAKE)`. This aggregate require is
6
+ # the entry point; it stays self-contained — depending on nothing else in
7
+ # lib/rubycc until a tool-substituting run reaches for the Driver — so it can be
8
+ # loaded on its own from the tests.
9
+ require_relative "errors"
10
+ require_relative "model"
11
+ require_relative "expander"
12
+ require_relative "parser"
13
+ require_relative "makefile"
14
+ require_relative "executor"
15
+ require_relative "cli"