PageRenderTime 47ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/tkimg1.4/tools/ldAout.tcl

#
TCL | 240 lines | 148 code | 35 blank | 57 comment | 32 complexity | 96ab09b410c09f14168c4201661bbbe9 MD5 | raw file
Possible License(s): AGPL-3.0
  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. # SCCS: @(#) ldAout.tcl 1.11 96/09/17 09:02:20
  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. if {$cc==""} {
  36. set cc $env(CC)
  37. }
  38. # if only two parameters are supplied there is assumed that the
  39. # only shlib_suffix is missing. This parameter is anyway available
  40. # as "info sharedlibextension" too, so there is no need to transfer
  41. # 3 parameters to the function tclLdAout. For compatibility, this
  42. # function now accepts both 2 and 3 parameters.
  43. if {$shlib_suffix==""} {
  44. set shlib_cflags $env(SHLIB_CFLAGS)
  45. } else {
  46. if {$shlib_cflags=="none"} {
  47. set shlib_cflags $shlib_suffix
  48. }
  49. }
  50. # seenDotO is nonzero if a .o or .a file has been seen
  51. set seenDotO 0
  52. # minusO is nonzero if the last command line argument was "-o".
  53. set minusO 0
  54. # head has command line arguments up to but not including the first
  55. # .o or .a file. tail has the rest of the arguments.
  56. set head {}
  57. set tail {}
  58. # nmCommand is the "nm" command that lists global symbols from the
  59. # object files.
  60. set nmCommand {|nm -g}
  61. # entryProtos is the table of prototypes found in the
  62. # module.
  63. set entryProtos {}
  64. # entryPoints is the table of entries found in the
  65. # module.
  66. set entryPoints {}
  67. # libraries is the list of -L and -l flags to the linker.
  68. set libraries {}
  69. set libdirs {}
  70. # Process command line arguments
  71. foreach a $argv {
  72. if {!$minusO && [regexp {\.[ao]$} $a]} {
  73. set seenDotO 1
  74. lappend nmCommand $a
  75. }
  76. if {$minusO} {
  77. set outputFile $a
  78. set minusO 0
  79. } elseif {![string compare $a -o]} {
  80. set minusO 1
  81. }
  82. if [regexp {^-[lL]} $a] {
  83. lappend libraries $a
  84. if [regexp {^-L} $a] {
  85. lappend libdirs [string range $a 2 end]
  86. }
  87. } elseif {$seenDotO} {
  88. lappend tail $a
  89. } else {
  90. lappend head $a
  91. }
  92. }
  93. lappend libdirs /lib /usr/lib
  94. # MIPS -- If there are corresponding G0 libraries, replace the
  95. # ordinary ones with the G0 ones.
  96. set libs {}
  97. foreach lib $libraries {
  98. if [regexp {^-l} $lib] {
  99. set lname [string range $lib 2 end]
  100. foreach dir $libdirs {
  101. if [file exists [file join $dir lib${lname}_G0.a]] {
  102. set lname ${lname}_G0
  103. break
  104. }
  105. }
  106. lappend libs -l$lname
  107. } else {
  108. lappend libs $lib
  109. }
  110. }
  111. set libraries $libs
  112. # Extract the module name from the "-o" option
  113. if {![info exists outputFile]} {
  114. error "-o option must be supplied to link a Tcl load module"
  115. }
  116. set m [file tail $outputFile]
  117. if [regexp {\.a$} $outputFile] {
  118. set shlib_suffix .a
  119. } else {
  120. set shlib_suffix ""
  121. }
  122. if [regexp {\..*$} $outputFile match] {
  123. set l [expr [string length $m] - [string length $match]]
  124. } else {
  125. error "Output file does not appear to have a suffix"
  126. }
  127. set modName [string tolower [string range $m 0 [expr $l-1]]]
  128. if [regexp {^lib} $modName] {
  129. set modName [string range $modName 3 end]
  130. }
  131. if [regexp {[0-9\.]*$} $modName match] {
  132. set modName [string range $modName 0 [expr [string length $modName]-[string length $match]-1]]
  133. }
  134. set modName "[string toupper [string index $modName 0]][string range $modName 1 end]"
  135. # Catalog initialization entry points found in the module
  136. set f [open $nmCommand r]
  137. while {[gets $f l] >= 0} {
  138. if [regexp {[0-9A-Fa-f]+ T[ ]*(((Img_)|(g?z)|(adler32)|((un)?compress)|(crc32)|((in)|(de)flate)|(png_)|(jpeg_)|(_?TIFF)|(TT_))[a-zA-Z0-9_]*)} $l trash symbol] {
  139. append entryProtos {extern int } $symbol { (); } \n
  140. append entryPoints { } \{ { "} $symbol {", } $symbol { } \} , \n
  141. }
  142. }
  143. close $f
  144. if {$entryPoints==""} {
  145. error "No entry point found in objects"
  146. }
  147. # Compose a C function that resolves the entry points and
  148. # embeds the required libraries in the object code.
  149. set C {#include <string.h>}
  150. append C \n
  151. append C {char TclLoadLibraries_} $modName { [] =} \n
  152. append C { "@LIBS: } $libraries {";} \n
  153. append C $entryProtos
  154. append C {static struct } \{ \n
  155. append C { char * name;} \n
  156. append C { int (*value)();} \n
  157. append C \} {dictionary [] = } \{ \n
  158. append C $entryPoints
  159. append C \{ 0, 0 \} \n \} \; \n
  160. append C {typedef struct Tcl_Interp Tcl_Interp;} \n
  161. append C {typedef int Tcl_PackageInitProc (Tcl_Interp *);} \n
  162. append C {Tcl_PackageInitProc *} \n
  163. append C TclLoadDictionary_ $modName { (symbol)} \n
  164. append C { char * symbol;} \n
  165. append C {{
  166. int i;
  167. for (i = 0; dictionary [i] . name != 0; ++i) {
  168. if (!strcmp (symbol, dictionary [i] . name)) {
  169. return dictionary [i].value;
  170. }
  171. }
  172. return 0;
  173. }} \n
  174. # Write the C module and compile it
  175. set cFile tcl$modName.c
  176. set f [open $cFile w]
  177. puts -nonewline $f $C
  178. close $f
  179. set ccCommand "$cc -c $shlib_cflags $cFile"
  180. puts stderr $ccCommand
  181. eval exec $ccCommand
  182. # Now compose and execute the ld command that packages the module
  183. if {$shlib_suffix == ".a"} {
  184. set ldCommand "ar cr $outputFile"
  185. regsub { -o} $tail {} tail
  186. } else {
  187. set ldCommand ld
  188. foreach item $head {
  189. lappend ldCommand $item
  190. }
  191. }
  192. lappend ldCommand tcl$modName.o
  193. foreach item $tail {
  194. lappend ldCommand $item
  195. }
  196. puts stderr $ldCommand
  197. if [catch "exec $ldCommand" msg] {
  198. puts stderr $msg
  199. }
  200. if {$shlib_suffix == ".a"} {
  201. exec ranlib $outputFile
  202. }
  203. # Clean up working files
  204. exec /bin/rm $cFile [file rootname $cFile].o
  205. }