Class: Rubycc::Driver

Inherits:
Object
  • Object
show all
Defined in:
lib/rubycc/driver.rb

Overview

The gcc-compatible command-line driver: it reads the same option and input vocabulary a compiler driver is invoked with (rubycc -c -fPIC -Iinc -o x.o x.c, rubycc -shared -o x.so a.o b.o -Llib -lz, rubycc -o prog main.c util.c) and drives the existing compiler and linker components to satisfy it. It owns no compilation or linking logic of its own — it classifies the inputs, picks the output mode gcc's flag precedence dictates, and hands the work to Compiler, SharedLinker, ExecutableLinker and LibraryResolver.

Three modes are selected exactly as gcc selects them: -c compiles each source to an object without linking; -shared links every input into a shared object; the absence of a mode flag links into an executable. A one-shot invocation (-c absent, a .c given) compiles each source in memory and feeds the resulting object bytes straight to the linker, so no intermediate .o is ever written to disk. -E runs the preprocessor only.

Unknown options are handled the tolerant way a build driver must (R6): a documented-but-unmodelled flag family (-O*, -g*, -W*, most -f*, -m*, -std=…, and friends) is accepted and ignored silently, and any other --prefixed token draws a warning and is ignored, so an environment-specific flag mkmf passes never derails a build. A genuine mistake with a definite meaning — a missing -o operand — is still an error.

Defined Under Namespace

Classes: UsageError

Constant Summary collapse

PROG =
"rubycc"
CPP_INPUT_EXTENSIONS =

C++ is outside rubycc's supported language scope (DESIGN §3.3). Keep the list in step with the corpus census gate so a C++ file passed directly to the driver is diagnosed instead of falling through as an object input.

%w[.cpp .cc .cxx .c++ .hpp .hxx .hh].freeze
ARG_CONSUMING_IGNORED =

Options that take a separate operand this driver does not act on. They are recognized only so the operand is not mistaken for an input file; both the option and its argument are skipped. (-isystem and friends are handled separately, as header search directories.)

%w[-Xlinker -z -u -T -MF -MT -MQ -include -isysroot
-aux-info -Xassembler -Xpreprocessor].freeze
SILENT_IGNORE_EXACT =

Bare flags accepted and ignored: linking/codegen switches whose effect this minimal toolchain does not model but whose presence must not be an error.

%w[-pipe -pthread -no-pie -pie -rdynamic -static -s
-nostdlib -nostartfiles -shared-libgcc -static-libgcc
-symbolic -fsyntax-only].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(argv, stdout: $stdout, stderr: $stderr) ⇒ Driver

Returns a new instance of Driver.



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/rubycc/driver.rb', line 69

def initialize(argv, stdout: $stdout, stderr: $stderr)
  @argv = argv
  @out = stdout
  @err = stderr
  @inputs = []          # [{ path:, kind: }] in command-line order
  @output = nil
  @mode_flag = nil      # :compile / :shared / :preprocess (nil => executable)
  @include_paths = []
  @defines = []         # ordered [:define, "NAME[=VAL]"] / [:undef, "NAME"]
  @libraries = []       # -l request strings, in order
  @lib_dirs = []        # -L directories, in order
  @pic = false
  @default_visibility = :default
  @soname = nil
  @system_includes = true  # -nostdinc clears this
  @default_libs = true     # -nodefaultlibs clears this
  @target = nil            # -target/--target; defaults to the host CPU
end

Class Method Details

.run(argv, stdout: $stdout, stderr: $stderr) ⇒ Object

Runs the driver for argv and returns the process exit status (0 on success, 1 on any diagnosed failure). stdout/stderr are injectable so a test can drive the driver in-process and capture its streams.



64
65
66
# File 'lib/rubycc/driver.rb', line 64

def run(argv, stdout: $stdout, stderr: $stderr)
  new(argv, stdout: stdout, stderr: stderr).run
end

Instance Method Details

#runObject



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
# File 'lib/rubycc/driver.rb', line 88

def run
  return print_version if version_requested?

  parse
  dispatch
  0
rescue UsageError => e
  @err.puts "#{PROG}: error: #{e.message}"
  1
rescue CompileError => e
  # A compiler diagnostic already carries its gcc-style file:line:col header
  # and caret, so it is printed verbatim.
  @err.puts e.message
  1
rescue Backend::UnsupportedError => e
  # A construct the selected backend cannot lower yet: valid C the target is
  # not ready for, reported as a diagnostic rather than a Ruby crash.
  @err.puts "#{PROG}: error: #{e.message}"
  1
rescue Link::LinkError => e
  @err.puts "#{PROG}: error: #{e.message}"
  1
rescue Errno::ENOENT => e
  @err.puts "#{PROG}: error: #{e.message}"
  1
end