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