Class: AsmCC
- Inherits:
-
Object
- Object
- AsmCC
- Defined in:
- lib/asmcc.rb
Instance Method Summary collapse
- #compiled_with(comment_str) ⇒ Object
- #compiler_cmd(path, summarize) ⇒ Object
- #edit_file(fpath) ⇒ Object
- #exception_flag ⇒ Object
- #file_extension ⇒ Object
- #flag_str ⇒ Object
- #flags ⇒ Object
- #flags_summary ⇒ Object
-
#initialize ⇒ AsmCC
constructor
A new instance of AsmCC.
- #invoke_compiler(path) ⇒ Object
- #is_cxx? ⇒ Boolean
- #is_darwin? ⇒ Boolean
- #is_objc? ⇒ Boolean
- #output(f, source, compiled) ⇒ Object
- #parse_settings! ⇒ Object
- #rtti_flag ⇒ Object
- #run ⇒ Object
- #should_demangle ⇒ Object
- #stdlib_flag ⇒ Object
- #template ⇒ Object
- #to_include(s) ⇒ Object
- #to_warning(s) ⇒ Object
- #try_again?(prompt, default) ⇒ Boolean
Constructor Details
#initialize ⇒ AsmCC
Returns a new instance of AsmCC.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/asmcc.rb', line 34 def initialize @parsed_settings = false @custom_template = nil @warnings = %W[all effc++] @includes = %W[#{Dir.pwd} #{Dir.pwd}/include /usr/local/include] @opt_level = '3' @input = nil @output = nil @defines = [] @undefs = [] @enable_exns = false @enable_rtti = false @accurate_fp = true @output = nil @arch = 'native' @xflags = [] @force_bits = nil @verbose_asm = true @edit_asm = false @show_encoding = false @debug = false @demangle = true @emit_llvm = false @combined_output = false @std = "c++1y" @lang = :"c++" end |
Instance Method Details
#compiled_with(comment_str) ⇒ Object
339 340 341 342 343 344 |
# File 'lib/asmcc.rb', line 339 def compiled_with comment_str cmd = "clang #{flags_summary} " cmd += " | clang -cc1as -show-encoding" if @show_encoding cmd += " | c++filt" if should_demangle "#{comment_str} Compiled with `#{cmd}`\n" end |
#compiler_cmd(path, summarize) ⇒ Object
333 334 335 336 337 |
# File 'lib/asmcc.rb', line 333 def compiler_cmd path, summarize command = "clang " + (summarize ? flags_summary : "#{flag_str} #{path} -o '-'") command += " | clang -cc1as -show-encoding" if @show_encoding command += " | c++filt" if should_demangle end |
#edit_file(fpath) ⇒ Object
226 227 228 |
# File 'lib/asmcc.rb', line 226 def edit_file fpath system(ENV['VISUAL'] || ENV['EDITOR'] || '/usr/bin/nano', fpath) end |
#exception_flag ⇒ Object
263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/asmcc.rb', line 263 def exception_flag if is_cxx? if @enable_exns "-fexceptions" + (is_objc? ? " -fobj-exceptions" : "") else "-fno-exceptions" + (is_objc? ? " -fno-objc-exceptions" : "") end else '' end end |
#file_extension ⇒ Object
242 243 244 245 246 247 248 249 250 251 252 253 |
# File 'lib/asmcc.rb', line 242 def file_extension case @lang when :"c" ".c" when :"c++" ".cpp" when :"objective-c" ".m" when :"objective-cpp" ".mm" end end |
#flag_str ⇒ Object
313 314 315 |
# File 'lib/asmcc.rb', line 313 def flag_str flags.join ' ' end |
#flags ⇒ Object
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
# File 'lib/asmcc.rb', line 283 def flags %W[ -x#{@lang} -march=#{@arch} #{@force_bits.nil? ? '' : "-m#{@force_bits}"} -S #{@emit_llvm ? '-emit-llvm': ''} #{@verbose_asm ? '-Xclang -masm-verbose' : ''} -std=#{@std} #{stdlib_flag} -O#{@opt_level.strip} #{exception_flag} #{rtti_flag} #{@accurate_fp ? '' : '-ffast-math'} #{@warnings.map{|s| to_warning s}.join ' '} #{@includes.map{|s| to_include s}.join ' '} #{@defines.reject(&:empty?).map{|d|"-D#{d.strip}"}.join ' '} #{@undefs.reject(&:empty?).map{|u|"-U#{d.strip}"}.join ' '} #{@debug ? '-g' : ''} #{@xflags.join ' '} ].reject(&:empty?) end |
#flags_summary ⇒ Object
325 326 327 |
# File 'lib/asmcc.rb', line 325 def flags_summary flags.reject{|f| /^-[WI]/ =~ f}.join ' ' end |
#invoke_compiler(path) ⇒ Object
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
# File 'lib/asmcc.rb', line 346 def invoke_compiler path # this is getting pretty hacky out = IO.popen("clang #{flag_str} #{path} -o '-'") do |pipe| pipe.read end unless $?.exitstatus == 0 return [false] end if @show_encoding out = IO.popen('clang -cc1as -show-encoding', 'r+') do |pipe| pipe.write out pipe.close_write pipe.read end unless $?.exitstatus == 0 return [false] end end if should_demangle out = IO.popen('c++filt', 'r+') do |pipe| pipe.write out pipe.close_write pipe.read end unless $?.exitstatus == 0 return [false] end end [true, out] end |
#is_cxx? ⇒ Boolean
234 235 236 |
# File 'lib/asmcc.rb', line 234 def is_cxx? @lang == :"c++" or @lang == :"objective-c++" end |
#is_darwin? ⇒ Boolean
230 231 232 |
# File 'lib/asmcc.rb', line 230 def is_darwin? `uname`.strip == 'Darwin' end |
#is_objc? ⇒ Boolean
238 239 240 |
# File 'lib/asmcc.rb', line 238 def is_objc? @lang == :"objective-c" or @lang == :"objective-c++" end |
#output(f, source, compiled) ⇒ Object
433 434 435 436 437 438 439 440 441 442 443 |
# File 'lib/asmcc.rb', line 433 def output f, source, compiled if @combined_output f.puts source f.puts "\n/******* Generated code *********/" f.puts compiled_with "/*" else f.puts compiled_with @emit_llvm ? ';' : '#' end f.puts compiled.each_line.to_a.map{|line| "#{line.gsub(/([^\t]*)(\t)/) { $1 + " " * (8 - $1.length % 8) }}"}.join f.puts "\n*/" if @combined_output end |
#parse_settings! ⇒ Object
74 75 76 77 78 79 80 81 82 83 84 85 86 87 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 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'lib/asmcc.rb', line 74 def parse_settings! return self if @parsed_settings @parsed_settings = true OptionParser.new do |opts| opts. = 'Usage: asmcc [options]' opts.separator '' opts.separator 'Options:' opts.on('-g', '--debug-info', 'Include debugging info?') do @debug = true end opts.on('-O', '--opt-level 0123s', '01234s'.split(''), 'Set optimization level (3 by default).') do |v| @opt_level = v end opts.on('-l', '--lang LANG', [:"c++", :c, :"objective-c", :"objective-c++"], 'Set language. Defaults to c++.', ' Must be one of ["c++", "c", "objective-c", "objective-c++"]') do |l| @lang = l end opts.on('-s', '--std STD', String, 'Use the specified standard. Defaults to c++1y for c++/objc++, c11 for c/objc.') do |std| @std = std end opts.on('-L', '--emit-llvm', 'Emit LLVM IR. (disables --show-encoding).') do |v| @emit_llvm = true end opts.on('-F', '--[no-]fast-math', 'Prefer speed to accuracy for floating point? (off by default).') do |b| @accurate_fp = !b end opts.on('-a', '--arch ARCH', String, 'Specify -march flag value (default is "native").') do |arch| @arch = arch end opts.on('--m32', 'Force 32 bit compilation.') do @force_bits = 32 end opts.on('--m64', 'Force 64 bit compilation.') do @force_bits = 64 end opts.on('-X', '--Xcc f,l,a,g,s', Array, 'Pass extra flags to the compiler.') do |fs| @xflags += fs end opts.on('-e', '--[no-]exceptions', 'Enable exceptions. Disabled by default.') do |e| @enable_exns = e end opts.on('-r', '--[no-]rtti', 'Enable runtime type info. Disabled by default.') do |r| @enable_rtti = r end opts.on('-E', '--edit-result', 'Open output file in editor.') do @edit_asm = true end opts.on('--no-verbose-asm', 'Disable verbose assembly output.') do @verbose_asm = false end opts.on('-D', '--define l,i,s,t', Array, 'Pass -Dl -Di -Ds -Dt to the compiler.') do |ds| @defines += ds end opts.on('-U', '--undef l,i,s,t', Array, 'Pass -Ul -Ui -Us -Ut to the compiler (overrides -D).') do |us| @undefs += us end opts.on('-W', '--warn w0,w1,etc', Array, 'Specify warnings to use (defaults to Wall,Wextra).') do |ws| @warnings = ws end opts.on('-I', '--include d,i,r,s', Array, 'Extra -I include directories.', ' Automatically contains "`pwd`,`pwd`/include,/usr/local/include".') do |is| @includes += is end opts.on('-S', '--show-encoding', 'Show encoding?') do @show_encoding = true end opts.on('-C', '--combined-output', 'Output both the source fed into the compiler and the generated assembly') do @combined_output = true end opts.on('-o', '--out FILE', 'Output to FILE instead of stdout.') do |f| @output = f end opts.on('-i', '--input FILE', 'Use FILE as input instead of opening from the editor.') do |f| if File.exist? f @input = f else abort "No such file: \"#{f}\"" end end opts.on('-T', '--template FILE', String, 'Use FILE for template') do |f| begin @custom_template = IO.read(f) rescue puts "Warning: Unable to read template file: \"#{f}\", ignoring -T option..." @custom_template = nil end end opts.on('--[no-]demangle', 'Demangle C++ identifiers (requires `c++filt`, ignored for c and objc)') do |d| @demangle = false end opts.on('-v', '--verbose', 'Pass -v to the compiler') do @xflags << '-v' end opts.on('-h', '--help', 'Show this message') do puts opts exit end end.parse! @show_encoding = false if @emit_llvm unless is_cxx? if @std.include? '++' @std = @std.include?('gnu') ? 'gnu11' : 'c11' end end self end |
#rtti_flag ⇒ Object
275 276 277 278 279 280 281 |
# File 'lib/asmcc.rb', line 275 def rtti_flag if is_cxx? @enable_rtti ? '-frtti' : '-fno-rtti' else '' end end |
#run ⇒ Object
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 |
# File 'lib/asmcc.rb', line 390 def run parse_settings! compiled = nil file = nil if @input.nil? templ = template else templ = IO.read @input end file = Tempfile.new(['asmcc', file_extension]) path = file.path file.print template file.close() compiled = nil tried_once = false while true edit_file path if @input.nil? or tried_once tried_once = true result = invoke_compiler path if result[0] compiled = result[1] break elsif not try_again? "Compilation failed, try again?", true exit(1) end end if @edit_asm or not @output.nil? out_path = @output.nil? ? path : @output File.open(out_path, 'w') { |f| output f, (IO.read path), compiled } edit_file out_path if @edit_asm else output $stdout, (IO.read path), compiled end end |
#should_demangle ⇒ Object
329 330 331 |
# File 'lib/asmcc.rb', line 329 def should_demangle @demangle and is_cxx?() end |
#stdlib_flag ⇒ Object
255 256 257 258 259 260 261 |
# File 'lib/asmcc.rb', line 255 def stdlib_flag if is_cxx? is_darwin? ? '-stdlib=libc++' : '-stdlib=libstdc++' else '' end end |
#template ⇒ Object
380 381 382 383 384 385 386 387 388 |
# File 'lib/asmcc.rb', line 380 def template if @custom_template @custom_template elsif is_cxx? CXX_TEMPLATE else C_TEMPLATE end end |
#to_include(s) ⇒ Object
321 322 323 |
# File 'lib/asmcc.rb', line 321 def to_include(s) s.strip.sub /^(?:-I)?/, "-I" end |
#to_warning(s) ⇒ Object
317 318 319 |
# File 'lib/asmcc.rb', line 317 def to_warning(s) s.strip.sub /^(?:-?W)?/, "-W" end |
#try_again?(prompt, default) ⇒ Boolean
212 213 214 215 216 217 218 219 220 221 222 223 224 |
# File 'lib/asmcc.rb', line 212 def try_again? prompt, default print "#{prompt} #{default ? '[Y/n]' : '[y/N]'}:" result = gets.strip if result.empty? default elsif result[0] == 'Y' || result[0] == 'y' true elsif result[0] == 'N' || result[0] == 'n' false else default end end |