Class: Rubycc::Rmake::Makefile
- Inherits:
-
Object
- Object
- Rubycc::Rmake::Makefile
- Defined in:
- lib/rubycc/rmake/makefile.rb
Overview
The public entry point: parse Makefile text, then answer "what would make
do?" for a goal as an execution Plan. It resolves the raw rules the Parser
produced into a working graph — a per-target index of explicit
prerequisites and recipes, the .c.o: suffix rules, the .PHONY/
.SUFFIXES special targets and VPATH — and walks that graph in
dependency order, comparing timestamps to decide which targets are stale.
It only plans: recipes are expanded and their @/-/+ prefixes
interpreted, but nothing is run (the runner is B2).
Constant Summary collapse
- SUFFIX_TARGET =
A target that names its own inference:
.c.obuilds.ofrom.c. Two dots and nothing else, which is how it stays distinct from the one-dot special targets.PHONY/.SUFFIXES. /\A(\.[^.\s]+)(\.[^.\s]+)\z/
Instance Attribute Summary collapse
-
#default_goal ⇒ Object
readonly
Returns the value of attribute default_goal.
-
#dir ⇒ Object
readonly
Returns the value of attribute dir.
-
#phony ⇒ Object
readonly
Returns the value of attribute phony.
-
#suffixes ⇒ Object
readonly
Returns the value of attribute suffixes.
-
#variables ⇒ Object
readonly
Returns the value of attribute variables.
Class Method Summary collapse
-
.parse(text, dir: ".", overrides: {}, defaults: {}) ⇒ Object
overridesare command-line variable definitions (make'sVAR=valueoperands) that take precedence over the Makefile's own assignments;defaultsare POSIX's built-in variables (currently justMAKE, seeded by CLI).
Instance Method Summary collapse
-
#initialize(variables, rules, dir: ".") ⇒ Makefile
constructor
A new instance of Makefile.
-
#plan(goal = nil, now: Time.now) ⇒ Object
Compute the execution plan for
goal(the default goal when omitted), judging staleness against the filesystem as ofnowis implicit in the file mtimes read from #dir. -
#run(goal = nil, out: $stdout, err: $stderr, dry_run: false, env: ENV, now: Time.now, tools: nil, jobs: 1) ⇒ Object
Plan
goaland then run it through the shell-less Executor (B2/B3). -
#tool_programs ⇒ Object
The set of program names a
-tools run substitutes for rubycc: the first word of$(CC)and of$(LDSHARED)(the compile and shared-link drivers mkmf emits). -
#variable_value(name) ⇒ Object
The fully-expanded value of a variable (empty string when undefined).
Constructor Details
#initialize(variables, rules, dir: ".") ⇒ Makefile
Returns a new instance of Makefile.
38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/rubycc/rmake/makefile.rb', line 38 def initialize(variables, rules, dir: ".") @variables = variables @dir = dir @expander = Expander.new(@variables) @explicit = {} # target name => {prereqs:, recipe:, double_colon:} @suffix_rules = [] # SuffixRule @phony = [] @suffixes = [] @default_goal = nil index_rules(rules) end |
Instance Attribute Details
#default_goal ⇒ Object (readonly)
Returns the value of attribute default_goal.
25 26 27 |
# File 'lib/rubycc/rmake/makefile.rb', line 25 def default_goal @default_goal end |
#dir ⇒ Object (readonly)
Returns the value of attribute dir.
25 26 27 |
# File 'lib/rubycc/rmake/makefile.rb', line 25 def dir @dir end |
#phony ⇒ Object (readonly)
Returns the value of attribute phony.
25 26 27 |
# File 'lib/rubycc/rmake/makefile.rb', line 25 def phony @phony end |
#suffixes ⇒ Object (readonly)
Returns the value of attribute suffixes.
25 26 27 |
# File 'lib/rubycc/rmake/makefile.rb', line 25 def suffixes @suffixes end |
#variables ⇒ Object (readonly)
Returns the value of attribute variables.
25 26 27 |
# File 'lib/rubycc/rmake/makefile.rb', line 25 def variables @variables end |
Class Method Details
.parse(text, dir: ".", overrides: {}, defaults: {}) ⇒ Object
overrides are command-line variable definitions (make's VAR=value
operands) that take precedence over the Makefile's own assignments;
defaults are POSIX's built-in variables (currently just MAKE, seeded
by CLI). Both are threaded to the Parser, which seeds them — protecting
overrides from any Makefile assignment, but leaving defaults as
ordinary variables a Makefile assignment can replace.
33 34 35 36 |
# File 'lib/rubycc/rmake/makefile.rb', line 33 def self.parse(text, dir: ".", overrides: {}, defaults: {}) parsed = Parser.parse(text, overrides: overrides, defaults: defaults) new(parsed.variables, parsed.rules, dir: dir) end |
Instance Method Details
#plan(goal = nil, now: Time.now) ⇒ Object
Compute the execution plan for goal (the default goal when omitted),
judging staleness against the filesystem as of now is implicit in the
file mtimes read from #dir. Returns a Plan of steps in the order make
would run them.
54 55 56 57 58 59 60 61 62 63 |
# File 'lib/rubycc/rmake/makefile.rb', line 54 def plan(goal = nil, now: Time.now) @now = now goal ||= @default_goal raise RmakeError, "no target specified and the Makefile has no default goal" if goal.nil? @steps = [] @state = {} build(goal) Plan.new(@steps) end |
#run(goal = nil, out: $stdout, err: $stderr, dry_run: false, env: ENV, now: Time.now, tools: nil, jobs: 1) ⇒ Object
Plan goal and then run it through the shell-less Executor (B2/B3). This
is the "make it" entry point that pairs with #plan (the "what would make
do" entry point). dry_run prints the recipe lines without running them
(make -n) and matches #plan's #command_lines.
tools turns on in-process tool substitution (B3): when truthy the
recipe commands whose argv is this Makefile's compiler/linker program
(the first word of $(CC) / $(LDSHARED), normally "gcc") are run by
rubycc's own Driver in a forked child instead of being exec'd, so no
external compiler is needed. It defaults off, leaving the B2 behaviour
(every command exec'd) exactly as it was. jobs is the maximum number of
independent steps to build concurrently (-j; default 1 = sequential).
Returns the Plan that was executed; raises CommandFailedError / UnsupportedRecipeError on the first failing or uninterpretable recipe line.
80 81 82 83 84 85 86 |
# File 'lib/rubycc/rmake/makefile.rb', line 80 def run(goal = nil, out: $stdout, err: $stderr, dry_run: false, env: ENV, now: Time.now, tools: nil, jobs: 1) computed = plan(goal, now: now) Executor.new(dir: @dir, out: out, err: err, dry_run: dry_run, env: env, tools: tools ? tool_programs : [], jobs: jobs).execute(computed) computed end |
#tool_programs ⇒ Object
The set of program names a -tools run substitutes for rubycc: the first
word of $(CC) and of $(LDSHARED) (the compile and shared-link drivers
mkmf emits). $(LDSHARED) is normally $(CC) -shared, so its flag words
already sit inside the expanded recipe and only the leading program name
is matched here; for the mkmf corpus both reduce to "gcc".
93 94 95 96 97 |
# File 'lib/rubycc/rmake/makefile.rb', line 93 def tool_programs [variable_value("CC"), variable_value("LDSHARED")] .map { |value| value.split(/\s+/).reject(&:empty?).first } .compact.uniq end |
#variable_value(name) ⇒ Object
The fully-expanded value of a variable (empty string when undefined).
100 101 102 |
# File 'lib/rubycc/rmake/makefile.rb', line 100 def variable_value(name) @expander.("$(#{name})") end |