metacc 0.2.0 → 0.4.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.
- checksums.yaml +4 -4
- data/bin/metacc +6 -1
- data/lib/metacc/cli.rb +121 -81
- data/lib/metacc/driver.rb +41 -18
- data/lib/metacc/toolchain.rb +179 -114
- data/lib/metacc/version.rb +3 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bb94d9b47a11ec5a78ea57ae19417e6423287918287f675e43579af8015e4c63
|
|
4
|
+
data.tar.gz: b1237b3e41f2ae7ae68066441d742892ca77fd0427dc3e7b8f02b7f92049e535
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4774d4160c9939259634b2625b28a2975360c477c56c53ac689b4208defb698c4fbcbccf829f540583dfb94cf801fc62664e94cc900f52c64c28bfd6f763247c
|
|
7
|
+
data.tar.gz: dfd5493d3789ea3f18dbd1d7a6a15c345fe6eaeb262e022af7a79039bdd7b2707416312fc08e1ca86b333d91520dbb41457f6be5006d30157af934d4fe8b1497
|
data/bin/metacc
CHANGED
|
@@ -7,7 +7,12 @@ require "metacc/cli"
|
|
|
7
7
|
|
|
8
8
|
begin
|
|
9
9
|
MetaCC::CLI.new.run(ARGV)
|
|
10
|
-
rescue MetaCC::
|
|
10
|
+
rescue MetaCC::ToolchainNotFoundError,
|
|
11
|
+
OptionParser::AmbiguousOption,
|
|
12
|
+
OptionParser::MissingArgument,
|
|
13
|
+
OptionParser::NeedlessArgument,
|
|
14
|
+
OptionParser::InvalidArgument,
|
|
15
|
+
OptionParser::InvalidOption => e
|
|
11
16
|
warn "#{$0} error: #{e.message}"
|
|
12
17
|
rescue MetaCC::CompileError => e
|
|
13
18
|
warn e.message
|
data/lib/metacc/cli.rb
CHANGED
|
@@ -9,57 +9,19 @@ module MetaCC
|
|
|
9
9
|
#
|
|
10
10
|
# Usage:
|
|
11
11
|
# metacc <sources...> -o <output> [options] – compile source file(s)
|
|
12
|
-
#
|
|
13
|
-
# General:
|
|
14
|
-
# -Wall -Werror
|
|
15
|
-
# --std=c11 --std=c17 --std=c23
|
|
16
|
-
# --std=c++11 --std=c++14 --std=c++17 --std=c++20 --std=c++23 --std=c++26
|
|
17
|
-
#
|
|
18
|
-
# Linking:
|
|
19
|
-
# -c – compile only; don't link
|
|
20
|
-
# -l, -L - specify linker input
|
|
21
|
-
# --shared – produce a shared library
|
|
22
|
-
# --static – produce a static library
|
|
23
|
-
# --lto - enable link time optimization
|
|
24
|
-
# --strip / -s – strip unneeded symbols
|
|
25
|
-
#
|
|
26
|
-
# Code generation:
|
|
27
|
-
# -O0, -O1, -O2, -O3 - Set the optimization level
|
|
28
|
-
# -msse4.2 -mavx -mavx2 -mavx512 --arch=native - Compile for the given target
|
|
29
|
-
# --no-rtti --no-exceptions
|
|
30
|
-
# --pic
|
|
31
|
-
#
|
|
32
|
-
# Debugging:
|
|
33
|
-
# --debug / -g
|
|
34
|
-
# --asan --ubsan --msan
|
|
35
|
-
#
|
|
36
|
-
# Toolchain-specific flags (passed to Driver#compile via xflags:):
|
|
37
|
-
# --xmsvc VALUE – appended to xflags[MSVC]
|
|
38
|
-
# --xgnu VALUE – appended to xflags[GNU]
|
|
39
|
-
# --xclang VALUE – appended to xflags[Clang]
|
|
40
|
-
# --xclangcl VALUE – appended to xflags[ClangCL]
|
|
41
12
|
class CLI
|
|
42
13
|
|
|
43
|
-
# Maps long-form CLI flag names to Driver::RECOGNIZED_FLAGS symbols.
|
|
44
|
-
# Optimization-level flags are handled separately via -O LEVEL.
|
|
45
|
-
LONG_FLAGS = {
|
|
46
|
-
"lto" => :lto,
|
|
47
|
-
"asan" => :asan,
|
|
48
|
-
"ubsan" => :ubsan,
|
|
49
|
-
"msan" => :msan,
|
|
50
|
-
"no-rtti" => :no_rtti,
|
|
51
|
-
"no-exceptions" => :no_exceptions,
|
|
52
|
-
"pic" => :pic,
|
|
53
|
-
"no-semantic-interposition" => :no_semantic_interposition,
|
|
54
|
-
"no-omit-frame-pointer" => :no_omit_frame_pointer,
|
|
55
|
-
"no-strict-aliasing" => :no_strict_aliasing
|
|
56
|
-
}.freeze
|
|
57
|
-
|
|
58
14
|
WARNING_CONFIGS = {
|
|
59
15
|
"all" => :warn_all,
|
|
60
16
|
"error" => :warn_error
|
|
61
17
|
}
|
|
62
18
|
|
|
19
|
+
SANITIZERS = {
|
|
20
|
+
nil => :sanitize_default,
|
|
21
|
+
"memory" => :sanitize_memory,
|
|
22
|
+
"thread" => :sanitize_thread,
|
|
23
|
+
}
|
|
24
|
+
|
|
63
25
|
TARGETS = {
|
|
64
26
|
"sse4.2" => :sse4_2,
|
|
65
27
|
"avx" => :avx,
|
|
@@ -85,7 +47,8 @@ module MetaCC
|
|
|
85
47
|
"xmsvc" => MSVC,
|
|
86
48
|
"xgnu" => GNU,
|
|
87
49
|
"xclang" => Clang,
|
|
88
|
-
"xclangcl" => ClangCL
|
|
50
|
+
"xclangcl" => ClangCL,
|
|
51
|
+
"xtinycc" => TinyCC
|
|
89
52
|
}.freeze
|
|
90
53
|
|
|
91
54
|
def initialize(driver: Driver.new)
|
|
@@ -110,6 +73,7 @@ module MetaCC
|
|
|
110
73
|
libs: [],
|
|
111
74
|
output_path: nil,
|
|
112
75
|
run: false,
|
|
76
|
+
dry_run: false,
|
|
113
77
|
flags: [],
|
|
114
78
|
xflags: {}
|
|
115
79
|
}
|
|
@@ -122,6 +86,11 @@ module MetaCC
|
|
|
122
86
|
private
|
|
123
87
|
|
|
124
88
|
def setup_compile_options(parser, options)
|
|
89
|
+
parser.require_exact = true
|
|
90
|
+
|
|
91
|
+
parser.separator ""
|
|
92
|
+
parser.separator "General options:"
|
|
93
|
+
|
|
125
94
|
parser.on("-o FILEPATH", "Output file path") do |value|
|
|
126
95
|
options[:output_path] = value
|
|
127
96
|
end
|
|
@@ -131,26 +100,85 @@ module MetaCC
|
|
|
131
100
|
parser.on("-D DEF", "Add a preprocessor definition") do |value|
|
|
132
101
|
options[:defs] << value
|
|
133
102
|
end
|
|
134
|
-
parser.on("
|
|
103
|
+
parser.on("--std=STANDARD", "Specify the language standard") do |value|
|
|
104
|
+
options[:flags] << STANDARDS[value]
|
|
105
|
+
end
|
|
106
|
+
parser.on(
|
|
107
|
+
"-W OPTION", "Configure warnings",
|
|
108
|
+
" -Wall => Enable a broad range of warnings",
|
|
109
|
+
" -Werror => Treat warnings as errrs"
|
|
110
|
+
) do |value|
|
|
111
|
+
options[:flags] << WARNING_CONFIGS[value]
|
|
112
|
+
end
|
|
113
|
+
parser.on("-r", "--run", "Run the compiled executable after a successful build") do
|
|
114
|
+
options[:run] = true
|
|
115
|
+
end
|
|
116
|
+
parser.on("--dry-run", "Print the command that would be issued") do
|
|
117
|
+
options[:dry_run] = true
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
parser.separator ""
|
|
121
|
+
parser.separator "Debugging:"
|
|
122
|
+
|
|
123
|
+
parser.on("-g", "--debug-info", "Emit debugging symbols") do
|
|
124
|
+
options[:flags] << :debug_info
|
|
125
|
+
end
|
|
126
|
+
parser.on(
|
|
127
|
+
"-S", "--sanitize=[SANITIZER]",
|
|
128
|
+
"Enable sanitizer(s)",
|
|
129
|
+
" --sanitize => address, undefined, leak",
|
|
130
|
+
" --sanitize=memory => memory",
|
|
131
|
+
" --sanitize=thread => thread",
|
|
132
|
+
) do |value|
|
|
133
|
+
options[:flags] << SANITIZERS[value]
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
parser.separator ""
|
|
137
|
+
parser.separator "Optimization:"
|
|
138
|
+
|
|
139
|
+
parser.on("-O LEVEL", /\A[0-3]|s\z/, "Optimization level (0, 1, 2, 3, or s)") do |level|
|
|
135
140
|
options[:flags] << :"o#{level}"
|
|
136
141
|
end
|
|
137
|
-
parser.on("
|
|
142
|
+
parser.on("--lto", "Enable link time optimization") do
|
|
143
|
+
options[:flags] << :lto
|
|
144
|
+
end
|
|
145
|
+
parser.on("--omit-frame-pointer") do |value|
|
|
146
|
+
options[:flags] << :omit_frame_pointer
|
|
147
|
+
end
|
|
148
|
+
parser.on("--strict-aliasing") do |value|
|
|
149
|
+
options[:flags] << :strict_aliasing
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
parser.separator ""
|
|
153
|
+
parser.separator "Code generation:"
|
|
154
|
+
|
|
155
|
+
parser.on("-m", "--arch=ARCH", "Target architecture") do |value|
|
|
138
156
|
options[:flags] << TARGETS[value]
|
|
139
157
|
end
|
|
140
|
-
parser.on("
|
|
141
|
-
options[:flags] << :
|
|
158
|
+
parser.on("--pic", "Generate position independent code") do |value|
|
|
159
|
+
options[:flags] << :pic
|
|
142
160
|
end
|
|
143
|
-
parser.on("--
|
|
144
|
-
options[:flags] <<
|
|
161
|
+
parser.on("--no-rtti", "Disable runtime type information") do |value|
|
|
162
|
+
options[:flags] << :no_rtti
|
|
145
163
|
end
|
|
146
|
-
parser.on("-
|
|
147
|
-
options[:flags] <<
|
|
164
|
+
parser.on("--no-exceptions", "Disable exceptions (and unwinding info)") do |value|
|
|
165
|
+
options[:flags] << :no_exceptions
|
|
148
166
|
end
|
|
149
|
-
|
|
150
|
-
|
|
167
|
+
|
|
168
|
+
parser.separator ""
|
|
169
|
+
parser.separator "Linking:"
|
|
170
|
+
|
|
171
|
+
parser.on("--static", "Produce a static library") do
|
|
172
|
+
options[:flags] << :static
|
|
151
173
|
end
|
|
152
|
-
parser.on("
|
|
153
|
-
options[:
|
|
174
|
+
parser.on("--shared", "Produce a shared library") do |value|
|
|
175
|
+
options[:flags] << :shared
|
|
176
|
+
end
|
|
177
|
+
parser.on("--shared-compat", "Produce a shared library with full LD_PRELOAD compatability") do |value|
|
|
178
|
+
options[:flags] << :shared_compat
|
|
179
|
+
end
|
|
180
|
+
parser.on("-c", "Compile only (produce object files without linking)") do
|
|
181
|
+
options[:link] = false
|
|
154
182
|
end
|
|
155
183
|
parser.on("-l LIB", "Link against library LIB") do |value|
|
|
156
184
|
options[:libs] << value
|
|
@@ -158,59 +186,71 @@ module MetaCC
|
|
|
158
186
|
parser.on("-L DIR", "Add linker library search path") do |value|
|
|
159
187
|
options[:link_paths] << value
|
|
160
188
|
end
|
|
161
|
-
parser.on("--shared", "Produce a shared library") do
|
|
162
|
-
options[:flags] << :shared
|
|
163
|
-
end
|
|
164
|
-
parser.on("--static", "Produce a static library") do
|
|
165
|
-
options[:flags] << :static
|
|
166
|
-
end
|
|
167
189
|
parser.on("-s", "--strip", "Strip unneeded symbols") do
|
|
168
190
|
options[:flags] << :strip
|
|
169
191
|
end
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
parser.on("--#{name}
|
|
177
|
-
options[:xflags][
|
|
178
|
-
options[:xflags][
|
|
192
|
+
|
|
193
|
+
parser.separator ""
|
|
194
|
+
parser.separator "Compiler specific:"
|
|
195
|
+
|
|
196
|
+
XFLAGS.each do |name, toolchain_class|
|
|
197
|
+
toolchain_name = toolchain_class.name.split("::").last
|
|
198
|
+
parser.on("--#{name} FLAG", "Forward FLAG to the compiler if compiling with #{toolchain_name}") do |value|
|
|
199
|
+
options[:xflags][toolchain_class] ||= []
|
|
200
|
+
options[:xflags][toolchain_class] << value
|
|
179
201
|
end
|
|
180
202
|
end
|
|
203
|
+
|
|
204
|
+
parser.separator ""
|
|
205
|
+
parser.separator "Informational:"
|
|
206
|
+
|
|
181
207
|
parser.on_tail("--version", "Print the toolchain version and exit") do
|
|
182
208
|
puts @driver.toolchain.version_banner
|
|
183
209
|
exit
|
|
184
210
|
end
|
|
211
|
+
parser.on_tail("-h", "--help", "Show this message") do
|
|
212
|
+
puts parser
|
|
213
|
+
exit
|
|
214
|
+
end
|
|
185
215
|
end
|
|
186
216
|
|
|
187
217
|
def validate_options!(flags, output_path, link:, run:)
|
|
188
218
|
if !link && output_path
|
|
189
|
-
raise InvalidOption, "cannot specify output path (-o) in compile only mode (-c)"
|
|
219
|
+
raise OptionParser::InvalidOption, "cannot specify output path (-o) in compile only mode (-c)"
|
|
190
220
|
end
|
|
191
221
|
|
|
192
222
|
if link && !output_path
|
|
193
|
-
raise InvalidOption, "must specify an output path (-o)"
|
|
223
|
+
raise OptionParser::InvalidOption, "must specify an output path (-o)"
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
if run && (!link || %i[static shared shared_compat].any? { |f| flags.include?(f) })
|
|
227
|
+
raise OptionParser::InvalidOption, "--run cannot be used with -c, --static, --shared, or --shared-compat"
|
|
194
228
|
end
|
|
195
229
|
|
|
196
|
-
if
|
|
197
|
-
raise InvalidOption, "
|
|
230
|
+
if !link && %i[static shared shared_compat].any? { |f| flags.include?(f) }
|
|
231
|
+
raise OptionParser::InvalidOption, "compile only mode (-c) cannot be used with --static, --shared, or --shared-compat"
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
if flags.include?(:debug_info) && flags.include?(:strip)
|
|
235
|
+
raise OptionParser::InvalidOption, "--debug-info (-g) cannot be combined with --strip (-s)"
|
|
198
236
|
end
|
|
199
237
|
end
|
|
200
238
|
|
|
201
239
|
def invoke(input_paths, desired_output_path = nil, link: true, run: false, **options)
|
|
240
|
+
result = nil
|
|
202
241
|
if link
|
|
203
|
-
|
|
204
|
-
system(
|
|
242
|
+
result = @driver.compile_and_link(input_paths, desired_output_path, **options)
|
|
243
|
+
system(result) if run && !options[:dry_run]
|
|
205
244
|
else
|
|
206
245
|
options.delete(:link_paths)
|
|
207
246
|
options.delete(:libs)
|
|
208
|
-
@driver.compile(input_paths, **options)
|
|
247
|
+
result = @driver.compile(input_paths, **options)
|
|
248
|
+
end
|
|
249
|
+
if options[:dry_run]
|
|
250
|
+
puts result.map { |cmd| cmd.join(" ") }
|
|
209
251
|
end
|
|
210
252
|
end
|
|
211
253
|
|
|
212
|
-
class InvalidOption < StandardError; end
|
|
213
|
-
|
|
214
254
|
end
|
|
215
255
|
|
|
216
256
|
end
|
data/lib/metacc/driver.rb
CHANGED
|
@@ -15,20 +15,24 @@ module MetaCC
|
|
|
15
15
|
# available compiler found on the system (Clang, GCC, or MSVC).
|
|
16
16
|
class Driver
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
LANGUAGE_STD_FLAGS = Set.new(%i[c11 c17 c23 cxx11 cxx14 cxx17 cxx20 cxx23 cxx26]).freeze
|
|
19
|
+
ARCHITECTURE_FLAGS = Set.new(%i[sse4_2 avx avx2 avx512 native]).freeze
|
|
20
|
+
OPTIMIZATION_FLAGS = Set.new(%i[o0 o1 o2 o3 os]).freeze
|
|
21
|
+
DBG_SANITIZE_FLAGS = Set.new(%i[sanitize_default sanitize_memory sanitize_thread]).freeze
|
|
22
|
+
|
|
23
|
+
ALL_FLAGS = Set.new([
|
|
24
|
+
*%i[
|
|
23
25
|
warn_all warn_error
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
debug_info
|
|
27
|
+
omit_frame_pointer strict_aliasing
|
|
28
|
+
no_rtti no_exceptions
|
|
29
|
+
pic shared shared_compat static strip
|
|
30
|
+
],
|
|
31
|
+
*LANGUAGE_STD_FLAGS,
|
|
32
|
+
*ARCHITECTURE_FLAGS,
|
|
33
|
+
*OPTIMIZATION_FLAGS,
|
|
34
|
+
*DBG_SANITIZE_FLAGS
|
|
35
|
+
]).freeze
|
|
32
36
|
|
|
33
37
|
# The detected toolchain (a Toolchain subclass instance).
|
|
34
38
|
attr_reader :toolchain
|
|
@@ -37,11 +41,11 @@ module MetaCC
|
|
|
37
41
|
#
|
|
38
42
|
# @param prefer [Array<Class>] toolchain classes to probe, in priority order.
|
|
39
43
|
# Each element must be a Class derived from Toolchain.
|
|
40
|
-
# Defaults to [Clang,
|
|
44
|
+
# Defaults to [Clang, GCC, MSVC].
|
|
41
45
|
# @param search_paths [Array<String>] directories to search for toolchain executables
|
|
42
46
|
# before falling back to PATH. Defaults to [].
|
|
43
47
|
# @raise [ToolchainNotFoundError] if no supported compiler is found.
|
|
44
|
-
def initialize(prefer: [MSVC], search_paths: [])
|
|
48
|
+
def initialize(prefer: [Clang, GCC, MSVC], search_paths: [])
|
|
45
49
|
@toolchain = select_toolchain!(prefer, search_paths)
|
|
46
50
|
end
|
|
47
51
|
|
|
@@ -63,7 +67,8 @@ module MetaCC
|
|
|
63
67
|
include_paths: [],
|
|
64
68
|
defs: [],
|
|
65
69
|
env: {},
|
|
66
|
-
working_dir: "."
|
|
70
|
+
working_dir: ".",
|
|
71
|
+
dry_run: false
|
|
67
72
|
)
|
|
68
73
|
flags = translate_flags(flags)
|
|
69
74
|
flags.concat(xflags[@toolchain.class] || [])
|
|
@@ -75,6 +80,8 @@ module MetaCC
|
|
|
75
80
|
defs:
|
|
76
81
|
)
|
|
77
82
|
|
|
83
|
+
return [cmd] if dry_run
|
|
84
|
+
|
|
78
85
|
!!run_command(cmd, env:, working_dir:)
|
|
79
86
|
end
|
|
80
87
|
|
|
@@ -105,7 +112,8 @@ module MetaCC
|
|
|
105
112
|
link_paths: [],
|
|
106
113
|
libs: [],
|
|
107
114
|
env: {},
|
|
108
|
-
working_dir: "."
|
|
115
|
+
working_dir: ".",
|
|
116
|
+
dry_run: false
|
|
109
117
|
)
|
|
110
118
|
output_type = if flags.include?(:shared) then :shared
|
|
111
119
|
elsif flags.include?(:static) then :static
|
|
@@ -126,6 +134,8 @@ module MetaCC
|
|
|
126
134
|
link_paths:
|
|
127
135
|
)
|
|
128
136
|
|
|
137
|
+
return cmds if dry_run
|
|
138
|
+
|
|
129
139
|
cmds.each { |cmd| run_command(cmd, env:, working_dir:) }
|
|
130
140
|
output_path
|
|
131
141
|
end
|
|
@@ -149,11 +159,24 @@ module MetaCC
|
|
|
149
159
|
end
|
|
150
160
|
|
|
151
161
|
def translate_flags(flags)
|
|
152
|
-
unrecognized_flag = flags.find { |flag| !
|
|
162
|
+
unrecognized_flag = flags.find { |flag| !ALL_FLAGS.include?(flag) }
|
|
153
163
|
if unrecognized_flag
|
|
154
164
|
raise "#{unrecognized_flag.inspect} is not a known flag"
|
|
155
165
|
end
|
|
156
166
|
|
|
167
|
+
lang_flags, flags = flags.partition { |flag| LANGUAGE_STD_FLAGS.include?(flag) }
|
|
168
|
+
arch_flags, flags = flags.partition { |flag| ARCHITECTURE_FLAGS.include?(flag) }
|
|
169
|
+
optm_flags, flags = flags.partition { |flag| OPTIMIZATION_FLAGS.include?(flag) }
|
|
170
|
+
sant_flags, flags = flags.partition { |flag| DBG_SANITIZE_FLAGS.include?(flag) }
|
|
171
|
+
|
|
172
|
+
flags << lang_flags.last unless lang_flags.empty?
|
|
173
|
+
flags << arch_flags.last unless arch_flags.empty?
|
|
174
|
+
flags << optm_flags.last unless optm_flags.empty?
|
|
175
|
+
flags << sant_flags.last unless sant_flags.empty?
|
|
176
|
+
|
|
177
|
+
flags << :no_omit_frame_pointer unless flags.include?(:omit_frame_pointer)
|
|
178
|
+
flags << :no_strict_aliasing unless flags.include?(:strict_aliasing)
|
|
179
|
+
|
|
157
180
|
flags.flat_map { |flag| @toolchain.flags[flag] }
|
|
158
181
|
end
|
|
159
182
|
|
data/lib/metacc/toolchain.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "rbconfig"
|
|
4
|
+
require "tempfile"
|
|
4
5
|
|
|
5
6
|
module MetaCC
|
|
6
7
|
|
|
@@ -40,6 +41,34 @@ module MetaCC
|
|
|
40
41
|
IO.popen([c, "--version", { err: :out }], &:read)
|
|
41
42
|
end
|
|
42
43
|
|
|
44
|
+
# Parses +banner_text+ (e.g. from +version_banner+) and returns the
|
|
45
|
+
# Toolchain subclass it most likely belongs to, or +nil+ if unrecognised.
|
|
46
|
+
#
|
|
47
|
+
# Detection is order-sensitive: ClangCL must be checked before Clang
|
|
48
|
+
# because both banners contain "clang", but only ClangCL's Target line
|
|
49
|
+
# contains "windows-msvc".
|
|
50
|
+
def self.detect_from_version_banner(banner_text)
|
|
51
|
+
case banner_text
|
|
52
|
+
when /windows-msvc/i then ClangCL
|
|
53
|
+
when /clang/i then Clang
|
|
54
|
+
when /\bgcc\b/i then GCC
|
|
55
|
+
when /microsoft/i then MSVC
|
|
56
|
+
when /\btcc\b/i then TinyCC
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def self.from_command(command)
|
|
61
|
+
toolchain_class = nil
|
|
62
|
+
%w[--version -v].each do |flag|
|
|
63
|
+
banner = IO.popen([command, flag, { err: :out }], &:read)
|
|
64
|
+
toolchain_class = detect_from_version_banner(banner)
|
|
65
|
+
break if toolchain_class
|
|
66
|
+
rescue Errno::ENOENT
|
|
67
|
+
# Do nothing
|
|
68
|
+
end
|
|
69
|
+
toolchain_class&.new
|
|
70
|
+
end
|
|
71
|
+
|
|
43
72
|
# Returns a Hash mapping universal flags to native flags for this toolchain.
|
|
44
73
|
def flags
|
|
45
74
|
raise "#{self.class}#flags not implemented"
|
|
@@ -114,7 +143,7 @@ module MetaCC
|
|
|
114
143
|
|
|
115
144
|
end
|
|
116
145
|
|
|
117
|
-
# GNU
|
|
146
|
+
# Base class for GNU compatible (ish) toolchains
|
|
118
147
|
class GNU < Toolchain
|
|
119
148
|
|
|
120
149
|
def initialize(cc_command = "gcc", search_paths: [])
|
|
@@ -150,43 +179,54 @@ module MetaCC
|
|
|
150
179
|
end
|
|
151
180
|
|
|
152
181
|
GNU_FLAGS = {
|
|
153
|
-
o0:
|
|
154
|
-
o1:
|
|
155
|
-
o2:
|
|
156
|
-
o3:
|
|
157
|
-
os:
|
|
158
|
-
sse4_2:
|
|
159
|
-
avx:
|
|
160
|
-
avx2:
|
|
161
|
-
avx512:
|
|
162
|
-
native:
|
|
163
|
-
|
|
164
|
-
lto:
|
|
165
|
-
warn_all:
|
|
166
|
-
warn_error:
|
|
167
|
-
c11:
|
|
168
|
-
c17:
|
|
169
|
-
c23:
|
|
170
|
-
cxx11:
|
|
171
|
-
cxx14:
|
|
172
|
-
cxx17:
|
|
173
|
-
cxx20:
|
|
174
|
-
cxx23:
|
|
175
|
-
cxx26:
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
no_rtti:
|
|
180
|
-
no_exceptions:
|
|
181
|
-
pic:
|
|
182
|
-
|
|
183
|
-
no_omit_frame_pointer:
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
182
|
+
o0: ["-O0"],
|
|
183
|
+
o1: ["-O1"],
|
|
184
|
+
o2: ["-O2"],
|
|
185
|
+
o3: ["-O3"],
|
|
186
|
+
os: ["-Os"],
|
|
187
|
+
sse4_2: ["-march=x86-64-v2"], # This is a better match for /arch:SSE4.2 than -msse4_2 is
|
|
188
|
+
avx: ["-march=x86-64-v2", "-mavx"],
|
|
189
|
+
avx2: ["-march=x86-64-v3"], # This is a better match for /arch:AVX2 than -mavx2 is
|
|
190
|
+
avx512: ["-march=x86-64-v4"],
|
|
191
|
+
native: ["-march=native", "-mtune=native"],
|
|
192
|
+
debug_info: ["-g3"],
|
|
193
|
+
lto: ["-flto"],
|
|
194
|
+
warn_all: ["-Wall", "-Wextra", "-pedantic"],
|
|
195
|
+
warn_error: ["-Werror"],
|
|
196
|
+
c11: ["-std=c11"],
|
|
197
|
+
c17: ["-std=c17"],
|
|
198
|
+
c23: ["-std=c23"],
|
|
199
|
+
cxx11: ["-std=c++11"],
|
|
200
|
+
cxx14: ["-std=c++14"],
|
|
201
|
+
cxx17: ["-std=c++17"],
|
|
202
|
+
cxx20: ["-std=c++20"],
|
|
203
|
+
cxx23: ["-std=c++23"],
|
|
204
|
+
cxx26: ["-std=c++2c"],
|
|
205
|
+
sanitize_default: ["-fsanitize=address,undefined,leak"],
|
|
206
|
+
sanitize_memory: [],
|
|
207
|
+
sanitize_thread: ["-fsanitize=thread"],
|
|
208
|
+
no_rtti: ["-fno-rtti"],
|
|
209
|
+
no_exceptions: ["-fno-exceptions", "-fno-unwind-tables"],
|
|
210
|
+
pic: ["-fPIC"],
|
|
211
|
+
omit_frame_pointer: ["-fomit-frame-pointer"],
|
|
212
|
+
no_omit_frame_pointer: ["-fno-omit-frame-pointer"],
|
|
213
|
+
strict_aliasing: ["-fstrict-aliasing"],
|
|
214
|
+
no_strict_aliasing: ["-fno-strict-aliasing"],
|
|
215
|
+
shared: ["-shared", "-Bsymbolic-non-weak-functions", "-fno-semantic-interposition"],
|
|
216
|
+
shared_compat: ["-shared"],
|
|
217
|
+
static: ["-static"],
|
|
218
|
+
strip: ["-Wl,--strip-unneeded"],
|
|
219
|
+
debug: ["-D_GLIBCXX_DEBUG", "-fasynchronous-unwind-tables"]
|
|
188
220
|
}.freeze
|
|
189
221
|
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
class GCC < GNU
|
|
225
|
+
|
|
226
|
+
def initialize(search_paths: [])
|
|
227
|
+
super("gcc", search_paths:)
|
|
228
|
+
end
|
|
229
|
+
|
|
190
230
|
def flags
|
|
191
231
|
GNU_FLAGS
|
|
192
232
|
end
|
|
@@ -200,7 +240,10 @@ module MetaCC
|
|
|
200
240
|
super("clang", search_paths:)
|
|
201
241
|
end
|
|
202
242
|
|
|
203
|
-
CLANG_FLAGS = GNU_FLAGS.merge(
|
|
243
|
+
CLANG_FLAGS = GNU_FLAGS.merge(
|
|
244
|
+
lto: ["-flto=thin"],
|
|
245
|
+
sanitize_memory: ["-fsanitize=memory"]
|
|
246
|
+
).freeze
|
|
204
247
|
|
|
205
248
|
def flags
|
|
206
249
|
CLANG_FLAGS
|
|
@@ -254,41 +297,43 @@ module MetaCC
|
|
|
254
297
|
end
|
|
255
298
|
|
|
256
299
|
MSVC_FLAGS = {
|
|
257
|
-
o0:
|
|
258
|
-
o1:
|
|
259
|
-
o2:
|
|
260
|
-
o3:
|
|
261
|
-
os:
|
|
262
|
-
sse4_2:
|
|
263
|
-
avx:
|
|
264
|
-
avx2:
|
|
265
|
-
avx512:
|
|
266
|
-
native:
|
|
267
|
-
|
|
268
|
-
lto:
|
|
269
|
-
warn_all:
|
|
270
|
-
warn_error:
|
|
271
|
-
c11:
|
|
272
|
-
c17:
|
|
273
|
-
c23:
|
|
274
|
-
cxx11:
|
|
275
|
-
cxx14:
|
|
276
|
-
cxx17:
|
|
277
|
-
cxx20:
|
|
278
|
-
cxx23:
|
|
279
|
-
cxx26:
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
no_rtti:
|
|
284
|
-
no_exceptions:
|
|
285
|
-
pic:
|
|
286
|
-
|
|
287
|
-
no_omit_frame_pointer:
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
300
|
+
o0: ["/Od"],
|
|
301
|
+
o1: ["/O1"],
|
|
302
|
+
o2: ["/O2"],
|
|
303
|
+
o3: ["/O2", "/Ob3"],
|
|
304
|
+
os: ["/O1"],
|
|
305
|
+
sse4_2: ["/arch:SSE4.2"],
|
|
306
|
+
avx: ["/arch:AVX"],
|
|
307
|
+
avx2: ["/arch:AVX2"],
|
|
308
|
+
avx512: ["/arch:AVX512"],
|
|
309
|
+
native: [],
|
|
310
|
+
debug_info: ["/Zi"],
|
|
311
|
+
lto: ["/GL"],
|
|
312
|
+
warn_all: ["/W4"],
|
|
313
|
+
warn_error: ["/WX"],
|
|
314
|
+
c11: ["/std:c11"],
|
|
315
|
+
c17: ["/std:c17"],
|
|
316
|
+
c23: ["/std:clatest"],
|
|
317
|
+
cxx11: [],
|
|
318
|
+
cxx14: ["/std:c++14"],
|
|
319
|
+
cxx17: ["/std:c++17"],
|
|
320
|
+
cxx20: ["/std:c++20"],
|
|
321
|
+
cxx23: ["/std:c++23preview"],
|
|
322
|
+
cxx26: ["/std:c++latest"],
|
|
323
|
+
sanitize_default: ["/fsanitize=address"],
|
|
324
|
+
sanitize_memory: [],
|
|
325
|
+
sanitize_thread: [],
|
|
326
|
+
no_rtti: ["/GR-"],
|
|
327
|
+
no_exceptions: ["/EHs-", "/EHc-"],
|
|
328
|
+
pic: [],
|
|
329
|
+
omit_frame_pointer: ["/Oy"],
|
|
330
|
+
no_omit_frame_pointer: ["/Oy-"],
|
|
331
|
+
strict_aliasing: [],
|
|
332
|
+
no_strict_aliasing: [],
|
|
333
|
+
shared: ["/LD"],
|
|
334
|
+
shared_compat: ["/LD"],
|
|
335
|
+
static: ["/c"],
|
|
336
|
+
strip: []
|
|
292
337
|
}.freeze
|
|
293
338
|
|
|
294
339
|
def flags
|
|
@@ -359,7 +404,7 @@ module MetaCC
|
|
|
359
404
|
# environment variables into the current process's ENV.
|
|
360
405
|
def MSVC.vcvarsall(devenv_path)
|
|
361
406
|
# See https://stackoverflow.com/a/19929778
|
|
362
|
-
return if ENV.
|
|
407
|
+
return if ENV.key?("DevEnvDir")
|
|
363
408
|
|
|
364
409
|
# Calculate the location of vcvarsall.bat
|
|
365
410
|
install_root = File.expand_path("../../..", devenv_path)
|
|
@@ -368,10 +413,21 @@ module MetaCC
|
|
|
368
413
|
vcvarsall = File.join(install_root, "VC", "Auxiliary", "Build", "vcvarsall.bat")
|
|
369
414
|
return unless File.exist?(vcvarsall)
|
|
370
415
|
|
|
371
|
-
#
|
|
372
|
-
output =
|
|
373
|
-
|
|
374
|
-
|
|
416
|
+
# Get environment info from vcvarsall.bat
|
|
417
|
+
output = nil
|
|
418
|
+
Tempfile.create(["vcvarsall", ".bat"]) do |file|
|
|
419
|
+
# Write a stub batch file that run vcvarsall.bat and dumps the
|
|
420
|
+
# environment to stdout
|
|
421
|
+
file.puts %Q{"#{vcvarsall.gsub('"', '""')}" x64 && set}
|
|
422
|
+
file.flush
|
|
423
|
+
|
|
424
|
+
# Run the stub batch file
|
|
425
|
+
output = IO.popen(["cmd", "/c", file.path], &:read)
|
|
426
|
+
status = $?
|
|
427
|
+
return unless status.success?
|
|
428
|
+
rescue Errno::ENOENT
|
|
429
|
+
return
|
|
430
|
+
end
|
|
375
431
|
|
|
376
432
|
output.each_line do |line|
|
|
377
433
|
key, value = line.chomp.split("=", 2)
|
|
@@ -392,8 +448,11 @@ module MetaCC
|
|
|
392
448
|
end
|
|
393
449
|
|
|
394
450
|
CLANG_CL_FLAGS = MSVC_FLAGS.merge(
|
|
395
|
-
|
|
396
|
-
|
|
451
|
+
lto: ["-flto=thin"],
|
|
452
|
+
o3: ["/Ot"], # Clang-CL treats /Ot as -O3
|
|
453
|
+
native: ["/clang:-march=native", "/clang:-mtune=native"],
|
|
454
|
+
strict_aliasing: ["/clang:-fstrict-aliasing"],
|
|
455
|
+
no_strict_aliasing: ["/clang:-fno-strict-aliasing"]
|
|
397
456
|
).freeze
|
|
398
457
|
|
|
399
458
|
def flags
|
|
@@ -416,6 +475,7 @@ module MetaCC
|
|
|
416
475
|
object_files = input_files.map { |f| f.sub(/\.c\z/, ".o") }
|
|
417
476
|
commands << [@ar, "rcs", output_file, *object_files]
|
|
418
477
|
end
|
|
478
|
+
commands
|
|
419
479
|
end
|
|
420
480
|
|
|
421
481
|
# TinyCC does not support C++.
|
|
@@ -428,41 +488,43 @@ module MetaCC
|
|
|
428
488
|
end
|
|
429
489
|
|
|
430
490
|
TINYCC_FLAGS = {
|
|
431
|
-
o0:
|
|
432
|
-
o1:
|
|
433
|
-
o2:
|
|
434
|
-
o3:
|
|
435
|
-
os:
|
|
436
|
-
sse4_2:
|
|
437
|
-
avx:
|
|
438
|
-
avx2:
|
|
439
|
-
avx512:
|
|
440
|
-
native:
|
|
441
|
-
|
|
442
|
-
lto:
|
|
443
|
-
warn_all:
|
|
444
|
-
warn_error:
|
|
445
|
-
c11:
|
|
446
|
-
c17:
|
|
447
|
-
c23:
|
|
448
|
-
cxx11:
|
|
449
|
-
cxx14:
|
|
450
|
-
cxx17:
|
|
451
|
-
cxx20:
|
|
452
|
-
cxx23:
|
|
453
|
-
cxx26:
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
no_rtti:
|
|
458
|
-
no_exceptions:
|
|
459
|
-
pic:
|
|
460
|
-
|
|
461
|
-
no_omit_frame_pointer:
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
491
|
+
o0: [],
|
|
492
|
+
o1: ["-O1"],
|
|
493
|
+
o2: ["-O2"],
|
|
494
|
+
o3: ["-O2"],
|
|
495
|
+
os: [],
|
|
496
|
+
sse4_2: [],
|
|
497
|
+
avx: [],
|
|
498
|
+
avx2: [],
|
|
499
|
+
avx512: [],
|
|
500
|
+
native: [],
|
|
501
|
+
debug_info: ["-g"],
|
|
502
|
+
lto: [],
|
|
503
|
+
warn_all: ["-Wall"],
|
|
504
|
+
warn_error: ["-Werror"],
|
|
505
|
+
c11: [],
|
|
506
|
+
c17: [],
|
|
507
|
+
c23: [],
|
|
508
|
+
cxx11: [],
|
|
509
|
+
cxx14: [],
|
|
510
|
+
cxx17: [],
|
|
511
|
+
cxx20: [],
|
|
512
|
+
cxx23: [],
|
|
513
|
+
cxx26: [],
|
|
514
|
+
sanitize_default: [],
|
|
515
|
+
sanitize_memory: [],
|
|
516
|
+
sanitize_thread: [],
|
|
517
|
+
no_rtti: [],
|
|
518
|
+
no_exceptions: [],
|
|
519
|
+
pic: [],
|
|
520
|
+
omit_frame_pointer: [],
|
|
521
|
+
no_omit_frame_pointer: [],
|
|
522
|
+
strict_aliasing: [],
|
|
523
|
+
no_strict_aliasing: [],
|
|
524
|
+
shared: ["-shared"],
|
|
525
|
+
shared_compat: ["-shared"],
|
|
526
|
+
static: ["-c"],
|
|
527
|
+
strip: []
|
|
466
528
|
}.freeze
|
|
467
529
|
|
|
468
530
|
def flags
|
|
@@ -471,4 +533,7 @@ module MetaCC
|
|
|
471
533
|
|
|
472
534
|
end
|
|
473
535
|
|
|
536
|
+
class AutoToolchain
|
|
537
|
+
end
|
|
538
|
+
|
|
474
539
|
end
|
data/lib/metacc/version.rb
CHANGED