home *** CD-ROM | disk | FTP | other *** search
- UNITREE -- display the UNIT dependency TREE from a Turbo Pascal compilation.
- Version 1.1.
-
- Copyright (C) 1992 J. C. Rice. All Rights Reserved.
-
- Individuals and business corporations may use UNITREE free of charge. You
- may neither sell it nor charge for distributing it without express consent of
- the copyright holder.
-
- rice@zizania.cray.com
-
- ---------------------------------------------------
-
- *** How to use it ***
-
- TPC /B [other options] main.pas | UNITREE > report.fil
- or TPC /B [other options] main.pas | UNITREE | viewer.exe
-
- where:
-
- other options are whatever else you need to compile your program
- main.pas is the name of your main program
- report.fil is the file you want the dependency tree written to
- viewer.exe is the name of your favorite display program (LIST, LESS,
- etc.)
-
- If you don't redirect the output of UNITREE, you'll see it on the screen.
- There are no command line parameters or options. TPCX can be substituted for
- TPC. You can redirect the output of TPC to a file and later redirect it as
- input to unitree.
-
- ---------------------------------------------------
-
- *** Why to use it ***
-
- I'm not going to explain UNITs and USES in this brief file. If you aren't
- already familiar with them, read chapter 3 of Borland's TP User's Guide --
- but if you aren't already familiar with them, odds are you don't need
- unitree.
-
- Unitree displays the *compilation-ordered* dependency tree of units. It does
- not display the complete graph of all interdependencies; rather, it shows how
- the TP compiler finds and resolves the USES statements, and in what order.
-
- To see what that means, consider the following trivial example, consisting
- of a main program and four units:
-
- program main; unit math; unit stats; unit ext_prec; unit prob_lib;
- uses uses uses {uses none} {uses none}
- stats, ext_prec; prob_lib,
- math; math;
-
- Here's what Turbo Pascal does in response to a full build of main.pas:
-
- step .PAS files open
-
- 1. Open main.pas main
- 2. Note the "uses stats" main
- 3. Open stats.pas main stats
- 4. Note the "uses prob_lib" main stats
- 5. Open prob_lib.pas main stats prob_lib
- 6. Compile prob_lib.pas main stats prob_lib
- 7. Close prob_lib.pas main stats
- 8. Return to stats.pas main stats
- 9. Note the "uses math" main stats
- 10. Open math.pas main stats math
- 11. Note the "uses ext_prec" main stats math
- 12. Open ext_prec.pas main stats math ext_prec
- 13. Compile ext_prec.pas main stats math ext_prec
- 14. Close ext_prec.pas main stats math
- 15. Return to math.pas main stats math
- 16. Compile math.pas main stats math
- 17. Close math.pas main stats
- 18. Return to stats.pas main stats
- 19. Compile stats.pas main stats
- 20. Close stats.pas main
- 21. Return to main.pas main
- 22. Note the "uses math" refers
- to an already-compiled unit main
- 23. Compile main.pas main
- 24. Close main.pas
-
- And here is the output of unitree for this compilation:
-
- MAIN
- └─STATS (4)
- ├─PROB_LIB (1)
- └─MATH (3)
- └─EXT_PREC (2)
-
- (Ignore the parenthetical numbers for now). As you can see, at one point in
- the compilation there were four modules in some intermediate stage of
- compilation. Now look what happens if we make a single change: switch the
- order of the units in the main program's USES statement:
-
- program main; unit math; unit stats; unit ext_prec; unit prob_lib;
- uses uses uses
- math, {***} ext_prec; prob_lib,
- stats;{***} math;
-
- step (some omitted .PAS files open
- for brevity)
-
- 1. Open main.pas main
- 2. Open math.pas main math
- 3. Open ext_prec.pas main math ext_prec
- 4. Close ext_prec.pas main math
- 5. Close math.pas main
- 6. Open stats.pas main stats
- 7. Open prob_lib.pas main stats prob_lib
- 8. Close prob_lib.pas main stats
- 9. math already compiled main stats
- 10. Close stats.pas main
- 11. Close main.pas
-
- Here is the output of unitree for this compilation:
-
- MAIN
- ├─MATH (2)
- │ └─EXT_PREC (1)
- └─STATS (4)
- └─PROB_LIB (3)
-
- Now the maximum "compilation depth" is three modules, rather than four.
- While this is obvious on inspection of these five trivial modules, imagine a
- project of 50+ units, each of which might use a dozen units -- not so easy to
- make the necessary mental picture any more. And definitely not easy to make
- this further refinement, as shown by the trivial example again:
-
- program main; unit math; unit stats; unit ext_prec; unit prob_lib;
- uses uses uses
- ext_prec,{***} ext_prec; prob_lib,
- prob_lib,{***} math;
- math,
- stats;
-
- Here is the output of unitree for this compilation:
-
- MAIN
- ├─EXT_PREC (1)
- ├─PROB_LIB (2)
- ├─MATH (3)
- └─STATS (4)
-
- By including units (ext_prec, prob_lib) in the main program that are *not*
- directly used, the compilation depth shrinks to two.
-
- Why the fuss over compilation depth? Because the compilation depth of a
- large project may cause TP to exceed MS-DOS's limit on the number of open
- files. The result is compile-time error 13, "too many open files." The
- Borland manuals diagnose this as an insufficient FILES= setting in
- CONFIG.SYS, but it's more likely to result from USES statements that aren't
- ordered to best advantage.
-
- Your strategy, then, is to move "leaf" units -- those that don't rely on any
- others -- to the beginning of the main program's USES statement. Then use
- the output of unitree to find other units that depend just on leaves, and
- place those next, etc. [Remember to leave the Borland overlay unit and the
- unit with your ovrinit call *before* anything that's overlaid.] You can also
- use unitree to look for the highest compilation depth (the units farthest to
- the right on the output) and try to shorten that path.
-
- There's another interesting consequence to the order in which Turbo Pascal
- resolves compilation dependencies: it determines the order in which unit
- intializtion code will be executed. Observe the unitree output for the three
- examples, along with the runtime output of the program:
-
- graph execution
-
- First example:
-
- MAIN initializing prob_lib
- └─STATS (4) initializing ext_prec
- ├─PROB_LIB (1) initializing math
- └─MATH (3) initializing stats
- └─EXT_PREC (2) executing main
-
-
- Second example:
-
- MAIN initializing ext_prec
- ├─MATH (2) initializing math
- │ └─EXT_PREC (1) initializing prob_lib
- └─STATS (4) initializing stats
- └─PROB_LIB (3) executing main
-
-
- Third example:
-
- MAIN initializing ext_prec
- ├─EXT_PREC (1) initializing prob_lib
- ├─PROB_LIB (2) initializing math
- ├─MATH (3) initializing stats
- └─STATS (4) executing main
-
-
- You can see that the initialization code is placed into sequence at the time
- each unit's compilation is finally resolved. In the first example, for
- instance, prob_lib is the first unit to be completely compiled, and its
- initialization code runs first. The numbers in parentheses, shown after the
- unit names, indicate the order in which initialization code will be executed.
-
- A final note: be sure to use the /B (build all) command line option on
- TPC/TPCX, to get the full tree. If you use /M (make as needed) you'll still
- get the output, but there's no telling what pieces of the picture might be
- omitted.
-
- ---------------------------------------------------
-
- *** History ***
-
- This little program is the result of a conversation I had with the
- ever-reliable Duncan Murdoch, about compilation error 13. I appreciate his
- advice.
-
- 92-06 Version 1.0. Represents nearly 70 minutes of development time, and
- almost 10 whole minutes of testing. Seems to work with
- TP versions 5.5 and 6.0; no idea about earlier versions.
- 92-06 Version 1.1. Fixed boneheaded error too embarassing to describe.
- Minor symptom: program does not run.
-
- If you use this program, consider dropping me a note to say that it was
- helpful or that it wasn't (and why). I'd appreciate it. The address is:
-
- internet: rice@zizania.cray.com
- uucp: [backbone]!uunet!cray!rice
-