User Manual
Portable Object Compiler


Version 3.3.10

David Stes

March 11, 2019


Contents

Introduction

How OBJECTIVE-C differs from C

OBJECTIVE-C adds a few constructs, borrowed from Smalltalk, to the C language. It is necessary, for using the OBJECTIVE-C constructs in a correct way, to learn some Smalltalk (as described, for instance, in [Goldberg and Robson, 1983]).

At least, some superficial hands on experience with a commercial Smalltalk system, or a freely available one, such as the Squeak system or such as perhaps Little Smalltalk, is an important advantage when learning OBJECTIVE-C.

Hello World

Let's start by giving our version of the well-known hello world tutorial program.

We should warn the reader at once that there is no difference with regular, plain C (as defined in [Kernighan and Ritchie, 1988]), for such a simple program.

Source code files in OBJECTIVE-C have a .m extension, so use a text-editor, such as vi, and create a file hello.m :

#include <stdio.h>

int main(int argc,char **argv)
{
    printf("hello world!\n");
}

Compile the file using the command :

objc -q hello.m -o hello

Run the program by typing hello. The -q option of the objc compiler suppresses a copyright message. If you'd like to always suppress this message, edit a file such as .cshrc (or .zshrc and so on) and do (the equivalent of):

setenv OBJCOPT "-q"

More Hello World

You normally mix regular C and OBJECTIVE-C extensions. For example, we'll extend the hello program to say hello to a Set of people.

#include <stdio.h>
#include <objpak.h>

int main(int argc,char **argv)
{
    id set = [Set new];
    argv++;while (--argc) [set add:[String str:*argv++]];
    [set do:{ :each | printf("hello, %s!\n",[each str]); }];
}

The program first includes a header file objpak.h, for defining OBJECTIVE-C datatypes. The id type (as used in the main function) is a C type that stands for an OBJECTIVE-C object. Message expressions are written inside square brackets ([receiver message]). The example creates a Set instance and adds String objects to the Set. Sets automatically remove duplicate entries, so there will be no duplicate names in the Set. Finally, the program prints a hello message for each String object in the Set, using the Block syntax, which is just using ordinary braces, as for compound statements in C.

objc -q hello.m -o hello
hello joe phil joe luke joe phil joe

You should see something like:

hello, joe!
hello, phil!
hello, luke!

Although some names were specified more than once on the command line, the program doesn't print multiple greetings for the same name; the Set object has filtered out duplicates; it uses String hashing to find equal strings.

More information

On UNIX, try man objc to read the manpage of the compiler. There are also manpages for most objects, e.g. man String or man OrdCltn will list a specification sheet for these Objects. There is also a set of HTML specification sheets.

Also see the original book [Cox, 1986] on the language, or later papers, such as [Cox, 1991]. Another good book is [Pinson and Wiener, 1990]. There exists a newsgroup, comp.lang.objective-c for asking questions, or you can just send some email.

Collection Classes

Object Pak

Object Pak is a set of classes that are interface compatible with Stepstone's ICpak101 classes, which in their turn, are modelled after Collection classes that you find in Smalltalk (see [Goldberg and Robson, 1983]).

Collections are an important set of classes; they are classes that manage groups of objects; it is almost impossible to write OBJECTIVE-C withouth using some sort of collection. A collection is simply a set of elements where each element is a pointer to an object.

Most collections do not care what class of object they manage. Each element in a collection could contain a different instance (object) from a different class. There are sometimes specific requirements, such as the fact that elements in a Set must implement the hash method.

Integer (BigInt)

BigInt instances represent (arbitrary length) integers. Typically, the OBJECTIVE-C BigInt class is much more efficient than a Smalltalk large integer, because the BigInt class is implemented in C.

OrdCltn

OrdCltn objects are the “work-horse” used most often in OBJECTIVE-C programs. They are what Smalltalk programmers call an OrderedCollection : a variable-sized collection of elements, in which the user of the collection specifies the location of each element; index keys begin at 0 and increase. The elements in the collection can be any class of Object; duplicate objects are allowed.

Set

Sets do not allow duplicate objects. A Set ignores any request that would add a duplicate to the colleciton.

String

Strings are objects that hold ordinary C strings. String objects are heavily used as elements of Collection classes.

SortCltn

SortCltn's are what Smalltalk programmers call a SortedCollection. Elements are stored in alphabetic order (by default, for Strings), or more generally, as specified by a block of code, called the SortBlock. SortCltn's are used for maintaining sorted lists of elements.

