summaryrefslogtreecommitdiff
path: root/rakelib/tester.rake
blob: 4caae20b06354d030bba0f04c16a12dfcf9b9b31 (plain)
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
# This Source Code Form is subject to the terms of the Mozilla Public License,
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
# obtain one at https://mozilla.org/MPL/2.0/. -}

require 'open3'
require 'rake/clean'
require_relative 'shared'

CLEAN.include(TMP + 'riscv')

LINKER = 'build/rootfs/riscv32-unknown-linux-gnu/bin/ld'
AS = 'build/rootfs/riscv32-unknown-linux-gnu/bin/as'

namespace :test do
  test_sources = FileList['tests/vm/*.elna', 'tests/vm/*.s']
  compiler = `cabal list-bin elna`.strip
  object_directory = TMP + 'riscv/tests'
  root_directory = TMP + 'riscv/root'
  executable_directory = root_directory + 'tests'
  expectation_directory = root_directory + 'expectations'
  init = TMP + 'riscv/root/init'
  builtin = TMP + 'riscv/builtin.o'

  directory root_directory
  directory object_directory
  directory executable_directory
  directory expectation_directory

  file builtin => ['tools/builtin.s', object_directory] do |task|
    sh AS, '-o', task.name, task.prerequisites.first
  end

  test_files = test_sources.flat_map do |test_source|
    test_basename = File.basename(test_source, '.*')
    test_object = object_directory + test_basename.ext('.o')

    file test_object => [test_source, object_directory] do |task|
      case File.extname(task.prerequisites.first)
      when '.s'
        sh AS, '-mno-relax', '-o', task.name, task.prerequisites.first
      when '.elna'
        sh compiler, '--output', task.name, task.prerequisites.first
      else
        raise "Unknown source file extension #{task.prerequisites.first}"
      end
    end
    test_executable = executable_directory + test_basename

    file test_executable => [test_object, executable_directory, builtin] do |task|
      objects = task.prerequisites.filter { |prerequisite| File.file? prerequisite }

      sh LINKER, '-o', test_executable.to_path, *objects
    end
    expectation_name = test_basename.ext '.txt'
    source_expectation = "tests/expectations/#{expectation_name}"
    target_expectation = expectation_directory + expectation_name

    file target_expectation => [source_expectation, expectation_directory] do
      cp source_expectation, target_expectation
    end

    [test_executable, target_expectation]
  end

  file init => [root_directory] do |task|
    cp (TMP + 'tools/init'), task.name
  end
  # Directories should come first.
  test_files.unshift executable_directory, expectation_directory, init

  file (TMP + 'riscv/root.cpio') => test_files do |task|
    root_files = task.prerequisites
      .map { |prerequisite| Pathname.new(prerequisite).relative_path_from(root_directory).to_path }

    File.open task.name, 'wb' do |cpio_file|
      cpio_options = {
        chdir: root_directory.to_path
      }
      cpio_stream = Open3.popen2 'cpio', '-o', '--format=newc', cpio_options do |stdin, stdout, wait_thread|
        stdin.write root_files.join("\n")
        stdin.close
        stdout.each { |chunk| cpio_file.write chunk }
        wait_thread.value
      end
    end
  end

  task :vm => (TMP + 'riscv/root.cpio') do |task|
    kernels = FileList.glob(TMP + 'tools/linux-*/arch/riscv/boot/Image')

    sh 'qemu-system-riscv32',
      '-nographic',
      '-M', 'virt',
      '-bios', 'default',
      '-kernel', kernels.first,
      '-append', 'quiet panic=1',
      '-initrd', task.prerequisites.first,
      '-no-reboot'
  end
end