~ubuntu-branches/ubuntu/utopic/critcl/utopic

« back to all changes in this revision

Viewing changes to lib/critcl-platform/platform.tcl

  • Committer: Package Import Robot
  • Author(s): Andrew Shadura
  • Date: 2013-05-11 00:08:06 UTC
  • Revision ID: package-import@ubuntu.com-20130511000806-7hq1zc3fnn0gat79
Tags: upstream-3.1.9
ImportĀ upstreamĀ versionĀ 3.1.9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- tcl -*-
 
2
# ### ### ### ######### ######### #########
 
3
## Overview
 
4
 
 
5
# Heuristics to assemble a platform identifier from publicly available
 
6
# information. The identifier describes the platform of the currently
 
7
# running tcl shell. This is a mixture of the runtime environment and
 
8
# of build-time properties of the executable itself.
 
9
#
 
10
# Examples:
 
11
# <1> A tcl shell executing on a x86_64 processor, but having a
 
12
#   wordsize of 4 was compiled for the x86 environment, i.e. 32
 
13
#   bit, and loaded packages have to match that, and not the
 
14
#   actual cpu.
 
15
#
 
16
# <2> The hp/solaris 32/64 bit builds of the core cannot be
 
17
#   distinguished by looking at tcl_platform. As packages have to
 
18
#   match the 32/64 information we have to look in more places. In
 
19
#   this case we inspect the executable itself (magic numbers,
 
20
#   i.e. fileutil::magic::filetype).
 
21
#
 
22
# The basic information used comes out of the 'os' and 'machine'
 
23
# entries of the 'tcl_platform' array. A number of general and
 
24
# os/machine specific transformation are applied to get a canonical
 
25
# result.
 
26
#
 
27
# General
 
28
# Only the first element of 'os' is used - we don't care whether we
 
29
# are on "Windows NT" or "Windows XP" or whatever.
 
30
#
 
31
# Machine specific
 
32
# % arm*   -> arm
 
33
# % sun4*  -> sparc
 
34
# % intel  -> ix86
 
35
# % i*86*  -> ix86
 
36
# % Power* -> powerpc
 
37
# % x86_64 + wordSize 4 => x86 code
 
38
#
 
39
# OS specific
 
40
# % AIX are always powerpc machines
 
41
# % HP-UX 9000/800 etc means parisc
 
42
# % linux has to take glibc version into account
 
43
# % sunos -> solaris, and keep version number
 
44
#
 
45
# NOTE: A platform like linux glibc 2.3, which can use glibc 2.2 stuff
 
46
# has to provide all possible allowed platform identifiers when
 
47
# searching search. Ditto a solaris 2.8 platform can use solaris 2.6
 
48
# packages. Etc. This is handled by the other procedure, see below.
 
49
 
 
50
# ### ### ### ######### ######### #########
 
51
## Requirements
 
52
 
 
53
namespace eval ::platform {}
 
54
 
 
55
# ### ### ### ######### ######### #########
 
56
## Implementation
 
57
 
 
58
# -- platform::generic
 
59
#
 
60
# Assembles an identifier for the generic platform. It leaves out
 
61
# details like kernel version, libc version, etc.
 