Collection Messages

new

The new message allocates a collection with a default size. It returns the new collection (empty, no elements) :

aCltn = [OrdCltn new];

When objects are added to the OrdCltn, at some point, additional space can be needed; the OrdCltn object automatically expands itself.

str:

The str: message creates a new instance by setting the contents of the object to the C string argument :

myString = [String str:"hello world"];

with:

Method to create a OrdCltn to hold the specified objects. This is an example of a method with a variable number of arguments : the first argument is the number of objects that follows.

aCltn = [OrdCltn with:1,[String str:"hello"]];

In this case, the size of this OrdCltn will equal to the number of arguments of the with: method, and the objects will be added in the same order as they are listed. But with: can also be used with other types of collections, such as a Set.

printLine

Method to print an Object on the stdout, followed by a newline.

[ [ BigInt str:"3141592654" ] printLine ];

size

Returns the number of elements currently in the collection. It is supported by all collections. If the collection is empty, the size is zero.

int n = [aCltn size];

If the receiver of the size method is nil, then this would set n to zero. If you compile with -noNilRcvr, an error message will be generated.

do:

The do: message is for looping through each element in a collection, and for running a one-argument block of code (specified by the argument) with each element as the argument (of the block). This message is used for side effects mostly, with no interest in the return value of do: itself.

The hello world example, of the introduction, is one example sending a do: message to print the elements of a Set.

Blocks are important for OBJECTIVE-C exception handling, but Blocks can also be used for simple purposes, such as counting the number of elements in a OrdCltn:

int size = 0;
[aOrdCltn do:{ :each | size++; }]
printf("%i",size);

add:

The add: message adds an element to a collection, and makes it dynamically grow (if more space is needed to hold the element). In Smalltalk, the method add: returns the element that was added. In OBJECTIVE-C, it traditionally returns the receiver (the collection) so that multiple add: messages can be nested.

[[aOrdCltn add:myObject] add:myString];

remove:

The remove: message removes the argument if it is in a collection. It returns the object that was deleted from the collection, and shrinks the size of the collection. If the object is not found, an exception is raised, which, if you do not catch it, will stop the program and display an error message.

[aOrdCltn add:myObject];
[aOrdCltn remove:myObject];

For some collections, the identity check is an equality check. For example, the Set class will remove by using the isEqual: as criterium. You should consult the class documentation (specification sheet) to be sure.

at:

This message is implemented by OrdCltn, but not by Set. It returns the object at the index specified by the argument.

for(i=0;i<[aCltn size];i++) [[aCltn at:i] foo];

is pretty much equivalent to :

[ aCltn do: { :each | [each foo]; } ];

removeAt:

This message removes the object at the specified index. This causes all succeeding elements to shift down one index position. It returns the removed object. It's most efficient to start with the last element and work towards the first element :

i = [aCltn size]; while (--i >= 0) {
    [aSet add:[aCltn removeAt:i]];
}

eachElement

This message returns a Sequence, an Object that can be used to sequentially access the contents of a OrdCltn.

id eachElement = [aCltn eachElement];
while (element = [eachElement next]) { [element foo]; }

All Collections implement eachElement so it's a good Collection-independent way to process the contents of a Collection.

addAll:

This message is to combine two collections. It can be used to move objects from Set's into OrdCltn's and vice versa. For example, the following is a quick way to delete all the duplicates from a OrdCltn :

[[OrdCltn new] addAll:[[Set new] addAll:aCltn]];

The SortCltn class can be used in the same way, as a filter to sort the objects in a collection, to then move the objects back into an indexable ordered OrdCltn.

collect:

The collect: message is similar to addAll:, but allows you to specify a transformBlock.

filter = [Set new];
aCltn  = [aCltn collect:{ :each | [filter addNTest:each] }];

The collect: method creates a new OrdCltn, which consists (in the example above) of the return values of the addNTest: method, which returns nil for duplicates. The transformBlock has as a side-effect, the creation of a Set, called “filter”, which has the same contents.

Exception Handling

Exceptions and Blocks

This chapter discusses exception handling for OBJECTIVE-C as outlined in [Cox, 1991]. The messages -error: and -ifError: are similar to messages in older Smalltalk versions. The message -on:do: is modeled after ANSI Smalltalk. The -on:do: message is supported by version 3.2.x (or higher) of OBJECTIVE-C.

