From: davids@davids.b11.ingr.com (David Reed Smith)
Subject: Re: #include file dependancies
Followup-To: comp.lang.c
Reply-To: davids@davids.b11.ingr.com
Organization: Intergraph Corp., Huntsville, AL
Date: Mon, 27 Jul 1992 18:57:03 GMT

Ok, I've gotten enough requests, and I've gotten enough time to post
my Perl script which figures out which include files are not needed.

As I stated before here's how the process works:

(1) You run mkmf (or something similar) to figure out the
    dependencies.  mkmf is a makefile generator.  The first time you
    run mkmf, you will need to tell it where to look for includes, if
    you use include directories other than /usr/include.  Like this:

	mkmf "CFLAGS=-I../include -I../common/include -O"

    mkmf is present in comp.sources.misc, volume 1.  One possible
    location:

	Host wuarchive.wustl.edu

    	Location: /usenet/comp.sources.misc/volume01
	      DIRECTORY drwxrwxr-x        512  Aug 29 1991  mkmf

(2) Run mkid on all the source files, all the local include files, and
    all the system includes - even system includes included by other
    system includes (which mkmf figures out for you).

    In Makefiles generated by mkmf, there are 3 variables we are
    interested in, 'SRCS', 'EXTHDRS' and 'HDRS'.  'SRCS' are all the C
    source files, 'EXTHDRS' are all the include files not in the
    current directory, and 'HDRS' are the include files in the current
    directory.  It is easy to set up a Makefile target to do this for
    you, like this:

	id:;		mkid $(SRCS) $(EXTHDRS) $(HDRS)


    mkid is, according to the man page:

	  Mkid builds a database that stores numbers and identifier
          names, as well as the names of the files in which they
          occur.  Mkid is particularly useful with large programs
          spread out across multiple source files.  It serves as an
          aid for program maintenance and as a guide for perusing a
          program.

    mkid2 (the second version) was posted to comp.sources.unix, volume
    24.  One possible location:

	Host wuarchive.wustl.edu

	    Location: /usenet/comp.sources.unix/volume24
	      DIRECTORY drwxrwxr-x        512  Jun  7 1991  mkid2

(3) Run the included perl script, called 'check_includes', on a C
    file.  It uses the 'fid' program (included in the mkid package) to
    query the database for all the identifiers that occur both in a
    include file and the C file.  If no identifiers occur in the
    include file that are used by the C file, it reports that the
    include file is unused.  This process is continued for all the
    include files that the C file uses.  You need to give the perl
    script the same '-Idirectory' arguments that you would give to cc.

    Now, this was one of the first perl scripts I wrote, and I haven't
    touched it since, so I hope it makes since.

-------------------start of check_includes--------------------------------
#!/usr/bin/perl
#
# Program:	check_includes
# Date:		20 June 1990
# Version:	1.00
# Last Mod:	20 June 1990
# Author:	David Reed Smith (davids@davids.b11.ingr.com)
#
# Usage:
#	check_includes [-v] [-Idirectory] file(s)
#		-Idirectory: adds "directory" to list of directories
#			where check_includes searches to find include
#			files
#
# Purpose:
#	Perl script to see if the include files a source file includes
#	are really necessary.  Uses the "mkid" and "fid" programs.
#	"mkid" must be run before this script can execute.
#
# Bugs:
#	
#


$#ARGV >= 0 || die "Usage: $0 [-Idirectory] file(s)\n";

@Dirs = ();

while ($_ = $ARGV[0], /^-/) {
  shift;
  /^-I(.*)/ && (push (@Dirs, $1));
}
foreach $file (@ARGV) {
  print "file: $file...\n";
  open (FILE, "$file");
  while (<FILE>) {
    if (/^#\s*include\s+/) {
	# find include file name
	if (/"(.*)"/) {			# "name" format
	  $inc_file = $1;
	  if (!-e $inc_file) {		# if file doesn't exist
	    SEARCH: foreach $dir (@Dirs) {	# look in all directories
	      next SEARCH if (!-e "$dir/$inc_file");
	      $inc_file = "$dir/$inc_file";
	    }
	    (-e $inc_file) || die "Can't find $inc_file\n";
	  }
  	}
	elsif (/<(.*)>/) {		# <name> format
	  $inc_file = "/usr/include/" . $1;
	  (-e $inc_file) || die "Can't find $inc_file\n";
	}
	print "... includes file $inc_file";
	open (SYMBOLS, "fid $file $inc_file |");
	$used = 0;
	while (<SYMBOLS>) {
	  # don't consider standard C symbols like "char" or "int"
	  if (/^char$/ || /^extern$/ || /^int$/ || /^long$/
	      || /^struct$/ || /^sizeof$/ || /^type$/
	      || /^ultrix$/ || /^unsigned$/ || /^void$/
	      || /^DEBUG$/ || /^\d+$/ || /^0x\d+$/) {
	    # do nothing
	  }
	  else {
	    if (! $used) {
	      print "\n";
	    }
	    $used = 1;
	    chop ($_);
	    print "$_ ";
	  }
	}
	if (! $used) {
	  print ": UNUSED";
	}
	print "\n";
	close (SYMBOLS);
      }
  }
  close (FILE);
}
-------------------end of check_includes-----------------------------------

davids
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
David Smith				davids@davids.b11.ingr.com (Internet)
Intergraph Corporation	 		uunet!ingr!b11!davids!davids (UUCP)
Huntsville, AL 35807			(205) 730-5752
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~