Skip to content

Commit dafa08c

Browse files
committed
pass ci
1 parent a68eb23 commit dafa08c

File tree

8 files changed

+96
-51
lines changed

8 files changed

+96
-51
lines changed

Rakefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ require "steep/cli"
88
task default: %i[test]
99

1010
Rake::TestTask.new do |t|
11-
t.test_files = FileList['test/test*.rb']
11+
t.test_files = FileList['test/test*.rb', 'test/**/test*.rb']
1212
end
1313

1414
namespace :steep do

lib/vaporware/compiler.rb

Lines changed: 11 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,47 +2,24 @@
22

33
require_relative "compiler/generator"
44
require_relative "compiler/assembler"
5+
require_relative "compiler/linker"
56

67
class Vaporware::Compiler
78
def self.compile(source, compiler: "gcc", dest: "tmp", debug: false, compiler_options: ["-O0"], shared: false)
8-
_precompile = "#{dest}.s"
9-
s = new(input: source, output: _precompile, debug:, shared:)
9+
s = new(input: source, output: dest, debug:, shared:)
1010
s.compile(compiler_options:)
11-
obj_file = s.assemble(input: _precompile, assembler: "as", debug:)
12-
output = File.basename(obj_file, ".o")
13-
output = "lib#{output}.so" if shared && output !~ /^lib.+\.so$/
14-
s.link(input: obj_file, output:, shared:)
15-
File.delete(obj_file) unless debug
16-
File.delete(_precompile) unless debug
17-
end
18-
19-
def initialize(input:, output: File.basename(input, ".*") + ".s", debug: false, shared: false)
20-
@generator = Vaporware::Compiler::Generator.new(input:, output:, debug:, shared:)
21-
@assembler = Vaporware::Compiler::Assembler.new(input: @generator.precompile, debug:,)
22-
end
23-
24-
def assemble(input:, output: File.basename(input, ".*") + ".o", assembler: "as", assembler_options: [], debug: false)
25-
if ["gcc", "as"].include?(assembler)
26-
assemble = [assembler, *assembler_options, "-o", output, input].compact
27-
call_command(assemble)
28-
else
29-
@assembler.assemble(input:, output:)
30-
end
31-
output
11+
s.assemble(input: dest.to_s + ".s", assembler: "as", debug:)
12+
s.link
3213
end
3314

34-
def link(input:, output: File.basename(input, ".*"), linker: "ld", linker_options: [], dyn_ld_path: ["-dynamic-linker", "/lib64/ld-linux-x86-64.so.2"], ld_path: ["/lib64/libc.so.6", "/usr/lib64/crt1.o"], shared: false)
35-
if shared
36-
dyn_ld_path = []
37-
ld_path = ["/usr/lib64/crti.o", "/usr/lib/gcc/x86_64-pc-linux-gnu/13/crtbeginS.o", "/usr/lib/gcc/x86_64-pc-linux-gnu/13/crtendS.o", "/usr/lib64/crtn.o",]
38-
39-
linker_options = ["-shared"]
40-
end
41-
linker_commands = [linker, *linker_options, *dyn_ld_path, "-o", output, *ld_path, input].compact
42-
call_command(linker_commands)
15+
def initialize(input:, output: File.basename(input, ".*"), linker: "ld", assembler: "as", debug: false, shared: false)
16+
@generator = Vaporware::Compiler::Generator.new(input:, output: output + ".s", debug:, shared:)
17+
@assembler = Vaporware::Compiler::Assembler.new(input: @generator.precompile, output: output + ".o", assembler:, debug:)
18+
output = "lib#{output}.so" if shared && output !~ /^lib.+\.so$/
19+
@linker = Vaporware::Compiler::Linker.new(input: @assembler.obj_file, output:, linker:, debug:, shared:)
4320
end
4421

45-
def call_command(commands) = IO.popen(commands.join(" ")).close
46-
22+
def assemble(input:, output: File.basename(input, ".*") + ".o", assembler: "as", assembler_options: [], debug: false) = @assembler.assemble(input:, output:, assembler:, assembler_options:, debug:)
23+
def link = @linker.link
4724
def compile(compiler_options: ["-O0"]) = @generator.compile
4825
end

lib/vaporware/compiler/assembler.rb

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
class Vaporware::Compiler::Assembler
1616
def self.assemble!(input, output = File.basename(input, ".*") + ".o") = new(input:, output:).assemble
1717

