[net.micro.mac] LightspeedC Conversion Saga

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   :-)