]>
Commit | Line | Data |
---|---|---|
1 | #!/bin/sh | |
2 | # | |
3 | # dllar - a tool to build both a .dll and an .a file | |
4 | # from a set of object (.o) files for EMX/OS2. | |
5 | # | |
6 | # Written by Andrew Zabolotny, bit@freya.etu.ru | |
7 | # Ported to Unix like shell by Stefan Neis, Stefan.Neis@t-online.de | |
8 | # | |
9 | # This script will accept a set of files on the command line. | |
10 | # All the public symbols from the .o files will be exported into | |
11 | # a .DEF file, then linker will be run (through gcc) against them to | |
12 | # build a shared library consisting of all given .o files. All libraries | |
13 | # (.a) will be first decompressed into component .o files then act as | |
14 | # described above. You can optionally give a description (-d "description") | |
15 | # which will be put into .DLL. To see the list of accepted options (as well | |
16 | # as command-line format) simply run this program without options. The .DLL | |
17 | # is built to be imported by name (there is no guarantee that new versions | |
18 | # of the library you build will have same ordinals for same symbols). | |
19 | # | |
20 | # dllar is free software; you can redistribute it and/or modify | |
21 | # it under the terms of the GNU General Public License as published by | |
22 | # the Free Software Foundation; either version 2, or (at your option) | |
23 | # any later version. | |
24 | # | |
25 | # dllar is distributed in the hope that it will be useful, | |
26 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
27 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
28 | # GNU General Public License for more details. | |
29 | # | |
30 | # You should have received a copy of the GNU General Public License | |
31 | # along with dllar; see the file COPYING. If not, write to the Free | |
32 | # Software Foundation, 59 Temple Place - Suite 330, Boston, MA | |
33 | # 02111-1307, USA. | |
34 | ||
35 | # To successfuly run this program you will need: | |
36 | # - Current drive should have LFN support (HPFS, ext2, network, etc) | |
37 | # (Sometimes dllar generates filenames which won't fit 8.3 scheme) | |
38 | # - gcc | |
39 | # (used to build the .dll) | |
40 | # - emxexp | |
41 | # (used to create .def file from .o files) | |
42 | # - emximp | |
43 | # (used to create .a file from .def file) | |
44 | # - GNU text utilites (cat, sort, uniq) | |
45 | # used to process emxexp output | |
46 | # - GNU file utilities (mv, rm) | |
47 | # - GNU sed | |
48 | # - lxlite (optional, see flag below) | |
49 | # (used for general .dll cleanup) | |
50 | # | |
51 | ||
52 | flag_USE_LXLITE=1; | |
53 | ||
54 | # | |
55 | # helper functions | |
56 | # basnam, variant of basename, which does _not_ remove the path, _iff_ | |
57 | # second argument (suffix to remove) is given | |
58 | basnam(){ | |
59 | case $# in | |
60 | 1) | |
61 | echo $1 | sed 's/.*\///' | sed 's/.*\\//' | |
62 | ;; | |
63 | 2) | |
64 | echo $1 | sed 's/'$2'$//' | |
65 | ;; | |
66 | *) | |
67 | echo "error in basnam $*" | |
68 | exit 8 | |
69 | ;; | |
70 | esac | |
71 | } | |
72 | ||
73 | # Cleanup temporary files and output | |
74 | CleanUp() { | |
75 | cd $curDir | |
76 | for i in $inputFiles ; do | |
77 | case $i in | |
78 | *!) | |
79 | rm -rf `basnam $i !` | |
80 | ;; | |
81 | *) | |
82 | ;; | |
83 | esac | |
84 | done | |
85 | ||
86 | # Kill result in case of failure as there is just to many stupid make/nmake | |
87 | # things out there which doesn't do this. | |
88 | if [ $# -eq 0 ]; then | |
89 | rm -f $arcFile $arcFile2 $defFile $dllFile | |
90 | fi | |
91 | } | |
92 | ||
93 | # Print usage and exit script with rc=1. | |
94 | PrintHelp() { | |
95 | echo 'Usage: dllar [-o[utput] output_file] [-i[mport] importlib_name]' | |
96 | echo ' [-d[escription] "dll descrption"] [-cc "CC"] [-f[lags] "CFLAGS"]' | |
97 | echo ' [-ord[inals]] -ex[clude] "symbol(s)"' | |
98 | echo ' [-libf[lags] "{INIT|TERM}{GLOBAL|INSTANCE}"] [-nocrt[dll]] [-nolxl[ite]]' | |
99 | echo ' [*.o] [*.a]' | |
100 | echo '*> "output_file" should have no extension.' | |
101 | echo ' If it has the .o, .a or .dll extension, it is automatically removed.' | |
102 | echo ' The import library name is derived from this and is set to "name".a,' | |
103 | echo ' unless overridden by -import' | |
104 | echo '*> "importlib_name" should have no extension.' | |
105 | echo ' If it has the .o, or .a extension, it is automatically removed.' | |
106 | echo ' This name is used as the import library name and may be longer and' | |
107 | echo ' more descriptive than the DLL name which has to follow the old ' | |
108 | echo ' 8.3 convention of FAT.' | |
109 | echo '*> "cc" is used to use another GCC executable. (default: gcc.exe)' | |
110 | echo '*> "flags" should be any set of valid GCC flags. (default: -s -Zcrtdll)' | |
111 | echo ' These flags will be put at the start of GCC command line.' | |
112 | echo '*> -ord[inals] tells dllar to export entries by ordinals. Be careful.' | |
113 | echo '*> -ex[clude] defines symbols which will not be exported. You can define' | |
114 | echo ' multiple symbols, for example -ex "myfunc yourfunc _GLOBAL*".' | |
115 | echo ' If the last character of a symbol is "*", all symbols beginning' | |
116 | echo ' with the prefix before "*" will be exclude, (see _GLOBAL* above).' | |
117 | echo '*> -libf[lags] can be used to add INITGLOBAL/INITINSTANCE and/or' | |
118 | echo ' TERMGLOBAL/TERMINSTANCE flags to the dynamically-linked library.' | |
119 | echo '*> -nocrt[dll] switch will disable linking the library against emx''s' | |
120 | echo ' C runtime DLLs.' | |
121 | echo '*> -nolxl[ite] switch will disable running lxlite on the resulting DLL.' | |
122 | echo '*> All other switches (for example -L./ or -lmylib) will be passed' | |
123 | echo ' unchanged to GCC at the end of command line.' | |
124 | echo '*> If you create a DLL from a library and you do not specify -o,' | |
125 | echo ' the basename for DLL and import library will be set to library name,' | |
126 | echo ' the initial library will be renamed to 'name'_s.a (_s for static)' | |
127 | echo ' i.e. "dllar gcc.a" will create gcc.dll and gcc.a, and the initial' | |
128 | echo ' library will be renamed into gcc_s.a.' | |
129 | echo '--------' | |
130 | echo 'Example:' | |
131 | echo ' dllar -o gcc290.dll libgcc.a -d "GNU C runtime library" -ord' | |
132 | echo ' -ex "__main __ctordtor*" -libf "INITINSTANCE TERMINSTANCE"' | |
133 | CleanUp | |
134 | exit 1 | |
135 | } | |
136 | ||
137 | # Execute a command. | |
138 | # If exit code of the commnad <> 0 CleanUp() is called and we'll exit the script. | |
139 | # @Uses Whatever CleanUp() uses. | |
140 | doCommand() { | |
141 | echo "$*" | |
142 | eval $* | |
143 | rcCmd=$? | |
144 | ||
145 | if [ $rcCmd -ne 0 ]; then | |
146 | echo "command failed, exit code="$rcCmd | |
147 | CleanUp | |
148 | exit $rcCmd | |
149 | fi | |
150 | } | |
151 | ||
152 | # main routine | |
153 | # setup globals | |
154 | cmdLine=$* | |
155 | outFile="" | |
156 | outimpFile="" | |
157 | inputFiles="" | |
158 | description="" | |
159 | CC=gcc.exe | |
160 | CFLAGS="-s -Zcrtdll" | |
161 | EXTRA_CFLAGS="" | |
162 | EXPORT_BY_ORDINALS=0 | |
163 | exclude_symbols="" | |
164 | library_flags="" | |
165 | curDir=`pwd` | |
166 | curDirS=curDir | |
167 | case $curDirS in | |
168 | */) | |
169 | ;; | |
170 | *) | |
171 | curDirS=${curDirS}"/" | |
172 | ;; | |
173 | esac | |
174 | # Parse commandline | |
175 | libsToLink=0 | |
176 | omfLinking=0 | |
177 | while [ $1 ]; do | |
178 | case $1 in | |
179 | -ord*) | |
180 | EXPORT_BY_ORDINALS=1; | |
181 | ;; | |
182 | -o*) | |
183 | shift | |
184 | outFile=$1 | |
185 | ;; | |
186 | -i*) | |
187 | shift | |
188 | outimpFile=$1 | |
189 | ;; | |
190 | -d*) | |
191 | shift | |
192 | description=$1 | |
193 | ;; | |
194 | -f*) | |
195 | shift | |
196 | CFLAGS=$1 | |
197 | ;; | |
198 | -c*) | |
199 | shift | |
200 | CC=$1 | |
201 | ;; | |
202 | -h*) | |
203 | PrintHelp | |
204 | ;; | |
205 | -ex*) | |
206 | shift | |
207 | exclude_symbols=${exclude_symbols}$1" " | |
208 | ;; | |
209 | -libf*) | |
210 | shift | |
211 | library_flags=${library_flags}$1" " | |
212 | ;; | |
213 | -nocrt*) | |
214 | CFLAGS="-s" | |
215 | ;; | |
216 | -nolxl*) | |
217 | flag_USE_LXLITE=0 | |
218 | ;; | |
219 | -* | /*) | |
220 | case $1 in | |
221 | -L* | -l*) | |
222 | libsToLink=1 | |
223 | ;; | |
224 | -Zomf) | |
225 | omfLinking=1 | |
226 | ;; | |
227 | *) | |
228 | ;; | |
229 | esac | |
230 | EXTRA_CFLAGS=${EXTRA_CFLAGS}" "$1 | |
231 | ;; | |
232 | *.dll) | |
233 | EXTRA_CFLAGS="${EXTRA_CFLAGS} `basnam $1 .dll`" | |
234 | if [ $omfLinking -eq 1 ]; then | |
235 | EXTRA_CFLAGS="${EXTRA_CFLAGS}.lib" | |
236 | else | |
237 | EXTRA_CFLAGS="${EXTRA_CFLAGS}.a" | |
238 | fi | |
239 | ;; | |
240 | *) | |
241 | found=0; | |
242 | if [ $libsToLink -ne 0 ]; then | |
243 | EXTRA_CFLAGS=${EXTRA_CFLAGS}" "$1 | |
244 | else | |
245 | for file in $1 ; do | |
246 | if [ -f $file ]; then | |
247 | inputFiles="${inputFiles} $file" | |
248 | found=1 | |
249 | fi | |
250 | done | |
251 | if [ $found -eq 0 ]; then | |
252 | echo "ERROR: No file(s) found: "$1 | |
253 | exit 8 | |
254 | fi | |
255 | fi | |
256 | ;; | |
257 | esac | |
258 | shift | |
259 | done # iterate cmdline words | |
260 | ||
261 | # | |
262 | if [ -z "$inputFiles" ]; then | |
263 | echo "dllar: no input files" | |
264 | PrintHelp | |
265 | fi | |
266 | ||
267 | # Now extract all .o files from .a files | |
268 | newInputFiles="" | |
269 | for file in $inputFiles ; do | |
270 | case $file in | |
271 | *.a | *.lib) | |
272 | case $file in | |
273 | *.a) | |
274 | suffix=".a" | |
275 | AR="ar" | |
276 | ;; | |
277 | *.lib) | |
278 | suffix=".lib" | |
279 | AR="emxomfar" | |
280 | EXTRA_CFLAGS="$EXTRA_CFLAGS -Zomf" | |
281 | ;; | |
282 | *) | |
283 | ;; | |
284 | esac | |
285 | dirname=`basnam $file $suffix`"_%" | |
286 | mkdir $dirname | |
287 | if [ $? -ne 0 ]; then | |
288 | echo "Failed to create subdirectory ./$dirname" | |
289 | CleanUp | |
290 | exit 8; | |
291 | fi | |
292 | # Append '!' to indicate archive | |
293 | newInputFiles="$newInputFiles ${dirname}!" | |
294 | doCommand "cd $dirname; $AR x ../$file" | |
295 | cd $curDir | |
296 | found=0; | |
297 | for subfile in $dirname/*.o* ; do | |
298 | if [ -f $subfile ]; then | |
299 | found=1 | |
300 | if [ -s $subfile ]; then | |
301 | # FIXME: This should be: is file size > 32 byte, _not_ > 0! | |
302 | newInputFiles="$newInputFiles $subfile" | |
303 | fi | |
304 | fi | |
305 | done | |
306 | if [ $found -eq 0 ]; then | |
307 | echo "WARNING: there are no files in archive \'$file\'" | |
308 | fi | |
309 | ;; | |
310 | *) | |
311 | newInputFiles="${newInputFiles} $file" | |
312 | ;; | |
313 | esac | |
314 | done | |
315 | inputFiles="$newInputFiles" | |
316 | ||
317 | # Output filename(s). | |
318 | do_backup=0; | |
319 | if [ -z $outFile ]; then | |
320 | do_backup=1; | |
321 | set outFile $inputFiles; outFile=$2 | |
322 | fi | |
323 | ||
324 | # If it is an archive, remove the '!' and the '_%' suffixes | |
325 | case $outFile in | |
326 | *_%!) | |
327 | outFile=`basnam $outFile _%!` | |
328 | ;; | |
329 | *) | |
330 | ;; | |
331 | esac | |
332 | case $outFile in | |
333 | *.dll) | |
334 | outFile=`basnam $outFile .dll` | |
335 | ;; | |
336 | *.DLL) | |
337 | outFile=`basnam $outFile .DLL` | |
338 | ;; | |
339 | *.o) | |
340 | outFile=`basnam $outFile .o` | |
341 | ;; | |
342 | *.obj) | |
343 | outFile=`basnam $outFile .obj` | |
344 | ;; | |
345 | *.a) | |
346 | outFile=`basnam $outFile .a` | |
347 | ;; | |
348 | *.lib) | |
349 | outFile=`basnam $outFile .lib` | |
350 | ;; | |
351 | *) | |
352 | ;; | |
353 | esac | |
354 | case $outimpFile in | |
355 | *.a) | |
356 | outimpFile=`basnam $outimpFile .a` | |
357 | ;; | |
358 | *.lib) | |
359 | outimpFile=`basnam $outimpFile .lib` | |
360 | ;; | |
361 | *) | |
362 | ;; | |
363 | esac | |
364 | if [ -z $outimpFile ]; then | |
365 | outimpFile=$outFile | |
366 | fi | |
367 | defFile="${outFile}.def" | |
368 | arcFile="${outimpFile}.a" | |
369 | arcFile2="${outimpFile}.lib" | |
370 | ||
371 | #create $dllFile as something matching 8.3 restrictions, | |
372 | dllFile="$outFile" | |
373 | case $dllFile in | |
374 | *wx_base_*) | |
375 | dllFile=`echo $dllFile | sed 's/base_\(...\)/b\1/'` | |
376 | ;; | |
377 | *wx_*_*) | |
378 | dllFile=`echo $dllFile | sed 's/_\(..\)[^_]*_\(..\)[^-]*-/\1\2/'` | |
379 | ;; | |
380 | *) | |
381 | ;; | |
382 | esac | |
383 | dllFile="`echo $dllFile | sed 's/\.//' | sed 's/_//' | sed 's/-//'`" | |
384 | ||
385 | ||
386 | if [ $do_backup -ne 0 ] ; then | |
387 | if [ -f $arcFile ] ; then | |
388 | doCommand "mv $arcFile ${outFile}_s.a" | |
389 | fi | |
390 | if [ -f $arcFile2 ] ; then | |
391 | doCommand "mv $arcFile2 ${outFile}_s.lib" | |
392 | fi | |
393 | fi | |
394 | ||
395 | # Extract public symbols from all the object files. | |
396 | tmpdefFile=${defFile}_% | |
397 | rm -f $tmpdefFile | |
398 | for file in $inputFiles ; do | |
399 | case $file in | |
400 | *!) | |
401 | ;; | |
402 | *) | |
403 | doCommand "emxexp -u $file >> $tmpdefFile" | |
404 | ;; | |
405 | esac | |
406 | done | |
407 | ||
408 | # Create the def file. | |
409 | rm -f $defFile | |
410 | echo "LIBRARY `basnam $dllFile` $library_flags" >> $defFile | |
411 | dllFile="$dllFile.dll" | |
412 | if [ ! -z $description ]; then | |
413 | echo "DESCRIPTION \"${description}\"" >> $defFile | |
414 | fi | |
415 | echo "EXPORTS" >> $defFile | |
416 | ||
417 | doCommand "cat $tmpdefFile | sort.exe | uniq.exe > ${tmpdefFile}%" | |
418 | grep -v "^ *;" < ${tmpdefFile}% | grep -v "^ *$" >$tmpdefFile | |
419 | ||
420 | # Checks if the export is ok or not. | |
421 | for word in $exclude_symbols; do | |
422 | grep -v $word < $tmpdefFile >${tmpdefFile}% | |
423 | mv ${tmpdefFile}% $tmpdefFile | |
424 | done | |
425 | ||
426 | ||
427 | if [ $EXPORT_BY_ORDINALS -ne 0 ]; then | |
428 | sed "=" < $tmpdefFile | \ | |
429 | sed ' | |
430 | N | |
431 | : loop | |
432 | s/^\([0-9]\+\)\([^;]*\)\(;.*\)\?/\2 @\1 NONAME/ | |
433 | t loop | |
434 | ' > ${tmpdefFile}% | |
435 | grep -v "^ *$" < ${tmpdefFile}% > $tmpdefFile | |
436 | else | |
437 | rm -f ${tmpdefFile}% | |
438 | fi | |
439 | cat $tmpdefFile >> $defFile | |
440 | rm -f $tmpdefFile | |
441 | ||
442 | # Do linking, create implib, and apply lxlite. | |
443 | gccCmdl=""; | |
444 | for file in $inputFiles ; do | |
445 | case $file in | |
446 | *!) | |
447 | ;; | |
448 | *) | |
449 | gccCmdl="$gccCmdl $file" | |
450 | ;; | |
451 | esac | |
452 | done | |
453 | doCommand "$CC $CFLAGS -Zdll -o $dllFile $defFile $gccCmdl $EXTRA_CFLAGS" | |
454 | touch "${outFile}.dll" | |
455 | ||
456 | doCommand "emximp -o $arcFile $defFile" | |
457 | if [ $flag_USE_LXLITE -ne 0 ]; then | |
458 | add_flags=""; | |
459 | if [ $EXPORT_BY_ORDINALS -ne 0 ]; then | |
460 | add_flags="-ynd" | |
461 | fi | |
462 | doCommand "lxlite -cs -t: -mrn -mln $add_flags $dllFile" | |
463 | fi | |
464 | doCommand "emxomf -s -l $arcFile" | |
465 | ||
466 | # Successful exit. | |
467 | CleanUp 1 | |
468 | exit 0 |