sl@0
|
1 |
# ldAout.tcl --
|
sl@0
|
2 |
#
|
sl@0
|
3 |
# This "tclldAout" procedure in this script acts as a replacement
|
sl@0
|
4 |
# for the "ld" command when linking an object file that will be
|
sl@0
|
5 |
# loaded dynamically into Tcl or Tk using pseudo-static linking.
|
sl@0
|
6 |
#
|
sl@0
|
7 |
# Parameters:
|
sl@0
|
8 |
# The arguments to the script are the command line options for
|
sl@0
|
9 |
# an "ld" command.
|
sl@0
|
10 |
#
|
sl@0
|
11 |
# Results:
|
sl@0
|
12 |
# The "ld" command is parsed, and the "-o" option determines the
|
sl@0
|
13 |
# module name. ".a" and ".o" options are accumulated.
|
sl@0
|
14 |
# The input archives and object files are examined with the "nm"
|
sl@0
|
15 |
# command to determine whether the modules initialization
|
sl@0
|
16 |
# entry and safe initialization entry are present. A trivial
|
sl@0
|
17 |
# C function that locates the entries is composed, compiled, and
|
sl@0
|
18 |
# its .o file placed before all others in the command; then
|
sl@0
|
19 |
# "ld" is executed to bind the objects together.
|
sl@0
|
20 |
#
|
sl@0
|
21 |
# RCS: @(#) $Id: ldAout.tcl,v 1.5 2001/09/28 01:21:53 dgp Exp $
|
sl@0
|
22 |
#
|
sl@0
|
23 |
# Copyright (c) 1995, by General Electric Company. All rights reserved.
|
sl@0
|
24 |
#
|
sl@0
|
25 |
# See the file "license.terms" for information on usage and redistribution
|
sl@0
|
26 |
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
sl@0
|
27 |
#
|
sl@0
|
28 |
# This work was supported in part by the ARPA Manufacturing Automation
|
sl@0
|
29 |
# and Design Engineering (MADE) Initiative through ARPA contract
|
sl@0
|
30 |
# F33615-94-C-4400.
|
sl@0
|
31 |
|
sl@0
|
32 |
proc tclLdAout {{cc {}} {shlib_suffix {}} {shlib_cflags none}} {
|
sl@0
|
33 |
global env
|
sl@0
|
34 |
global argv
|
sl@0
|
35 |
|
sl@0
|
36 |
if {[string equal $cc ""]} {
|
sl@0
|
37 |
set cc $env(CC)
|
sl@0
|
38 |
}
|
sl@0
|
39 |
|
sl@0
|
40 |
# if only two parameters are supplied there is assumed that the
|
sl@0
|
41 |
# only shlib_suffix is missing. This parameter is anyway available
|
sl@0
|
42 |
# as "info sharedlibextension" too, so there is no need to transfer
|
sl@0
|
43 |
# 3 parameters to the function tclLdAout. For compatibility, this
|
sl@0
|
44 |
# function now accepts both 2 and 3 parameters.
|
sl@0
|
45 |
|
sl@0
|
46 |
if {[string equal $shlib_suffix ""]} {
|
sl@0
|
47 |
set shlib_cflags $env(SHLIB_CFLAGS)
|
sl@0
|
48 |
} elseif {[string equal $shlib_cflags "none"]} {
|
sl@0
|
49 |
set shlib_cflags $shlib_suffix
|
sl@0
|
50 |
}
|
sl@0
|
51 |
|
sl@0
|
52 |
# seenDotO is nonzero if a .o or .a file has been seen
|
sl@0
|
53 |
set seenDotO 0
|
sl@0
|
54 |
|
sl@0
|
55 |
# minusO is nonzero if the last command line argument was "-o".
|
sl@0
|
56 |
set minusO 0
|
sl@0
|
57 |
|
sl@0
|
58 |
# head has command line arguments up to but not including the first
|
sl@0
|
59 |
# .o or .a file. tail has the rest of the arguments.
|
sl@0
|
60 |
set head {}
|
sl@0
|
61 |
set tail {}
|
sl@0
|
62 |
|
sl@0
|
63 |
# nmCommand is the "nm" command that lists global symbols from the
|
sl@0
|
64 |
# object files.
|
sl@0
|
65 |
set nmCommand {|nm -g}
|
sl@0
|
66 |
|
sl@0
|
67 |
# entryProtos is the table of _Init and _SafeInit prototypes found in the
|
sl@0
|
68 |
# module.
|
sl@0
|
69 |
set entryProtos {}
|
sl@0
|
70 |
|
sl@0
|
71 |
# entryPoints is the table of _Init and _SafeInit entries found in the
|
sl@0
|
72 |
# module.
|
sl@0
|
73 |
set entryPoints {}
|
sl@0
|
74 |
|
sl@0
|
75 |
# libraries is the list of -L and -l flags to the linker.
|
sl@0
|
76 |
set libraries {}
|
sl@0
|
77 |
set libdirs {}
|
sl@0
|
78 |
|
sl@0
|
79 |
# Process command line arguments
|
sl@0
|
80 |
foreach a $argv {
|
sl@0
|
81 |
if {!$minusO && [regexp {\.[ao]$} $a]} {
|
sl@0
|
82 |
set seenDotO 1
|
sl@0
|
83 |
lappend nmCommand $a
|
sl@0
|
84 |
}
|
sl@0
|
85 |
if {$minusO} {
|
sl@0
|
86 |
set outputFile $a
|
sl@0
|
87 |
set minusO 0
|
sl@0
|
88 |
} elseif {![string compare $a -o]} {
|
sl@0
|
89 |
set minusO 1
|
sl@0
|
90 |
}
|
sl@0
|
91 |
if {[regexp {^-[lL]} $a]} {
|
sl@0
|
92 |
lappend libraries $a
|
sl@0
|
93 |
if {[regexp {^-L} $a]} {
|
sl@0
|
94 |
lappend libdirs [string range $a 2 end]
|
sl@0
|
95 |
}
|
sl@0
|
96 |
} elseif {$seenDotO} {
|
sl@0
|
97 |
lappend tail $a
|
sl@0
|
98 |
} else {
|
sl@0
|
99 |
lappend head $a
|
sl@0
|
100 |
}
|
sl@0
|
101 |
}
|
sl@0
|
102 |
lappend libdirs /lib /usr/lib
|
sl@0
|
103 |
|
sl@0
|
104 |
# MIPS -- If there are corresponding G0 libraries, replace the
|
sl@0
|
105 |
# ordinary ones with the G0 ones.
|
sl@0
|
106 |
|
sl@0
|
107 |
set libs {}
|
sl@0
|
108 |
foreach lib $libraries {
|
sl@0
|
109 |
if {[regexp {^-l} $lib]} {
|
sl@0
|
110 |
set lname [string range $lib 2 end]
|
sl@0
|
111 |
foreach dir $libdirs {
|
sl@0
|
112 |
if {[file exists [file join $dir lib${lname}_G0.a]]} {
|
sl@0
|
113 |
set lname ${lname}_G0
|
sl@0
|
114 |
break
|
sl@0
|
115 |
}
|
sl@0
|
116 |
}
|
sl@0
|
117 |
lappend libs -l$lname
|
sl@0
|
118 |
} else {
|
sl@0
|
119 |
lappend libs $lib
|
sl@0
|
120 |
}
|
sl@0
|
121 |
}
|
sl@0
|
122 |
set libraries $libs
|
sl@0
|
123 |
|
sl@0
|
124 |
# Extract the module name from the "-o" option
|
sl@0
|
125 |
|
sl@0
|
126 |
if {![info exists outputFile]} {
|
sl@0
|
127 |
error "-o option must be supplied to link a Tcl load module"
|
sl@0
|
128 |
}
|
sl@0
|
129 |
set m [file tail $outputFile]
|
sl@0
|
130 |
if {[regexp {\.a$} $outputFile]} {
|
sl@0
|
131 |
set shlib_suffix .a
|
sl@0
|
132 |
} else {
|
sl@0
|
133 |
set shlib_suffix ""
|
sl@0
|
134 |
}
|
sl@0
|
135 |
if {[regexp {\..*$} $outputFile match]} {
|
sl@0
|
136 |
set l [expr {[string length $m] - [string length $match]}]
|
sl@0
|
137 |
} else {
|
sl@0
|
138 |
error "Output file does not appear to have a suffix"
|
sl@0
|
139 |
}
|
sl@0
|
140 |
set modName [string tolower $m 0 [expr {$l-1}]]
|
sl@0
|
141 |
if {[regexp {^lib} $modName]} {
|
sl@0
|
142 |
set modName [string range $modName 3 end]
|
sl@0
|
143 |
}
|
sl@0
|
144 |
if {[regexp {[0-9\.]*(_g0)?$} $modName match]} {
|
sl@0
|
145 |
set modName [string range $modName 0 [expr {[string length $modName]-[string length $match]-1}]]
|
sl@0
|
146 |
}
|
sl@0
|
147 |
set modName [string totitle $modName]
|
sl@0
|
148 |
|
sl@0
|
149 |
# Catalog initialization entry points found in the module
|
sl@0
|
150 |
|
sl@0
|
151 |
set f [open $nmCommand r]
|
sl@0
|
152 |
while {[gets $f l] >= 0} {
|
sl@0
|
153 |
if {[regexp {T[ ]*_?([A-Z][a-z0-9_]*_(Safe)?Init(__FP10Tcl_Interp)?)$} $l trash symbol]} {
|
sl@0
|
154 |
if {![regexp {_?([A-Z][a-z0-9_]*_(Safe)?Init)} $symbol trash s]} {
|
sl@0
|
155 |
set s $symbol
|
sl@0
|
156 |
}
|
sl@0
|
157 |
append entryProtos {extern int } $symbol { (); } \n
|
sl@0
|
158 |
append entryPoints { } \{ { "} $s {", } $symbol { } \} , \n
|
sl@0
|
159 |
}
|
sl@0
|
160 |
}
|
sl@0
|
161 |
close $f
|
sl@0
|
162 |
|
sl@0
|
163 |
if {[string equal $entryPoints ""]} {
|
sl@0
|
164 |
error "No entry point found in objects"
|
sl@0
|
165 |
}
|
sl@0
|
166 |
|
sl@0
|
167 |
# Compose a C function that resolves the initialization entry points and
|
sl@0
|
168 |
# embeds the required libraries in the object code.
|
sl@0
|
169 |
|
sl@0
|
170 |
set C {#include <string.h>}
|
sl@0
|
171 |
append C \n
|
sl@0
|
172 |
append C {char TclLoadLibraries_} $modName { [] =} \n
|
sl@0
|
173 |
append C { "@LIBS: } $libraries {";} \n
|
sl@0
|
174 |
append C $entryProtos
|
sl@0
|
175 |
append C {static struct } \{ \n
|
sl@0
|
176 |
append C { char * name;} \n
|
sl@0
|
177 |
append C { int (*value)();} \n
|
sl@0
|
178 |
append C \} {dictionary [] = } \{ \n
|
sl@0
|
179 |
append C $entryPoints
|
sl@0
|
180 |
append C { 0, 0 } \n \} \; \n
|
sl@0
|
181 |
append C {typedef struct Tcl_Interp Tcl_Interp;} \n
|
sl@0
|
182 |
append C {typedef int Tcl_PackageInitProc (Tcl_Interp *);} \n
|
sl@0
|
183 |
append C {Tcl_PackageInitProc *} \n
|
sl@0
|
184 |
append C TclLoadDictionary_ $modName { (symbol)} \n
|
sl@0
|
185 |
append C { CONST char * symbol;} \n
|
sl@0
|
186 |
append C {
|
sl@0
|
187 |
{
|
sl@0
|
188 |
int i;
|
sl@0
|
189 |
for (i = 0; dictionary [i] . name != 0; ++i) {
|
sl@0
|
190 |
if (!strcmp (symbol, dictionary [i] . name)) {
|
sl@0
|
191 |
return dictionary [i].value;
|
sl@0
|
192 |
}
|
sl@0
|
193 |
}
|
sl@0
|
194 |
return 0;
|
sl@0
|
195 |
}
|
sl@0
|
196 |
}
|
sl@0
|
197 |
append C \n
|
sl@0
|
198 |
|
sl@0
|
199 |
|
sl@0
|
200 |
# Write the C module and compile it
|
sl@0
|
201 |
|
sl@0
|
202 |
set cFile tcl$modName.c
|
sl@0
|
203 |
set f [open $cFile w]
|
sl@0
|
204 |
puts -nonewline $f $C
|
sl@0
|
205 |
close $f
|
sl@0
|
206 |
set ccCommand "$cc -c $shlib_cflags $cFile"
|
sl@0
|
207 |
puts stderr $ccCommand
|
sl@0
|
208 |
eval exec $ccCommand
|
sl@0
|
209 |
|
sl@0
|
210 |
# Now compose and execute the ld command that packages the module
|
sl@0
|
211 |
|
sl@0
|
212 |
if {[string equal $shlib_suffix ".a"]} {
|
sl@0
|
213 |
set ldCommand "ar cr $outputFile"
|
sl@0
|
214 |
regsub { -o} $tail {} tail
|
sl@0
|
215 |
} else {
|
sl@0
|
216 |
set ldCommand ld
|
sl@0
|
217 |
foreach item $head {
|
sl@0
|
218 |
lappend ldCommand $item
|
sl@0
|
219 |
}
|
sl@0
|
220 |
}
|
sl@0
|
221 |
lappend ldCommand tcl$modName.o
|
sl@0
|
222 |
foreach item $tail {
|
sl@0
|
223 |
lappend ldCommand $item
|
sl@0
|
224 |
}
|
sl@0
|
225 |
puts stderr $ldCommand
|
sl@0
|
226 |
eval exec $ldCommand
|
sl@0
|
227 |
if {[string equal $shlib_suffix ".a"]} {
|
sl@0
|
228 |
exec ranlib $outputFile
|
sl@0
|
229 |
}
|
sl@0
|
230 |
|
sl@0
|
231 |
# Clean up working files
|
sl@0
|
232 |
exec /bin/rm $cFile [file rootname $cFile].o
|
sl@0
|
233 |
}
|