Skip to content

Commit

Permalink
pass ci
Browse files Browse the repository at this point in the history
  • Loading branch information
katsyoshi committed Sep 16, 2023
1 parent a68eb23 commit a253c01
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 52 deletions.
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require "steep/cli"
task default: %i[test]

Rake::TestTask.new do |t|
t.test_files = FileList['test/test*.rb']
t.test_files = FileList['test/test*.rb', 'test/**/test*.rb']
end

namespace :steep do
Expand Down
45 changes: 11 additions & 34 deletions lib/vaporware/compiler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,24 @@

require_relative "compiler/generator"
require_relative "compiler/assembler"
require_relative "compiler/linker"

class Vaporware::Compiler
def self.compile(source, compiler: "gcc", dest: "tmp", debug: false, compiler_options: ["-O0"], shared: false)
_precompile = "#{dest}.s"
s = new(input: source, output: _precompile, debug:, shared:)
s = new(input: source, output: dest, debug:, shared:)
s.compile(compiler_options:)
obj_file = s.assemble(input: _precompile, assembler: "as", debug:)
output = File.basename(obj_file, ".o")
output = "lib#{output}.so" if shared && output !~ /^lib.+\.so$/
s.link(input: obj_file, output:, shared:)
File.delete(obj_file) unless debug
File.delete(_precompile) unless debug
end

def initialize(input:, output: File.basename(input, ".*") + ".s", debug: false, shared: false)
@generator = Vaporware::Compiler::Generator.new(input:, output:, debug:, shared:)
@assembler = Vaporware::Compiler::Assembler.new(input: @generator.precompile, debug:,)
end

def assemble(input:, output: File.basename(input, ".*") + ".o", assembler: "as", assembler_options: [], debug: false)
if ["gcc", "as"].include?(assembler)
assemble = [assembler, *assembler_options, "-o", output, input].compact
call_command(assemble)
else
@assembler.assemble(input:, output:)
end
output
s.assemble(input: dest.to_s + ".s", assembler: "as", debug:)
s.link
end

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)
if shared
dyn_ld_path = []
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",]

linker_options = ["-shared"]
end
linker_commands = [linker, *linker_options, *dyn_ld_path, "-o", output, *ld_path, input].compact
call_command(linker_commands)
def initialize(input:, output: File.basename(input, ".*"), linker: "ld", assembler: "as", debug: false, shared: false)
@generator = Vaporware::Compiler::Generator.new(input:, output: output + ".s", debug:, shared:)
@assembler = Vaporware::Compiler::Assembler.new(input: @generator.precompile, output: output + ".o", assembler:, debug:)
output = "lib#{output}.so" if shared && output !~ /^lib.+\.so$/
@linker = Vaporware::Compiler::Linker.new(input: @assembler.obj_file, output:, linker:, debug:, shared:)
end

def call_command(commands) = IO.popen(commands.join(" ")).close

def assemble(input:, output: File.basename(input, ".*") + ".o", assembler: "as", assembler_options: [], debug: false) = @assembler.assemble(input:, output:, assembler:, assembler_options:, debug:)
def link = @linker.link
def compile(compiler_options: ["-O0"]) = @generator.compile
end
15 changes: 13 additions & 2 deletions lib/vaporware/compiler/assembler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
class Vaporware::Compiler::Assembler
def self.assemble!(input, output = File.basename(input, ".*") + ".o") = new(input:, output:).assemble

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

def assemble(assemble_command: "as", assemble_options: [], input: @input, output: @output)
def assemble(assembler: "as", assembler_options: [], input: @input, output: @output, debug: false)
if ["gcc", "as"].include?(assembler)
IO.popen([assembler, *assembler_options, "-o", output, input].join(" ")).close
else
to_elf(input:, output:)
end
output
end
def obj_file = @output

private
def to_elf(input: @input, output: @output, debug: false)
f = File.open(output, "wb")
read = { main: false }
program_size = 0
Expand Down
44 changes: 31 additions & 13 deletions lib/vaporware/compiler/linker.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,38 @@
# frozen_string_literal: true
module Vaporware
class Compiler
class Linker
DEFAULT_LIBRARY_PATH = %w(/lib64/libc.so.6 /usr/lib64/crt1.o /usr/lib64/crtn.o)
def self.link!(source, dest = "a.out", linker: "mold", lib_path: [], options: []) = new(source, dest, linker:, lib_path:, options:)
class Vaporware::Compiler::Linker
def self.link!(source, dest = "a.out", linker: "mold", options: []) = new(input: source, output: dest, linker:, options:).link

