Previous Page
Next Page

3.5. Compiled Script Files

A compiled script file is just what you think it is: it's a file containing the bytecode of a compiled script. Unlike text, a compiled script file can be executed without being compiled (because it's already compiled); the runtime engine is fed the bytecode and can leap into action immediately. A lengthy script can take several seconds to compile, so a compiled script file clearly saves some time and overhead when the script is executed. Obviously this architecture is advantageous when the script is not going to change and therefore will not need compiling ever againwhen you distribute the script to others, for example. Applications that act as script runners typically operate on compiled script files (see "Script Runner" in Chapter 2). Script editor applications save a script as a compiled script file by default. When an application has asked the AppleScript scripting component to compile some text, a compiled script file is the only way for the compiled script to outlive that instance of the AppleScript scripting component, which will go out of existence when the host application quits.

(There is actually more to a script, and therefore there can be more to a compiled script file, than the compiled bytecode. I'll discuss these further contents of a compiled script file in "Persistence of Top-Level Entities" in Chapter 8 and "Closures and Stored Script Objects" in Chapter 10.)

You cannot save as a compiled script file code that, for whatever reason, will not compile. This seems tautological, but it can be surprising nevertheless, so it is worth mentioning.

3.5.1. Compiled Script File Formats

To make things more complicated, a compiled script file can come in not one, not two, but three different formats :


Resource-fork file

The bytecode is kept in the file's resource fork ; there is no data fork . The type is 'osas'; the extension is .scpt. Historically, this is the oldest form. Script Editor will not create a file in this form (though Script Debugger can), but if Script Editor encounters such a file it can open, edit, and save it in the same form.


Data-fork file

The bytecode is kept in the file's data fork. (There may be a resource fork, but it's for other things, such as the script's description and window state.) The type is 'osas'; the extension is .scpt. This is the default form created by Script Editor, where it is called simply "script"; Script Debugger calls it "Compiled Script (Data Fork)."


Script Bundle

The bytecode is kept in the data fork of a file called main.scpt, which has no resource fork and lives inside the Contents/Resources/Scripts folder of a bundle . (A bundle is a folder that is presented through the graphical user interface as a file.) Other information is stored in the data fork of other files in the bundle; the description, if any, lives in a file called description.rtfd, and window state is stored in the bundle's Info.plist. The bundle can be used to hold further ancillary resources (an example appears in Chapter 25). Script Editor calls this format "script bundle "; Script Debugger calls it "Compiled Script (Bundle)."

Originally there was just one compiled script formatthe resource-fork file . Life was simple: any context that might open a compiled script file in order to run it (technically known as loading the script) could be relied upon to deal with any compiled script file whatsoever. Then when Mac OS X came along, there was a general move to eliminate use of the resource fork everywhere; this resulted in the data-fork file format. Finally, Panther introduced the script bundle format, along with some system functionality that in theory would allow an application to load a compiled script file without worrying about its format.

A resource-fork script file and a data-fork script file look exactly the same from the outside, so to distinguish them you have to be sneaky. You can do it using the command line in the Terminal; an easy GUI-based alternative is HexEdit (http://www.ifd.com/hexedit).

The wholesale deprecation of resource forks early in the history of Mac OS X has now, ironically enough, been countered by a move in the opposite direction, generalizing the resource-fork mechanism to allow multiple, arbitrarily named forks. See John Siracusa's article on file metadata in Tiger: http://arstechnica.com/reviews/os/macosx-10.4.ars/6.


Two kinds of problem have resulted from this proliferation of compiled script file formats . The first has to do with backwards compatibility. A script bundle can't be opened on any system before Panther (Mac OS X 10.3). A data-fork file can't be opened on most pre-Mac OS X systems. But those are the only two formats that Apple's Script Editor can create, so any compiled script file created by Script Editor will lack some backwards compatibility.

(To be precise about data-fork file compatibility, a data-fork file created by the current Script Editor can usually be opened by Script Editor 1.8.3 on a pre-Mac OS X system. But if you go back any further, to Script Editor 1.4.3which was the standard as recently as the early days of Mac OS 9it won't be able to open it.)

The second problem is that some applications in common use predate the development of one or both of the more recent formats, or for some other reason fail to take proper account of the multiplicity of possible formats. So, for example, Entourage X can't deal with data-fork scripts, and Entourage 2004 can't deal with script bundles. (In fact, iTunes doesn't deal very well with script bundles either.) NSAppleScript (used by Cocoa applications to load compiled scripts) can deal with resource-fork files in Tiger, but couldn't do so in Jaguar (Mac OS X 10.2). This puts the onus on the programmer to make sure the intended script file format will work properly in the particular context where it is to be run, while longing for the good old days when a script was a script was a script.

3.5.2. Run-only Scripts

Normally, a compiled script actually contains two kinds of information:

  • The tokens (bytecode) needed to run the script

  • Further information needed to decompile the script and display it to the user

For example, let's say you put a comment into your script. This comment is nothing that the runtime can execute; that's what it means to be a comment. But clearly you don't want this comment thrown away merely because you compile the script; the compiled script therefore retains it, so that when the script is decompiled, you can still read the comment. Similarly, the names of variables are intended entirely for humans; as far as bytecode is concerned, it would be sufficient to assign them numbers, and that's probably what AppleScript bytecode does. But you want to be able to read your variable names the next time you edit the script, so they are saved as part of the compiled script, even though they aren't needed for execution.

A compiled script can optionally be saved as run-only . (In Script Editor, this option appears as a checkbox in the Save dialog; in Script Debugger, choose File Export Run-Only Script.) In this case, the tokens needed merely to decompile the script and display it to the user are not written into the resulting compiled script file. This makes the compiled script file much smaller and probably causes it to run a bit faster, but it cannot be opened for display or editing.

Be careful when saving a script as run-only. If you have not retained a separate copy that isn't run-only, you will never again be able to read or edit that script.


The usual reason for saving a script as run-only is to keep it from prying eyesyou want to be able to send the script to other people so they can use it, without their being able to read it. There are, however, alternative ways to accomplish the same goal, which may be easier or friendlier. The scripts in an Automator action or an AppleScript Studio application are run-only; but these built products are separate from the original scripts, which remain editable on your machine.


Previous Page
Next Page