18-
def initialize(input:, output: File.basename(input, ".*") + ".o", type: :relocator, debug: false)
18+
def initialize(input:, output: File.basename(input, ".*") + ".o", assembler: "as", type: :relocator, debug: false)
1919
@input, @output = input, output
2020
@elf_header = ELF::Header.new(type:)
2121
@sections = {
@@ -31,7 +31,18 @@ def initialize(input:, output: File.basename(input, ".*") + ".o", type: :relocat
3131
@debug = debug
3232
end
3333

34-
def assemble(assemble_command: "as", assemble_options: [], input: @input, output: @output)
34+
def assemble(assembler: "as", assembler_options: [], input: @input, output: @output, debug: false)
35+
if ["gcc", "as"].include?(assembler)
36+
IO.popen([assembler, *assembler_options, "-o", output, input].join(" ")).close
37+
else
38+
to_elf(input:, output:)
39+
end
40+
output
41+
end
42+
def obj_file = @output
43+
44+
private
45+
def to_elf(input: @input, output: @output, debug: false)
3546
f = File.open(output, "wb")
3647
read = { main: false }
3748
program_size = 0

lib/vaporware/compiler/linker.rb

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,38 @@
11
# frozen_string_literal: true
2-
module Vaporware
3-
class Compiler
4-
class Linker
5-
DEFAULT_LIBRARY_PATH = %w(/lib64/libc.so.6 /usr/lib64/crt1.o /usr/lib64/crtn.o)
6-
def self.link!(source, dest = "a.out", linker: "mold", lib_path: [], options: []) = new(source, dest, linker:, lib_path:, options:)
2+
class Vaporware::Compiler::Linker
3+
def self.link!(source, dest = "a.out", linker: "mold", options: []) = new(input: source, output: dest, linker:, options:).link
74

8-
def initialize(input, output = "a.out", linker: "mold", lib_path: [], options: [])
9-
@input, @output, @linker = input, output, linker
10-
@lib_path = DEFAULT_LIBRARY_PATH + lib_path
11-
@options = options
12-
end
5+
def initialize(input:, output: "a.out", linker: "mold", linker_options: [], shared: false, debug: false)
6+
@input, @output, @linker = input, output, linker
7+
@options = linker_options
8+
@debug, @shared = debug, shared
9+
end
1310

14-
def link = IO.popen(link_command).close
11+
def link(input: @input, output: @output, debug: @debug, shared: @shared) = IO.popen(link_command).close
1512

16-
private
17-
def link_command = %Q|#{@linker} -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o #{@output} #{@lib_path.join(' ')} #{@input}|.split(/\s+/)
13+
def link_command
14+
ld_path = []
15+
if @shared
16+
ld_path << "--shared"
17+
ld_path << "#{libpath}/crti.o"
18+
ld_path << "#{gcc_libpath}/crtbeginS.o"
19+
ld_path << "#{gcc_libpath}/crtendS.o"
20+
else
21+
ld_path << "-dynamic-linker"
22+
ld_path << "/lib64/ld-linux-x86-64.so.2"
23+
ld_path << "#{libpath}/crt1.o"
24+
ld_path << "#{libpath}/crti.o"
25+
ld_path << "#{gcc_libpath}/crtbegin.o"
26+
# for not static compile
27+
ld_path << "#{gcc_libpath}/crtend.o"
1828
end
29+
ld_path << "#{libpath}/libc.so"
30+
ld_path << "#{libpath}/crtn.o"
31+
cmd = [@linker, "-o", @output, "-m", "elf_x86_64", *@options, *ld_path, @input].join(' ')
32+
puts cmd if @debug
33+
cmd
1934
end
35+
36+
def libpath = @libpath ||= File.dirname(Dir.glob("/usr/lib*/**/crti.o").last)
37+
def gcc_libpath = @gcc_libpath ||= File.dirname(Dir.glob("/usr/lib/gcc/x86_64-*/*/crtbegin.o").last)
2038
end

sig/vaporware/compiler.rbs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
class Vaporware::Compiler
2+
GCC_LD_PATH: String
3+
LD_PATH: String
4+
DYN_LD_PATH: String
5+
SHARED_LD_PATH: String
26
# class methods
37
def self.compile: (String, ?compiler: String, ?dest: String, ?debug: bool, ?compiler_options: Array[String], ?shared: bool) -> void
48
def initialize: (input: String, ?output: String, ?debug: bool, ?shared: bool) -> void

sig/vaporware/compiler/assembler.rbs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,8 @@ class Vaporware::Compiler::Assembler
55
@debug: bool
66

77
def initialize: (input: String, ?output: String, ?type: Symbol, ?debug: bool) -> void
8-
def assemble: (?assemble_command: String, ?assemble_options: Array[String], ?input: String, ?output: String) -> void
8+
def assemble: (?assembler: String, ?assembler_options: Array[String] | [], ?input: String, ?output: String, ?debug: bool) -> String
9+
def obj_file: () -> String
10+
11+
private def to_elf: (?input: String, ?output: String, ?debug: bool) -> void
912
end

sig/vaporware/compiler/linker.rbs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
class Vaporware::Compiler::Linker
2+
@input: String
3+
@output: String
4+
@linker: String
5+
@options: Array[String]
6+
@shared: bool
7+
@debug: bool
8+
9+
def initialize: (input: String, ?output: String, ?linker: String, ?linker_options: Array[String], ?shared: bool, ?debug: bool) -> void
10+
def link: (input: String, ?output: String, ?shared: bool, ?debug: bool) -> void
11+
12+
def link_command: () -> String
13+
def libpath: () -> String
14+
def gcc_libpath: () -> String
15+
end

test/vaporware/test_compiler.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
require "vaporware"
2+
require "test/unit"
3+
4+
class Vaporware::LinkerTest < Test::Unit::TestCase
5+
def test_librarie
6+
linker = Vaporware::Compiler::Linker.new(input: "tmp.o")
7+
assert_false(linker.libpath.empty?, "should not be empty")
8+
assert_false(linker.gcc_libpath.empty?, "should not be empty")
9+
end
10+
11+
def test_link_command
12+
linker = Vaporware::Compiler::Linker.new(input: "tmp.o", output: "tmp")
13+
assert_match(%r|mold -o tmp -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /.+/crt1.o /.+/crti.o /.+/crtbegin.o /.+/crtend.o /.+/libc.so /.+/crtn.o tmp.o|, linker.link_command)
14+
linker = Vaporware::Compiler::Linker.new(input: "tmp.o", output: "tmp", shared: true)
15+
assert_match(%r|mold -o tmp -m elf_x86_64 --shared /.+/crti.o /.+/crtbeginS.o /.+/crtendS.o /.+/libc.so /.+/crtn.o tmp.o|, linker.link_command)
16+
end
17+
end

0 commit comments

Comments
 (0)