1 |
#! /usr/bin/env python |
2 |
|
3 |
|
4 |
import sys, os.path, platform |
5 |
|
6 |
def find_tclConfigsh(tclsh = None): |
7 |
""" |
8 |
Do platform-specific tricks to located the tclConfig.sh file. On Windows, we |
9 |
assume the ActiveState distribution is used, and hunt for its registry keys to |
10 |
locate the installed files. On other platforms, we use the program 'tclsh' to |
11 |
locate the file, and allow the path to tclsh to be specified, in order to allow |
12 |
the tcl/tk version to be selected if multiple versions are present. |
13 |
""" |
14 |
tclconfigfile = None |
15 |
|
16 |
if sys.platform.startswith("win") and tclsh is not None: |
17 |
# check for ActiveState Tcl in Windows registry |
18 |
try: |
19 |
import _winreg |
20 |
x=_winreg.ConnectRegistry(None,_winreg.HKEY_LOCAL_MACHINE) |
21 |
y= _winreg.OpenKey(x,r"SOFTWARE\ActiveState\ActiveTcl") |
22 |
_regversion,t = _winreg.QueryValueEx(y,"CurrentVersion") |
23 |
z= _winreg.OpenKey(x,r"SOFTWARE\ActiveState\ActiveTcl\%s" % str(_regversion)) |
24 |
_regpath,t = _winreg.QueryValueEx(z,None) |
25 |
_winreg.CloseKey(y) |
26 |
_winreg.CloseKey(z) |
27 |
_winreg.CloseKey(x) |
28 |
# typically, c:\Tcl\lib\tclConfig.sh. |
29 |
_regconfig = os.path.join(_regpath,os.path.join("lib","tclConfig.sh")) |
30 |
if os.path.exists(_regconfig): |
31 |
# if the file exists, good... |
32 |
tclconfigfile = _regconfig |
33 |
except: |
34 |
pass |
35 |
|
36 |
if tclsh is None: |
37 |
tclsh = "tclsh" |
38 |
|
39 |
if tclconfigfile is None: |
40 |
import subprocess |
41 |
# first check that tclsh can be run |
42 |
tclshcheck = """exit 0""" |
43 |
res = 1 |
44 |
try: |
45 |
p = subprocess.Popen([tclsh],stdin=subprocess.PIPE, stdout=subprocess.PIPE) |
46 |
p.communicate(input=tclshcheck) |
47 |
res = p.returncode |
48 |
assert res == 0 |
49 |
except Exception,e: |
50 |
if tclsh != "tclsh": |
51 |
print >> sys.stderr,"Unable to locate 'tclsh' in PATH. Suspect tcl/tk not installed, or PATH not correctly set. (%s)" % str(e) |
52 |
else: |
53 |
print >> sys.stderr,"The specifed tclsh, '%s' appears to be unrunnable. Check your Tcl/Tk installation and path." |
54 |
sys.exit(1) |
55 |
|
56 |
# use a 'tclsh' script to find location of tclConfig.sh |
57 |
# location of tclConfig.sh is canonical tcl_pkgPath |
58 |
tclscript = """ |
59 |
#puts stderr "searching for tclConfig.sh ..." |
60 |
foreach d [concat \ |
61 |
[concat $tcl_library $tcl_pkgPath ] \ |
62 |
$auto_path \ |
63 |
[list [file dirname $tcl_library] \ |
64 |
[file dirname [lindex $tcl_pkgPath 0]] \ |
65 |
[file dirname [file dirname $tcl_library]] \ |
66 |
[file dirname [file dirname [lindex $tcl_pkgPath 0]]] \ |
67 |
[file dirname [file dirname [file dirname $tcl_library]]] \ |
68 |
[file dirname [file dirname [file dirname [lindex $tcl_pkgPath 0]]]]\ |
69 |
] \ |
70 |
] { |
71 |
if {[file exists [file join $d tclConfig.sh]]} { |
72 |
puts "[file join $d tclConfig.sh]" |
73 |
#puts stderr "found $d : [file join $d tclConfig.sh]" |
74 |
exit 1 |
75 |
} else { |
76 |
#puts stderr "not in $d" |
77 |
} |
78 |
} |
79 |
""" |
80 |
|
81 |
output = subprocess.Popen([tclsh], stdin=subprocess.PIPE, stdout=subprocess.PIPE).communicate(input=tclscript)[0] |
82 |
# print output |
83 |
# print output.strip() |
84 |
# tcl will not return it if not there; already checked |
85 |
if os.path.exists(output.strip()): |
86 |
# print "path exists" |
87 |
# only report the file if it actually exists... |
88 |
tclconfigfile = output.strip() |
89 |
# print tclconfigfile |
90 |
|
91 |
# print tclconfigfile |
92 |
if tclconfigfile is None: |
93 |
print >> sys.stderr, "Unable to locate tclConfig.sh." |
94 |
if platform.system()=="Linux": |
95 |
print >> sys.stderr, "It is likely that you do not have tcl-devel or equivalent package installed on your system." |
96 |
else: |
97 |
print >> sys.stderr, "On non-Linux platforms, the free ActiveTcl distribution for activestate.com is recommended." |
98 |
sys.exit(1) |
99 |
|
100 |
return tclconfigfile |
101 |
|
102 |
def get_tcl_options(tclconfigfile): |
103 |
""" |
104 |
Given the tclConfig.sd file location, open the file and parse its options into |
105 |
a dictionary. |
106 |
""" |
107 |
|
108 |
# parse the file to determine the names of the variables it contains |
109 |
|
110 |
f = file(tclconfigfile) |
111 |
|
112 |
# default build environment variables that are assumed to already be defined |
113 |
# note that these are normally given default values in GNU Make, but we're |
114 |
# not inside make, so we might not have these. |
115 |
# FIXME: could try importing these from the environment? |
116 |
d = { |
117 |
"CC":"gcc" |
118 |
,"CFLAGS":"" |
119 |
,"LDFLAGS":"" |
120 |
,"AR":"" |
121 |
,"LIBS":"" |
122 |
,"VERSION":"" |
123 |
,"DBGX":"" |
124 |
,"NODOT_VERSION":"" # required for ActiveState Tcl 8.4 on Windows |
125 |
} |
126 |
|
127 |
# regular expression used for variable substitution |
128 |
import re |
129 |
r = re.compile(r'\$\{([A-Z_0-9]+)\}') |
130 |
|
131 |
# variable substitution/expansion function |
132 |
def expand(s,d): |
133 |
m = r.search(s) |
134 |
# print "MATCHING",s |
135 |
if m: |
136 |
# print "MATCH!" |
137 |
if d.has_key(m.group(1)): |
138 |
return expand(s[:m.start()] + d[m.group(1)] + s[m.end():],d) |
139 |
else: |
140 |
raise RuntimeError("Missing variable '%s'" % m.group(1)) |
141 |
return s |
142 |
|
143 |
for l in f: |
144 |
ls = l.strip() |
145 |
if ls == "" or ls[0]=="#": |
146 |
continue |
147 |
k,v = ls.split("=",1) |
148 |
if len(v) >= 2 and v[0] == "'" and v[len(v)-1] == "'": |
149 |
v = v[1:len(v)-1] |
150 |
|
151 |
try: |
152 |
d[k] = expand(v,d) |
153 |
except RuntimeError, err: |
154 |
# print str(err),"probably unneeded" |
155 |
pass |
156 |
|
157 |
return d |
158 |
|
159 |
# output the variable that the user requests |
160 |
|
161 |
import getopt, sys |
162 |
|
163 |
def usage(progname): |
164 |
print "%s [--cflags] [--libs] [--var=TCL_VAR_NAME] [--vars]" % progname |
165 |
print "Output configuration variables for the Tcl script interpreter." |
166 |
print "Options:" |
167 |
print "\t--cflags Compiler flags for C code that uses Tcl" |
168 |
print "\t--libs Linker flags for code that uses Tcl" |
169 |
print "\t--vars List all variables defined in tclConfig.sh" |
170 |
print "\t--var=VARNAME Output the value of a specific variable" |
171 |
print "\nSee http://ascendwiki.cheme.cmu.edu/Tcl-config for more info." |
172 |
|
173 |
try: |
174 |
opts, args = getopt.getopt(sys.argv[1:], "h", |
175 |
["help", "cflags", "libs", "var=","vars","tclsh="] |
176 |
) |
177 |
except getopt.GetoptError, err: |
178 |
print str(err) |
179 |
usage(sys.argv[0]) |
180 |
sys.exit(2) |
181 |
|
182 |
tclsh = None |
183 |
for o, a in opts: |
184 |
if o == "--tclsh": |
185 |
tclsh = a |
186 |
|
187 |
tclconfigfile = find_tclConfigsh(tclsh) |
188 |
d = get_tcl_options(tclconfigfile) |
189 |
|
190 |
for o, a in opts: |
191 |
if o == "-h" or o == "--help": |
192 |
usage(sys.argv[0]) |
193 |
sys.exit() |
194 |
elif o == "--cflags": |
195 |
print d['TCL_INCLUDE_SPEC'] |
196 |
elif o == "--libs": |
197 |
print d['TCL_LIB_SPEC'] |
198 |
elif o == "--var": |
199 |
if d.has_key(a): |
200 |
print d[a] |
201 |
else: |
202 |
raise RuntimeError("Unknown variable '%s'" % a) |
203 |
elif o == "--vars": |
204 |
for k in sorted(d.keys()): |
205 |
print k |
206 |
elif o == "--tclsh": |
207 |
pass |
208 |
else: |
209 |
assert False, "unhandled option" |
210 |
|
211 |
|
212 |
|