shulman@topaz.RUTGERS.EDU (Jeff Shulman) (04/09/86)
[ From Delphi - Jeff ] Name: LIGHTSPEEDC CONVERSION SAGA Date: 8-APR-1986 14:09 by PEABO This is the story of my experience with converting a medium sized application program from the MANX Aztec C development environment to the LightspeedC development environment from THINK Technologies, Inc. ------------------------------------------------------------------------- This is a report on the conversion of a medium sized application program from the MANX Aztec C programming environment to LightspeedC(tm) from Think Technologies. I'm not going to go into detail about LightspeedC since you can find out about that from other sources. However, to summarize, it is an interactive development environment for C on the Mac which emphasizes quick turnaround time. It collects the files used in building a program into a 'project', which is a data structure analogous to a UNIX-like makefile and all the object code and libraries used in the compile/link. The source files are still maintained as standard text files. A built-in editor accesses files and can be used in conjunction with multiple file searches, with or without regular expression matching. Time between closing the edit window and launching the rebuilt application can typically be in the range of 10 to 30 seconds depending on how many modules need to be recompiled. After the program is debugged, an additional step is performed to produce a clickable application module from the project workspace. -------------------------------------------------------------- The nitty-gritty: I received my copy of LightspeedC on Friday, April 4, and like any cautious developer would do, I first read the manual to find out what kind of surprises I might be in store for. Finding none, I proceeded to install LightspeedC on my system. (I am using a MacPlus with an Apple HD-20.) The manual mentions that LightspeedC works with HFS, but doesn't go into detail about how to install it. They refer repeatedly to 'put this and that on the same volume', and that does translate accurately to an HFS environment if you reword it as 'in the same folder'. My working configuration (after some experimentation) looks like this: Desktop AA Light <----- folder for Lightspeed stuff, easy to click from Standard File dialogs Compiler <----- 96 files: compiler, includes, and libraries, including library sources for my convenience Demo <----- I haven't looked closely at these LCRelease <----- other misc files from the release disks #include catalog.c <----- a C file which includes all the .h's StdInclude <----- a project file for #include catalog.c I put the LightspeedC application in my Waystation menu, so I never have to open the AA Light and Compiler folders when launching the development environment. Elsewhere in the HFS hierarchy, I created a folder with all my MANX project stuff. This folder looks like this: Desktop Project <----- named the same as my program, with a P appended Source <----- .c's, .h's, .r and .rsrc, LightspeedC project workspace, and clickable application, totalling about 21 files MANX Obj <----- the MANX make file, .o's, and comparison copy of the application, also .lnk and .sym, so I have something to refer back to (discard after) Misc <----- some other related files I didn't feel like leaving out in the Project folder a couple files <----- that I want to be able to get at quickly I might at some point decide to bring the contents of Source up to the top level of the Project folder, since it would make the treewalking easier. At this point I got rid of about 90 files used by the MANX compiler which I had to leave on the Desktop of my HD-20. Halleluiah, a clean desk at last! (The version of MANX I am running is 1.06F and it does not function unless the shell, compiler, linker, assembler, all utility programs, all includes, and all source files are on the desktop in a pseudo-MFS configuration.) So I started up LightspeedC and told it to run the project, which causes it to ascertain that everything needs recompiling. Kaboom! "Include file not found". So this is surprise number one: most of the include files for the Mac managers are named differently in LightspeedC from the way they are named in MANX. OK, I can dig it. It is good practice using the editor to rewrite the includes. Most of the names are obvious variations (such as menu.h => MenuMgr.h), but a few require some investigation (like pb.h => FileMgr.h). Then I told it to rebuild, and got surprise number two. Syntax error. Sure. There doesn't appear to be anything wrong with the statement it is complaining about. I should mention that the compiler does not produce a list of errors as output. When it hits the first error it zips back to the editor and leaves the cursor at the left margin of the line it doesn't like and an alert box at the top of the screen saying what is wrong. Cute bug icon. You click the alert out of existence, make the fix, close the window, and rebuild. Well this works great when you are making small changes, but in the case of a conversion, it can be a bit tedious. (Think Technologies admits this is a potential hassle.) The real problem in this case though, was that the error message 'syntax error' was not real helpful. However, most of the other error messages are not as obscure, so I won't complain very much. It turned out to be a conflict between a symbol I #defined to fix a bug in the MANX toolbox.h file. The symbol was defined properly in the LightspeedC include, so I took the patchwork out of my .c file. I think the alert box ought to display the C code *after* preprocessing of macro invocations, and with the point of the error highlighted. This would be a feature not found in other C compilers, and a very appropriate method of improving ease of use. Now we get into the interesting case: syntax error on "struct Rect rect;". Turns out that MANX does this: struct Rect { short top; short left; short bottom; short right; }; typedef struct Rect Rect; but I had been in the habit of saying "struct Rect" anyway. LightspeedC does this instead: typedef struct { int top,left,bottom,right ; } Rect ; so the only valid way to use this is to say "Rect rect;". OK, so I do another multi-file search and destroy. The multi-file stuff works very well, by the way, and will probably encourage me to split up my programs into smaller source files. (I'm not real enthusiastic about the use of "int" in these .h files. I always use "short" or "long". MANX and LightspeedC both use "int = short", but I also develop programs for the VAX, which uses "int = long", and there are other Macintosh C compilers that use "int = long".) Next I ran into some very minor differences in the spelling of field names in structures, and a major difference in the way the ParamBlock is declared. In MANX, the fixed part of the PB is declared and there is a giant union of the variants for file, volume, etc. LightspeedC cuts out some of the excess structure, so the intermediate field names need to be changed. Also, since LightspeedC supports passing of structures, I don't have to use the pass() macro to convert Points to longs in calling sequences. Rather than edit out the pass()'s, I using a #define to make pass() do nothing. I'm not dumb -- it is a LOT harder to put the pass()'s back in than to take them out! Somewhere along the way I needed to do a multifile search of the standard .h files. No go, they aren't listed in the project, so you can't search them. (Later I did see some of them listed in the project box, so there is more to this that I understand just at the moment. It probably depends on the state of the project, such as whether a given .c file is open or not.) It was at this point that I followed the advice of the manual and created the StdInclude project referencing "#include catalog.c". Now if I have to search the system .h's, I close the project I'm working on, walk the HFS tree over to my compiler folder ("Aha!" you exclaim, "that's why he called it 'AA Light' on the Desktop.") Well, this is dandy, but it takes too damn long to get from the context of the error to the StdInclude project, and I find I lose my train of thought seriously, even though it's only 10 or 15 seconds. Too many mouseclicks in the process. There should be a way of opening a second project read-only for the purpose of searching, or of opening a folder of files as if it were a Project list. Let me also mention at this point that the editor is very good, but has a few peculiarities. For one thing, if you do a search and replace and click Replace Again too many times, it winds up pasting extra copies of the replace string into the text right after the last legitimate one. This sounds like a bug to me. The other will affect only users familiar with MDS Edit -- the trick of selecting a bit of text and invoking the Find dialog to get the search string pasted from the selection does not work. Instead you have to Copy and Paste into the Find dialog. Tabs and return characters are easily incorporated into find/replace strings though. Just hold down Option while typing tab or return. OK, back to the saga. After a bit of work, I got clean compiles all around, and of course the link failed. I should mention that I had already segmented the code to match the way I had done it with MANX. This is very easy, because the project list window shows the the segments of the program by drawing horizontal rules between segments and you simply drag the source module names around to associate them with specific segments. So I inserted a few libraries into the project. I had to do a little experimenting to find out which libraries contain which modules, but it was easier (and FASTER) to just plug libraries in by trial and error and see which symbols got resolved than to open up the book and look up the library calling sequence descriptions to see which module each of the unresolved symbols was in! Kaboom! Code segment 1 overflowed the 32768 barrier. It seems that the LightspeedC library is not very granular, and one of my favorite routines, sprintf() was responsible for dragging in about 16K of code. (Actually it is not just sprintf() that is doing this, but you get the picture -- big runtime library.) So I dragged the standard I/O package off into a segment of its own and that fixed the problem. When the linker diagnoses errors, it leaves a list of errors in a small window on the screen. I suppose you can Copy the contents of this window into the Clipboard if you need to keep the list around in a file while you fix things, but I didn't try it. Note the difference in philosophy: an error during compile is diagnosed in isolation and you are sent to the editor to fix it, whereas the link shows you all the errors it can find. Except for during massive infusions of code, I think this works very well. When you are first developing a large chunk of code, you can easily compile repeatedly to check syntax (it takes about as long as Saving the file does). So by getting into proper habits, you should never be faced with repeated and annoying cycles between the editor and the compiler. On the other hand, having a complete list of linker errors was essential for the rapid determination of which libraries were needed to complete the link. Note that all these compile and link cycles were managed by the automatic build procedures triggered when I try to RUN the application. It is also possible to compile a specific module or check the link without running the application. When you edit inside the LightspeedC development environment, it notes when you update something and computes the make list quickly. If you edit outside LightspeedC, you have to tell it to check the modification timestamps explicitly (a little slower) when computing the make. The first time the link was OK, the program launched. It also ran just fine. Then I tested the turnaround performance by making some trivial changes to the program. All worked very nicely and speedily. I tried out MacsBug, and was very pleased with the results. (LightspeedC allows you a choice of getting procedure names inserted into the code or not. MANX does not. Until now, it has not been as easy to work with MacsBug as it should have been, because of the lack of symbols in the disassembly. I'm looking forward to a more enjoyable low level debugging as well as drastically improved turnaround time.) The big deal from my point of view is that with this fast turnaround, source level debugging should be a peach. No longer will there be any point to worrying about how many print statements to put in to get information, since it does not take 5 minutes to get another make done. The last step was to build the application. This ran pretty fast, and it produced a clickable application module which worked just fine outside the LightspeedC environment. The only problem is that it is 17K bigger, and this I attribute mainly to the problem with the library routines. Aztec C seems to be pretty good about avoiding unnecessary runtime overhead, and in addition I have been suppressing the floating point library, since I don't need it for the program I am writing. LightspeedC has a way to go in this regard, but I don't regard that as a fundamental defect, but rather an opportunity for improvement in the next release. It's also not clear what the deal is if library routines are called from more than one segment. You can include the library in the root, but in MANX it was possible (and required) to list the libraries in each segment that might have symbols not yet resolved. MANX is not too clear about what they do either, since a symbol called from segment 7 and segment 13 might more properly go into segment 1 than segment 7 or both segments 7 and 13. That brings up one last point: the licensing agreement has the following language in it: You have the right to include object code derived from the libraries in programs that you develop using the software and you also have the right to use, distribute and license such programs to third parties without payment of any further license fees providing you include the following copyright notice (no less prominently than your own copyright notice) in the graphic display of your software, in the documentation for it, and on the labels affixed to the media on which your software is distributed: "Copyright 1986 THINK Technologies, Inc. Certain portions of this software are copyrighted by Think Technologies, Inc." Well, I regard that as an advertisement, and I'm not interested in being compelled to advertise another company's product in my own, EVEN THOUGH I THINK IT'S A GREAT PRODUCT. What this means is that I should write my own library routines (I might want to do that anyway, given the problems with the size of the library code). Or, I maintain some compatibility with MANX so that when I finish developing, I can go run the code through the MANX compiler to get the final executable product for shipping. What a pain. My point is that I bought a DEVELOPMENT SYSTEM from THINK, *not* a nifty C library. Come on guys, you have a great product, don't get into the nickel and dime business with this silly copyright notice. If I like your product (I do) I'll tell several thousand of my closest friends about it, and that will be a much better exposure than forcing your name into my product image. -------------------------------------------------------------- Peter Olson DELPHI ICONtact Mac User Group SIG Manager PEABO @ DELPHI PEABO @ Unison PEABO @ MCI Mail PEABO @ GEnie [76174,1670] @ CIS :-)