def initialize(input, output = "a.out", linker: "mold", lib_path: [], options: [])
@input, @output, @linker = input, output, linker
@lib_path = DEFAULT_LIBRARY_PATH + lib_path
@options = options
end
def initialize(input:, output: "a.out", linker: "mold", linker_options: [], shared: false, debug: false)
@input, @output, @linker = input, output, linker
@options = linker_options
@debug, @shared = debug, shared
end

def link = IO.popen(link_command).close
def link(input: @input, output: @output, debug: @debug, shared: @shared) = IO.popen(link_command).close

private
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+/)
def link_command
ld_path = []
if @shared
ld_path << "--shared"
ld_path << "#{libpath}/crti.o"
ld_path << "#{gcc_libpath}/crtbeginS.o"
ld_path << "#{gcc_libpath}/crtendS.o"
else
ld_path << "-dynamic-linker"
ld_path << "/lib64/ld-linux-x86-64.so.2"
ld_path << "#{libpath}/crt1.o"
ld_path << "#{libpath}/crti.o"
ld_path << "#{gcc_libpath}/crtbegin.o"
# for not static compile
ld_path << "#{gcc_libpath}/crtend.o"
end
ld_path << "#{libpath}/libc.so"
ld_path << "#{libpath}/crtn.o"
cmd = [@linker, "-o", @output, "-m", "elf_x86_64", *@options, *ld_path, @input].join(' ')
puts cmd if @debug
cmd
end

def libpath = @libpath ||= File.dirname(Dir.glob("/usr/lib*/**/crti.o").last)
def gcc_libpath = @gcc_libpath ||= File.dirname(Dir.glob("/usr/lib/gcc/x86_64-*/*/crtbegin.o").last)
end
4 changes: 4 additions & 0 deletions sig/vaporware/compiler.rbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
class Vaporware::Compiler
GCC_LD_PATH: String
LD_PATH: String
DYN_LD_PATH: String
SHARED_LD_PATH: String
# class methods
def self.compile: (String, ?compiler: String, ?dest: String, ?debug: bool, ?compiler_options: Array[String], ?shared: bool) -> void
def initialize: (input: String, ?output: String, ?debug: bool, ?shared: bool) -> void
Expand Down
5 changes: 4 additions & 1 deletion sig/vaporware/compiler/assembler.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,8 @@ class Vaporware::Compiler::Assembler
@debug: bool

def initialize: (input: String, ?output: String, ?type: Symbol, ?debug: bool) -> void
def assemble: (?assemble_command: String, ?assemble_options: Array[String], ?input: String, ?output: String) -> void
def assemble: (?assembler: String, ?assembler_options: Array[String] | [], ?input: String, ?output: String, ?debug: bool) -> String
def obj_file: () -> String

private def to_elf: (?input: String, ?output: String, ?debug: bool) -> void
end
15 changes: 15 additions & 0 deletions sig/vaporware/compiler/linker.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class Vaporware::Compiler::Linker
@input: String
@output: String
@linker: String
@options: Array[String]
@shared: bool
@debug: bool

def initialize: (input: String, ?output: String, ?linker: String, ?linker_options: Array[String], ?shared: bool, ?debug: bool) -> void
def link: (input: String, ?output: String, ?shared: bool, ?debug: bool) -> void

def link_command: () -> String
def libpath: () -> String
def gcc_libpath: () -> String
end
17 changes: 17 additions & 0 deletions test/vaporware/compiler/test_linker.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
require "vaporware"
require "test/unit"

class Vaporware::Compiler::LinkerTest < Test::Unit::TestCase
def test_librarie
linker = Vaporware::Compiler::Linker.new(input: "tmp.o")
assert_false(linker.libpath.empty?, "should not be empty")
assert_false(linker.gcc_libpath.empty?, "should not be empty")
end

def test_link_command
linker = Vaporware::Compiler::Linker.new(input: "tmp.o", output: "tmp")
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)
linker = Vaporware::Compiler::Linker.new(input: "tmp.o", output: "tmp", shared: true)
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)
end
end
2 changes: 1 addition & 1 deletion test/test_vaporware.rb → test/vaporware/test_compiler.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require "vaporware"
require "test/unit"

class VaporwareTest < Test::Unit::TestCase
class Vaporware::CompilerTest < Test::Unit::TestCase
def tear_down = File.delete("tmp") rescue File.delete(@generated)
def test_sample_plus
@file = "sample/plus.rb"
Expand Down

0 comments on commit a253c01

Please sign in to comment.