Python and MPW ============== There is conditional code in Python for MPW. This has been used with different compilers at various points in time. Right now it is being used to turn the entire interpreter into a shared library on 68K Macs, so we can build "applets" (see below). I have used MPW 3.2 and the OpenDoc development environment from an OpenDoc CD released in 1984. This contains the Symantec C compiler for MPW (version 7.0.4), the Universal Headers (version 2.0a1), and early versions of CFM-68K (version 1.0a1) (the Code Fragment Manager ported back to the 68K Mac) and MixedModeInit (version 1.0d12), which are required to use shared libraries. I've created a Makefile that does everything, plus a three-line Build script that calls Make and runs its output. The Makefile assumes that it lives in a 1-deep subdirectory of the root, so e.g. the Python Include directory can be referenced through "::Include". All object files are collected in the subsubdirectory Objcode. I use these feature test macros: MPW for all MPW compilers (e.g. long double in ) __SC__ for things specific to the Symantec C compiler (e.g. doesn't like static forward) __CFM68K__ for things specific to CFM-68K (e.g. it requires the use of #pragma lib_export on|off) HAVE_UNIVERSAL_HEADERS for things not yet in Think's headers (e.g. UPPs) GENERATINGCFM for both PPC and 68K Code Fragment Manager MPW is defined in config.h (if it finds that applec is defined); HAVE_UNIVERSAL_HEADERS is defined in macglue.h depending on whether it thinks we are using Universal Headers. The others are defined by the compiler or by the system headers. Compiler switches were a nightmare until I found I had to use -b. This wasn't mentioned in the CFM-68K docs that came on the OpenDoc CD-ROM. Apparently it is only needed for large projects... Warning: Mixing Think C and MPW =============================== (XXX Need to check what convention SC uses -- I hope it uses Think's.) If you are mixing Think C and MPW, you may experience weird errors in previously correct modules. These disappear when you throw away the module's .pyc file. The errors usually have to do with string literals containing '\n' or '\r'. The reason is an incompatibility between their handling of '\n' and '\r' -- in MPW C, '\n' actually is ASCII CR while '\r' is ASCII LF, which is the reverse situation from any other ASCII based C implementation. This behaviour is inherited by Python compiled with MPW C. This is normally not a problem, but *binary* files written by one system will be mis-interpreted by the other, and this is what happens to the .pyc files. There is no easy way to fix this in the source. (This is a real shame, since the format of .pyc files was carefully designed to be independent of byte order and integer size -- deviations in the ASCII character codes were never anticipated.) Building "Applets" for the Mac ============================== An "applet" is a tiny application that's written in a scripting language but behaves like a real application. The behavior is much like that of executable scripts in Unix -- but the implementation is entirely different. The applet's file can be small because it doesn't contain the actual interpreter for the scripting language -- this has to be installed in the Extensions folder (usually) before the applet will work. The applet file itself only contains a tiny bootstrap program and the script itself -- possibly "compiled" or otherwise encoded to save on parsing time and space, and to make it harder to reverse engineer the script (some people care about this). In Python's case, the Python interpreter, without its main program, is built as a shared library that is dropped in the Extensions folder. Some more shared libraries must also be present -- these form the C run-time system. [[XXX perhaps we should link these in statically with the Python library, for simpler distribution???]] On the 68K Mac, two more extensions are needed: CFM-68K (the Code Fragment Manager) and MixedModeInit. These provide functionality that's built in the Power Mac's OS. It seems that System 7.1.1 or higher is also required. The applet file contains a small main program program, plus a 'PYC ' resource named __main__ which contains the "compiled" version of the script. A 'PYC ' resource contains exactly the same data as a ".pyc" file. (The advantage of storing compiled modules as resources instead of files is that many modules can be stored in a single file.) The applet's main program initializes most of the toolbox managers (it uses the same sequence as stdwin or the Think C console I/O library), then initializes Python, then loads the resource and decodes it into a Python code object, and finally passes the code object to the Python interpreter for execution. [[XXX Actually, the applet's main program could be moved entirely to the shared library -- there's nothing in it that's dependent on the applet's configuration. The applet itself could then be reduced to main() { applet_main(); } ]] [[XXX I tried this but it only save 512 bytes on a total of 10K -- the rest is boilerplate that the linker always seems to create. Wonder how this is on the Power Mac...]] A big restriction for applets is that they have no standard input and their standard output and error streams are diverted to files called "stdout" and "stderr". This means that in order to interact with the user, or even just to provide some feedback while they're grinding along, they must make use of Mac toolbox calls to create windows, etc. I plan to provide a library that at least has the output functionality of the Think C Console I/O library or CodeWarrior's SIOX. The current procedure to create an applet is not as simple as it could be. I have written a Python script (which itself can be -- and has been -- made into an applet!) which asks for a Python source file (input) and an existing applet file (output). It adds a 'PYC ' resource to the applet named __main__, which contains the compiled code of the script (it compiles on the fly, so you don't need to have a .pyc file for the script). Although this seems fairly simple, the practical complication is that you need to copy the applet template first -- if you specify the template as the output, you will overwrite the template! [[XXX I guess a simplification could be made by using the convention that the applet built from a script has the same name as the script but with ".py" stripped; the applet-making script could then search for the template in a few common locations (e.g. the Python module search path) and copy it, reducing the user interaction to just indicating the Python source file to be converted into an applet.]]