62
 
 
63
proc ::platform::generic {} {
 
64
    global tcl_platform
 
65
 
 
66
    set plat [string tolower [lindex $tcl_platform(os) 0]]
 
67
    set cpu  $tcl_platform(machine)
 
68
 
 
69
    switch -glob -- $cpu {
 
70
        sun4* {
 
71
            set cpu sparc
 
72
        }
 
73
        intel -
 
74
        i*86* {
 
75
            set cpu ix86
 
76
        }
 
77
        x86_64 {
 
78
            if {$tcl_platform(wordSize) == 4} {
 
79
                # See Example <1> at the top of this file.
 
80
                set cpu ix86
 
81
            }
 
82
        }
 
83
        "Power*" {
 
84
            set cpu powerpc
 
85
        }
 
86
        "arm*" {
 
87
            set cpu arm
 
88
        }
 
89
        ia64 {
 
90
            if {$tcl_platform(wordSize) == 4} {
 
91
                append cpu _32
 
92
            }
 
93
        }
 
94
    }
 
95
 
 
96
    switch -- $plat {
 
97
        windows {
 
98
            set plat win32
 
99
            if {$cpu eq "amd64"} {
 
100
                # Do not check wordSize, win32-x64 is an IL32P64 platform.
 
101
                set cpu x86_64
 
102
            }
 
103
        }
 
104
        sunos {
 
105
            set plat solaris
 
106
            if {[string match "ix86" $cpu]} {
 
107
                if {$tcl_platform(wordSize) == 8} {
 
108
                    set cpu x86_64
 
109
                }
 
110
            } elseif {![string match "ia64*" $cpu]} {
 
111
                # sparc
 
112
                if {$tcl_platform(wordSize) == 8} {
 
113
                    append cpu 64
 
114
                }
 
115
            }
 
116
        }
 
117
        darwin {
 
118
            set plat macosx
 
119
            # Correctly identify the cpu when running as a 64bit
 
120
            # process on a machine with a 32bit kernel
 
121
            if {$cpu eq "ix86"} {
 
122
                if {$tcl_platform(wordSize) == 8} {
 
123
                    set cpu x86_64
 
124
                }
 
125
            }
 
126
        }
 
127
        aix {
 
128
            set cpu powerpc
 
129
            if {$tcl_platform(wordSize) == 8} {
 
130
                append cpu 64
 
131
            }
 
132
        }
 
133
        hp-ux {
 
134
            set plat hpux
 
135
            if {![string match "ia64*" $cpu]} {
 
136
                set cpu parisc
 
137
                if {$tcl_platform(wordSize) == 8} {
 
138
                    append cpu 64
 
139
                }
 
140
            }
 
141
        }
 
142
        osf1 {
 
143
            set plat tru64
 
144
        }
 
145
    }
 
146
 
 
147
    return "${plat}-${cpu}"
 
148
}
 
149
 
 
150
# -- platform::identify
 
151
#
 
152
# Assembles an identifier for the exact platform, by extending the
 
153
# generic identifier. I.e. it adds in details like kernel version,
 
154
# libc version, etc., if they are relevant for the loading of
 
155
# packages on the platform.
 
