|Delphi Uses Cleanup|
As a contract Delphi programmer, I get a lot of projects to work on that I did not start, and therefore this issue is an important one to me. For Turbo Pascal programs TurboPower's Turbo Analyst works very well. It is only recently that I've found a similar product for Delphi. For more information see the list of recommended solutions near the bottom of this page.
When you drop a VCL component on a Delphi form the Delphi IDE automatically adds the unit(s) required by the component to the interface section uses statement. If you later remove the component, the units are not removed from the uses statement. This causes the need to sometimes clean the uses statement of unused units.
The Delphi smart linker will ignore unused code so normally the presence of these "extra" units does not increase the size of the compiled program.
One reason to optimize the uses is to improve the "documentation" of the project. Many times after I use some of these techniques I'll find that several (or sometimes many) of the units and forms in a project are not being used anywhere. I especially enjoy moving those out to a "NotUsed" directory and ignoring them.
Another benefit of removing unused units is to remove the dependency of the project on some third-party component. I've received projects where folks had dropped some third-party component on their form and later removed the component but it still had units in the uses. I get the project and I have to delete these units from the uses before I can compile it.
Special thanks go to Brian Long for his "Delphi Clinic" column in The Delphi Magazine issue 64 (December 2000). His discussion of this topic helped me to improve my technique.
I generally copy the default Delphi-5 uses clause (above) into the unit and comment out the original uses clause (in both the interface and implementation sections). Then I do save and Delphi will add all the units that the components on the form need. Next I remove all of those units from the original (commented out) unit clause so it is just left with the list of units I'll need to draw from.
Then I repeatedly compile the unit (thankfully Delphi has one of the fastest compilers) and try to guess at what unit I need to add back into the uses clause. This should help me to learn a little more about this program. I add these units manually to the TOP (or front) of the uses clause. That way if I add some components to the form later and then remove them all I need to do is to put a semicolon at the end of the default uses line (it should still be there intact), remove the units after that line, and do save and I'll get just what I need. The manually added units are put in the uses clause first so you can do this later anytime you want.
For the manually added units, I sometimes put those each on a separate line and add a comment about why it is needed.
As long as the compiler errors are in the interface section of the unit then I add the units to the interface uses clause. Once I hit the first compiler error in the implementation section I move what is left of the original commented out uses clause down to the uses clause in the implementation section. Then I add the units to the implementation section uses statement as needed to get a compile.
Once I do this to all the units in a project, I generate a map file and look for units that are not used. Any of those I find I remove from the project (dpr) file. At that point I delete all the DCU files in the project directory, do a build all, and then look again for units that do not have a corresponding DCU file. Any of those go into the "NotUsed" directory also (unless they are include files).
After cleaning all the uses my next step is generally to start eliminating any compiler warnings or hints.
Possible problems with this technique
> Doesn't this leave you open to possible hard-to-find bugs?
I can see where this could be a problem but I've never had that problem yet. In every case I've seen the parameters of the calls were different so the compiler caught the error.
What names does the VCL use in two units that you are aware of? Please let me know.
Here are the ones I know about (only one so far but probably more to come):
Another possible problem is removing a unit with only initialization and/or finalization code. If I ever find myself writing and using such a unit I would hope that I would put a big comment whenever I added the unit to a uses statement so the "trick" would be obvious.
Also note that when the compiler resolves duplicate unqualified identifiers the later units take precedence over earlier ones. You can always qualify the identifier with the unit name (as SysUtils.FindClose or Windows.FindClose above) which I think would be a better solution than re-ordering the units in the uses clause.
Pascal Analyzer from http://www.peganza.com/
Icarus - a free Uses List Analyzer for Delphi from http://www.peganza.com/
OPXperts from http://opedit.home.att.net/opxperts.htm
Customer support is our top priority!
Contact information on home page
email: see the image to the left