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