156
 
 
157
proc ::platform::identify {} {
 
158
    global tcl_platform
 
159
 
 
160
    set id [generic]
 
161
    regexp {^([^-]+)-([^-]+)$} $id -> plat cpu
 
162
 
 
163
    switch -- $plat {
 
164
        solaris {
 
165
            regsub {^5} $tcl_platform(osVersion) 2 text
 
166
            append plat $text
 
167
            return "${plat}-${cpu}"
 
168
        }
 
169
        macosx {
 
170
            set major [lindex [split $tcl_platform(osVersion) .] 0]
 
171
            if {$major > 8} {
 
172
                incr major -4
 
173
                append plat 10.$major
 
174
                return "${plat}-${cpu}"
 
175
            }
 
176
        }
 
177
        linux {
 
178
            # Look for the libc*.so and determine its version
 
179
            # (libc5/6, libc6 further glibc 2.X)
 
180
 
 
181
            set v unknown
 
182
 
 
183
            # Determine in which directory to look. /lib, or /lib64.
 
184
            # For that we use the tcl_platform(wordSize).
 
185
            #
 
186
            # We could use the 'cpu' info, per the equivalence below,
 
187
            # that however would be restricted to intel. And this may
 
188
            # be a arm, mips, etc. system. The wordsize is more
 
189
            # fundamental.
 
190
            #
 
191
            # ix86   <=> (wordSize == 4) <=> 32 bit ==> /lib
 
192
            # x86_64 <=> (wordSize == 8) <=> 64 bit ==> /lib64
 
193
            #
 
194
            # Do not look into /lib64 even if present, if the cpu
 
195
            # doesn't fit.
 
196
 
 
197
            # TODO: Determine the prefixes (i386, x86_64, ...) for
 
198
            # other cpus.  The path after the generic one is utterly
 
199
            # specific to intel right now.  Ok, on Ubuntu, possibly
 
200
            # other Debian systems we may apparently be able to query
 
201
            # the necessary CPU code. If we can't we simply use the
 
202
            # hardwired fallback.
 
203
 
 
204
            switch -exact -- $tcl_platform(wordSize) {
 
205
                4 {
 
206
                    lappend bases /lib
 
207
                    if {[catch {
 
208
                        exec dpkg-architecture -qDEB_HOST_MULTIARCH
 
209
                    } res]} {
 
210
                        lappend bases /lib/i386-linux-gnu
 
211
                    } else {
 
212
                        # dpkg-arch returns the full tripled, not just cpu.
 
213
                        lappend bases /lib/$res
 
214
                    }
 
215
                }
 
216
                8 {
 
217
                    lappend bases /lib64
 
218
                    if {[catch {
 
219
                        exec dpkg-architecture -qDEB_HOST_MULTIARCH
 
220
                    } res]} {
 
221
                        lappend bases /lib/x86_64-linux-gnu
 
222
                    } else {
 
223
                        # dpkg-arch returns the full tripled, not just cpu.
 
224
                        lappend bases /lib/$res
 
225
                    }
 
226
                }
 
227
                default {
 
228
                    return -code error "Bad wordSize $tcl_platform(wordSize), expected 4 or 8"
 
229
                }
 
230
            }
 
231
 
 
232
            foreach base $bases {
 
233
                if {[LibcVersion $base -> v]} break
 
234
            }
 
235
 
 
236
            append plat -$v
 
237
            return "${plat}-${cpu}"
 
238
        }
 
239
    }
 
240
 
 
241
    return $id
 
242
}
 
243
 
 
244
proc ::platform::LibcVersion {base _->_ vv} {
 
245
    upvar 1 $vv v
 
246
    set libclist [lsort [glob -nocomplain -directory $base libc*]]
 
247
 
 
248
    if {![llength $libclist]} { return 0 }
 
249
 
 
250
    set libc [lindex $libclist 0]
 
251
 
 
252
    # Try executing the library first. This should suceed
 
253
    # for a glibc library, and return the version
 
254
    # information.
 
255
 
 
256
    if {![catch {
 
257
        set vdata [lindex [split [exec $libc] \n] 0]
 
258
    }]} {
 
259
        regexp {version ([0-9]+(\.[0-9]+)*), by} $vdata -> v
 
260
        foreach {major minor} [split $v .] break
 
261
        set v glibc${major}.${minor}
 
262
        return 1
 
263
    } else {
 
264
        # We had trouble executing the library. We are now
 
265
        # inspecting its name to determine the version
 
266
        # number. This code by Larry McVoy.
 
267
 
 
268
        if {[regexp -- {libc-([0-9]+)\.([0-9]+)} $libc -> major minor]} {
 
269
            set v glibc${major}.${minor}
 
270
            return 1
 
271
        }
 
272
    }
 
273
    return 0
 
274
}
 
275
 
 
276
# -- platform::patterns
 
277
#
 
278
# Given an exact platform identifier, i.e. _not_ the generic
 
279
# identifier it assembles a list of exact platform identifier
 
280
# describing platform which should be compatible with the
 
281
# input.
 
282
#
 
283
# I.e. packages for all platforms in the result list should be
 
284
# loadable on the specified platform.
 
285
 
 
286
# << Should we add the generic identifier to the list as well ? In
 
287
#    general it is not compatible I believe. So better not. In many
 
288
#    cases the exact identifier is identical to the generic one
 
