Artifact
308edf5400e1cef669bc11ebbdfae9891ad6bc01:
Attachment "makedep.tcl" to
ticket [427697ffff]
added by
dkf
2001-05-27 19:34:17.
#! /bin/sh
# Restart with Tcl... \
exec tclsh "$0" ${1+"$@"}
package require Tcl 8.3
# Set up some global variables; some may also be adjusted from the
# command-line, so this procedure also acts as a command-line parser
proc SetupGlobals {} {
global SOURCEDIRS MAKEFILE argv argv0 markerString includeRE
set SOURCEDIRS {../compat ../generic}
set MAKEFILE test.mk
set markerString "### Automatically generated after this line:\
do not edit ###"
set includeRE {^#\s*include\s+[<"](?:.*?/)?([^/]+?)[">]\s*$}
for {set i 0} {$i<[llength $argv]} {incr i} {
switch -- [lindex $argv $i] {
-makefile {
set MAKEFILE [lindex $argv [incr i]]
}
-directory {
set filename [lindex $argv [incr i]]
if {[string equal $filename "-"]} {
set SOURCEDIRS {}
} else {
lappend SOURCEDIRS $filename
}
}
-version {
puts "makedep version 0.1a1, using Tcl [package require Tcl]"
exit 0
}
-help - default {
puts stderr "usage: $argv0 ?-option argument ...?\n"
puts stderr "Options that are understood are:"
puts stderr " -makefile filename\tSpecifies the makefile to\
place the dependency\n \
\tinformation in.\n -directory dir \tSpecifies\
an additional directory to search\
for\n \tsource and include\
files; the special value \"-\"\n \
\tclears the list of directories.\n \
-help \tPrint this message.\n \
-version \tPrint the script version number."
exit 1
}
}
}
}
# get list of source files; *always* process the current directory
proc MakeFileList {} {
global SOURCEDIRS filelist tails objects
set filelist [glob -types f {*.[ch]}]
foreach dir $SOURCEDIRS {
eval lappend filelist [glob -types f -directory $dir {*.[ch]}]
}
array set tails {}
set objects {}
foreach filename $filelist {
if {[info exist tail([file tail $filename])]} {
error "\"[info exist tail([file tail $filename])]\" has\
potential duplicate in \"$filename\""
}
set tails([file tail $filename]) $filename
if {[string equal [string index $filename end] "c"]} {
lappend objects [file rootname [file tail $filename]].o
} else {
lappend objects ""
}
}
}
# work out what file includes what
proc ReadSourceFiles {} {
global includes filelist includeRE tails
array set includes {}
foreach filename $filelist {
set includes($filename) {}
set f [open $filename r]
while {[gets $f line] >= 0} {
# skip non-include lines
if {![regexp $includeRE $line -> incfile]} {
continue
}
# skip inclusions of files not in the source tree we examined
# earlier (assume it refers to a system include file.)
if {![info exist tails($incfile)]} {
continue
}
# map to the file to actually include
lappend includes($filename) $tails($incfile)
}
close $f
}
}
# filename comparison routine; produces a relatively aesthetic
# ordering for dependency lists.
proc cmpFilenames {a b} {
set cmp [string compare [file extension $a] [file extension $b]]
if {$cmp == 0} {
set cmp [string compare [file tail $a] [file tail $b]]
}
return $cmp
}
# Now calculate the dependencies, which are effectively the
# transitive-closure of the includes - we simplify by assuming that
# every .c file generates a .o file in the current directory (not
# actually true, but the difference won't be harmful)
proc BuildDependencyGraph {} {
global dependencies objects filelist includes
set dependencies {}
foreach object $objects source $filelist {
if {![string length $object]} {
continue
}
array set ihash {}
set inc [list $source]
for {set i 0} {$i < [llength $inc]} {incr i} {
set file [lindex $inc $i]
if {[info exist ihash($file)]} {
continue
}
set ihash($file) 1
eval lappend inc $includes($file)
}
lappend dependencies "${object}:\
[lsort -command cmpFilenames [array names ihash]]"
unset ihash
}
}
# Splice the dependcy-information into the makefile
proc UpdateMakefile {} {
global MAKEFILE markerString dependencies
set lines {}
if {[file exists $MAKEFILE]} {
set f [open $MAKEFILE]
while {[gets $f line] >= 0 && ![string equal $line $markerString]} {
lappend lines $line
}
close $f
}
lappend lines $markerString ""
set f [open $MAKEFILE w]
foreach line $lines {puts $f $line}
foreach line $dependencies {puts $f $line}
close $f
}
SetupGlobals
MakeFileList
ReadSourceFiles
BuildDependencyGraph
UpdateMakefile
exit