diff --git a/Rakefile b/Rakefile index 4e8cbbc..1f175f8 100644 --- a/Rakefile +++ b/Rakefile @@ -17,10 +17,6 @@ CLEAN.include 'build/boot', 'build/valid' CLEAN.include 'doc/*.pdf' CLOBBER.include 'build' -def compile(*arguments) - sh(ENV.fetch('CC', 'gcc'), '-fpie', '-g', *arguments) -end - def run(exe) ENV.fetch('QEMU', '').split << exe end @@ -50,75 +46,74 @@ task :convert do end end -rule /^build\/[[:alpha:]]+\/stage[[:digit:]]+\/cl$/ => ->(match) { - "#{match}.o" -} do |t| - arguments_path = Pathname.new('boot') + Pathname.new(t.name).dirname.basename + 'linker.arg' - if arguments_path.exist? - arguments1 = ['--dynamic-linker', '/lib32/ld-linux-riscv32-ilp32d.so.1', '/usr/lib/crt1.o', '/usr/lib/crti.o', '-lc'] - arguments2 = ['/usr/lib/crtn.o'] - else - arguments1 = arguments2 = [] +file 'build/build.ninja' => ['build'] do |t| + File.open t.name, 'w' do |f| + f << <<~NINJA + builddir = build + cflags = -fpie -g + + rule cc + command = gcc $cflags -nostdlib -o $out $in + + rule as + command = gcc $cflags -c -o $out $in + + rule link1 + command = ld -o $out $in + + rule link2 + command = ld -o $out --dynamic-linker /lib32/ld-linux-riscv32-ilp32d.so.1 /usr/lib/crt1.o /usr/lib/crti.o -lc $in /usr/lib/crtn.o + + rule boot1 + command = build/boot/stage1/cl < \$in > \$out + + rule valid1 + command = build/valid/stage1/cl < \$in > \$out + NINJA + STAGES.each do |stage| + stage_number = stage.delete_prefix('stage').to_i + + f << <<~NINJA + + rule valid#{stage_number} + command = build/valid/stage#{stage_number}/cl < \$in > \$out + + rule boot#{stage_number} + command = build/boot/stage#{stage_number}/cl < \$in > \$out + NINJA + end + f << <<~NINJA + + build build/boot/stage1/cl: cc boot/stage1.s + + build build/valid/stage1/cl.s: boot1 boot/stage1.s | build/boot/stage1/cl + build build/valid/stage1/cl.o: as build/valid/stage1/cl.s + build build/valid/stage1/cl: link1 build/valid/stage1/cl.o + NINJA + STAGES.each do |stage| + stage_number = stage.delete_prefix('stage').to_i + + arguments_path = Pathname.new('boot') + stage + 'linker.arg' + if arguments_path.exist? + link = 'link2' + else + link = 'link1' + end + boot_stage = "build/boot/stage#{stage_number}" + valid_stage = "build/valid/stage#{stage_number}" + f << <<~NINJA + + build #{boot_stage}/cl.s: valid#{stage_number.pred} boot/stage#{stage_number}/cl.elna | build/valid/stage#{stage_number.pred}/cl + build #{boot_stage}/cl.o: as #{boot_stage}/cl.s + build #{boot_stage}/cl: #{link} #{boot_stage}/cl.o + + build #{valid_stage}/cl.s: boot#{stage_number} boot/stage#{stage_number}/cl.elna | #{boot_stage}/cl + build #{valid_stage}/cl.o: as #{valid_stage}/cl.s + build #{valid_stage}/cl: #{link} #{valid_stage}/cl.o + NINJA + end + f << "\ndefault build/valid/stage18/cl\n" end - - sh(ENV.fetch('LD', 'ld'), '-o', t.name, *arguments1, *t.prerequisites, *arguments2) -end - -rule /^build\/[[:alpha:]]+\/stage[[:digit:]]+\/cl.o$/ => ->(match) { - match.ext('.s') -} do |t| - compile('-c', '-o', t.name, *t.prerequisites) -end - -STAGES.each do |stage| - previous = stage.delete_prefix('stage').to_i.pred - - directory "build/valid/#{stage}" - directory "build/boot/#{stage}" - - file "build/valid/#{stage}/cl.s" => ["build/boot/#{stage}/cl", "boot/#{stage}/cl.elna", "build/valid/#{stage}"] do |t| - exe, source = t.prerequisites - - cat_arguments = ['cat', source] - last_stdout, wait_threads = Open3.pipeline_r(cat_arguments, run(exe)) - - IO.copy_stream last_stdout, t.name - end - - file "build/boot/#{stage}/cl.s" => ["build/valid/stage#{previous}/cl", "boot/#{stage}/cl.elna", "build/boot/#{stage}"] do |t| - exe, source = t.prerequisites - - cat_arguments = ['cat', source] - last_stdout, wait_threads = Open3.pipeline_r(cat_arguments, run(exe)) - - IO.copy_stream last_stdout, t.name - end -end - -# -# Stage 1. -# - -directory 'build/valid/stage1' -directory 'build/boot/stage1' - -file 'build/valid/stage1/cl' => ['build/valid/stage1.s'] do |t| - compile('-nostdlib', '-o', t.name, *t.prerequisites) -end - -file 'build/valid/stage1.s' => ['build/boot/stage1/cl', 'boot/stage1.s', 'build/valid/stage1'] do |t| - source, exe, = t.prerequisites.partition { |prerequisite| prerequisite.end_with? '.s' } - - cat_arguments = ['cat', *source] - last_stdout, wait_threads = Open3.pipeline_r(cat_arguments, run(exe.first)) - - IO.copy_stream last_stdout, t.name -end - -file 'build/boot/stage1/cl' => ['build/boot/stage1', 'boot/stage1.s'] do |t| - source = t.prerequisites.select { |prerequisite| prerequisite.end_with? '.s' } - - compile('-nostdlib', '-o', t.name, *source) end rule '.pdf' => '.adoc' do |t|