Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/tcl8.5.2/tools/mkdepend.tcl @ 25

Last change on this file since 25 was 25, checked in by landauf, 16 years ago

added tcl to libs

File size: 9.4 KB
Line 
1#==============================================================================
2#
3# mkdepend : generate dependency information from C/C++ files
4#
5# Copyright (c) 1998, Nat Pryce
6#
7# Permission is hereby granted, without written agreement and without
8# license or royalty fees, to use, copy, modify, and distribute this
9# software and its documentation for any purpose, provided that the
10# above copyright notice and the following two paragraphs appear in
11# all copies of this software.
12#
13# IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
14# SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
15# THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE AUTHOR HAS BEEN ADVISED
16# OF THE POSSIBILITY OF SUCH DAMAGE.
17#
18# THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20# PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
21# BASIS, AND THE AUTHOR HAS NO OBLIGATION TO PROVIDE  MAINTENANCE, SUPPORT,
22# UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23#==============================================================================
24#
25# Modified heavily by David Gravereaux <davygrvy@pobox.com> about 9/17/2006.
26# Original can be found @
27#       http://web.archive.org/web/20070616205924/http://www.doc.ic.ac.uk/~np2/software/mkdepend.html
28#
29#==============================================================================
30# RCS: @(#) $Id: mkdepend.tcl,v 1.6 2007/12/13 15:28:40 dgp Exp $
31#==============================================================================
32
33array set mode_data {}
34set mode_data(vc32) {cl -nologo -E}
35
36set source_extensions [list .c .cpp .cxx .cc]
37
38set excludes [list]
39if [info exists env(INCLUDE)] {
40    set rawExcludes [split [string trim $env(INCLUDE) ";"] ";"]
41    foreach exclude $rawExcludes {
42        lappend excludes [file normalize $exclude]
43    }
44}
45
46
47# openOutput --
48#
49#       Opens the output file.
50#
51# Arguments:
52#       file    The file to open
53#
54# Results:
55#       None.
56
57proc openOutput {file} {
58    global output
59    set output [open $file w]
60    puts $output "# Automatically generated at [clock format [clock seconds] -format "%Y-%m-%dT%H:%M:%S"] by [info script]\n"
61}
62
63# closeOutput --
64#
65#       Closes output file.
66#
67# Arguments:
68#       none
69#
70# Results:
71#       None.
72
73proc closeOutput {} {
74    global output
75    if {[string match stdout $output] != 0} {
76        close $output
77    }
78}
79
80# readDepends --
81#
82#       Read off CCP pipe for #line references.
83#
84# Arguments:
85#       chan    The pipe channel we are reading in.
86#
87# Results:
88#       Raw dependency list pairs.
89
90proc readDepends {chan} {
91    set line ""
92    array set depends {}
93
94    while {[gets $chan line] != -1} {
95        if {[regexp {^#line [0-9]+ \"(.*)\"$} $line dummy fname] != 0} {
96            set fname [file normalize $fname]
97            if {![info exists target]} {
98                # this is ourself
99                set target $fname
100                puts stderr "processing [file tail $fname]"
101            } else {
102                # don't include ourselves as a dependency of ourself.
103                if {![string compare $fname $target]} {continue}
104                # store in an array so multiple occurances are not counted.
105                set depends($target|$fname) ""
106            }
107        }
108    }
109
110    set result {}
111    foreach n [array names depends] {
112        set pair [split $n "|"]
113        lappend result [list [lindex $pair 0] [lindex $pair 1]]
114    }
115
116    return $result
117}
118
119# writeDepends --
120#
121#       Write the processed list out to the file.
122#
123# Arguments:
124#       out             The channel to write to.
125#       depends         The list of dependency pairs
126#
127# Results:
128#       None.
129
130proc writeDepends {out depends} {
131    foreach pair $depends {
132        puts $out "[lindex $pair 0] : \\\n\t[join [lindex $pair 1] " \\\n\t"]"
133    }
134}
135
136# stringStartsWith --
137#
138#       Compares second string to the beginning of the first.
139#
140# Arguments:
141#       str             The string to test the beginning of.
142#       prefix          The string to test against
143#
144# Results:
145#       the result of the comparison.
146
147proc stringStartsWith {str prefix} {
148    set front [string range $str 0 [expr {[string length $prefix] - 1}]]
149    return [expr {[string compare [string tolower $prefix] \
150                                  [string tolower $front]] == 0}]
151}
152
153# filterExcludes --
154#
155#       Remove non-project header files.
156#
157# Arguments:
158#       depends         List of dependency pairs.
159#       excludes        List of directories that should be removed
160#
161# Results:
162#       the processed dependency list.
163
164proc filterExcludes {depends excludes} {
165    set filtered {}
166
167    foreach pair $depends {
168        set excluded 0
169        set file [lindex $pair 1]
170
171        foreach dir $excludes {
172            if [stringStartsWith $file $dir] {
173                set excluded 1
174                break;
175            }
176        }
177
178        if {!$excluded} {
179            lappend filtered $pair
180        }
181    }
182
183    return $filtered
184}
185
186# replacePrefix --
187#
188#       Take the normalized search path and put back the
189#       macro name for it.
190#
191# Arguments:
192#       file    filename.
193#
194# Results:
195#       filename properly replaced with macro for it.
196
197proc replacePrefix {file} {
198    global srcPathList srcPathReplaceList
199
200    foreach was $srcPathList is $srcPathReplaceList {
201        regsub $was $file $is file
202    }
203    return $file
204}
205
206# rebaseFiles --
207#
208#       Replaces normalized paths with original macro names.
209#
210# Arguments:
211#       depends         Dependency pair list.
212#
213# Results:
214#       The processed dependency pair list.
215
216proc rebaseFiles {depends} {
217    set rebased {}
218    foreach pair $depends {
219        lappend rebased [list \
220                [replacePrefix [lindex $pair 0]] \
221                [replacePrefix [lindex $pair 1]]]
222
223    }
224    return $rebased
225}
226
227# compressDeps --
228#
229#       Compresses same named tragets into one pair with
230#       multiple deps.
231#
232# Arguments:
233#       depends Dependency pair list.
234#
235# Results:
236#       The processed list.
237
238proc compressDeps {depends} {
239    array set compressed [list]
240
241    foreach pair $depends {
242        lappend compressed([lindex $pair 0]) [lindex $pair 1]
243    }
244
245    set result [list]
246    foreach n [array names compressed] {
247        lappend result [list $n [lsort $compressed($n)]]
248    }
249
250    return $result
251}
252
253# addSearchPath --
254#
255#       Adds a new set of path and replacement string to the global list.
256#
257# Arguments:
258#       newPathInfo     comma seperated path and replacement string
259#
260# Results:
261#       None.
262
263proc addSearchPath {newPathInfo} {
264    global srcPathList srcPathReplaceList
265
266    set infoList [split $newPathInfo ,]
267    lappend srcPathList [file normalize [lindex $infoList 0]]
268    lappend srcPathReplaceList [lindex $infoList 1]
269}
270
271
272# displayUsage --
273#
274#       Displays usage to stderr
275#
276# Arguments:
277#       none.
278#
279# Results:
280#       None.
281
282proc displayUsage {} {
283    puts stderr "mkdepend.tcl \[options\] genericDir,macroName compatDir,macroName platformDir,macroName"
284}
285
286# readInputListFile --
287#
288#       Open and read the object file list.
289#
290# Arguments:
291#       objectListFile - name of the file to open.
292#
293# Results:
294#       None.
295
296proc readInputListFile {objectListFile} {
297    global srcFileList srcPathList source_extensions
298    set f [open $objectListFile r]
299    set fl [read $f]
300    close $f
301
302    # fix native path seperator so it isn't treated as an escape.
303    regsub -all {\\} $fl {/} fl
304
305    # Treat the string as a list so filenames between double quotes are
306    # treated as list elements.
307    foreach fname $fl {
308        # Compiled .res resource files should be ignored.
309        if {[file extension $fname] ne ".obj"} {continue}
310
311        # Just filename without path or extension because the path is
312        # the build directory, not where the source files are located.
313        set baseName [file rootname [file tail $fname]]
314
315        set found 0
316        foreach path $srcPathList {
317            foreach ext $source_extensions {
318                set test [file join $path ${baseName}${ext}]
319                if {[file exist $test]} {
320                    lappend srcFileList $test
321                    set found 1
322                    break
323                }
324            }
325            if {$found} break
326        }
327    }
328}
329
330# main --
331#
332#       The main procedure of this script.
333#
334# Arguments:
335#       none.
336#
337# Results:
338#       None.
339
340proc main {} {
341    global argc argv mode mode_data srcFileList srcPathList excludes
342    global remove_prefix target_prefix output env
343
344    set srcPathList [list]
345    set srcFileList [list]
346
347    if {$argc == 1} {displayUsage}
348
349    # Parse mkdepend input
350    for {set i 0} {$i < [llength $argv]} {incr i} {
351        switch -glob -- [set arg [lindex $argv $i]] {
352            -vc32 {
353                set mode vc32
354            }
355            -bc32 {
356                set mode bc32
357            }
358            -wc32 {
359                set mode wc32
360            }
361            -lc32 {
362                set mode lc32
363            }
364            -mgw32 {
365                set mode mgw32
366            }
367            -passthru:* {
368                set passthru [string range $arg 10 end]
369                regsub -all {"} $passthru {\"} passthru
370                regsub -all {\\} $passthru {/} passthru
371            }
372            -out:* {
373                openOutput [string range $arg 5 end]
374            }
375            @* {
376                set objfile [string range $arg 1 end]
377                regsub -all {\\} $objfile {/} objfile
378                readInputListFile $objfile
379            }
380            -? - -help - --help {
381                displayUsage
382                exit 1
383            }
384            default {
385                if {![info exist mode]} {
386                    puts stderr "mode not set"
387                    displayUsage
388                }
389                addSearchPath $arg
390            }
391        }
392    }
393
394    # Execute the CPP command and parse output
395
396    foreach srcFile $srcFileList {
397        if {[catch {
398            set command "$mode_data($mode) $passthru \"$srcFile\""
399            set input [open |$command r]
400            set depends [readDepends $input]
401            set status [catch {close $input} result]
402            if {$status == 1 && [lindex $::errorCode 0] eq "CHILDSTATUS"} {
403                foreach { - pid code } $::errorCode break
404                if {$code == 2} {
405                    # preprocessor died a cruel death.
406                    error $result
407                }
408            }
409        } err]} {
410            puts stderr "error ocurred: $err\n"
411            continue
412        }
413        set depends [filterExcludes $depends $excludes]
414        set depends [rebaseFiles $depends]
415        set depends [compressDeps $depends]
416        writeDepends $output $depends
417    }
418
419    closeOutput
420}
421
422# kick it up.
423main
Note: See TracBrowser for help on using the repository browser.