The pibake script (Compilers)
Like all our other compilers, the one in Lab 4 is an OCaml program that inputs a text – the source code of a program in picoPascal – and outputs a text, this time, the same program translated into ARM assembly language. Consequently, the compiler itself can run on any machine, including the x86-based machines in the lab, or an ordinary laptop. What's not possible without installing special software is to assemble and link the compiler output, or to run the resulting object code.
make in the
lab4 directory will build the compiler as usual, but the command
make test that's typically used to run regression tests has been replaced by three commands:
make test0 will compile the whole test suite, but only compare the object code with the previous version stored in the test files, and not try to run it. The command
make test1 compiles the test cases, then assembles them using a cross-assembler and runs them on an emulator called
qemu-arm. The third option,
test2, runs the code on a real ARM chip: I've set up an immense server farm of Raspberry Pi's somewhere on the internet to act as a batch service, and
make test2 submits the object code for each test case as a batch job and checks the results.
There's a shell script
tools/pibake that mediates the process of submitting batch jobs, and is called with the assembly code for each test. It generates a shell script in which the assembly code is embedded, and uses the Secure Shell protocol
ssh to submit it to a machine called
iota for execution. It goes like this:
$ make test2-digits *** Test digits.p ./ppc -O2 test/digits.p >b.s sed -n -e '1,/^(\*\[\[/d' -e '/^]]\*)/q' -e p test/digits.p | diff -u -b - b.s tools/pibake b.s >b.test + gcc -o b.out /home/guest/lib/pas0.o b.s + ./b.out sed -n -e '1,/^(\*<</d' -e '/^>>\*)/q' -e p test/digits.p | diff - b.test *** Passed
Here you can see the picoPascal compiler being run on the source program
test/digits.p to produce an assembly language file
b.s. This is compared with the saved code, then
tools/pibake is invoked to assemble and run it, capturing the output in a file
b.test. The next two lines show commands executed on the
iota server: first using
gcc to assemble the code and link it with the library
pas0.o, a precompiled copy of which is conveniently located on the target machine; then running the object code as a native program on the ARM. Finally, the output of the program is compared (on the host) with the expected output contained in the test file.
I've introduced a rudimentary mechanism that aims to prevent batch jobs from different people from interfering with each other: the batch job works inside a directory named according to your user name on the host machine. That is not enforced, however. There's no provision for avoiding interference between two simultaneous batch jobs from the same person, and in fact there's no mechanism to stop you from using the login token to connect to
iota and do whatever takes your fancy. No mechanism, that is, apart from the forbidding phrase, Tout abus sera puni.
- Although we use the
gccprogram for assembly and linking, that does not mean we are using the Gnu C Compiler. It's just that the
gcccommand provides a convenient way to invoke the assembler and linker with all the standard libraries.