metacc 0.3.0 → 0.5.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 +1 -2
- data/lib/metacc/cli.rb +60 -34
- data/lib/metacc/driver.rb +56 -31
- data/lib/metacc/platform.rb +47 -0
- data/lib/metacc/toolchain.rb +159 -75
- data/lib/metacc/version.rb +1 -1
- data/lib/metacc.rb +3 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d68166f1cf0263814b009c61e2b615ee36521656734bb4ef0b0e48677751fafa
|
|
4
|
+
data.tar.gz: 12133182cb6f8b899714eb7fdbc95868ecdbfd40fe80bbe43084ed79d0fa5e88
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d3257e9318b06bfdc812d3a344dc3bece65e22199e4bbc68f3c5f9867593d8b1c4fa8e9376078abf0a056d75f6fa4a8782716152d50f24e6c0a314632f27d3d1
|
|
7
|
+
data.tar.gz: c413d78b53e7a7486a895e1595ec064173cca98235cd35ae595dcd31af9f95b4c526ce8c47b452b53955615ba0166e341a3b9e071508d457580479ca4397fb1f
|
data/bin/metacc
CHANGED
|
@@ -7,8 +7,7 @@ require "metacc/cli"
|
|
|
7
7
|
|
|
8
8
|
begin
|
|
9
9
|
MetaCC::CLI.new.run(ARGV)
|
|
10
|
-
rescue MetaCC::
|
|
11
|
-
MetaCC::ToolchainNotFoundError,
|
|
10
|
+
rescue MetaCC::ToolchainNotFoundError,
|
|
12
11
|
OptionParser::AmbiguousOption,
|
|
13
12
|
OptionParser::MissingArgument,
|
|
14
13
|
OptionParser::NeedlessArgument,
|
data/lib/metacc/cli.rb
CHANGED
|
@@ -12,32 +12,28 @@ module MetaCC
|
|
|
12
12
|
class CLI
|
|
13
13
|
|
|
14
14
|
WARNING_CONFIGS = {
|
|
15
|
-
"all"
|
|
15
|
+
"all" => :warn_all,
|
|
16
16
|
"error" => :warn_error
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
SANITIZERS = {
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"ub" => :ubsan,
|
|
24
|
-
"memory" => :msan,
|
|
25
|
-
"mem" => :msan,
|
|
26
|
-
"leak" => :lsan
|
|
20
|
+
nil => :sanitize_default,
|
|
21
|
+
"memory" => :sanitize_memory,
|
|
22
|
+
"thread" => :sanitize_thread
|
|
27
23
|
}
|
|
28
24
|
|
|
29
25
|
TARGETS = {
|
|
30
26
|
"sse4.2" => :sse4_2,
|
|
31
|
-
"avx"
|
|
32
|
-
"avx2"
|
|
27
|
+
"avx" => :avx,
|
|
28
|
+
"avx2" => :avx2,
|
|
33
29
|
"avx512" => :avx512,
|
|
34
30
|
"native" => :native
|
|
35
31
|
}.freeze
|
|
36
32
|
|
|
37
33
|
STANDARDS = {
|
|
38
|
-
"c11"
|
|
39
|
-
"c17"
|
|
40
|
-
"c23"
|
|
34
|
+
"c11" => :c11,
|
|
35
|
+
"c17" => :c17,
|
|
36
|
+
"c23" => :c23,
|
|
41
37
|
"c++11" => :cxx11,
|
|
42
38
|
"c++14" => :cxx14,
|
|
43
39
|
"c++17" => :cxx17,
|
|
@@ -48,11 +44,11 @@ module MetaCC
|
|
|
48
44
|
|
|
49
45
|
# Maps --x<name> CLI option names to xflags toolchain-class keys.
|
|
50
46
|
XFLAGS = {
|
|
51
|
-
"xmsvc"
|
|
52
|
-
"xgnu"
|
|
53
|
-
"xclang"
|
|
47
|
+
"xmsvc" => MSVC,
|
|
48
|
+
"xgnu" => GNU,
|
|
49
|
+
"xclang" => Clang,
|
|
54
50
|
"xclangcl" => ClangCL,
|
|
55
|
-
"xtinycc"
|
|
51
|
+
"xtinycc" => TinyCC
|
|
56
52
|
}.freeze
|
|
57
53
|
|
|
58
54
|
def initialize(driver: Driver.new)
|
|
@@ -77,6 +73,7 @@ module MetaCC
|
|
|
77
73
|
libs: [],
|
|
78
74
|
output_path: nil,
|
|
79
75
|
run: false,
|
|
76
|
+
dry_run: false,
|
|
80
77
|
flags: [],
|
|
81
78
|
xflags: {}
|
|
82
79
|
}
|
|
@@ -106,12 +103,19 @@ module MetaCC
|
|
|
106
103
|
parser.on("--std=STANDARD", "Specify the language standard") do |value|
|
|
107
104
|
options[:flags] << STANDARDS[value]
|
|
108
105
|
end
|
|
109
|
-
parser.on(
|
|
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|
|
|
110
111
|
options[:flags] << WARNING_CONFIGS[value]
|
|
111
112
|
end
|
|
112
113
|
parser.on("-r", "--run", "Run the compiled executable after a successful build") do
|
|
113
114
|
options[:run] = true
|
|
114
115
|
end
|
|
116
|
+
parser.on("--dry-run", "Print the command that would be issued") do
|
|
117
|
+
options[:dry_run] = true
|
|
118
|
+
end
|
|
115
119
|
|
|
116
120
|
parser.separator ""
|
|
117
121
|
parser.separator "Debugging:"
|
|
@@ -119,7 +123,13 @@ module MetaCC
|
|
|
119
123
|
parser.on("-g", "--debug-info", "Emit debugging symbols") do
|
|
120
124
|
options[:flags] << :debug_info
|
|
121
125
|
end
|
|
122
|
-
parser.on(
|
|
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|
|
|
123
133
|
options[:flags] << SANITIZERS[value]
|
|
124
134
|
end
|
|
125
135
|
|
|
@@ -132,10 +142,10 @@ module MetaCC
|
|
|
132
142
|
parser.on("--lto", "Enable link time optimization") do
|
|
133
143
|
options[:flags] << :lto
|
|
134
144
|
end
|
|
135
|
-
parser.on("--omit-frame-pointer") do
|
|
145
|
+
parser.on("--omit-frame-pointer") do
|
|
136
146
|
options[:flags] << :omit_frame_pointer
|
|
137
147
|
end
|
|
138
|
-
parser.on("--strict-aliasing") do
|
|
148
|
+
parser.on("--strict-aliasing") do
|
|
139
149
|
options[:flags] << :strict_aliasing
|
|
140
150
|
end
|
|
141
151
|
|
|
@@ -145,13 +155,13 @@ module MetaCC
|
|
|
145
155
|
parser.on("-m", "--arch=ARCH", "Target architecture") do |value|
|
|
146
156
|
options[:flags] << TARGETS[value]
|
|
147
157
|
end
|
|
148
|
-
parser.on("--pic", "Generate position independent code") do
|
|
158
|
+
parser.on("--pic", "Generate position independent code") do
|
|
149
159
|
options[:flags] << :pic
|
|
150
160
|
end
|
|
151
|
-
parser.on("--no-rtti", "Disable runtime type information") do
|
|
161
|
+
parser.on("--no-rtti", "Disable runtime type information") do
|
|
152
162
|
options[:flags] << :no_rtti
|
|
153
163
|
end
|
|
154
|
-
parser.on("--no-exceptions", "Disable exceptions (and unwinding info)") do
|
|
164
|
+
parser.on("--no-exceptions", "Disable exceptions (and unwinding info)") do
|
|
155
165
|
options[:flags] << :no_exceptions
|
|
156
166
|
end
|
|
157
167
|
|
|
@@ -161,10 +171,10 @@ module MetaCC
|
|
|
161
171
|
parser.on("--static", "Produce a static library") do
|
|
162
172
|
options[:flags] << :static
|
|
163
173
|
end
|
|
164
|
-
parser.on("--shared", "Produce a shared library") do
|
|
174
|
+
parser.on("--shared", "Produce a shared library") do
|
|
165
175
|
options[:flags] << :shared
|
|
166
176
|
end
|
|
167
|
-
parser.on("--shared-compat", "Produce a shared library with full LD_PRELOAD compatability") do
|
|
177
|
+
parser.on("--shared-compat", "Produce a shared library with full LD_PRELOAD compatability") do
|
|
168
178
|
options[:flags] << :shared_compat
|
|
169
179
|
end
|
|
170
180
|
parser.on("-c", "Compile only (produce object files without linking)") do
|
|
@@ -176,7 +186,6 @@ module MetaCC
|
|
|
176
186
|
parser.on("-L DIR", "Add linker library search path") do |value|
|
|
177
187
|
options[:link_paths] << value
|
|
178
188
|
end
|
|
179
|
-
|
|
180
189
|
parser.on("-s", "--strip", "Strip unneeded symbols") do
|
|
181
190
|
options[:flags] << :strip
|
|
182
191
|
end
|
|
@@ -207,27 +216,44 @@ module MetaCC
|
|
|
207
216
|
|
|
208
217
|
def validate_options!(flags, output_path, link:, run:)
|
|
209
218
|
if !link && output_path
|
|
210
|
-
raise OptionParser::InvalidOption,
|
|
219
|
+
raise OptionParser::InvalidOption,
|
|
220
|
+
"cannot specify output path (-o) in compile only mode (-c)"
|
|
211
221
|
end
|
|
212
222
|
|
|
213
223
|
if link && !output_path
|
|
214
|
-
raise OptionParser::InvalidOption,
|
|
224
|
+
raise OptionParser::InvalidOption,
|
|
225
|
+
"must specify an output path (-o)"
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
if run && (!link || %i[static shared shared_compat].any? { |f| flags.include?(f) })
|
|
229
|
+
raise OptionParser::InvalidOption,
|
|
230
|
+
"--run cannot be used with -c, --static, --shared, or --shared-compat"
|
|
215
231
|
end
|
|
216
232
|
|
|
217
|
-
if
|
|
218
|
-
raise OptionParser::InvalidOption,
|
|
233
|
+
if !link && %i[static shared shared_compat].any? { |f| flags.include?(f) }
|
|
234
|
+
raise OptionParser::InvalidOption,
|
|
235
|
+
"compile only mode (-c) cannot be used with --static, --shared, or --shared-compat"
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
if flags.include?(:debug_info) && flags.include?(:strip)
|
|
239
|
+
raise OptionParser::InvalidOption,
|
|
240
|
+
"--debug-info (-g) cannot be combined with --strip (-s)"
|
|
219
241
|
end
|
|
220
242
|
end
|
|
221
243
|
|
|
222
244
|
def invoke(input_paths, desired_output_path = nil, link: true, run: false, **options)
|
|
245
|
+
result = nil
|
|
223
246
|
if link
|
|
224
|
-
|
|
225
|
-
system(
|
|
247
|
+
result = @driver.compile_and_link(input_paths, desired_output_path, **options)
|
|
248
|
+
system(result) if run && !options[:dry_run]
|
|
226
249
|
else
|
|
227
250
|
options.delete(:link_paths)
|
|
228
251
|
options.delete(:libs)
|
|
229
|
-
@driver.compile(input_paths, **options)
|
|
252
|
+
result = @driver.compile(input_paths, **options)
|
|
230
253
|
end
|
|
254
|
+
return unless options[:dry_run]
|
|
255
|
+
|
|
256
|
+
puts(result.map { |cmd| cmd.join(" ") })
|
|
231
257
|
end
|
|
232
258
|
|
|
233
259
|
end
|
data/lib/metacc/driver.rb
CHANGED
|
@@ -15,20 +15,29 @@ 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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
+
:warn_all,
|
|
25
|
+
:warn_error,
|
|
26
|
+
:debug_info,
|
|
27
|
+
:omit_frame_pointer,
|
|
28
|
+
:strict_aliasing,
|
|
29
|
+
:no_rtti,
|
|
30
|
+
:no_exceptions,
|
|
31
|
+
:pic,
|
|
32
|
+
:shared,
|
|
33
|
+
:shared_compat,
|
|
34
|
+
:static,
|
|
35
|
+
:strip,
|
|
36
|
+
*LANGUAGE_STD_FLAGS,
|
|
37
|
+
*ARCHITECTURE_FLAGS,
|
|
38
|
+
*OPTIMIZATION_FLAGS,
|
|
39
|
+
*DBG_SANITIZE_FLAGS
|
|
40
|
+
]).freeze
|
|
32
41
|
|
|
33
42
|
# The detected toolchain (a Toolchain subclass instance).
|
|
34
43
|
attr_reader :toolchain
|
|
@@ -37,11 +46,11 @@ module MetaCC
|
|
|
37
46
|
#
|
|
38
47
|
# @param prefer [Array<Class>] toolchain classes to probe, in priority order.
|
|
39
48
|
# Each element must be a Class derived from Toolchain.
|
|
40
|
-
# Defaults to [Clang,
|
|
49
|
+
# Defaults to [Clang, GCC, MSVC].
|
|
41
50
|
# @param search_paths [Array<String>] directories to search for toolchain executables
|
|
42
51
|
# before falling back to PATH. Defaults to [].
|
|
43
52
|
# @raise [ToolchainNotFoundError] if no supported compiler is found.
|
|
44
|
-
def initialize(prefer: [MSVC], search_paths: [])
|
|
53
|
+
def initialize(prefer: [Clang, GCC, MSVC], search_paths: [])
|
|
45
54
|
@toolchain = select_toolchain!(prefer, search_paths)
|
|
46
55
|
end
|
|
47
56
|
|
|
@@ -58,12 +67,13 @@ module MetaCC
|
|
|
58
67
|
# @raise [CompileError] if the underlying toolchain executable returns a non-zero exit status
|
|
59
68
|
def compile(
|
|
60
69
|
input_files,
|
|
61
|
-
flags:
|
|
62
|
-
xflags:
|
|
70
|
+
flags: [],
|
|
71
|
+
xflags: {},
|
|
63
72
|
include_paths: [],
|
|
64
|
-
defs:
|
|
65
|
-
env:
|
|
66
|
-
working_dir:
|
|
73
|
+
defs: [],
|
|
74
|
+
env: {},
|
|
75
|
+
working_dir: ".",
|
|
76
|
+
dry_run: false
|
|
67
77
|
)
|
|
68
78
|
flags = translate_flags(flags)
|
|
69
79
|
flags.concat(xflags[@toolchain.class] || [])
|
|
@@ -75,6 +85,8 @@ module MetaCC
|
|
|
75
85
|
defs:
|
|
76
86
|
)
|
|
77
87
|
|
|
88
|
+
return [cmd] if dry_run
|
|
89
|
+
|
|
78
90
|
!!run_command(cmd, env:, working_dir:)
|
|
79
91
|
end
|
|
80
92
|
|
|
@@ -98,17 +110,18 @@ module MetaCC
|
|
|
98
110
|
def compile_and_link(
|
|
99
111
|
input_files,
|
|
100
112
|
output_path,
|
|
101
|
-
flags:
|
|
102
|
-
xflags:
|
|
113
|
+
flags: [],
|
|
114
|
+
xflags: {},
|
|
103
115
|
include_paths: [],
|
|
104
|
-
defs:
|
|
105
|
-
link_paths:
|
|
106
|
-
libs:
|
|
107
|
-
env:
|
|
108
|
-
working_dir:
|
|
116
|
+
defs: [],
|
|
117
|
+
link_paths: [],
|
|
118
|
+
libs: [],
|
|
119
|
+
env: {},
|
|
120
|
+
working_dir: ".",
|
|
121
|
+
dry_run: false
|
|
109
122
|
)
|
|
110
|
-
output_type = if flags.include?(:shared)
|
|
111
|
-
elsif flags.include?(:static)
|
|
123
|
+
output_type = if flags.include?(:shared) then :shared
|
|
124
|
+
elsif flags.include?(:static) then :static
|
|
112
125
|
else :executable
|
|
113
126
|
end
|
|
114
127
|
output_path = apply_default_extension(output_path, output_type)
|
|
@@ -126,6 +139,8 @@ module MetaCC
|
|
|
126
139
|
link_paths:
|
|
127
140
|
)
|
|
128
141
|
|
|
142
|
+
return cmds if dry_run
|
|
143
|
+
|
|
129
144
|
cmds.each { |cmd| run_command(cmd, env:, working_dir:) }
|
|
130
145
|
output_path
|
|
131
146
|
end
|
|
@@ -149,11 +164,21 @@ module MetaCC
|
|
|
149
164
|
end
|
|
150
165
|
|
|
151
166
|
def translate_flags(flags)
|
|
152
|
-
unrecognized_flag = flags.find { |flag| !
|
|
167
|
+
unrecognized_flag = flags.find { |flag| !ALL_FLAGS.include?(flag) }
|
|
153
168
|
if unrecognized_flag
|
|
154
169
|
raise "#{unrecognized_flag.inspect} is not a known flag"
|
|
155
170
|
end
|
|
156
171
|
|
|
172
|
+
lang_flags, flags = flags.partition { |flag| LANGUAGE_STD_FLAGS.include?(flag) }
|
|
173
|
+
arch_flags, flags = flags.partition { |flag| ARCHITECTURE_FLAGS.include?(flag) }
|
|
174
|
+
optm_flags, flags = flags.partition { |flag| OPTIMIZATION_FLAGS.include?(flag) }
|
|
175
|
+
sant_flags, flags = flags.partition { |flag| DBG_SANITIZE_FLAGS.include?(flag) }
|
|
176
|
+
|
|
177
|
+
flags << lang_flags.last unless lang_flags.empty?
|
|
178
|
+
flags << arch_flags.last unless arch_flags.empty?
|
|
179
|
+
flags << optm_flags.last unless optm_flags.empty?
|
|
180
|
+
flags << sant_flags.last unless sant_flags.empty?
|
|
181
|
+
|
|
157
182
|
flags << :no_omit_frame_pointer unless flags.include?(:omit_frame_pointer)
|
|
158
183
|
flags << :no_strict_aliasing unless flags.include?(:strict_aliasing)
|
|
159
184
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rbconfig"
|
|
4
|
+
|
|
5
|
+
module MetaCC
|
|
6
|
+
|
|
7
|
+
module Platform
|
|
8
|
+
|
|
9
|
+
def self.windows?
|
|
10
|
+
@windows ||= RbConfig::CONFIG["host_os"].match?(/mswin|mingw32|windows/)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.cygwin?
|
|
14
|
+
@cygwin ||= RbConfig::CONFIG["host_os"].match?(/cygwin/)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.apple?
|
|
18
|
+
@apple ||= RbConfig::CONFIG["host_os"].match?(/darwin/)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.executable_ext
|
|
22
|
+
if windows? || cygwin?
|
|
23
|
+
".exe"
|
|
24
|
+
elsif apple?
|
|
25
|
+
".dylib"
|
|
26
|
+
else
|
|
27
|
+
""
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.executable_ext
|
|
32
|
+
windows? || cygwin? ? ".exe" : ""
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.shared_library_ext
|
|
36
|
+
if windows? || cygwin?
|
|
37
|
+
".dll"
|
|
38
|
+
elsif apple?
|
|
39
|
+
".dylib"
|
|
40
|
+
else
|
|
41
|
+
".so"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
data/lib/metacc/toolchain.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "
|
|
3
|
+
require "tempfile"
|
|
4
|
+
require_relative "platform"
|
|
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"
|
|
@@ -49,7 +78,7 @@ module MetaCC
|
|
|
49
78
|
# The output mode (object files, shared library, static library, or
|
|
50
79
|
# executable) is determined by the translated flags.
|
|
51
80
|
def compile_command(
|
|
52
|
-
|
|
81
|
+
_input_files,
|
|
53
82
|
flags:,
|
|
54
83
|
include_paths:,
|
|
55
84
|
defs:
|
|
@@ -58,8 +87,8 @@ module MetaCC
|
|
|
58
87
|
end
|
|
59
88
|
|
|
60
89
|
def compile_and_link_commands(
|
|
61
|
-
|
|
62
|
-
|
|
90
|
+
_input_files,
|
|
91
|
+
_output_file,
|
|
63
92
|
flags:,
|
|
64
93
|
include_paths:,
|
|
65
94
|
defs:,
|
|
@@ -76,20 +105,11 @@ module MetaCC
|
|
|
76
105
|
# @param output_type [:objects, :shared, :static, :executable]
|
|
77
106
|
# @return [String]
|
|
78
107
|
def default_extension(output_type)
|
|
79
|
-
host_os = RbConfig::CONFIG["host_os"]
|
|
80
108
|
case output_type
|
|
81
109
|
when :objects then ".o"
|
|
82
|
-
when :static then ".a"
|
|
83
|
-
when :shared
|
|
84
|
-
|
|
85
|
-
".dll"
|
|
86
|
-
elsif host_os.match?(/darwin/)
|
|
87
|
-
".dylib"
|
|
88
|
-
else
|
|
89
|
-
".so"
|
|
90
|
-
end
|
|
91
|
-
when :executable
|
|
92
|
-
host_os.match?(/mswin|mingw|cygwin/) ? ".exe" : ""
|
|
110
|
+
when :static then ".a" # MingGW uses .a, not .lib
|
|
111
|
+
when :shared then MetaCC::Platform.shared_library_ext
|
|
112
|
+
when :executable then MetaCC::Platform.executable_ext
|
|
93
113
|
else
|
|
94
114
|
raise ArgumentError, "unknown output_type: #{output_type.inspect}"
|
|
95
115
|
end
|
|
@@ -114,7 +134,7 @@ module MetaCC
|
|
|
114
134
|
|
|
115
135
|
end
|
|
116
136
|
|
|
117
|
-
# GNU
|
|
137
|
+
# Base class for GNU compatible (ish) toolchains
|
|
118
138
|
class GNU < Toolchain
|
|
119
139
|
|
|
120
140
|
def initialize(cc_command = "gcc", search_paths: [])
|
|
@@ -149,6 +169,30 @@ module MetaCC
|
|
|
149
169
|
[[c, *flags, *inc_flags, *def_flags, *input_files, *lib_path_flags, *lib_flags, "-o", output_file]]
|
|
150
170
|
end
|
|
151
171
|
|
|
172
|
+
def self.platform_flags
|
|
173
|
+
if MetaCC::Platform.windows?
|
|
174
|
+
{
|
|
175
|
+
# MingGW doesn't have full UBsan support, but it can trap on detected errors.
|
|
176
|
+
# It does not support the address or leak sanitizers.
|
|
177
|
+
sanitize_default: ["-fsanitize=undefined", "-fsanitize-undefined-trap-on-error"],
|
|
178
|
+
# MingGW doesn't support the thread sanitizer
|
|
179
|
+
sanitize_thread: []
|
|
180
|
+
}
|
|
181
|
+
elsif MetaCC::Platform.apple?
|
|
182
|
+
# gcc's support for sanitizers on OSX/iOS is *very* spotty.
|
|
183
|
+
# So we disable everything.
|
|
184
|
+
{
|
|
185
|
+
sanitize_default: [],
|
|
186
|
+
sanitize_thread: []
|
|
187
|
+
}
|
|
188
|
+
else
|
|
189
|
+
# Otherwise assume Linux/BSD and keep the default
|
|
190
|
+
{}
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
private_class_method :platform_flags
|
|
195
|
+
|
|
152
196
|
GNU_FLAGS = {
|
|
153
197
|
o0: ["-O0"],
|
|
154
198
|
o1: ["-O1"],
|
|
@@ -173,10 +217,9 @@ module MetaCC
|
|
|
173
217
|
cxx20: ["-std=c++20"],
|
|
174
218
|
cxx23: ["-std=c++23"],
|
|
175
219
|
cxx26: ["-std=c++2c"],
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
lsan: ["-fsanitize=leak"],
|
|
220
|
+
sanitize_default: ["-fsanitize=address,undefined,leak"],
|
|
221
|
+
sanitize_memory: [],
|
|
222
|
+
sanitize_thread: ["-fsanitize=thread"],
|
|
180
223
|
no_rtti: ["-fno-rtti"],
|
|
181
224
|
no_exceptions: ["-fno-exceptions", "-fno-unwind-tables"],
|
|
182
225
|
pic: ["-fPIC"],
|
|
@@ -189,7 +232,15 @@ module MetaCC
|
|
|
189
232
|
static: ["-static"],
|
|
190
233
|
strip: ["-Wl,--strip-unneeded"],
|
|
191
234
|
debug: ["-D_GLIBCXX_DEBUG", "-fasynchronous-unwind-tables"]
|
|
192
|
-
}.freeze
|
|
235
|
+
}.merge(platform_flags).freeze
|
|
236
|
+
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
class GCC < GNU
|
|
240
|
+
|
|
241
|
+
def initialize(search_paths: [])
|
|
242
|
+
super("gcc", search_paths:)
|
|
243
|
+
end
|
|
193
244
|
|
|
194
245
|
def flags
|
|
195
246
|
GNU_FLAGS
|
|
@@ -204,7 +255,26 @@ module MetaCC
|
|
|
204
255
|
super("clang", search_paths:)
|
|
205
256
|
end
|
|
206
257
|
|
|
207
|
-
|
|
258
|
+
def self.platform_flags
|
|
259
|
+
if MetaCC::Platform.windows?
|
|
260
|
+
{
|
|
261
|
+
# The leak sanitizer is not supported on Windows
|
|
262
|
+
sanitize_default: ["-fsanitize=address,undefined"],
|
|
263
|
+
# The thread sanitizer is not supported on Windows
|
|
264
|
+
sanitize_thread: []
|
|
265
|
+
}
|
|
266
|
+
else
|
|
267
|
+
# For all other platforms, stick with the defaults
|
|
268
|
+
{}
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
private_class_method :platform_flags
|
|
273
|
+
|
|
274
|
+
CLANG_FLAGS = GNU_FLAGS.merge(
|
|
275
|
+
lto: ["-flto=thin"],
|
|
276
|
+
sanitize_memory: ["-fsanitize=memory"]
|
|
277
|
+
).merge(platform_flags)
|
|
208
278
|
|
|
209
279
|
def flags
|
|
210
280
|
CLANG_FLAGS
|
|
@@ -281,17 +351,16 @@ module MetaCC
|
|
|
281
351
|
cxx20: ["/std:c++20"],
|
|
282
352
|
cxx23: ["/std:c++23preview"],
|
|
283
353
|
cxx26: ["/std:c++latest"],
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
lsan: [],
|
|
354
|
+
sanitize_default: ["/fsanitize=address"],
|
|
355
|
+
sanitize_memory: [],
|
|
356
|
+
sanitize_thread: [],
|
|
288
357
|
no_rtti: ["/GR-"],
|
|
289
|
-
no_exceptions: ["/EHs-", "/EHc-"],
|
|
358
|
+
no_exceptions: ["/EHs-", "/EHc-", "/D_HAS_EXCEPTIONS=0"],
|
|
290
359
|
pic: [],
|
|
291
360
|
omit_frame_pointer: ["/Oy"],
|
|
292
361
|
no_omit_frame_pointer: ["/Oy-"],
|
|
293
|
-
strict_aliasing: [
|
|
294
|
-
no_strict_aliasing: [
|
|
362
|
+
strict_aliasing: [],
|
|
363
|
+
no_strict_aliasing: [],
|
|
295
364
|
shared: ["/LD"],
|
|
296
365
|
shared_compat: ["/LD"],
|
|
297
366
|
static: ["/c"],
|
|
@@ -364,9 +433,9 @@ module MetaCC
|
|
|
364
433
|
#
|
|
365
434
|
# Parses the output of `vcvarsall.bat … && set` and merges the resulting
|
|
366
435
|
# environment variables into the current process's ENV.
|
|
367
|
-
def
|
|
436
|
+
def self.vcvarsall(devenv_path)
|
|
368
437
|
# See https://stackoverflow.com/a/19929778
|
|
369
|
-
return if ENV.
|
|
438
|
+
return if ENV.key?("DevEnvDir")
|
|
370
439
|
|
|
371
440
|
# Calculate the location of vcvarsall.bat
|
|
372
441
|
install_root = File.expand_path("../../..", devenv_path)
|
|
@@ -375,10 +444,21 @@ module MetaCC
|
|
|
375
444
|
vcvarsall = File.join(install_root, "VC", "Auxiliary", "Build", "vcvarsall.bat")
|
|
376
445
|
return unless File.exist?(vcvarsall)
|
|
377
446
|
|
|
378
|
-
#
|
|
379
|
-
output =
|
|
380
|
-
|
|
381
|
-
|
|
447
|
+
# Get environment info from vcvarsall.bat
|
|
448
|
+
output = nil
|
|
449
|
+
Tempfile.create(["vcvarsall", ".bat"]) do |file|
|
|
450
|
+
# Write a stub batch file that run vcvarsall.bat and dumps the
|
|
451
|
+
# environment to stdout
|
|
452
|
+
file.puts %("#{vcvarsall.gsub('"', '""')}" x64 && set)
|
|
453
|
+
file.flush
|
|
454
|
+
|
|
455
|
+
# Run the stub batch file
|
|
456
|
+
output = IO.popen(["cmd", "/c", file.path], &:read)
|
|
457
|
+
status = $?
|
|
458
|
+
return unless status.success?
|
|
459
|
+
rescue Errno::ENOENT
|
|
460
|
+
return
|
|
461
|
+
end
|
|
382
462
|
|
|
383
463
|
output.each_line do |line|
|
|
384
464
|
key, value = line.chomp.split("=", 2)
|
|
@@ -399,8 +479,11 @@ module MetaCC
|
|
|
399
479
|
end
|
|
400
480
|
|
|
401
481
|
CLANG_CL_FLAGS = MSVC_FLAGS.merge(
|
|
402
|
-
|
|
403
|
-
|
|
482
|
+
lto: ["-flto=thin"],
|
|
483
|
+
o3: ["/Ot"], # Clang-CL treats /Ot as -O3
|
|
484
|
+
native: ["/clang:-march=native", "/clang:-mtune=native"],
|
|
485
|
+
strict_aliasing: ["/clang:-fstrict-aliasing"],
|
|
486
|
+
no_strict_aliasing: ["/clang:-fno-strict-aliasing"]
|
|
404
487
|
).freeze
|
|
405
488
|
|
|
406
489
|
def flags
|
|
@@ -418,7 +501,7 @@ module MetaCC
|
|
|
418
501
|
end
|
|
419
502
|
|
|
420
503
|
def compile_and_link_commands(input_files, output_file, **options)
|
|
421
|
-
commands = super
|
|
504
|
+
commands = super
|
|
422
505
|
if options[:flags].include?(:static)
|
|
423
506
|
object_files = input_files.map { |f| f.sub(/\.c\z/, ".o") }
|
|
424
507
|
commands << [@ar, "rcs", output_file, *object_files]
|
|
@@ -436,42 +519,43 @@ module MetaCC
|
|
|
436
519
|
end
|
|
437
520
|
|
|
438
521
|
TINYCC_FLAGS = {
|
|
439
|
-
o0:
|
|
440
|
-
o1:
|
|
441
|
-
o2:
|
|
442
|
-
o3:
|
|
443
|
-
os:
|
|
444
|
-
sse4_2:
|
|
445
|
-
avx:
|
|
446
|
-
avx2:
|
|
447
|
-
avx512:
|
|
448
|
-
native:
|
|
449
|
-
debug_info:
|
|
450
|
-
lto:
|
|
451
|
-
warn_all:
|
|
452
|
-
warn_error:
|
|
453
|
-
c11:
|
|
454
|
-
c17:
|
|
455
|
-
c23:
|
|
456
|
-
cxx11:
|
|
457
|
-
cxx14:
|
|
458
|
-
cxx17:
|
|
459
|
-
cxx20:
|
|
460
|
-
cxx23:
|
|
461
|
-
cxx26:
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
522
|
+
o0: [],
|
|
523
|
+
o1: ["-O1"],
|
|
524
|
+
o2: ["-O2"],
|
|
525
|
+
o3: ["-O2"],
|
|
526
|
+
os: [],
|
|
527
|
+
sse4_2: [],
|
|
528
|
+
avx: [],
|
|
529
|
+
avx2: [],
|
|
530
|
+
avx512: [],
|
|
531
|
+
native: [],
|
|
532
|
+
debug_info: ["-g"],
|
|
533
|
+
lto: [],
|
|
534
|
+
warn_all: ["-Wall"],
|
|
535
|
+
warn_error: ["-Werror"],
|
|
536
|
+
c11: [],
|
|
537
|
+
c17: [],
|
|
538
|
+
c23: [],
|
|
539
|
+
cxx11: [],
|
|
540
|
+
cxx14: [],
|
|
541
|
+
cxx17: [],
|
|
542
|
+
cxx20: [],
|
|
543
|
+
cxx23: [],
|
|
544
|
+
cxx26: [],
|
|
545
|
+
sanitize_default: [],
|
|
546
|
+
sanitize_memory: [],
|
|
547
|
+
sanitize_thread: [],
|
|
548
|
+
no_rtti: [],
|
|
549
|
+
no_exceptions: [],
|
|
550
|
+
pic: [],
|
|
551
|
+
omit_frame_pointer: [],
|
|
552
|
+
no_omit_frame_pointer: [],
|
|
553
|
+
strict_aliasing: [],
|
|
554
|
+
no_strict_aliasing: [],
|
|
555
|
+
shared: ["-shared"],
|
|
556
|
+
shared_compat: ["-shared"],
|
|
557
|
+
static: ["-c"],
|
|
558
|
+
strip: []
|
|
475
559
|
}.freeze
|
|
476
560
|
|
|
477
561
|
def flags
|
data/lib/metacc/version.rb
CHANGED
data/lib/metacc.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: metacc
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Praneeth Sadda
|
|
@@ -22,6 +22,7 @@ files:
|
|
|
22
22
|
- lib/metacc.rb
|
|
23
23
|
- lib/metacc/cli.rb
|
|
24
24
|
- lib/metacc/driver.rb
|
|
25
|
+
- lib/metacc/platform.rb
|
|
25
26
|
- lib/metacc/toolchain.rb
|
|
26
27
|
- lib/metacc/version.rb
|
|
27
28
|
homepage: https://github.com/psadda/metacc
|
|
@@ -38,7 +39,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
38
39
|
requirements:
|
|
39
40
|
- - ">="
|
|
40
41
|
- !ruby/object:Gem::Version
|
|
41
|
-
version: 3.
|
|
42
|
+
version: 3.4.0
|
|
42
43
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
43
44
|
requirements:
|
|
44
45
|
- - ">="
|