Maze: a ZX Spectrum oriented build tool --------------------------------------- Matt Westcott Maze is a tool for building projects, in the spirit of Make, Ant, Rake and goodness knows what else, with specific features for ZX Spectrum Z80 coding: * Separation of source files and generated files All generated files are output to the 'build' subdirectory to make it easy to clear them away when distributing source files, or committing to version control, or whatever you like to do with source files. Because .asm files are often generated, you can't just say 'delete all .obj files'... * Automatic dependency scanning It will scan .asm files for 'include' / 'incbin' lines and treat those files as dependencies to be built, so you don't have to explicitly list them in your build specification. * Built in rules for dealing with .bas, .asm, .tap, hrust compression... Prerequisites ------------- You definitely need Ruby: http://www.ruby-lang.org/ , because that's what Maze is written in. Out of the box, it also makes calls to the following programs: - Pasmo, to assemble .asm files: http://www.arrakis.es/~ninsesabe/pasmo/ - zmakebas, to compile .bas files: http://www.svgalib.org/rus/zmakebas.html - cat, to concatenate output from the above into a single .tap file (supplied as standard on Linux / OS X / Unix; for Windows, http://www.cygwin.com/ ) - chrust, to compress binary files to .hr format: http://www.west.co.tt/matt/speccy/chrust/ - Fuse, the emulator launched on completing a build: http://fuse-emulator.sourceforge.net/ Usage ----- Create a file called 'Mazefile', and run 'maze' to set the ball rolling. Mazefile is executed as a normal Ruby script, with a set of functions available to allow you to define build tasks; maze will run the first task defined in the file. The functions are: task :target => 'outputfile', :dependencies => ['onefile', 'anotherfile'] do # some ruby code here end Defines a rule for building the target 'outputfile' (which will typically be the name of the file generated by this task, but doesn't have to be). The dependencies will be built first, and then the block of ruby code is executed. If the target is a file that already exists and has a datestamp newer than any of the dependencies, the task will be skipped. (In other words, maze will only rebuild the things that have changed.) tap :target => 'output.tap' do |tap| tap.basic :source => 'loader.bas', :as => 'Loader', :line => 10 tap.asm :source => 'code.asm', :as => 'code' end Defines a rule for building a TAP file 'output.tap' containing a series of Program: and Bytes: blocks created from .bas and .asm files respectively. (There is currently no way to insert a binary file directly into the .tap as a Bytes: block, although you can easily wrap the binary in an .asm file containing a single 'incbin' line.) Any 'include' or 'incbin' lines contained in .asm files will be automatically picked up as dependencies. ':as' specifies the Spectrum-side filename to use for that block - this defaults to the source filename with its file extension removed. ':line' specifies the auto-run line number of the Basic program - this defaults to the start of the program. launch 'output.tap' Launches output.tap in the emulator (hard-coded to /Applications/Fuse.app/Contents/MacOS/Fuse - you'll probably want to edit this in the 'maze' script if you're not using a Mac), after building it if necessary. Built-in rules -------------- maze has a set of built-in rules for certain file extensions which will kick in whenever it's called upon to build a target that doesn't have an explicit rule: * For targets ending in .obj, it will try to assemble a correspondingly-named .asm file (scanning it for 'include' and 'incbin' lines to treat as dependencies first). * For targets ending in .hr, it will look for a file without the .hr extension and compress it with chrust. Final thoughts -------------- If in doubt, look at the sample Mazefile for Ninja Milkman Conspiracy :-) Matt Westcott - 2008-10-04