10 Step program to build NeXTified GNU Smalltalk 1.2Alpha3 1. gunzip smalltalk-1.2.alpha3.ns.tar.gz 2 tar xf smalltalk-1.2.alpha3.ns.tar 3. cd smalltalk-1.2.alpha3.ns 4. ./configure 5. make 6. cd objc 7. make <- Will generate some warnings, ignore them 8. ./mst -qiV <- should work no problem on any hardware platform, (Control-d) to exit mst 9. ./mst -qV OCObject.st <- Known to fail on motorolla 10 ./mst -qV browser/STBrowser.st <- the big test or 10 ./mst -qV browser/Main.st <- the big test Step 8 builds the original kernel image. Once you have created an image it is unwise to move it around. The same goes for the executable, mst, and the kernel smalltalk files. Step 9 will take anywhere from 4 to 15 minutes depending on the hardware. On my pentium 90 it takes a little longer than 4 minutes, usually.
Installing If you're going to be trying to run this on an architecture other than intel you may want to first backup all the makefiles and then run configure. If you're on an intel machine you should just type 'make'. If not on intel then diff the new makefiles with the backups and insert the changes I made. The changes I made are mainy o Compiling with the -ObjC flag (use cc not gcc) o Linking with NEXSTEP libaries o Building and linking with a new library called libOCCode.a. Once mst is built do the following machine> ./mst -Viq st> OCInterface createInterface! "<- on my pentium 90 this takes well over 4 minutes. I have also had problem where mst crashes with a floating point error but have never bothered to track it down. If this happens please let me know so that I know its not my computer. " st> Smalltalk snapshot! st> Smalltalk quitPrimitive! " or control d" machine> ./mst -qV STBrowser.st A simple browser should popup in a moment or two. It is not currently very functional. All you can do is browse the class heirarchy while looking at the class's categories and methods. There is no support for compiling changes to the methods. It wouldn't have been hard to add but I couldn't think of a way of setting it up so that it looked right. If you want to add something feel free to do so. Under the tools menu you'll find a Workspace menu button, pushing this brings up a panel in which you can enter pieces of code and have them executed. The result will be appended to the current bit of text in the window. This works. The console doens't not work and I don't know why. Look through the file STBrowser.st to see what I have done. There is an example of a new subclass of View called TextScrollView that is written entirely in smalltalk but made from objective-c objects. Smalltalk subclasses of the delegate classes found in ./OCInterfaceSupport that support a 2-way interface with smalltalk and objc. Somethings to note are o Never pass a smalltalk object to an objc object as in text setDelegate: self. Everything will die. The above should be text setDelegate: (self id). So that the value forwarded to the objc object is really an objc object. o If you subclass any objc object through smalltalk and override the init method make sure to call its super's init method. o If you're getting crashes and can't figure it out, run mst from gdb and when it crashes do a where to see what was being executed. Feel free to email (jehu@vt.edu) with your suggestions. I have hi hopes for this little baby. Future The code that creates the interface between smalltalk and objective-c is in the file OCObject.st. The instanceless class OCInterface is responsible for this undertaking. Stuff still to be done o When creating the interface or maybe updating it, only have it compile the methods for a class if they haven't already been compile. Maybe add the option to rescan a selected class. o Give each class a generic comment. o Try and make it faster some how. The library libOCCode.a contains objective-c objects that supports a two way interface with smalltalk. Currently most of these objects are delegate objects which forward the delegate methods to their smalltalk twin. I am working on writing a palette with the standard NS objects that will support this interface while allowing a user to use IB when doing the interface. The nib would then be controlled by an object that will scan the content view of window (only 1 window per nib would be allowed) and return a list of UI objects with an associated name. From there they could be used from smalltalk. John Stanhope jehu@vt.edu
GNU Smalltalk 1.2 alpha 3 <-> NeXT Objective-c Interface Explanations, Guidelines, and Hints A Crappy Explanation Of How The Interface Works. If you read this and it makes no sense to you please email me with suggestions. Its kind of hard to explain this crap. Table of pure smalltalk object pure objective-c object Abstract Creating the Classes What this interface does is create a new smalltalk classes for each class in the appkit by quering the objective-c runtime system using a few functions written by me or snagged from other code and adopted for this evil purpose. Starting with objective-c's Object and mapping it to smalltalk's OCObject the entire objective-c class heirarchy is duplicated (well not all, I wrote some smalltalk code that ignores most of the undocumented appkit classes). Each class has a single class variable to the objectice-c class and an inherited instance var which points to the id of the objective-c objects, once it has been instantiated. See the file OCInterface.st and cfunc.c to see the C and smalltalk code used to create the interface. Creating the Methods The methods are created by querying the objective-c runtime system with some special functions and then creating smalltalk code to invoke the objective-c method. The actual methods are sent using the function objc_msgSend(). For each new method a class needs to implement it creates a special call to the function objc_msgSend using the following smalltalk code Behavior defineCFunc: 'msgSend' withSelectorArgs: 'cObjectMsgSend1: anId sel: aSelector argSmalltalk: arg0' forClass: OCInterface class returning: #cObject args: #(cObject cObject smalltalk). The value 'msgSend' in the first line tells smalltalk to associate the next line with the C function objc_msgSend(). The next line is created by some C code that looks at the objective-c selector to see what its return type is and args are and then creates a unique string to represent this smalltalk callout to C code. The forClass: field tells smalltalk to add this method as a class method to OCInterface. BTW OCInterface is a instances less class used to create the smalltalk<->objective-c interface. The last two lines tell smalltalk host to convert the args passed to cObjectMsgSend1 to C types. The cObject type is a pointer and is used to pass objective-c's id type around. But you you're saying I don't want every method to go through OCInterface and have these horrid names. But wait it gets better. The new Class method to OCInterface is then used by a automatically created class like so setOOP: arg0 | anId aSelector rValue | anId _ id. aSelector _ OCInterface getUid: 'setOOP:'. rValue _ OCInterface cObjectMsgSend1: anId sel: aSelector argSmalltalk: arg0. ((OCInterface id: id equalTo: rValue) = 1) ifTrue: [ ^self ] ifFalse: [ ^OCObject newFromId: rValue. ]. The code from above is for the smalltalk version of the objective-c class STObject. This code is (usually) automatically generated for each method. Notice that is checks to see what the return type is, if its a cObject (maybe an id) we check to see if it is equal to our id, if it is we return our smalltalk self. If its not equal to our id then it wraps the object in another smalltalk object using OCObject's class method newFromId:. If the value returned is a pointer to a structure or something along those lines, things will die. Luckily appkit functions almost never return any pointers via return but by reference. Passing stuff by reference will work but you need to get a handle to the pointer first. We'll discuss how that works later though. To forward an objective-c message to smalltalk works a little different. In order for an objective-c object to forward a method to a smalltalk object it must know it exists and it also needs a way to tell the code that creates the interface between the two languages that certain objective-c methods aren't to be wrapped by smalltalk. For this to work a new objective-c class was created called STObject. It has an OOP type (the type OOP is how smalltalk objects are represented in the C smalltalk interpreter) ivar that has to be set explicitly or things will not work. The OOP ivar, named stObejct, is set using the setOOP: method and can be called from smalltalk code as self setOOP: self. This work because the self setOOP part sends the setOOP: message to the id and passes self (Internally represented as an OOP in the smalltalk interpreter) as an OOP to the objective-c method. If this is confusing dont' worry I don't think you'll need to understand it to be able to use it. Problems, Make Sure You Aren't Doing the Following 1. Avoid doing this browser setDelegate: aDelegate. because your telling an objective-c object (NXBrowser) that its delegate is a smalltalk object. What you meant was browser setDelegate: aDelegate id. The #id method returns the actual id value of a smalltalk/objective-c object. 2. If you're subclass STObject of one of the STDelegate subclasses make sure you call super's init method since it is this method that properly sets up the 2-way communication.
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.