# Platform-specific notes

## Overview

The documentation and whatever experience you may have in using &CCL; under Linux should also apply to using it under Darwin/MacOS X and FreeBSD. There are some differences between the platforms, and these differences are sometimes exposed in the implementation.

### Differences Between 32-bit and 64-bit implementations

Fixnums on 32-bit systems are 30 bits long, and are in the range -536870912 through 536870911. Fixnums on 64-bit systems are 61 bits long, and are in the range -1152921504606846976 through 1152921504606846975. (see )

Since we have much larger fixnums on 64-bit systems, `INTERNAL-TIME-UNITS-PER-SECOND` is 1000000 on 64-bit systems but remains 1000 on 32-bit systems. This enables much finer grained timing on 64-bit systems.

### File-system case

Darwin and MacOS X use HFS+ file systems by default; HFS+ file systems are usually case-insensitive. Most of &CCL;'s filesystem and pathname code assumes that the underlying filesystem is case-sensitive; this assumption extends to functions like EQUAL, which assumes that #p"FOO" and #p"foo" denote different, un-EQUAL filenames. Since Darwin/MacOS X can also use UFS and NFS filesystems, the opposite assumption would be no more correct than the one that's currently made.

Whatever the best solution to this problem turns out to be, there are some practical considerations. Doing:

    ? (save-application "DPPCCL")

on 32-bit DarwinPPC has the unfortunate side-effect of trying to overwrite the Darwin &CCL; kernel, "dppccl", on a case-insensitive filesystem.

To work around this, the Darwin &CCL; kernel expects the default heap image file name to be the kernel's own filename with the string ".image" appended, so the idiom would be:

    ? (save-application "dppccl.image")

### Line Termination Characters

MacOSX effectively supports two distinct line-termination conventions. Programs in its Darwin substrate follow the Unix convention of recognizing #\LineFeed as a line terminator; traditional MacOS programs use #\Return for this purpose. Many modern GUI programs try to support several different line-termination conventions (on the theory that the user shouldn't be too concerned about what conventions are used an that it probably doesn't matter. Sometimes this is true, other times ... not so much.

&CCL; follows the Unix convention on both Darwin and LinuxPPC, but offers some support for reading and writing files that use other conventions (including traditional MacOS conventions) as well.