289
#    anyway.
 
290
# >>
 
291
 
 
292
proc ::platform::patterns {id} {
 
293
    set res [list $id]
 
294
    if {$id eq "tcl"} {return $res}
 
295
 
 
296
    switch -glob --  $id {
 
297
        solaris*-* {
 
298
            if {[regexp {solaris([^-]*)-(.*)} $id -> v cpu]} {
 
299
                if {$v eq ""} {return $id}
 
300
                foreach {major minor} [split $v .] break
 
301
                incr minor -1
 
302
                for {set j $minor} {$j >= 6} {incr j -1} {
 
303
                    lappend res solaris${major}.${j}-${cpu}
 
304
                }
 
305
            }
 
306
        }
 
307
        linux*-* {
 
308
            if {[regexp {linux-glibc([^-]*)-(.*)} $id -> v cpu]} {
 
309
                foreach {major minor} [split $v .] break
 
310
                incr minor -1
 
311
                for {set j $minor} {$j >= 0} {incr j -1} {
 
312
                    lappend res linux-glibc${major}.${j}-${cpu}
 
313
                }
 
314
            }
 
315
        }
 
316
        macosx*-*    {
 
317
            # 10.5+ 
 
318
            if {[regexp {macosx([^-]*)-(.*)} $id -> v cpu]} {
 
319
 
 
320
                switch -exact -- $cpu {
 
321
                    ix86    -
 
322
                    x86_64  { set alt i386-x86_64 }
 
323
                    default { set alt {} }
 
324
                }
 
325
 
 
326
                if {$v ne ""} {
 
327
                    foreach {major minor} [split $v .] break
 
328
 
 
329
                    # Add 10.5 to 10.minor to patterns.
 
330
                    set res {}
 
331
                    for {set j $minor} {$j >= 5} {incr j -1} {
 
332
                        lappend res macosx${major}.${j}-${cpu}
 
333
                        lappend res macosx${major}.${j}-universal
 
334
                        if {$alt ne {}} {
 
335
                            lappend res macosx${major}.${j}-$alt
 
336
                        }
 
337
                    }
 
338
 
 
339
                    # Add unversioned patterns for 10.3/10.4 builds.
 
340
                    lappend res macosx-${cpu}
 
341
                    lappend res macosx-universal
 
342
                    if {$alt ne {}} {
 
343
                        lappend res macosx-$alt
 
344
                    }
 
345
                } else {
 
346
                    lappend res macosx-universal
 
347
                    if {$alt ne {}} {
 
348
                        lappend res macosx-$alt
 
349
                    }
 
350
                }
 
351
            } else {
 
352
                lappend res macosx-universal
 
353
            }
 
354
        }
 
355
        macosx-powerpc {
 
356
            lappend res macosx-universal
 
357
        }
 
358
        macosx-x86_64 -
 
359
        macosx-ix86 {
 
360
            lappend res macosx-universal macosx-i386-x86_64
 
361
        }
 
362
    }
 
363
    lappend res tcl ; # Pure tcl packages are always compatible.
 
364
    return $res
 
365
}
 
366
 
 
367
 
 
368
# ### ### ### ######### ######### #########
 
369
## Ready
 
370
 
 
371
package provide critcl::platform 1.0.11
 
372
 
 
373
# ### ### ### ######### ######### #########
 
374
## Demo application
 
375
 
 
376
if {[info exists argv0] && ($argv0 eq [info script])} {
 
377
    puts ====================================
 
378
    parray tcl_platform
 
379
    puts ====================================
 
380
    puts Generic\ identification:\ [::platform::generic]
 
381
    puts Exact\ identification:\ \ \ [::platform::identify]
 
382
    puts ====================================
 
383
    puts Search\ patterns:
 
384
    puts *\ [join [::platform::patterns [::platform::identify]] \n*\ ]
 
385
    puts ====================================
 
386
    exit 0
 
387
}