asmcc 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +7 -0
  2. data/bin/asmcc +4 -0
  3. data/lib/asmcc.rb +445 -0
  4. metadata +49 -0
@@ -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
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require 'asmcc'
3
+
4
+ AsmCC.new.run
@@ -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: []