The messages -error: and -ifError:

The message -error: can be used in response to some abnormal program conditio. This message can be sent to any Object.

if (!h) [ anObject error:"h can't be zero" ];

This is similar to how in Stepstone OBJECTIVE-C an error action (aborting the process) is performed.

However, in our case, the user might substitute a different Block (called exception handler) for the default handler (which aborts the process). This is done by using the method ifError: :

[ { c = [a foo]; } ifError: { :msg :rcv | printf("got an exception"); } ];

Instead of evaluating the default handler, error: will execute the exception handler specified by ifError:. The handler is invoked with a message object and with the receiver of the error: message.

Debugging Exceptions

An uncaught exception is easy to debug with OBJECTIVE-C exceptions : because the exception handler is evaluated as subroutine of the error: method, the stack backtrace towards the function that is raising the exception, is not lost.

The message -on:do:

In release 3.2.x, and newer versions, Block instances respond to the message -on:do:. This messages takes as argument the class of exceptions that should be handled, and a handler, which is a Block, taking one argument (the exception instance).

For example, to handle an exception using -on:do: :

[ { c = [a foo]; } on:OutOfMemory do: { :exc | printf("got an exception"); } ];

The -on:do: message works together with subclasses of the Exception class. You can subclass the Exception class to make your custom Exception classes. An exception is signalled as follows :

[[MyException new] signal];

The instance of the exception class that is created (by sending +new), is the argument of the handler block of the -on:do: message.

Language Elements

Class Definitions

You normally define your own class by subclassing an existing class, such as the root class, Object. A class automatically responds to all methods inherited from the superclass.

The header file, say MyObject.h, would contain:

@interface MyObject : Object { id ivar; }
+ bar;
- foo;
@end

This prototypes a class called MyObject, which is declared to be a subclass of Object, with one instance variable (called ivar) of type “id”.

The interface also exports two methods : a factory method (preceded by a “+”) and an instance method (foo). The class itself responds to factory methods; instances of the class, respond to instance methods.

The implementation file, say MyObject.m, must include the interface file, and defines the implementation of the methods.

#include "MyObject.h"

@implementation MyObject 
+ bar { return [self new] };
- foo { return ivar; }
@end

Old Style Definitions