This support (and anything like it) is by nature heuristic: it can successfully hide the distinction between newline conventions much of the time, but could mistakenly change the meaning of otherwise correct programs (typically when files contain both #\Return and #\Linefeed characters or when files contain mixtures of text and binary data.) Because of this concern, the default settings of some of the variables that control newline translation and interpretation are somewhat conservative.

Although the issue of multiple newline conventions primarily affects MacOSX users, the functionality described here is available under LinuxPPC as well (and may occasionally be useful there.)

None of this addresses issues related to the third newline convention ("CRLF") in widespread use (since that convention isn't native to any platform on which &CCL; currently runs). If &CCL; is ever ported to such a platform, that issue might be revisited.

Note that some MacOS programs (including some versions of commercial MCL) may use HFS file type information to recognize TEXT and other file types and so may fail to recognize files created with &CCL; or other Darwin applications (regardless of line termination issues.)

Unless otherwise noted, the symbols mentioned in this documentation are exported from the CCL package.

### Single-precision trig & transcendental functions

Despite what Darwin's man pages say, early versions of its math library (up to and including at least OSX 10.2 (Jaguar) don't implement single-precision variants of the transcendental and trig functions (#_sinf, #_atanf, etc.) &CCL; worked around this by coercing single-precision args to double-precision, calling the double-precision version of the math library function, and coercing the result back to a SINGLE-FLOAT. These steps can introduce rounding errors (and potentially overflow conditions) that might not be present or as severe if true 32-bit variants were available.

### Shared libraries

Darwin/MacOS X distinguishes between "shared libraries" and "bundles" or "extensions"; Linux and FreeBSD don't. In Darwin, "shared libraries" have the file type "dylib" : the expectation is that this class of file is linked against when executable files are created and loaded by the OS when the executable is launched. The latter class - "bundles/extensions" - are expected to be loaded into and unloaded from a running application, via a mechanism like the one used by &CCL;'s OPEN-SHARED-LIBRARY function.

## Unix/Posix/Darwin Features

&CCL; has several convenience functions which allow you to make Posix (portable Unix) calls without having to use the foreign-function interface. Each of these corresponds directly to a single Posix function call, as it might be made in C. There is no attempt to make these calls correspond to Lisp idioms, such as `setf`. This means that their behavior is simple and predictable.

For working with environment variables, there are CCL::GETENV and CCL::SETENV.

For working with user and group IDs, there are CCL::GETUID, CCL::SETUID, and CCL::SETGID. To find the home directory of an arbitrary user, as set in the user database (/etc/passwd), there is CCL::GET-USER-HOME-DIR.

For process IDs, there is CCL::GETPID.

For the `system()` function, there is CCL::OS-COMMAND. Ordinarily, it is better - both more efficient and more predictable - to use the features described in . However, sometimes you may want to specifically ask the shell to invoke a command for you.

## Cocoa Programming in &CCL;

Cocoa is one of Apple's APIs for GUI programming; for most purposes, development is considerably faster with Cocoa than with the alternatives. You should have a little familiarity with it, to better understand this section.

A small sample Cocoa program can be invoked by evaluating (REQUIRE 'TINY) and then (CCL::TINY-SETUP). This program provides a simple example of using several of the bridge's capabilities.

The Tiny demo creates Cocoa objects dynamically, at runtime, which is always an option. However, for large applications, it is usually more convenient to create your objects with Apple Interface Builder, and store them in .nib files to be loaded when needed. Both approaches can be freely mixed in a single program.

### The Command Line and the Window System

&CCL; is ordinarily a command-line application (it doesn't have a connection to the OSX Window server, doesn't have its own menubar or dock icon, etc.) By opening some libraries and jumping through some hoops, it's able to sort of transform itself into a full-fledged GUI application (while retaining its original TTY-based listener.) The general idea is that this hybrid environment can be used to test and protoype UI ideas and the resulting application can eventually be fully transformed into a bundled, double-clickable application. This is to some degree possible, but there needs to be a bit more infrastructure in place before many people would find it easy.

Cocoa applications use the NSLog function to write informational/warning/error messages to the application's standard output stream. When launched by the Finder, a GUI application's standard output is diverted to a logging facility that can be monitored with the Console application (found in /Applications/Utilities/Console.app). In the hybrid environment, the application's standard output stream is usually the initial listener's standard output stream. With two different buffered stream mechanisms trying to write to the same underlying Unix file descriptor, it's not uncommon to see NSLog output mixed with lisp output on the initial listener.

### Writing (and reading) Cocoa code

The syntax of the constructs used to define Cocoa classes and methods has changed a bit (it was never documented outside of the source code and never too well documented at all), largely as the result of functionality offered by Randall Beer's bridge; the “standard name-mapping conventions” referenced below are described in his CocoaBridgeDoc.txt file, as are the constructs used to invoke (“send messages to”) Cocoa methods.

All of the symbols described below are currently internal to the CCL package.

### The Application Kit and Multiple Threads

The Cocoa API is broken into several pieces. The Application Kit, affectionately called AppKit, is the one which deals with window management, drawing, and handling events. AppKit really wants all these things to be done by a "distinguished thread". creation, and drawing to take place on a distinguished thread.

Apple has published some guidelines which discuss these issues in some detail; see the Apple Multithreading Documentation, and in particular the guidelines on Using the Application Kit from Multiple Threads. The upshot is that there can sometimes be unexpected behavior when objects are created in threads other than the distinguished event thread; eg, the event thread sometimes starts performing operations on objects that haven't been fully initialized.

It's certainly more convenient to do certain types of exploratory programming by typing things into a listener or evaluating a “defun” in an Emacs buffer; it may sometimes be necessary to be aware of this issue while doing so.

Each thread in the Cocoa runtime system is expected to maintain a current “autorelease pool” (an instance of the NSAutoreleasePool class); newly created objects are often added to the current autorelease pool (via the -autorelease method), and periodically the current autorelease pool is sent a “-release” message, which causes it to send “-release” messages to all of the objects that have been added to it.

If the current thread doesn't have a current autorelease pool, the attempt to autorelease any object will result in a severe-looking warning being written via NSLog. The event thread maintains an autorelease pool (it releases the current pool after each event is processed and creates a new one for the next event), so code that only runs in that thread should never provoke any of these severe-looking NSLog messages.

To try to suppress these messages (and still participate in the Cocoa memory management scheme), each listener thread (the initial listener and any created via the “New Listener” command in the IDE) is given a default autorelease pool; there are REPL colon-commands for manipulating the current listener's “toplevel autorelease pool”.

In the current scheme, every time that Cocoa calls lisp code, a lisp error handler is established which maps any lisp conditions to ObjC exceptions and arranges that this exception is raised when the callback to lisp returns. Whenever lisp code invokes a Cocoa method, it does so with an ObjC exception handler in place; this handler maps ObjC exceptions to lisp conditions and signals those conditions.

Any unhandled lisp error or ObjC exception that occurs during the execution of the distinguished event thread's event loop causes a message to be NSLog'ed and the event loop to (try to) continue execution. Any error that occurs in other threads is handled at the point of the outermost Cocoa method invocation. (Note that the error is not necessarily “handled” in the dynamic context in which it occurs.)

Both of these behaviors could possibly be improved; both of them seem to be substantial improvements over previous behaviors (where, for instance, a misspelled message name typically terminated the application.)

### Acknowledgement

The Cocoa bridge was originally developed, and generously contributed by, Randall Beer.

## Building an Application Bundle

You may have noticed that (require "COCOA") takes a long time to load. It is possible to avoid this by saving a Lisp heap image which has everything already loaded. There is an example file which allows you to do this, "ccl/examples/cocoa-application.lisp", by producing a double-clickable application which runs your program. First, load your own program. Then, do:

    ? (require "COCOA-APPLICATION")

When it finishes, you should be able to double-click the &CCL; icon in the ccl directory, to quickly start your program.

The OS may have already decided that &CCL;.app isn't a valid executable bundle, and therefore won't let you double-click it. If this happens to you, to force it to reconsider, just update the last-modified time of the bundle. In Terminal:

    > touch &CCL;.app

When an image which had contained ObjC classes (which are also CLOS classes) is re-launched, those classes are "revived": all preexisting classes have their addresses updated destructively, so that existing subclass/superclass/metaclass relationships are maintained. It's not possible (and may never be) to preserve foreign instances across SAVE-APPLICATION. (It may be the case that NSArchiver and NSCoder and related classes offer some approximation of that.)

## Recommended Reading

Mac OS X - Cocoa
Cocoa Core Competencies
Cocoa Fundamentals Guide

  These are top-level pages pertaining to Cocoa in Apple's Mac OS X Developer Library. If you are unfamiliar with Cocoa, these links are good places to start.

The Objective-C Programming Language
Objective-C Runtime Programming Guide

  These provide a conceptual overview and programming guide to Objective-C the language and runtime, respectively.

Objective-C Runtime Reference

  This is one of the two most important Cocoa references; it covers all of the basics, except for GUI programming. This is a reference, not a tutorial.

Application Kit Framework Reference

  This is the other very important Cocoa reference; it covers GUI programming with Cocoa / Application Kit Framework in considerable depth. This is a reference, not a tutorial.

Mac OS X Developer Library

  This is the top page for Mac OS X developer documentation. Go here to find the documentation on any other Mac OS X API. Also go here if you need general guidance about OS X, Carbon, Cocoa, Core Foundation, or Objective-C.

Resources for Apple Developers

  This is the top page for all Apple developer documentation.

## Operating-System Dictionary

### CCL::GETENV

Function

    getenv name => value

#### Arguments and Values

name

  a string which is the name of an existing environment variable; case-sensitive

value

  if there is an environment variable named `name`, its value, as a string; if there is not, NIL

#### Description

Looks up the value of the environment variable named by `name`, in the OS environment.

### CCL::SETENV

Function

    setenv name value => errno

#### Arguments and Values

name

  a string which is the name of a new or existing environment variable; case-sensitive

value

  a string, to be the new value of the environment variable named by `name`

errno

  zero if the function call completes successfully; otherwise, a platform-dependent integer which describes the problem

#### Description

Sets the value of the environment variable named by `name`, in the OS environment. If there is no such environment variable, creates it.

### CCL::CURRENT-DIRECTORY-NAME

Function

    current-directory-name
    	      => path

#### Values

path

  a string, an absolute pathname in Posix format - with directory components separated by slashes

#### Description

Looks up the current working directory of the &CCL; process; unless it has been changed, this is the directory &CCL; was started in.

### CCL::GETUID

Function

    getuid => uid

#### Values

uid

  a non-negative integer, identifying a specific user account as defined in the OS user database

#### Description

Returns the ("real") user ID of the current user.

### CCL::SETUID

Function

    setuid uid => errno

#### Arguments and Values

uid

  a non-negative integer, identifying a specific user account as defined in the OS user database

errno

  zero if the function call completes successfully; otherwise, a platform-dependent integer which describes the problem

#### Description

Attempts to change the current user ID (both "real" and "effective"); fails unless the &CCL; process has super-user privileges or the ID given is that of the current user.

### CCL::SETGID

Function

    setgid gid => errno

#### Arguments and Values

gid

  a non-negative integer, identifying a specific group as defined in the OS user database

errno

  zero if the function call completes successfully; otherwise, a platform-dependent integer which describes the problem

#### Description

Attempts to change the current group ID (both "real" and "effective"); fails unless the &CCL; process has super-user privileges or the ID given is that of a group to which the current user belongs.

### CCL::GETPID

Function

    getpid => pid

#### Values

pid

  a non-negative integer, identifying an OS process

#### Description

Returns the ID of the &CCL; OS process.

### CCL::GET-USER-HOME-DIR

Function

    get-user-home-dir
    	      uid => path

#### Values

uid

  a non-negative integer, identifying a specific user account as defined in the OS user database

path

  a string, an absolute pathname in Posix format - with directory components separated by slashes; or NIL

#### Description

Looks up and returns the defined home directory of the user identified by `uid`. This value comes from the OS user database, not from the `$HOME` environment variable. Returns NIL if there is no user with the ID `uid`.

### CCL::OS-COMMAND

Function

    os-command command-line
    	      => exit-code

#### Values

command-line

  a string, obeying all the whitespace and escaping conventions required by the user's default system shell

exit-code

  a non-negative integer, returned as the exit code of a subprocess; zero indicates success

#### Description

Invokes the Posix function `system()`, which invokes the user's default system shell (such as sh or tcsh) as a new process, and has that shell execute `command-line`.

If the shell was able to find the command specified in `command-line`, then `exit-code` is the exit code of that command. If not, it is the exit code of the shell itself.

#### Notes

By convention, an exit code of 0 indicates success. There are also other conventions; unfortunately, they are OS-specific, and the portable macros to decode their meaning are implemented by the system headers as C preprocessor macros. This means that there is no good, automated way to make them available to Lisp.

### CCL::@CLASS

Macro

    @class class-name

#### Arguments and Values

class-name

  a string which denotes an existing class name, or a symbol which can be mapped to such a string via the standard name-mapping conventions for class names

#### Description

Used to refer to a known ObjC class by name. (Via the use LOAD-TIME-VALUE, the results of a class-name -> class lookup are cached.)

`@class` is obsolete as of late 2004, because find-class now works on ObjC classes. It is described here only because some old code still uses it.

### CCL::@SELECTOR

Macro

    @selector string

#### Arguments and Values

string

  a string constant, used to canonically refer to an ObjC method selector

#### Description

Used to refer to an ObjC method selector (method name). Uses LOAD-TIME-VALUE to cache the result of a string -> selector lookup.

### objc:defmethod

Macro

    objc:defmethod
    	      name-and-result-type ((receiver-arg-and-class) &rest;
    	      other-args) &body; body

#### Arguments and Values

name-and-result-type

  either an Objective-C message name, for methods that return a value of type `:ID`, or a list containing an Objective-C message name and a foreign type specifier for methods with a different foreign result type.

receiver-arg-and-class

  a two-element list whose first element is a variable name and whose second element is the Lisp name of an Objective-C class or metaclass. The receiver variable name can be any bindable lisp variable name, but `SELF` might be a reasonable choice. The receiver variable is declared to be "unsettable"; i.e., it is an error to try to change the value of the receiver in the body of the method definition.

other-args

  either variable names (denoting parameters of type `:ID`) or 2-element lists whose first element is a variable name and whose second element is a foreign type specifier.

#### Description

Defines an Objective-C-callable method which implements the specified message selector for instances of the existing named Objective-C class.

For a detailed description of the features and restrictions of the `OBJC:DEFMETHOD` macro, see the section Using `objc:defmethod`.

### CCL::DEFINE-OBJC-METHOD

Macro

    define-objc-method
    	        (selector class-name) &body; body

#### Arguments and Values

selector

  either a string which represents the name of the selector or a list which describes the method's return type, selector components, and argument types (see below.) If the first form is used, then the first form in the body must be a list which describes the selector's argument types and return value type, as per DEFCALLBACK.

class-name

  either a string which names an existing ObjC class name or a list symbol which can map to such a string via the standard name-mapping conventions for class names. (Note that the "canonical" lisp class name is such a symbol)

#### Description

Defines an ObjC-callable method which implements the specified message selector for instances of the existing ObjC class class-name.

### CCL::DEFINE-OBJC-CLASS-METHOD

Macro

    define-objc-class-method
    	        (selector class-name) &body; body

#### Arguments and Values

As per DEFINE-OBJC-METHOD

#### Description

Like DEFINE-OBJC-METHOD, only used to define methods on the class named by class-name and on its subclasses.

For both DEFINE-OBJC-METHOD and DEFINE-OBJC-CLASS-METHOD, the "selector" argument can be a list whose first element is a foreign type specifier for the method's return value type and whose subsequent elements are either:

- a non-keyword symbol, which can be mapped to a selector string for a parameterless method according to the standard name-mapping conventions for method selectors.

- a list of alternating keywords and variable/type specifiers, where the set of keywords can be mapped to a selector string for a parameterized method according to the standard name-mapping conventions for method selectors and each variable/type-specifier is either a variable name (denoting a value of type :ID) or a list whose CAR is a variable name and whose CADR is the corresponding argument's foreign type specifier.

### CCL:*ALTERNATE-LINE-TERMINATOR*

Variable

#### Description

This variable is currently only used by the standard reader macro function for #\; (single-line comments); that function reads successive characters until EOF, a #\NewLine is read, or a character EQL to the value of *alternate-line-terminator* is read. In &CCL; for Darwin, the value of this variable is initially #\Return ; in &CCL; for other OSes, it's initially NIL.

Their default treatment by the #\; reader macro is the primary way in which #\Return and #\Linefeed differ syntactically; by extending the #\; reader macro to (conditionally) treat #\Return as a comment-terminator, that distinction is eliminated. This seems to make LOAD and COMPILE-FILE insensitive to line-termination issues in many cases. It could fail in the (hopefully rare) case where a LF-terminated (Unix) text file contains embedded #\Return characters, and this mechanism isn't adequate to handle cases where newlines are embedded in string constants or other tokens (and presumably should be translated from an external convention to the external one) : it doesn't change what READ-CHAR or READ-LINE "see", and that may be necessary to handle some more complicated cases.

### CCL::NS-LISP-STRING

Class

#### Superclasses

NS:NS-STRING

#### Initargs

:string

  a Lisp string which is to be the content of the newly-created ns-lisp-string.

#### Description

This class implements the interface of an NSString, which means that it can be passed to any Cocoa or Core Foundation function which expects one.

The string itself is stored on the Lisp heap, which means that its memory management is automatic. However, the ns-lisp-string object itself is a foreign object (that is, it has an objc metaclass), and resides on the foreign heap. Therefore, it is necessary to explicitly free it, by sending a dealloc message.

#### Examples

You can create an ns-lisp-string with `make-instance`, just like any normal Lisp class:

    ? (defvar *the-string*
         (make-instance 'ccl::ns-lisp-string
                        :string "Hello, Cocoa."))

When you are done with the string, you must explicitly deallocate it:

    ? (ccl::send *the-string* 'dealloc)

You may wish to use an `unwind-protect` form to ensure that this happens:

    (let (*the-string*)
      (unwind-protect (progn (setq *the-string*
                                   (make-instance 'ccl::ns-lisp-string
                                                  :string "Hello, Cocoa."))
                             (format t "~&The string is ~D characters long.~%"
                                     (ccl::send *the-string* 'length)))
        (when *the-string*
          (ccl::send *the-string* 'dealloc))))

#### Notes

Currently, ns-lisp-string is defined in the file ccl/examples/cocoa-backtrace.lisp, which is a rather awkward place. It was probably not originally meant as a public utility at all. It would be good if it were moved someplace else. Use at your own risk.