-
Notifications
You must be signed in to change notification settings - Fork 2
/
build.rb
executable file
·123 lines (104 loc) · 3.1 KB
/
build.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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
73
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
#!/usr/bin/env ruby
$LOAD_PATH << File.dirname(__FILE__)
require 'compiler'
require 'asm/text'
require 'asm/binary'
require 'asm/machosymtab'
require 'asm/machofile'
# usage: build.rb <filename> [output filename] [elf | macho ] [asm | bin]
DefaultBinFormats = Hash.new('bin')
def binformat(p,f) DefaultBinFormats[p]=f end
binformat 'darwin', 'macho'
binformat 'linux', 'elf'
def main
filename = ARGV.shift.to_s
raise "can't read #{filename}" unless File.readable?(filename)
outdir = ARGV.shift || '.'
platform = `uname -s`.chomp.downcase
binformat = ARGV[1] ? ARGV[1].downcase : DefaultBinFormats[platform]
puts "Building #{filename} for #{platform}, binformat is #{binformat} ..."
outfile = build(filename, outdir, platform, binformat)
puts outfile
exit
end
def error(msg) STDERR.puts(msg) end
# name part (filename minus extension)
def base(filename)
filename.sub(/\.[^.]*$/, '')
end
# infile: input filename
# outfile: output filename
# asm: assembler to use
def compile(infile, outfile, asm)
File.open(infile, 'r') do |input|
File.open(outfile, 'wb') do |out|
compiler = Compiler.new(input, asm)
out.print(compiler.compile)
end
end
rescue ParseError => e
error("[error] #{e.message}")
error("[context] #{e.context}")
# error("Aborting!")
error(e.caller)
exit(1)
end
def run_and_warn_on_failure(command)
output = `#{command}`
if $?.exitstatus != 0
puts
print output
name = command.split.first
raise "#{name} failed: #{$?.exitstatus}"
end
end
# assemble using nasm, return resulting filename.
def assemble(filename, binformat='elf')
f = base(filename)
outfile = "#{f}.o"
run_and_warn_on_failure("nasm -f #{binformat} -g -o #{outfile} #{filename} 2>&1")
return outfile
end
# link with ld, return resulting filename.
def link(filename, outdir, platform='linux')
f = base(filename)
cmd, args = *case platform
when 'darwin'
['gcc', '-arch i386']
when 'linux'
['ld', '']
else
raise "unsupported platform: #{platform}"
end
run_and_warn_on_failure("#{cmd} #{args} -o #{f} #{filename} 2>&1")
`chmod u+x #{f}`
return f
end
def build(filename, outdir, platform='linux', binformat='elf')
objfile = File.join(outdir, base(filename) + '.o')
symtab, objwriter_class =
case binformat
when 'elf'
[Assembler::ELFSymtab.new, Assembler::ELFFile]
when 'macho'
[Assembler::MachOSymtab.new, Assembler::MachOFile]
else
raise "unsupported binary format: #{binformat}"
end
compile(filename, objfile, Assembler::Binary.new(platform, symtab, objwriter_class))
exefile = link(objfile, outdir, platform)
return exefile
end
def build_asm(filename, platform='linux', binformat='elf')
asmfile = base(filename) + '.asm'
compile(filename, asmfile, Assembler::Text.new(platform))
objfile = assemble(asmfile, binformat)
exefile = link(objfile, platform)
return exefile
end
def run(filename)
filename = "./#{filename}" unless filename.include?('/')
`#{filename}`
return $?.exitstatus
end
main if $0 == __FILE__