summaryrefslogtreecommitdiffstats
path: root/tools/mkdepend.tcl
diff options
context:
space:
mode:
Diffstat (limited to 'tools/mkdepend.tcl')
-rw-r--r--tools/mkdepend.tcl420
1 files changed, 420 insertions, 0 deletions
diff --git a/tools/mkdepend.tcl b/tools/mkdepend.tcl
new file mode 100644
index 0000000..de5fdba
--- /dev/null
+++ b/tools/mkdepend.tcl
@@ -0,0 +1,420 @@
+#==============================================================================
+#
+# mkdepend : generate dependency information from C/C++ files
+#
+# Copyright (c) 1998, Nat Pryce
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+# SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
+# THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE AUTHOR HAS BEEN ADVISED
+# OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+# BASIS, AND THE AUTHOR HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
+# UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#==============================================================================
+#
+# Modified heavily by David Gravereaux <davygrvy@pobox.com> about 9/17/2006.
+# Original can be found @
+# http://web.archive.org/web/20070616205924/http://www.doc.ic.ac.uk/~np2/software/mkdepend.html
+#==============================================================================
+
+array set mode_data {}
+set mode_data(vc32) {cl -nologo -E}
+
+set source_extensions [list .c .cpp .cxx .cc]
+
+set excludes [list]
+if [info exists env(INCLUDE)] {
+ set rawExcludes [split [string trim $env(INCLUDE) ";"] ";"]
+ foreach exclude $rawExcludes {
+ lappend excludes [file normalize $exclude]
+ }
+}
+
+
+# openOutput --
+#
+# Opens the output file.
+#
+# Arguments:
+# file The file to open
+#
+# Results:
+# None.
+
+proc openOutput {file} {
+ global output
+ set output [open $file w]
+ puts $output "# Automatically generated at [clock format [clock seconds] -format "%Y-%m-%dT%H:%M:%S"] by [info script]\n"
+}
+
+# closeOutput --
+#
+# Closes output file.
+#
+# Arguments:
+# none
+#
+# Results:
+# None.
+
+proc closeOutput {} {
+ global output
+ if {[string match stdout $output] != 0} {
+ close $output
+ }
+}
+
+# readDepends --
+#
+# Read off CCP pipe for #line references.
+#
+# Arguments:
+# chan The pipe channel we are reading in.
+#
+# Results:
+# Raw dependency list pairs.
+
+proc readDepends {chan} {
+ set line ""
+ array set depends {}
+
+ while {[gets $chan line] != -1} {
+ if {[regexp {^#line [0-9]+ \"(.*)\"$} $line dummy fname] != 0} {
+ set fname [file normalize $fname]
+ if {![info exists target]} {
+ # this is ourself
+ set target $fname
+ puts stderr "processing [file tail $fname]"
+ } else {
+ # don't include ourselves as a dependency of ourself.
+ if {![string compare $fname $target]} {continue}
+ # store in an array so multiple occurances are not counted.
+ set depends($target|$fname) ""
+ }
+ }
+ }
+
+ set result {}
+ foreach n [array names depends] {
+ set pair [split $n "|"]
+ lappend result [list [lindex $pair 0] [lindex $pair 1]]
+ }
+
+ return $result
+}
+
+# writeDepends --
+#
+# Write the processed list out to the file.
+#
+# Arguments:
+# out The channel to write to.
+# depends The list of dependency pairs
+#
+# Results:
+# None.
+
+proc writeDepends {out depends} {
+ foreach pair $depends {
+ puts $out "[lindex $pair 0] : \\\n\t[join [lindex $pair 1] " \\\n\t"]"
+ }
+}
+
+# stringStartsWith --
+#
+# Compares second string to the beginning of the first.
+#
+# Arguments:
+# str The string to test the beginning of.
+# prefix The string to test against
+#
+# Results:
+# the result of the comparison.
+
+proc stringStartsWith {str prefix} {
+ set front [string range $str 0 [expr {[string length $prefix] - 1}]]
+ return [expr {[string compare [string tolower $prefix] \
+ [string tolower $front]] == 0}]
+}
+
+# filterExcludes --
+#
+# Remove non-project header files.
+#
+# Arguments:
+# depends List of dependency pairs.
+# excludes List of directories that should be removed
+#
+# Results:
+# the processed dependency list.
+
+proc filterExcludes {depends excludes} {
+ set filtered {}
+
+ foreach pair $depends {
+ set excluded 0
+ set file [lindex $pair 1]
+
+ foreach dir $excludes {
+ if [stringStartsWith $file $dir] {
+ set excluded 1
+ break;
+ }
+ }
+
+ if {!$excluded} {
+ lappend filtered $pair
+ }
+ }
+
+ return $filtered
+}
+
+# replacePrefix --
+#
+# Take the normalized search path and put back the
+# macro name for it.
+#
+# Arguments:
+# file filename.
+#
+# Results:
+# filename properly replaced with macro for it.
+
+proc replacePrefix {file} {
+ global srcPathList srcPathReplaceList
+
+ foreach was $srcPathList is $srcPathReplaceList {
+ regsub $was $file $is file
+ }
+ return $file
+}
+
+# rebaseFiles --
+#
+# Replaces normalized paths with original macro names.
+#
+# Arguments:
+# depends Dependency pair list.
+#
+# Results:
+# The processed dependency pair list.
+
+proc rebaseFiles {depends} {
+ set rebased {}
+ foreach pair $depends {
+ lappend rebased [list \
+ [replacePrefix [lindex $pair 0]] \
+ [replacePrefix [lindex $pair 1]]]
+
+ }
+ return $rebased
+}
+
+# compressDeps --
+#
+# Compresses same named tragets into one pair with
+# multiple deps.
+#
+# Arguments:
+# depends Dependency pair list.
+#
+# Results:
+# The processed list.
+
+proc compressDeps {depends} {
+ array set compressed [list]
+
+ foreach pair $depends {
+ lappend compressed([lindex $pair 0]) [lindex $pair 1]
+ }
+
+ set result [list]
+ foreach n [array names compressed] {
+ lappend result [list $n [lsort $compressed($n)]]
+ }
+
+ return $result
+}
+
+# addSearchPath --
+#
+# Adds a new set of path and replacement string to the global list.
+#
+# Arguments:
+# newPathInfo comma seperated path and replacement string
+#
+# Results:
+# None.
+
+proc addSearchPath {newPathInfo} {
+ global srcPathList srcPathReplaceList
+
+ set infoList [split $newPathInfo ,]
+ lappend srcPathList [file normalize [lindex $infoList 0]]
+ lappend srcPathReplaceList [lindex $infoList 1]
+}
+
+
+# displayUsage --
+#
+# Displays usage to stderr
+#
+# Arguments:
+# none.
+#
+# Results:
+# None.
+
+proc displayUsage {} {
+ puts stderr "mkdepend.tcl \[options\] genericDir,macroName compatDir,macroName platformDir,macroName"
+}
+
+# readInputListFile --
+#
+# Open and read the object file list.
+#
+# Arguments:
+# objectListFile - name of the file to open.
+#
+# Results:
+# None.
+
+proc readInputListFile {objectListFile} {
+ global srcFileList srcPathList source_extensions
+ set f [open $objectListFile r]
+ set fl [read $f]
+ close $f
+
+ # fix native path seperator so it isn't treated as an escape.
+ regsub -all {\\} $fl {/} fl
+
+ # Treat the string as a list so filenames between double quotes are
+ # treated as list elements.
+ foreach fname $fl {
+ # Compiled .res resource files should be ignored.
+ if {[file extension $fname] ne ".obj"} {continue}
+
+ # Just filename without path or extension because the path is
+ # the build directory, not where the source files are located.
+ set baseName [file rootname [file tail $fname]]
+
+ set found 0
+ foreach path $srcPathList {
+ foreach ext $source_extensions {
+ set test [file join $path ${baseName}${ext}]
+ if {[file exist $test]} {
+ lappend srcFileList $test
+ set found 1
+ break
+ }
+ }
+ if {$found} break
+ }
+ }
+}
+
+# main --
+#
+# The main procedure of this script.
+#
+# Arguments:
+# none.
+#
+# Results:
+# None.
+
+proc main {} {
+ global argc argv mode mode_data srcFileList srcPathList excludes
+ global remove_prefix target_prefix output env
+
+ set srcPathList [list]
+ set srcFileList [list]
+
+ if {$argc == 1} {displayUsage}
+
+ # Parse mkdepend input
+ for {set i 0} {$i < [llength $argv]} {incr i} {
+ switch -glob -- [set arg [lindex $argv $i]] {
+ -vc32 {
+ set mode vc32
+ }
+ -bc32 {
+ set mode bc32
+ }
+ -wc32 {
+ set mode wc32
+ }
+ -lc32 {
+ set mode lc32
+ }
+ -mgw32 {
+ set mode mgw32
+ }
+ -passthru:* {
+ set passthru [string range $arg 10 end]
+ regsub -all {"} $passthru {\"} passthru
+ regsub -all {\\} $passthru {/} passthru
+ }
+ -out:* {
+ openOutput [string range $arg 5 end]
+ }
+ @* {
+ set objfile [string range $arg 1 end]
+ regsub -all {\\} $objfile {/} objfile
+ readInputListFile $objfile
+ }
+ -? - -help - --help {
+ displayUsage
+ exit 1
+ }
+ default {
+ if {![info exist mode]} {
+ puts stderr "mode not set"
+ displayUsage
+ }
+ addSearchPath $arg
+ }
+ }
+ }
+
+ # Execute the CPP command and parse output
+
+ foreach srcFile $srcFileList {
+ if {[catch {
+ set command "$mode_data($mode) $passthru \"$srcFile\""
+ set input [open |$command r]
+ set depends [readDepends $input]
+ set status [catch {close $input} result]
+ if {$status == 1 && [lindex $::errorCode 0] eq "CHILDSTATUS"} {
+ foreach { - pid code } $::errorCode break
+ if {$code == 2} {
+ # preprocessor died a cruel death.
+ error $result
+ }
+ }
+ } err]} {
+ puts stderr "error ocurred: $err\n"
+ continue
+ }
+ set depends [filterExcludes $depends $excludes]
+ set depends [rebaseFiles $depends]
+ set depends [compressDeps $depends]
+ writeDepends $output $depends
+ }
+
+ closeOutput
+}
+
+# kick it up.
+main