Before OBJECTIVE-C version 4.x, the `=' syntax was used for defining classes. The Portable Object Compiler supports this syntax (in addition to the version 4.x '@' syntax) :

= MyClass : Object { id ivar; }
+ new { self = [super new]; ivar = [String new]; return self; }
=:

Class Variables

The Portable Object Compiler has an experimental implementation of class variables, using the same syntax as the K.Lerman extended Stepstone compiler.

= MyClass : Object { id ivar; } : { id cvar; }
- foo { cvar = [Object new]; return self; }
+ bar { return cvar; }
- boo:aString { ivar = aString; return self; }
- boo { return ivar; }
=:

It's currently advised, and anyhow a safe thing to do, to compile with -noSelfAssign when using class variables.

Missing Interface Definitions

Although normally you would define a .h file containing an @interface for each class, the Portable Object Compiler allows you to use @implementation without matching @interface :

@implementation MyClass : Object { id ivar; }
+ new { self = [super new]; ivar = [String new]; return self; }
@end

The compiler is warning you if it can't find an interface declaration. You can suppress the warning by using the -w flag.

Classes

Classes are implemented in the Portable Object Compiler as global variables. There is a slight (implementation) difference in the -dynamic case, but the semantics are the same.

Unlike some other compilers, but like the original Stepstone compiler, class names are ordinary expressions. Usually a class will be receiver of a message (a factory method), but it is possible to use classnames as arguments as well (in the Portable Object Compiler) :

[[ Set inheritsFrom: Object ] ifTrue: { printf("yes"); } ];

For writing completely portable code, that also compiles on older or less powerful OBJECTIVE-C compilers, you might want to write:

[[ Set inheritsFrom:[Object self] ] ifTrue: { printf("yes"); } ];

Messages

(to be completed)

Blocks

(to be completed)

Runtime

Boehm Garbage Collection

The -boehm option option simply sets the function vectors for allocating memory to the malloc() functions of the Boehm gc package. Except for some initialization code emitted for the main() of your program, there's no difference in code generation, so this is in fact a runtime issue. You have to recompile however the runtime with the Boehm library.

objc -boehm main.m

Reference Counted Garbage Collection

The -refcnt (or -gc) flag selects a different kind of garbage collection to be used : it instructs the compiler to generate reference counting code, and links a version of the runtime that supports reference counting.

objc -gc main.m

This option also causes a different runtime to be used, and it forces assignments to id variables to be translated to calls to the runtime function idassign(). This function modifies the reference count of the objects in the assignment.

By defining a variable as volatile it is possible to prevent reference count code to be used.

volatile id myObject;

Selectors

One mistake, when using the method perform:, is to assume that Selectors (of type SEL) are compatible with C Strings (of type STR). This is not the case. Selectors are uniqued strings, maintained by the runtime in a hashtable. The messenger assumes that equal selectors are also pointer equal.

The function cvtToSel in the runtime is used to convert a string to a selector. This function should not be used (it is static) because some other OBJECTIVE-C runtimes use a function of the same name, which might, in a mixed environment, give problems. You can use @selector or the method findSel:.

SEL aSel = [Object findSel:"foo"];
if (aSel) [myCltn makeElementsPerform:aSel];

Note that in many cases, a clean (and much more powerful) solution is to use a Block, instead of just a selector:

[myCltn do: { :each | [each foo]; }];

Sending Messages to Nil

The -noNilRcvr option can be used to prevent messages being sent to nil (the NULL pointer). It is in fact a runtime option, since the only effect of this option is that, when the main() of the program is compiled with this option, a nilHandler() function will be registered that stops the process, instead of simply returning nil (as the default handler does).

objc -noNilRcvr main.m

Message Tracing

It's possible to use the global msgFlag to turn message tracing on and off. Trace messages are written to msgIOD, which is normally set to stderr, unless the environment variable OBJCRTMSG is set to some filename, in which case that file is used.

setenv OBJCRTMSG "/tmp/trace"

Maybe the file should be opened in append mode (currently the file just overwrites the existing file). An easy way to prevent users to trace executables, is to set msgFlag to NO after runtime initialization (so that the OBJCRTMSG env.variable has no effect).

Initialization

General

Runtime initialization is one of the more complex aspects of OBJECTIVE-C compilers. Whenever the program launches, or whenever a dynamical library is loaded, it is necessary to make method selectors unique and to send +initialize messages to classes.

The Portable Object Compiler, like the Stepstone compiler, guarantuees that every class receives a +initialize message at start-up, during runtime initialization, and before the user program starts sending messages.

There are two different strategies implemented for runtime initialization, postlink initialization and automatic initialization. Whatever method is used, initialization works by processing an array objcModules which contains pointers to class structures in each module (object file).

The difference between the two methods is, how they construct the objcModules array.

A third method, which has not yet been done so far for the Portable Object Compiler, since it is totally unportable, would be to modify the link editor, or to use link editor specific features, for OBJECTIVE-C runtime initialization.

Postlink

The postlink method constructs the objcModules array at compile time. A small utility program, also called postlink, is used for this.

The postlink program takes as input a link map (or the output of the UNIX nm command) and writes to the stdout a C program that defines the objcModules array.

This file, automatically generated by the compiler, is then compiled and linked into the program, using a second link.

The name postlink comes from the fact that the objcModules is generated, at compile time, after a first link.

Automatic

The automatic runtime initialization strategy constructs the objcModules pointer at runtime, and requires only a single link.

This strategy depends on some compiler support, where for each function that is being called in a .m source file, an OCU entry is generated (OCU stands for OBJECTIVE-C use).

At runtime, the objcModules array is constructed by traversing the tree of dependencies, starting with the OCU_main entry, for the main() function.

Automatic runtime initialization is slightly less portable than postlink. It is however up to 30% faster during linking of larger executables, and has little overhead in space and time compared to postlink. Most UNIX drivers are configured for automatic runtime initialization, but allow you to use the -postlink option to change runtime initialization procedure, which is the safest strategy.

Note on portability

The default configuration for our compiler drivers is for automatic initialization on all UNIX platforms, on OS/2 and on Windows with the Microsoft compiler. On other platforms (Macintosh, some non-Microsoft C compilers on Windows) the default is to use postlink initialization, because it is the only alternative.

This is because our implementation of automatic runtime initialization depends on the availability of an ANSI C compiler that follows the so-called common storage linker model (see Appendix 10.6 in [Kernighan and Ritchie, 1988]).

Specifically, for the automatic runtime code to work, the C compiler is supposed to place uninitialized global variables in a segment, called the common segment, as opposed to placing them immediately, per translation unit, in the bss segment (the runtime segment of uninitialized globals).

Examples of compilers that do this by default : GNU cc, Sun acc, HP-UX cc, DEC cc, Microsoft cl, IBM icc and AIX cc. Some compilers don't do it by default, but have an option for it, such as the SGI cc or MIPSpro cc. And finally, examples of C compilers that provide the definition-reference model only : Metrowerks mwcc, WATCOM wcc.

For the interesting history of this issue, see [J.E.Lapin, 1987], a book that contains a discussion on how this C language feature was removed from the C compiler in some UNIX dialects, and how it then reappeared.

In any case, our postlink alternative, which works for both common storage and other linkage models (such as definition-reference and perhaps other models), even when it might be considerably slower for linking larger applications, is useful because it might be the only alternative for C compilers that do not provide a switch for the common storagel model.

CONCLUSION: the postlink approach works everywhere and is conceptually most portable; however, if your compiler supports the common storage model, it's best to configure our compiler driver to take advantage of this, and use the automatic initialization approach.

Threads

By default, the runtime of the Portable Object Compiler is not thread-safe. It can be made thread-safe, however, by compiling the main() of the program with -pthreads.

objc -pthreads -q main.m

This will force the compiler to link against the libpthreads library, and use locks around the OBJECTIVE-C messenger.

Compiler

Testing for Portable Object Compiler

Sometimes, it is necessary to test for the compiler that is compiling a program. It is much better to write OBJECTIVE-C code that works for all OBJECTIVE-C compilers, but in cases where compiler dependencies cannot be avoided, it is possible to test for the Portable Object Compiler by using the __PORTABLE_OBJC__ symbol :

#ifdef __PORTABLE_OBJC__
	msgFlag = YES;
#endif

Compiling C++

Because the Portable Object Compiler compiles OBJECTIVE-C into C, and because C++ is a C extension, C++ compilers can sometimes be used to compile the output of Portable Object Compiler. The option -cplus can be used to use the Portable Object Compiler in C++ mode and to make it produce intermediate code that is suitable for compilation by a C++ compiler.

objc -cplus foo.m

The C++ back-end of the Portable Object Compiler is not as widely used as the C back-end, and might therefore still be incomplete. In fact, it has only been used with GNU C++, IRIX CC and HP-UX CC up to now. However, users have successfully compiled programs that mix the C++ STL (Standard Template Library) or C++ GUI libraries, and OBJECTIVE-C.

Assignments to self

The -noSelfAssign option can be used to prevent assignments to the self pointer inside method definitions.

objc -c -noSelfAssign foo.m

By default, the compiler allows you to assign values to self.

Inline Cache

The -inlineCache option can be used to speed up the messenger. For each message expression, the compiler will generate a one-slot cache to store the resulting IMP pointer for the method look-up. In many cases, subsequent method-lookups are not needed any more.

objc -c -inlineCache foo.m

This option is not the default. It trades in speed for flexibility. It will give, for example, incorrect results when tracing messages (with the msgFlag option).

Speeding up compiles

Binary driver

You can win a few seconds, by using the binary driver instead of the Bourne shell driver on UNIX :

configure -e OBJCC=objc.exe

This will set up Makefiles that use objc.exe instead of objc. How much you win, depends on the quality of the /bin/sh interpreter that your system uses to interpret the objc script. If this is a modern, fast implementation, then using the binary driver objc.exe will not be a big win.

Temporary Files

Compiles can be made substantially faster by using a directory for temporary files that is located on a local disk (as opposed to some NFS mounted volume).

export OBJCOPT=-T/tmp/

This will place temporary files in /tmp. The Portable Object Compiler is ideal software for kernels that allow memory mapped files (the mfs filesystem on BSD UNIX for instance), since the temporary files generated by the compiler, are normally immediately removed after being created.

C Compiler Backend

Finally, consider using appropriate flags for your C compiler, since normally most time is spent in processing the output of the Portable Object Compiler (the translated sources).

export CC=lcc
export CPP="lcc -E"

It might be worthwhile to try out several compilers, some are better for producing tight, optimized executables, some compile simply faster (while producing less optimized object code).

Link Editor

Static Libraries

There's no special compiler option for building static libraries.

Static libraries can be, regardless of whether the object files are compiled with -postlink or -noPostLink, combined with the usual tools, ld, ar, ranlib etc.

Of course the same rules apply to static libraries as for ordinary object files; for example, a static library compiled with -postlink can later not be used with automatic runtime initialization. The UNIX driver would issue a warning for this (the Windows driver is configured for postlink anyhow).

OBJECTIVE-C and Dynamic Libraries

OBJECTIVE-C is well suited for development of dynamic libraries. OBJECTIVE-C messages always work through a centralized message dispatcher, which means that messages are bound to implementations only at runtime. In the case of dynamic libraries, there is no problem of undefined references, as long as you remember to resolve classnames (typically implemented as global variables) via the findClass: or findClass: methods.

id aClass = [Object findClass:"MyClass"];
if (aClass) [[aClass new] doSpecificMethod];

There will be no unresolved reference to MyClass, nor to doMyClassSpecificMethod.

In other words, the OBJECTIVE-C syntax for working with classes and methods loaded in at runtime, is, with the exception of the use of findClass:, the same as for statically linked libraries (or for shared libraries with an import library). There's no need to use functions such as dlsym() to obtain the methods.

UNIX

Dynamic Libraries

A dynamic library is an object file that can be loaded into a running OBJECTIVE-C program.

Dynamic libraries need to be compiled as follows :

objc -c -pic foo.m
objc -c -pic bar.m
objc -dl foo.o bar.o -o pkg.so

The -pic option indicates that we want to produce Position Independent Code. The -dl option instructs the compiler to generate a table of modules to be initialized, to be used by the runtime when the dynamic library is loaded.

Programs that possibly load such dynamical libraries, must be compiled with -dynamic. On some systems, the symbols of the program must be marked as exportable to the dynamic library.

objc -dynamic main.m -o main

On HP-UX,

h = shl_load(path, BIND_IMMEDIATE, 0L);
if (!h) [Object error:strerror(errno)];

On SunOS or Linux,

h = dlopen(path, 1);
if (!h) [Object error:dlerror()];

Once the package is loaded, classes (defined in the dynamic library) can be found by the usual methods :

aClass = [Object findClass:"MyClass"];
anObject = [aClass new];

Shared Libraries

Since release 1.7.5 of the compiler, shared libraries are dealt with in the same way as dynamically loaded libraries.

There's no difference in building a shared library or a dynamically loaded library :

objc -c -pic foo.m
objc -c -pic bar.m
objc -dl foo.o bar.o -o pkg.so

The only difference is that shared libraries are specified on the command line, rather than explicitely being loaded by the program:

objc -dynamic main.m pkg.so -o myprogram

Note that programs that possibly load such dynamical libraries, must be compiled with -dynamic. On some systems, the symbols of the program must be marked as exportable to the dynamic library.

The -static option can be used to prevent linking against shared libraries.

Prior to 1.7.5, the strategy was to use some sort of import library, which was, on UNIX, simply the same library, built as a static library.

Import libraries are still supported for systems that do not support initializers in shared objects using the -stubLib and -realLib options, but the disadvantage of that approach is that whenever the shared library is updated, the stub library needs to be updated too, and the program that links against the shared library should be recompiled.

objpak_s.a and objcrt_s.a

The shared library versions of the libraries objcrt.a and objpak.a can be named objpak_s.a and objcrt_s.a and the driver will automatically select these libraries, when given the -dynamic flag.

To build the libraries, simply go to the source directory of those libraries, and type (for example, for objpak.a) :

cd src/objpak
setenv OBJCOPT -pic
make
objc -dl *.o -o objpak_s.a

If you now install this version of objpak_s.a, the compiler driver will link against a shared library when given the -dynamic flag.

The procedure for objcrt_s.a is identical; it's possible to switch between static objcrt.a and shared objcrt_s.a.

Windows

Building a DLL

Building a DLL (for WIN32) is similar as for shared libraries on UNIX, but there is an extra step involved.

You need to build a Windows import library (to use the DLL). This is a .lib library that references the .dll. The import library, not the .dll itself, is specified on the command line, when linking against the .dll.

Compile the DLL as follows. The PIC flag translates to -bd -br using the WATCOM driver, and also adds a -dllexport flag, to emit dllexport directives in front of generated OBJECTIVE-C BIND functions, to export them from the DLL.

objc -c -pic foo.m
objc -c -pic bar.m
objc -dl foo.obj bar.obj -o pkg.dll

The -dl option adds an approriate LibMain() function. It's essential that this function is in the DLL, since it initializes the OBJECTIVE-C classes in the archive.

Now, install pkg.dll somewhere on the PATH, e.g. in C:\OBJC\BIN.

Next, build a (Windows) import library for the DLL. This is done as for a regular C DLL :

For WATCOM:,

wlib -n pkg.lib +pkg.dll

For lcc-win32:,

buildlib pkg.lib pkg.exp pkg.dll

Finally, to use the DLL, just specify the import library and use -dynamic. If you do not specify -dynamic, you will get undefined references.

objc -dynamic main.m pkg.lib -o main.exe

Dynamically loading DLL's

It is also possible to use the LoadLibrary function call to load in an OBJECTIVE-C DLL. The DLL will automatically initialize the classes that it contains.

To avoid including windows.h, you can have a .c file with a dlopen() definition:

int dlopen(char *name,int x) { return LoadLibrary(name) < 32; }

And in OBJECTIVE-C you simply do:

if (!dlopen("foo.dll",1)) [Object error:"can't load foo.dll"];

[[Object findClass:"FooClass"] new];

OBJCRT.DLL

There is a prebuilt binary available of the DLL at the website. The import library can be called objcrt_s.lib and the driver will select this library when given the -dynamic option.

The flags to correctly build the DLL, are:

set OBJCOPT=-pic -DOBJCRTDLL

The .dll needs to be built with:

For Watcom:

wmake -u -c
objc -dl objcrt.obj Object.obj Block.obj -o objcrt.dll
wlib -n objcrt_s.lib +objcrt.dll

For lcc-win32:

Edit the Makefile as follows:

MFLAGS=$(DLL_MFLAGS)
ALL : $(DLL)

Then run make.

OBJPAK.DLL

There is a prebuilt binary available of the DLL at the website. The import library can be called objpak_s.lib and the driver will select this library when given the -dynamic option.

The flags to correctly build the DLL, are:

set OBJCOPT=-pic

The .dll needs to be built with:

wmake -u -c
objc -dl @objpak.lnk
wlib -n objpak +objpak.dll

where objpak.lnk is a file containing the commands:

ascfiler.obj assoc.obj
cltn.obj cltnseq.obj 
dictnary.obj keyseq.obj 
ocstring.obj point.obj 
rectangl.obj sequence.obj 
set.obj setseq.obj tree.obj 
treeseq.obj valueseq.obj -o objpak.dll

Other Development Tools

Editors

ctags

ctags is a utility to generate a tags file, used by editors such as vi or vim, for their tag feature. The command :ta jumps to the line (and file) that defines the given tag.

ctags.awk is a version of an AWK implementation of ctags, that was modified to deal with OBJECTIVE-C. It works with nawk, mawk and gawk. If you use gawk, it's recommended to place the file in some location that is in the AWKPATH (so that gawk will find the file).

gawk -f ctags.awk file.m > tags

For each OBJECTIVE-C class implementation, a tag of the same name is generated.

:ta String

for instance, will jump to the file that defines the String class.

For each method implementation, two tags are generated : one which is simply the first keyword of the selector, and also a tag which is the full selector name.

:ta -remove:ifAbsent:

would jump for instance to the instance method of the same name. The tag which consists of just the first keyword, is so that the Control-] and Control-t mechanism of vi also works for methods.

vim

vim is a popular vi clone. For editing OBJECTIVE-C code, it's possible to add `[' to `cinwords' in the .vimrc file; indeed, when `[' is followed by a `{', you are most likely editing a Block expression.

set smartindent
set cinwords=if,else,while,do,for,switch,[
set showmatch

elvis

ELVIS is a vi clone with extensive support for tags. The ctags.awk program that comes with the Portable Object Compiler, supports ELVIS hints, which makes it possible to browse through all classes that implement a certain method :

:browse -reject:ifNone:

would show, for example, a list of all classes that implement -reject:ifNone:, so that it's possible to select (from a table that ELVIS shows) the implementation that you want to see.

It's also possible to jump in ELVIS immediately to a method of a specific class, like in:

:tag +new class@MyClass

which would bring you to the implementation of +new in MyClass.

ELVIS has an OBJECTIVE-C language mode (for syntax highlighting) and recognizes files with a .m extension.

emacs

I've never used the following package, but I know that there exists an Objective-C mode for emacs. Available at, for example, ftp.uni-mainz.de in the directory /pub/gnu/elisp-archive/modes/objective-C-mode.el.gz.

indent

There is a patch available (included with the compiler) for GNU indent 1.9.1, so that it works with OBJECTIVE-C. This can be used to format OBJECTIVE-C programs using the various, commonly used indentation styles. The compiler sources are indented with the following settings :

-kr -psl -i2 -bad -Tid -TBOOL -TSEL -TSTR

Debuggers

Symbolic Representation of Objects

To print an ASCII representation of an (arbitrary) Object, do something like :

call __showOn(cltn,0)

This uses the AsciiFiler class, to dump the instance variables of some object cltn to the stderr.

For example, for a collection containing one String instance, you'd get:

(gdb) call __showOn(cltn,0)
#AsciiFiler i144 
1 #OrdCltn i1 @2 
2 #String i11 i12 *11"hello world 
$1 = 86080

The first column is a number, then follows the classname, then (for a OrdCltn) the number of elements, then pointers towards the Objects that the collection contains. In this case, the collection contains a String of 11 characters.

Message Tracing in gdb

For message tracing from withing the debugger, it's useful to have the following definitions in a .gdbinit file:

# message tracing

document showmsg
turn on Objective-C message tracing
end

document stopmsg
turn off Objective-C message tracing
end

define stopmsg
set var msgFlag = 0
end

define showmsg
set var msgFlag = 1
end

Setting breakpoints

One way to set break-points on an OBJECTIVE-C method, which should work by the way with any C debugger (not just gdb), is to “fabricate” the name of the translated function yourself:

(gdb) br c_String_new
Breakpoint 1 at 0x6eac

would set a breakpoint on the (class) method “new” of the class “String”. For instance methods, the prefix is “i” instead of “c”.

This might also be useful, as some means of sending a message from within an ordinary (and arbitrary) C debugger:

(gdb) p i_OrdCltn_size(cltn,0)
$1 = 1

WATCOM wd and wdw

OBJECTIVE-C source files are compatible with the wd debugger (or wdw, the windowed debugger), and it is possible to step through OBJECTIVE-C source, set breakpoints with the mouse on specific OBJECTIVE-C method implementations etc.

objc -d3 -c test.m -o test.obj
objc -d3 test.obj -o test.exe
wd test.exe

to debug a sample project.

Integrated Development Environment

WATCOM IDE

The files ide.cfg and idew32.cfg have been modified so that automatic makefile generation works for OBJECTIVE-C source files. The IDE also offers the possibility to create an OBJECTIVE-C DLL or executable, when starting a new project.

gprof

The compiler driver has a -pg option to support gprof program profiles. The driver will also attempt to link against objcrt_p.a and objpak_p.a, if it can find them, when compiling with -pg.

objc -pg myprogram.m -o myprogram
myprogram
gprof myprogram gmon.out > myprofile

purify

The compiler was verified to work with purify on Silicon Graphics machines. Add the command purify before the normal commands to compile, and the purify driver recognizes objc as compiler, and the -o flag for producing a .pure executable.

purify objc -g myprogram.m -o myprogram

When running the executable produced in this way, memory leak and memory allocation information is obtained as for normal C programs.

Bibliography

Cox, 1986
Cox, B. J. (1986).
Object-Oriented Programming : An Evolutionary Approach.
Addison-Wesley, Reading, Mass.
Cox, 1991
Cox, B. J. (1991).
Taskmaster ecoop position paper.
In ECOOP'91, Workshop on Exception Handling And OOPLS, Geneva, Switzerland.
Goldberg and Robson, 1983
Goldberg, A. and Robson, D. (1983).
Smalltalk-80 : The Language and its Implementation.
Addison-Wesley, Reading, Mass.
J.E.Lapin, 1987
J.E.Lapin (1987).
Portable C and UNIX System Programming.
Prentice-Hall, Englewood Cliffs, N.J.
Kernighan and Ritchie, 1988
Kernighan, B. W. and Ritchie, D. M. (1988).
The C Programming Language, 2nd edition.
Prentice-Hall.
Pinson and Wiener, 1990
Pinson, L. J. and Wiener, R. S. (1990).
Applications of Object-Oriented Programming.
Addison-Wesley, Reading, Mass.

About this document ...

User Manual
Portable Object Compiler


Version 3.3.10

This document was generated using the LaTeX2HTML translator Version 2019 (Released January 1, 2019)

The command line arguments were:
latex2html -split 0 -no_images -no_navigation manual

The translation was initiated on 2019-03-11