A little-known fact about Xcode is that is supports syntax colouring and function pop-ups for Dylan files.
Whilst this is nice, it inevitably leads to the desire to be able to build Dylan programs directly from within Xcode.
There are a few problems with this, but it turns out that with a bit of scripting it is possible. To save everyone else going through the same pain that I went through, I’ve made some template projects that you can install into Xcode.
Version
The current version is 1.1.
At the moment the file archive doesn’t include any obvious indication of the version number. I’ll try to fix that at some point. For now, if in doubt, check the output of the Build Results window - you should see a version scroll past at some point!
Downloading
You can download the templates from here.
Installation
Eventually I will make an installer, but for now you have to do the installation manually.
Extract the dylan-xcode-latest.tar.gz archive:
tar xzcf dylan-xcode-latest.tar.gzThis should produce a single folder called “Dylan Tool”. Copy this into /Library/Application Support/Apple/Developer Tools/Project Templates/Command Line Utility/
Start Xcode, and choose New Project, you should now be able to choose “Dylan Tool” from the list of templates.
Usage
Once you’ve installed the template, you can create a new Dylan project by choosing File/New Project…, then selecting Dylan Tool from the Command Line Utilities section of the assistant.
You should see a new project with three source files:
- hello.lid
- hello.dylan
- hello.dylan-exports
If you know any Dylan, you should know what these are for! If not, you probably need to check out some of the tutorials first.
You should be able to build and run this project by choosing Build and Run from the Build menu.
Known Problems
- When a file changes, all the .lid files in the same directory are rebuilt; this means that a .dylan file must be in the same directory as it’s corresponding .lid file for the dependency tracking to function correctly.
Gory Details
Xcode allows you to add custom build rules to a target. These let you specify a file type (or pattern), and state which compiler should build files of that type. Although there is no way to plug in new compilers directly, what you can do is define a shell script which runs instead. For a simple language where a source file hello.mysource would produce an output file hello.myoutput, that is all you need.
Unfortunately, Dylan is a bit more complicated, because it uses two types of ‘source’ file - the .dylan and .lid files. The compiler is only invoked on the .lid files, but each .lid file uses one or more .dylan files, so there is a dependency there. The challenge is to convince Xcode to recompile a lid file when it has changed, but also when any of its dylan files have changed.
When you add a custom build rule script, you have to specify a list of intermediate output files that the script will generate. Xcode seems to use this list in two ways:
- it will trigger the build script if the intermediate file is missing
- it will attempt to trigger a build on the intermediate file once the current build script has completed, thus allowing one tool to generate a file, then another tool to process it
Xcode allows some basic variable replacement on these file names, so it is possible for a tool to indicate simple relationships - for example when each source file generates an output file with the same name but a different extension. However, there is no way to express a more complex relationship, such as that between Dylan’s .dylan and .lid files. I had hoped that I could simply make a ‘compiler’ script for .dylan files which told Xcode that it had ‘generated’ the .lid file, and then add another compiler script for .lid files which invoked d2c. Unfortunately, there’s no way to do this when the name of the .lid files can’t be inferred from the name of the .dylan file.
The scheme I eventually settled on is a little bit more complex:
First, there is a custom script for all Dylan files (.dylan and .lid). For each file in a particular directory, the ‘compiler’ generates an index.lids file. This file is actually a shell script itself, which when executed will compile all .lid files in the directory that it was generated from.
Second, there is a script which is set to compile .lids files (an extension that I invented, and which hopefully isn’t in use by anyone else). This script will be invoked automatically by Xcode, once for every .dylan or .lid file that was processed in the previous phase. Through some stroke of luck (or good design more like), it seems that the .lids compiler will only get invoked once all of the .dylan and .lid files have been processed - which is important.
Finally, when the .lids compiler is invoked, it does two things. It starts by executing the lids file that it was invoked for. Remember that this is actually a script file itself, so it will run, and will invoke d2c. Next, the .lids compiler will replace the .lids file with a new script that just does a harmless echo to the console. The result of this is that the d2c compiler will be invoked only once for each directory processed.
That’s the theory anyway! It seems to work in my tests, but I’m keen to see how other people fare.
There are many potential improvements to this scheme, listed in the To Do section below.
Finding The Executable
One other nice thing that my scripts do is to invoke d2c in a way which causes all the intermediate c and o files to be generated inside Xcode’s DerivedSources directories, so that they don’t clutter up the dylan source folders. The downside of this right now is that the compiled executable file also ends up buried in the same directories, which isn’t very helpful! To fix this, after compiling all the lids in each source directory, the build script searches the directory for a file with a name matching the target’s “Product Name” setting. If it finds one, it copies the file back into the place where Xcode expects the product to be placed.
This allows you to easily find it, and also allows Xcode to find it, and hence to launch it for you.
Version History
1.1 - added copying of executable back to correct place - added ability to launch executable from within Xcode
1.0 - first attempt
To Do
- Installer
- Debugging?
- Get Xcode To Compile C Files?
- Template Dylan Target (for New Target menu)
- Teach Xcode about the d2c build settings
- Rename the executable when copying it?
- File Bindings & Icons?
(More coming soon…)
