require 'pathname' require 'rake/clean' require 'open3' M2C = 'gm2' # Modula-2 compiler. BOOT_OBJECTS = FileList['boot/*.mod'] .map do |source| Pathname.new(source).basename.sub_ext('.o') end def source_for_object(out_file) path = Pathname.new(out_file).relative_path_from('build') result = ['build/boot'] definition = File.join('boot', path.basename.sub_ext('.def')) result << definition if File.exist? definition implementation = path.sub_ext('.mod').to_path implementation = File.join 'build', implementation unless File.exist? implementation result << implementation end directory 'build/boot' directory 'build/self' CLEAN.include 'build' rule(/build\/.+\.o$/ => ->(file) { source_for_object(file) }) do |t| sources = t.prerequisites.filter { |f| f.end_with? '.mod' } sh M2C, '-c', '-I', 'boot', '-o', t.name, *sources end rule(/build\/self\/.+\.mod$/ => [ 'build/self', 'build/boot/Compiler', ->(file) { File.join('boot', Pathname.new(file).basename) } ]) do |t| sources, compiler = t.prerequisites .reject { |f| File.directory? f } .partition { |f| f.end_with? '.mod' } File.open t.name, 'w' do |output| puts puts(compiler * ' ') Open3.popen2(*compiler) do |cl_in, cl_out| cl_in.write File.read(*sources) cl_in.close IO.copy_stream cl_out, output cl_out.close end end end ['boot', 'self'].each do |sub| compiler_binary = Pathname.new('build') + sub + 'Compiler' file compiler_binary.to_path => BOOT_OBJECTS.map { |file| File.join('build', sub, file) } do |t| sh M2C, '-o', t.name, *t.prerequisites end compiler_object = compiler_binary.sub_ext('.o') file compiler_object.to_path => source_for_object(compiler_object) do |t| sources = t.prerequisites.filter { |f| f.end_with? '.mod' } sh M2C, '-fscaffold-main', '-c', '-I', 'boot', '-o', t.name, *sources end end task default: 'build/self/Compiler' task default: 'build/self/Compiler.mod' task default: 'boot/Compiler.mod' task :default do |t| exe, previous_output, source = t.prerequisites cat_arguments = ['cat', source] diff_arguments = ['diff', '-Nur', '--text', previous_output, '-'] puts [cat_arguments * ' ', exe, diff_arguments * ' '].join(' | ') Open3.pipeline(cat_arguments, exe, diff_arguments) end