asmcc 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 +7 -0
- data/bin/asmcc +4 -0
- data/lib/asmcc.rb +445 -0
- metadata +49 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9bb8677cf4a4a7825e28b603b32a032a75a805f6
|
4
|
+
data.tar.gz: b77f28755ad622294173b9a4fc50b0b3d2e8d2ff
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6871ff27f02b4ffdf139715951af599a85357e5cea46495285705bf8f7fe1946c9c80b0bb03c1ddd21275a6ce30929e54e7e50995806d24e4f5066d474a9a6dd
|
7
|
+
data.tar.gz: c0cc1fe622d6b82e6cc55dccd908d033702a5733dddf28c8b4f9bde083dfd47b7bbc7ca2ef915f685bb5d9f95b40d1dbed27d486c7518c2d2051fd2cb47d8334
|
data/bin/asmcc
ADDED
data/lib/asmcc.rb
ADDED
@@ -0,0 +1,445 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
CXX_TEMPLATE = <<-CODE_EOF
|
5
|
+
#include <cinttypes>
|
6
|
+
#include <cmath>
|
7
|
+
#include <cstddef>
|
8
|
+
#include <cstring>
|
9
|
+
#include <climits>
|
10
|
+
|
11
|
+
uint64_t factorial(uint64_t arg) {
|
12
|
+
if (arg <= 1) return 1;
|
13
|
+
return arg * factorial(arg - 1);
|
14
|
+
}
|
15
|
+
CODE_EOF
|
16
|
+
|
17
|
+
|
18
|
+
C_TEMPLATE = <<-CODE_EOF
|
19
|
+
#include <inttypes.h>
|
20
|
+
#include <math.h>
|
21
|
+
#include <stddef.h>
|
22
|
+
#include <string.h>
|
23
|
+
#include <limits.h>
|
24
|
+
#include <stdbool.h>
|
25
|
+
|
26
|
+
uint64_t factorial(uint64_t arg) {
|
27
|
+
if (arg <= 1) return 1;
|
28
|
+
return arg * factorial(arg - 1);
|
29
|
+
}
|
30
|
+
CODE_EOF
|
31
|
+
|
32
|
+
|
33
|
+
class AsmCC
|
34
|
+
def initialize
|
35
|
+
@parsed_settings = false
|
36
|
+
@custom_template = nil
|
37
|
+
@warnings = %W[all effc++]
|
38
|
+
@includes = %W[#{Dir.pwd} #{Dir.pwd}/include /usr/local/include]
|
39
|
+
@opt_level = '3'
|
40
|
+
|
41
|
+
@input = nil
|
42
|
+
@output = nil
|
43
|
+
|
44
|
+
@defines = []
|
45
|
+
@undefs = []
|
46
|
+
|
47
|
+
@enable_exns = false
|
48
|
+
@enable_rtti = false
|
49
|
+
|
50
|
+
@accurate_fp = true
|
51
|
+
|
52
|
+
@output = nil
|
53
|
+
|
54
|
+
@arch = 'native'
|
55
|
+
|
56
|
+
@xflags = []
|
57
|
+
|
58
|
+
@force_bits = nil
|
59
|
+
|
60
|
+
@verbose_asm = true
|
61
|
+
|
62
|
+
@edit_asm = false
|
63
|
+
@show_encoding = false
|
64
|
+
@debug = false
|
65
|
+
@demangle = true
|
66
|
+
@emit_llvm = false
|
67
|
+
|
68
|
+
@combined_output = false
|
69
|
+
|
70
|
+
@std = "c++1y"
|
71
|
+
@lang = :"c++"
|
72
|
+
end
|
73
|
+
|
74
|
+
def parse_settings!
|
75
|
+
return self if @parsed_settings
|
76
|
+
@parsed_settings = true
|
77
|
+
OptionParser.new do |opts|
|
78
|
+
opts.banner = 'Usage: asmcc [options]'
|
79
|
+
opts.separator ''
|
80
|
+
opts.separator 'Options:'
|
81
|
+
|
82
|
+
opts.on('-g', '--debug-info', 'Include debugging info?') do
|
83
|
+
@debug = true
|
84
|
+
end
|
85
|
+
|
86
|
+
opts.on('-O', '--opt-level 0123s', '01234s'.split(''), 'Set optimization level (3 by default).') do |v|
|
87
|
+
@opt_level = v
|
88
|
+
end
|
89
|
+
|
90
|
+
opts.on('-l', '--lang LANG', [:"c++", :c, :"objective-c", :"objective-c++"],
|
91
|
+
'Set language. Defaults to c++.',
|
92
|
+
' Must be one of ["c++", "c", "objective-c", "objective-c++"]') do |l|
|
93
|
+
@lang = l
|
94
|
+
end
|
95
|
+
|
96
|
+
opts.on('-s', '--std STD', String, 'Use the specified standard. Defaults to c++1y for c++/objc++, c11 for c/objc.') do |std|
|
97
|
+
@std = std
|
98
|
+
end
|
99
|
+
|
100
|
+
opts.on('-L', '--emit-llvm', 'Emit LLVM IR. (disables --show-encoding).') do |v|
|
101
|
+
@emit_llvm = true
|
102
|
+
end
|
103
|
+
|
104
|
+
opts.on('-F', '--[no-]fast-math', 'Prefer speed to accuracy for floating point? (off by default).') do |b|
|
105
|
+
@accurate_fp = !b
|
106
|
+
end
|
107
|
+
|
108
|
+
opts.on('-a', '--arch ARCH', String, 'Specify -march flag value (default is "native").') do |arch|
|
109
|
+
@arch = arch
|
110
|
+
end
|
111
|
+
|
112
|
+
opts.on('--m32', 'Force 32 bit compilation.') do
|
113
|
+
@force_bits = 32
|
114
|
+
end
|
115
|
+
|
116
|
+
opts.on('--m64', 'Force 64 bit compilation.') do
|
117
|
+
@force_bits = 64
|
118
|
+
end
|
119
|
+
|
120
|
+
opts.on('-X', '--Xcc f,l,a,g,s', Array, 'Pass extra flags to the compiler.') do |fs|
|
121
|
+
@xflags += fs
|
122
|
+
end
|
123
|
+
|
124
|
+
opts.on('-e', '--[no-]exceptions', 'Enable exceptions. Disabled by default.') do |e|
|
125
|
+
@enable_exns = e
|
126
|
+
end
|
127
|
+
|
128
|
+
opts.on('-r', '--[no-]rtti', 'Enable runtime type info. Disabled by default.') do |r|
|
129
|
+
@enable_rtti = r
|
130
|
+
end
|
131
|
+
|
132
|
+
opts.on('-E', '--edit-result', 'Open output file in editor.') do
|
133
|
+
@edit_asm = true
|
134
|
+
end
|
135
|
+
|
136
|
+
opts.on('--no-verbose-asm', 'Disable verbose assembly output.') do
|
137
|
+
@verbose_asm = false
|
138
|
+
end
|
139
|
+
|
140
|
+
opts.on('-D', '--define l,i,s,t', Array, 'Pass -Dl -Di -Ds -Dt to the compiler.') do |ds|
|
141
|
+
@defines += ds
|
142
|
+
end
|
143
|
+
|
144
|
+
opts.on('-U', '--undef l,i,s,t', Array, 'Pass -Ul -Ui -Us -Ut to the compiler (overrides -D).') do |us|
|
145
|
+
@undefs += us
|
146
|
+
end
|
147
|
+
|
148
|
+
opts.on('-W', '--warn w0,w1,etc', Array, 'Specify warnings to use (defaults to Wall,Wextra).') do |ws|
|
149
|
+
@warnings = ws
|
150
|
+
end
|
151
|
+
|
152
|
+
opts.on('-I', '--include d,i,r,s', Array, 'Extra -I include directories.',
|
153
|
+
' Automatically contains "`pwd`,`pwd`/include,/usr/local/include".') do |is|
|
154
|
+
@includes += is
|
155
|
+
end
|
156
|
+
|
157
|
+
opts.on('-S', '--show-encoding', 'Show encoding?') do
|
158
|
+
@show_encoding = true
|
159
|
+
end
|
160
|
+
|
161
|
+
opts.on('-C', '--combined-output', 'Output both the source fed into the compiler and the generated assembly') do
|
162
|
+
@combined_output = true
|
163
|
+
end
|
164
|
+
|
165
|
+
opts.on('-o', '--out FILE', 'Output to FILE instead of stdout.') do |f|
|
166
|
+
@output = f
|
167
|
+
end
|
168
|
+
|
169
|
+
opts.on('-i', '--input FILE', 'Use FILE as input instead of opening from the editor.') do |f|
|
170
|
+
if File.exist? f
|
171
|
+
@input = f
|
172
|
+
else
|
173
|
+
abort "No such file: \"#{f}\""
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
opts.on('-T', '--template FILE', String, 'Use FILE for template') do |f|
|
178
|
+
begin
|
179
|
+
@custom_template = IO.read(f)
|
180
|
+
rescue
|
181
|
+
puts "Warning: Unable to read template file: \"#{f}\", ignoring -T option..."
|
182
|
+
@custom_template = nil
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
opts.on('--[no-]demangle', 'Demangle C++ identifiers (requires `c++filt`, ignored for c and objc)') do |d|
|
187
|
+
@demangle = false
|
188
|
+
end
|
189
|
+
|
190
|
+
opts.on('-v', '--verbose', 'Pass -v to the compiler') do
|
191
|
+
@xflags << '-v'
|
192
|
+
end
|
193
|
+
|
194
|
+
opts.on('-h', '--help', 'Show this message') do
|
195
|
+
puts opts
|
196
|
+
exit
|
197
|
+
end
|
198
|
+
|
199
|
+
end.parse!
|
200
|
+
|
201
|
+
@show_encoding = false if @emit_llvm
|
202
|
+
|
203
|
+
unless is_cxx?
|
204
|
+
if @std.include? '++'
|
205
|
+
@std = @std.include?('gnu') ? 'gnu11' : 'c11'
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
self
|
210
|
+
end
|
211
|
+
|
212
|
+
def try_again? prompt, default
|
213
|
+
print "#{prompt} #{default ? '[Y/n]' : '[y/N]'}:"
|
214
|
+
result = gets.strip
|
215
|
+
if result.empty?
|
216
|
+
default
|
217
|
+
elsif result[0] == 'Y' || result[0] == 'y'
|
218
|
+
true
|
219
|
+
elsif result[0] == 'N' || result[0] == 'n'
|
220
|
+
false
|
221
|
+
else
|
222
|
+
default
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def edit_file fpath
|
227
|
+
system(ENV['VISUAL'] || ENV['EDITOR'] || '/usr/bin/nano', fpath)
|
228
|
+
end
|
229
|
+
|
230
|
+
def is_darwin?
|
231
|
+
`uname`.strip == 'Darwin'
|
232
|
+
end
|
233
|
+
|
234
|
+
def is_cxx?
|
235
|
+
@lang == :"c++" or @lang == :"objective-c++"
|
236
|
+
end
|
237
|
+
|
238
|
+
def is_objc?
|
239
|
+
@lang == :"objective-c" or @lang == :"objective-c++"
|
240
|
+
end
|
241
|
+
|
242
|
+
def file_extension
|
243
|
+
case @lang
|
244
|
+
when :"c"
|
245
|
+
".c"
|
246
|
+
when :"c++"
|
247
|
+
".cpp"
|
248
|
+
when :"objective-c"
|
249
|
+
".m"
|
250
|
+
when :"objective-cpp"
|
251
|
+
".mm"
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def stdlib_flag
|
256
|
+
if is_cxx?
|
257
|
+
is_darwin? ? '-stdlib=libc++' : '-stdlib=libstdc++'
|
258
|
+
else
|
259
|
+
''
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def exception_flag
|
264
|
+
if is_cxx?
|
265
|
+
if @enable_exns
|
266
|
+
"-fexceptions" + (is_objc? ? " -fobj-exceptions" : "")
|
267
|
+
else
|
268
|
+
"-fno-exceptions" + (is_objc? ? " -fno-objc-exceptions" : "")
|
269
|
+
end
|
270
|
+
else
|
271
|
+
''
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
def rtti_flag
|
276
|
+
if is_cxx?
|
277
|
+
@enable_rtti ? '-frtti' : '-fno-rtti'
|
278
|
+
else
|
279
|
+
''
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
def flags
|
284
|
+
%W[
|
285
|
+
-x#{@lang}
|
286
|
+
-march=#{@arch}
|
287
|
+
#{@force_bits.nil? ? '' : "-m#{@force_bits}"}
|
288
|
+
-S
|
289
|
+
#{@emit_llvm ? '-emit-llvm': ''}
|
290
|
+
#{@verbose_asm ? '-Xclang -masm-verbose' : ''}
|
291
|
+
|
292
|
+
-std=#{@std}
|
293
|
+
#{stdlib_flag}
|
294
|
+
-O#{@opt_level.strip}
|
295
|
+
|
296
|
+
#{exception_flag}
|
297
|
+
|
298
|
+
#{rtti_flag}
|
299
|
+
|
300
|
+
#{@accurate_fp ? '' : '-ffast-math'}
|
301
|
+
|
302
|
+
#{@warnings.map{|s| to_warning s}.join ' '}
|
303
|
+
#{@includes.map{|s| to_include s}.join ' '}
|
304
|
+
|
305
|
+
#{@defines.reject(&:empty?).map{|d|"-D#{d.strip}"}.join ' '}
|
306
|
+
#{@undefs.reject(&:empty?).map{|u|"-U#{d.strip}"}.join ' '}
|
307
|
+
|
308
|
+
#{@debug ? '-g' : ''}
|
309
|
+
#{@xflags.join ' '}
|
310
|
+
].reject(&:empty?)
|
311
|
+
end
|
312
|
+
|
313
|
+
def flag_str
|
314
|
+
flags.join ' '
|
315
|
+
end
|
316
|
+
|
317
|
+
def to_warning(s)
|
318
|
+
s.strip.sub /^(?:-?W)?/, "-W"
|
319
|
+
end
|
320
|
+
|
321
|
+
def to_include(s)
|
322
|
+
s.strip.sub /^(?:-I)?/, "-I"
|
323
|
+
end
|
324
|
+
|
325
|
+
def flags_summary
|
326
|
+
flags.reject{|f| /^-[WI]/ =~ f}.join ' '
|
327
|
+
end
|
328
|
+
|
329
|
+
def should_demangle
|
330
|
+
@demangle and is_cxx?()
|
331
|
+
end
|
332
|
+
|
333
|
+
def compiler_cmd path, summarize
|
334
|
+
command = "clang " + (summarize ? flags_summary : "#{flag_str} #{path} -o '-'")
|
335
|
+
command += " | clang -cc1as -show-encoding" if @show_encoding
|
336
|
+
command += " | c++filt" if should_demangle
|
337
|
+
end
|
338
|
+
|
339
|
+
def compiled_with comment_str
|
340
|
+
cmd = "clang #{flags_summary} "
|
341
|
+
cmd += " | clang -cc1as -show-encoding" if @show_encoding
|
342
|
+
cmd += " | c++filt" if should_demangle
|
343
|
+
"#{comment_str} Compiled with `#{cmd}`\n"
|
344
|
+
end
|
345
|
+
|
346
|
+
def invoke_compiler path
|
347
|
+
# this is getting pretty hacky
|
348
|
+
out = IO.popen("clang #{flag_str} #{path} -o '-'") do |pipe|
|
349
|
+
pipe.read
|
350
|
+
end
|
351
|
+
|
352
|
+
unless $?.exitstatus == 0
|
353
|
+
return [false]
|
354
|
+
end
|
355
|
+
|
356
|
+
if @show_encoding
|
357
|
+
out = IO.popen('clang -cc1as -show-encoding', 'r+') do |pipe|
|
358
|
+
pipe.write out
|
359
|
+
pipe.close_write
|
360
|
+
pipe.read
|
361
|
+
end
|
362
|
+
unless $?.exitstatus == 0
|
363
|
+
return [false]
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
if should_demangle
|
368
|
+
out = IO.popen('c++filt', 'r+') do |pipe|
|
369
|
+
pipe.write out
|
370
|
+
pipe.close_write
|
371
|
+
pipe.read
|
372
|
+
end
|
373
|
+
unless $?.exitstatus == 0
|
374
|
+
return [false]
|
375
|
+
end
|
376
|
+
end
|
377
|
+
[true, out]
|
378
|
+
end
|
379
|
+
|
380
|
+
def template
|
381
|
+
if @custom_template
|
382
|
+
@custom_template
|
383
|
+
elsif is_cxx?
|
384
|
+
CXX_TEMPLATE
|
385
|
+
else
|
386
|
+
C_TEMPLATE
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
def run
|
391
|
+
parse_settings!
|
392
|
+
|
393
|
+
compiled = nil
|
394
|
+
file = nil
|
395
|
+
|
396
|
+
if @input.nil?
|
397
|
+
templ = template
|
398
|
+
else
|
399
|
+
templ = IO.read @input
|
400
|
+
end
|
401
|
+
|
402
|
+
file = Tempfile.new(['asmcc', file_extension])
|
403
|
+
|
404
|
+
path = file.path
|
405
|
+
|
406
|
+
file.print template
|
407
|
+
file.close()
|
408
|
+
|
409
|
+
compiled = nil
|
410
|
+
tried_once = false
|
411
|
+
|
412
|
+
while true
|
413
|
+
edit_file path if @input.nil? or tried_once
|
414
|
+
tried_once = true
|
415
|
+
result = invoke_compiler path
|
416
|
+
if result[0]
|
417
|
+
compiled = result[1]
|
418
|
+
break
|
419
|
+
elsif not try_again? "Compilation failed, try again?", true
|
420
|
+
exit(1)
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
if @edit_asm or not @output.nil?
|
425
|
+
out_path = @output.nil? ? path : @output
|
426
|
+
File.open(out_path, 'w') { |f| output f, (IO.read path), compiled }
|
427
|
+
edit_file out_path if @edit_asm
|
428
|
+
else
|
429
|
+
output $stdout, (IO.read path), compiled
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
def output f, source, compiled
|
434
|
+
if @combined_output
|
435
|
+
f.puts source
|
436
|
+
f.puts "\n/******* Generated code *********/"
|
437
|
+
f.puts compiled_with "/*"
|
438
|
+
else
|
439
|
+
f.puts compiled_with @emit_llvm ? ';' : '#'
|
440
|
+
end
|
441
|
+
f.puts compiled.each_line.to_a.map{|line| "#{line.gsub(/([^\t]*)(\t)/) { $1 + " " * (8 - $1.length % 8) }}"}.join
|
442
|
+
f.puts "\n*/" if @combined_output
|
443
|
+
end
|
444
|
+
|
445
|
+
end
|
metadata
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: asmcc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Thom Chiovoloni
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-16 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: |
|
14
|
+
AsmCC is a command line tool to view the assembly or LLVM IR produced by
|
15
|
+
clang for a given file. It's essentially a command-line version of the
|
16
|
+
(now disabled) llvm online demo page.
|
17
|
+
email: chiovolonit@gmail.com
|
18
|
+
executables:
|
19
|
+
- asmcc
|
20
|
+
extensions: []
|
21
|
+
extra_rdoc_files: []
|
22
|
+
files:
|
23
|
+
- lib/asmcc.rb
|
24
|
+
- bin/asmcc
|
25
|
+
homepage: https://github.com/thomcc/asmcc
|
26
|
+
licenses:
|
27
|
+
- CC0
|
28
|
+
metadata: {}
|
29
|
+
post_install_message:
|
30
|
+
rdoc_options: []
|
31
|
+
require_paths:
|
32
|
+
- lib
|
33
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
requirements: []
|
44
|
+
rubyforge_project:
|
45
|
+
rubygems_version: 2.0.3
|
46
|
+
signing_key:
|
47
|
+
specification_version: 4
|
48
|
+
summary: A script which painlessly compiles C/C++ to assembly.
|
49
|
+
test_files: []
|