]>
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.sh [-o[utput] output_file] [-i[mport] importlib_name]' | |
96 | echo ' [-name-mangler-script script.sh]' | |
97 | echo ' [-d[escription] "dll descrption"] [-cc "CC"] [-f[lags] "CFLAGS"]' | |
98 | echo ' [-ord[inals]] -ex[clude] "symbol(s)"' | |
99 | echo ' [-libf[lags] "{INIT|TERM}{GLOBAL|INSTANCE}"] [-nocrt[dll]] [-nolxl[ite]]' | |
100 | echo ' [*.o] [*.a]' | |
101 | echo '*> "output_file" should have no extension.' | |
102 | echo ' If it has the .o, .a or .dll extension, it is automatically removed.' | |
103 | echo ' The import library name is derived from this and is set to "name".a,' | |
104 | echo ' unless overridden by -import' | |
105 | echo '*> "importlib_name" should have no extension.' | |
106 | echo ' If it has the .o, or .a extension, it is automatically removed.' | |
107 | echo ' This name is used as the import library name and may be longer and' | |
108 | echo ' more descriptive than the DLL name which has to follow the old ' | |
109 | echo ' 8.3 convention of FAT.' | |
110 | echo '*> "script.sh may be given to override the output_file name by a' | |
111 | echo ' different name. It is mainly useful if the regular make process' | |
112 | echo ' of some package does not take into account OS/2 restriction of' | |
113 | echo ' DLL name lengths. It takes the importlib name as input and is' | |
114 | echo ' supposed to procude a shorter name as output. The script should' | |
115 | echo ' expect to get importlib_name without extension and should produce' | |
116 | echo ' a (max.) 8 letter name without extension.' | |
117 | echo '*> "cc" is used to use another GCC executable. (default: gcc.exe)' | |
118 | echo '*> "flags" should be any set of valid GCC flags. (default: -s -Zcrtdll)' | |
119 | echo ' These flags will be put at the start of GCC command line.' | |
120 | echo '*> -ord[inals] tells dllar to export entries by ordinals. Be careful.' | |
121 | echo '*> -ex[clude] defines symbols which will not be exported. You can define' | |
122 | echo ' multiple symbols, for example -ex "myfunc yourfunc _GLOBAL*".' | |
123 | echo ' If the last character of a symbol is "*", all symbols beginning' | |
124 | echo ' with the prefix before "*" will be exclude, (see _GLOBAL* above).' | |
125 | echo '*> -libf[lags] can be used to add INITGLOBAL/INITINSTANCE and/or' | |
126 | echo ' TERMGLOBAL/TERMINSTANCE flags to the dynamically-linked library.' | |
127 | echo '*> -nocrt[dll] switch will disable linking the library against emx''s' | |
128 | echo ' C runtime DLLs.' | |
129 | echo '*> -nolxl[ite] switch will disable running lxlite on the resulting DLL.' | |
130 | echo '*> All other switches (for example -L./ or -lmylib) will be passed' | |
131 | echo ' unchanged to GCC at the end of command line.' | |
132 | echo '*> If you create a DLL from a library and you do not specify -o,' | |
133 | echo ' the basename for DLL and import library will be set to library name,' | |
134 | echo ' the initial library will be renamed to 'name'_s.a (_s for static)' | |
135 | echo ' i.e. "dllar gcc.a" will create gcc.dll and gcc.a, and the initial' | |
136 | echo ' library will be renamed into gcc_s.a.' | |
137 | echo '--------' | |
138 | echo 'Example:' | |
139 | echo ' dllar -o gcc290.dll libgcc.a -d "GNU C runtime library" -ord' | |
140 | echo ' -ex "__main __ctordtor*" -libf "INITINSTANCE TERMINSTANCE"' | |
141 | CleanUp | |
142 | exit 1 | |
143 | } | |
144 | ||
145 | # Execute a command. | |
146 | # If exit code of the commnad <> 0 CleanUp() is called and we'll exit the script. | |
147 | # @Uses Whatever CleanUp() uses. | |
148 | doCommand() { | |
149 | echo "$*" | |
150 | eval $* | |
151 | rcCmd=$? | |
152 | ||
153 | if [ $rcCmd -ne 0 ]; then | |
154 | echo "command failed, exit code="$rcCmd | |
155 | CleanUp | |
156 | exit $rcCmd | |
157 | fi | |
158 | } | |
159 | ||
160 | # main routine | |
161 | # setup globals | |
162 | cmdLine=$* | |
163 | outFile="" | |
164 | outimpFile="" | |
165 | inputFiles="" | |
166 | renameScript="" | |
167 | description="" | |
168 | CC=gcc.exe | |
169 | CFLAGS="-s -Zcrtdll" | |
170 | EXTRA_CFLAGS="" | |
171 | EXPORT_BY_ORDINALS=0 | |
172 | exclude_symbols="" | |
173 | library_flags="" | |
174 | curDir=`pwd` | |
175 | curDirS=curDir | |
176 | case $curDirS in | |
177 | */) | |
178 | ;; | |
179 | *) | |
180 | curDirS=${curDirS}"/" | |
181 | ;; | |
182 | esac | |
183 | # Parse commandline | |
184 | libsToLink=0 | |
185 | omfLinking=0 | |
186 | while [ $1 ]; do | |
187 | case $1 in | |
188 | -ord*) | |
189 | EXPORT_BY_ORDINALS=1; | |
190 | ;; | |
191 | -o*) | |
192 | shift | |
193 | outFile=$1 | |
194 | ;; | |
195 | -i*) | |
196 | shift | |
197 | outimpFile=$1 | |
198 | ;; | |
199 | -name-mangler-script) | |
200 | shift | |
201 | renameScript=$1 | |
202 | ;; | |
203 | -d*) | |
204 | shift | |
205 | description=$1 | |
206 | ;; | |
207 | -f*) | |
208 | shift | |
209 | CFLAGS=$1 | |
210 | ;; | |
211 | -c*) | |
212 | shift | |
213 | CC=$1 | |
214 | ;; | |
215 | -h*) | |
216 | PrintHelp | |
217 | ;; | |
218 | -ex*) | |
219 | shift | |
220 | exclude_symbols=${exclude_symbols}$1" " | |
221 | ;; | |
222 | -libf*) | |
223 | shift | |
224 | library_flags=${library_flags}$1" " | |
225 | ;; | |
226 | -nocrt*) | |
227 | CFLAGS="-s" | |
228 | ;; | |
229 | -nolxl*) | |
230 | flag_USE_LXLITE=0 | |
231 | ;; | |
232 | -* | /*) | |
233 | case $1 in | |
234 | -L* | -l*) | |
235 | libsToLink=1 | |
236 | ;; | |
237 | -Zomf) | |
238 | omfLinking=1 | |
239 | ;; | |
240 | *) | |
241 | ;; | |
242 | esac | |
243 | EXTRA_CFLAGS=${EXTRA_CFLAGS}" "$1 | |
244 | ;; | |
245 | *.dll) | |
246 | EXTRA_CFLAGS="${EXTRA_CFLAGS} `basnam $1 .dll`" | |
247 | if [ $omfLinking -eq 1 ]; then | |
248 | EXTRA_CFLAGS="${EXTRA_CFLAGS}.lib" | |
249 | else | |
250 | EXTRA_CFLAGS="${EXTRA_CFLAGS}.a" | |
251 | fi | |
252 | ;; | |
253 | *) | |
254 | found=0; | |
255 | if [ $libsToLink -ne 0 ]; then | |
256 | EXTRA_CFLAGS=${EXTRA_CFLAGS}" "$1 | |
257 | else | |
258 | for file in $1 ; do | |
259 | if [ -f $file ]; then | |
260 | inputFiles="${inputFiles} $file" | |
261 | found=1 | |
262 | fi | |
263 | done | |
264 | if [ $found -eq 0 ]; then | |
265 | echo "ERROR: No file(s) found: "$1 | |
266 | exit 8 | |
267 | fi | |
268 | fi | |
269 | ;; | |
270 | esac | |
271 | shift | |
272 | done # iterate cmdline words | |
273 | ||
274 | # | |
275 | if [ -z "$inputFiles" ]; then | |
276 | echo "dllar: no input files" | |
277 | PrintHelp | |
278 | fi | |
279 | ||
280 | # Now extract all .o files from .a files | |
281 | newInputFiles="" | |
282 | for file in $inputFiles ; do | |
283 | case $file in | |
284 | *.a | *.lib) | |
285 | case $file in | |
286 | *.a) | |
287 | suffix=".a" | |
288 | AR="ar" | |
289 | ;; | |
290 | *.lib) | |
291 | suffix=".lib" | |
292 | AR="emxomfar" | |
293 | EXTRA_CFLAGS="$EXTRA_CFLAGS -Zomf" | |
294 | ;; | |
295 | *) | |
296 | ;; | |
297 | esac | |
298 | dirname=`basnam $file $suffix`"_%" | |
299 | mkdir $dirname | |
300 | if [ $? -ne 0 ]; then | |
301 | echo "Failed to create subdirectory ./$dirname" | |
302 | CleanUp | |
303 | exit 8; | |
304 | fi | |
305 | # Append '!' to indicate archive | |
306 | newInputFiles="$newInputFiles ${dirname}!" | |
307 | doCommand "cd $dirname; $AR x ../$file" | |
308 | cd $curDir | |
309 | found=0; | |
310 | for subfile in $dirname/*.o* ; do | |
311 | if [ -f $subfile ]; then | |
312 | found=1 | |
313 | if [ -s $subfile ]; then | |
314 | # FIXME: This should be: is file size > 32 byte, _not_ > 0! | |
315 | newInputFiles="$newInputFiles $subfile" | |
316 | fi | |
317 | fi | |
318 | done | |
319 | if [ $found -eq 0 ]; then | |
320 | echo "WARNING: there are no files in archive \'$file\'" | |
321 | fi | |
322 | ;; | |
323 | *) | |
324 | newInputFiles="${newInputFiles} $file" | |
325 | ;; | |
326 | esac | |
327 | done | |
328 | inputFiles="$newInputFiles" | |
329 | ||
330 | # Output filename(s). | |
331 | do_backup=0; | |
332 | if [ -z $outFile ]; then | |
333 | do_backup=1; | |
334 | set outFile $inputFiles; outFile=$2 | |
335 | fi | |
336 | ||
337 | # If it is an archive, remove the '!' and the '_%' suffixes | |
338 | case $outFile in | |
339 | *_%!) | |
340 | outFile=`basnam $outFile _%!` | |
341 | ;; | |
342 | *) | |
343 | ;; | |
344 | esac | |
345 | case $outFile in | |
346 | *.dll) | |
347 | outFile=`basnam $outFile .dll` | |
348 | ;; | |
349 | *.DLL) | |
350 | outFile=`basnam $outFile .DLL` | |
351 | ;; | |
352 | *.o) | |
353 | outFile=`basnam $outFile .o` | |
354 | ;; | |
355 | *.obj) | |
356 | outFile=`basnam $outFile .obj` | |
357 | ;; | |
358 | *.a) | |
359 | outFile=`basnam $outFile .a` | |
360 | ;; | |
361 | *.lib) | |
362 | outFile=`basnam $outFile .lib` | |
363 | ;; | |
364 | *) | |
365 | ;; | |
366 | esac | |
367 | case $outimpFile in | |
368 | *.a) | |
369 | outimpFile=`basnam $outimpFile .a` | |
370 | ;; | |
371 | *.lib) | |
372 | outimpFile=`basnam $outimpFile .lib` | |
373 | ;; | |
374 | *) | |
375 | ;; | |
376 | esac | |
377 | if [ -z $outimpFile ]; then | |
378 | outimpFile=$outFile | |
379 | fi | |
380 | defFile="${outFile}.def" | |
381 | arcFile="${outimpFile}.a" | |
382 | arcFile2="${outimpFile}.lib" | |
383 | ||
384 | #create $dllFile as something matching 8.3 restrictions, | |
385 | if [ -z $renameScript ] ; then | |
386 | dllFile="$outFile" | |
387 | else | |
388 | dllFile=`$renameScript $outimpFile` | |
389 | fi | |
390 | ||
391 | if [ $do_backup -ne 0 ] ; then | |
392 | if [ -f $arcFile ] ; then | |
393 | doCommand "mv $arcFile ${outFile}_s.a" | |
394 | fi | |
395 | if [ -f $arcFile2 ] ; then | |
396 | doCommand "mv $arcFile2 ${outFile}_s.lib" | |
397 | fi | |
398 | fi | |
399 | ||
400 | # Extract public symbols from all the object files. | |
401 | tmpdefFile=${defFile}_% | |
402 | rm -f $tmpdefFile | |
403 | for file in $inputFiles ; do | |
404 | case $file in | |
405 | *!) | |
406 | ;; | |
407 | *) | |
408 | # we do not want to export weak symbols in general, so we filter | |
409 | # those out using grep. | |
410 | doCommand "emxexp -u $file >> $tmpdefFile || true" | |
411 | ;; | |
412 | esac | |
413 | done | |
414 | ||
415 | # Create the def file. | |
416 | rm -f $defFile | |
417 | echo "LIBRARY `basnam $dllFile` $library_flags" >> $defFile | |
418 | dllFile="${dllFile}.dll" | |
419 | if [ ! -z $description ]; then | |
420 | echo "DESCRIPTION \"${description}\"" >> $defFile | |
421 | fi | |
422 | echo "EXPORTS" >> $defFile | |
423 | ||
424 | doCommand "cat $tmpdefFile | sort.exe | uniq.exe > ${tmpdefFile}%" | |
425 | grep -v "^ *;" < ${tmpdefFile}% | grep -v "^ *$" >$tmpdefFile | |
426 | ||
427 | # Checks if the export is ok or not. | |
428 | for word in $exclude_symbols; do | |
429 | grep -v $word < $tmpdefFile >${tmpdefFile}% | |
430 | mv ${tmpdefFile}% $tmpdefFile | |
431 | done | |
432 | ||
433 | ||
434 | if [ $EXPORT_BY_ORDINALS -ne 0 ]; then | |
435 | sed "=" < $tmpdefFile | \ | |
436 | sed ' | |
437 | N | |
438 | : loop | |
439 | s/^\([0-9]\+\)\([^;]*\)\(;.*\)\?/\2 @\1 NONAME/ | |
440 | t loop | |
441 | ' > ${tmpdefFile}% | |
442 | grep -v "^ *$" < ${tmpdefFile}% > $tmpdefFile | |
443 | else | |
444 | rm -f ${tmpdefFile}% | |
445 | fi | |
446 | cat $tmpdefFile >> $defFile | |
447 | rm -f $tmpdefFile | |
448 | ||
449 | # Do linking, create implib, and apply lxlite. | |
450 | gccCmdl=""; | |
451 | for file in $inputFiles ; do | |
452 | case $file in | |
453 | *!) | |
454 | ;; | |
455 | *) | |
456 | gccCmdl="$gccCmdl $file" | |
457 | ;; | |
458 | esac | |
459 | done | |
460 | doCommand "$CC $CFLAGS -Zdll -o $dllFile $defFile $gccCmdl $EXTRA_CFLAGS" | |
461 | touch "${outFile}.dll" | |
462 | ||
463 | doCommand "emximp -o $arcFile $defFile" | |
464 | if [ $flag_USE_LXLITE -ne 0 ]; then | |
465 | add_flags=""; | |
466 | if [ $EXPORT_BY_ORDINALS -ne 0 ]; then | |
467 | add_flags="-ynd" | |
468 | fi | |
469 | doCommand "lxlite -cs -t: $add_flags `echo $dllFile | sed 's/\//\\\\/g'`" | |
470 | fi | |
471 | ||
472 | #New version of emxomf do no longer want the "-l" flag | |
473 | case `emxomf` in | |
474 | emxomf\ 0.6*) | |
475 | omflibflag="" | |
476 | ;; | |
477 | *) | |
478 | omflibflag=" -l" | |
479 | ;; | |
480 | esac | |
481 | doCommand "emxomf -s$omflibflag $arcFile" | |
482 | ||
483 | # Successful exit. | |
484 | CleanUp 1 | |
485 | exit 0 |