Initial revision
[AROS-Contrib.git] / development / compilers / freepascal / compiler / t_win32.pas
blob779a5c7177fbd398368e022104f2bd798371bcaf
2 $Id$
3 Copyright (c) 1998-2000 by Peter Vreman
5 This unit implements support import,export,link routines
6 for the (i386) Win32 target
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 ****************************************************************************
24 unit t_win32;
26 interface
28 uses
29 import,export,link;
31 const
32 winstackpagesize = 4096;
34 type
35 pimportlibwin32=^timportlibwin32;
36 timportlibwin32=object(timportlib)
37 procedure preparelib(const s:string);virtual;
38 procedure importprocedure(const func,module:string;index:longint;const name:string);virtual;
39 procedure importvariable(const varname,module:string;const name:string);virtual;
40 procedure generatelib;virtual;
41 procedure generatesmartlib;virtual;
42 end;
44 pexportlibwin32=^texportlibwin32;
45 texportlibwin32=object(texportlib)
46 st : string;
47 last_index : longint;
48 procedure preparelib(const s:string);virtual;
49 procedure exportprocedure(hp : pexported_item);virtual;
50 procedure exportvar(hp : pexported_item);virtual;
51 procedure generatelib;virtual;
52 end;
54 plinkerwin32=^tlinkerwin32;
55 tlinkerwin32=object(tlinker)
56 private
57 Function WriteResponseFile(isdll:boolean) : Boolean;
58 Function PostProcessExecutable(const fn:string;isdll:boolean) : Boolean;
59 public
60 Constructor Init;
61 Procedure SetDefaultInfo;virtual;
62 function MakeExecutable:boolean;virtual;
63 function MakeSharedLibrary:boolean;virtual;
64 end;
67 implementation
69 uses
70 {$ifdef PAVEL_LINKLIB}
71 {$ifdef Delphi}
72 dmisc,
73 {$else Delphi}
74 dos,
75 {$endif Delphi}
76 impdef,
77 {$endif PAVEL_LINKLIB}
78 aasm,files,globtype,globals,cobjects,systems,verbose,
79 script,gendef,
80 cpubase,cpuasm
81 {$ifdef GDB}
82 ,gdb
83 {$endif}
86 function DllName(Const Name : string) : string;
87 var n : string;
88 begin
89 n:=Upper(SplitExtension(Name));
90 if (n='.DLL') or (n='.DRV') or (n='.EXE') then
91 DllName:=Name
92 else
93 DllName:=Name+target_os.sharedlibext;
94 end;
97 {*****************************************************************************
98 TIMPORTLIBWIN32
99 *****************************************************************************}
101 procedure timportlibwin32.preparelib(const s : string);
102 begin
103 if not(assigned(importssection)) then
104 importssection:=new(paasmoutput,init);
105 end;
108 procedure timportlibwin32.importprocedure(const func,module : string;index : longint;const name : string);
110 hp1 : pimportlist;
111 hp2 : pimported_item;
112 hs : string;
113 begin
114 hs:=DllName(module);
115 { search for the module }
116 hp1:=pimportlist(current_module^.imports^.first);
117 while assigned(hp1) do
118 begin
119 if hs=hp1^.dllname^ then
120 break;
121 hp1:=pimportlist(hp1^.next);
122 end;
123 { generate a new item ? }
124 if not(assigned(hp1)) then
125 begin
126 hp1:=new(pimportlist,init(hs));
127 current_module^.imports^.concat(hp1);
128 end;
129 { search for reuse of old import item }
130 hp2:=pimported_item(hp1^.imported_items^.first);
131 while assigned(hp2) do
132 begin
133 if hp2^.func^=func then
134 break;
135 hp2:=pimported_item(hp2^.next);
136 end;
137 if not assigned(hp2) then
138 begin
139 hp2:=new(pimported_item,init(func,name,index));
140 hp1^.imported_items^.concat(hp2);
141 end;
142 end;
145 procedure timportlibwin32.importvariable(const varname,module:string;const name:string);
147 hp1 : pimportlist;
148 hp2 : pimported_item;
149 hs : string;
150 begin
151 hs:=DllName(module);
152 { search for the module }
153 hp1:=pimportlist(current_module^.imports^.first);
154 while assigned(hp1) do
155 begin
156 if hs=hp1^.dllname^ then
157 break;
158 hp1:=pimportlist(hp1^.next);
159 end;
160 { generate a new item ? }
161 if not(assigned(hp1)) then
162 begin
163 hp1:=new(pimportlist,init(hs));
164 current_module^.imports^.concat(hp1);
165 end;
166 hp2:=new(pimported_item,init_var(varname,name));
167 hp1^.imported_items^.concat(hp2);
168 end;
171 procedure timportlibwin32.generatesmartlib;
173 hp1 : pimportlist;
174 hp2 : pimported_item;
175 lhead,lname,lcode,
176 lidata4,lidata5 : pasmlabel;
177 r : preference;
178 begin
179 hp1:=pimportlist(current_module^.imports^.first);
180 while assigned(hp1) do
181 begin
182 { Get labels for the sections }
183 getdatalabel(lhead);
184 getdatalabel(lname);
185 getlabel(lidata4);
186 getlabel(lidata5);
187 { create header for this importmodule }
188 importssection^.concat(new(pai_cut,init_begin));
189 importssection^.concat(new(pai_section,init(sec_idata2)));
190 importssection^.concat(new(pai_label,init(lhead)));
191 { pointer to procedure names }
192 importssection^.concat(new(pai_const_symbol,init_rva(lidata4)));
193 { two empty entries follow }
194 importssection^.concat(new(pai_const,init_32bit(0)));
195 importssection^.concat(new(pai_const,init_32bit(0)));
196 { pointer to dll name }
197 importssection^.concat(new(pai_const_symbol,init_rva(lname)));
198 { pointer to fixups }
199 importssection^.concat(new(pai_const_symbol,init_rva(lidata5)));
200 { first write the name references }
201 importssection^.concat(new(pai_section,init(sec_idata4)));
202 importssection^.concat(new(pai_const,init_32bit(0)));
203 importssection^.concat(new(pai_label,init(lidata4)));
204 { then the addresses and create also the indirect jump }
205 importssection^.concat(new(pai_section,init(sec_idata5)));
206 importssection^.concat(new(pai_const,init_32bit(0)));
207 importssection^.concat(new(pai_label,init(lidata5)));
209 { create procedures }
210 hp2:=pimported_item(hp1^.imported_items^.first);
211 while assigned(hp2) do
212 begin
213 { insert cuts }
214 importssection^.concat(new(pai_cut,init));
215 { create indirect jump }
216 if not hp2^.is_var then
217 begin
218 getlabel(lcode);
219 new(r);
220 reset_reference(r^);
221 r^.symbol:=lcode;
222 { place jump in codesegment, insert a code section in the
223 importsection to reduce the amount of .s files (PFV) }
224 importssection^.concat(new(pai_section,init(sec_code)));
225 {$IfDef GDB}
226 if (cs_debuginfo in aktmoduleswitches) then
227 importssection^.concat(new(pai_stab_function_name,init(nil)));
228 {$EndIf GDB}
229 importssection^.concat(new(pai_symbol,initname_global(hp2^.func^,0)));
230 importssection^.concat(new(paicpu,op_ref(A_JMP,S_NO,r)));
231 importssection^.concat(new(pai_align,init_op(4,$90)));
232 end;
233 { create head link }
234 importssection^.concat(new(pai_section,init(sec_idata7)));
235 importssection^.concat(new(pai_const_symbol,init_rva(lhead)));
236 { fixup }
237 getlabel(pasmlabel(hp2^.lab));
238 importssection^.concat(new(pai_section,init(sec_idata4)));
239 importssection^.concat(new(pai_const_symbol,init_rva(hp2^.lab)));
240 { add jump field to importsection }
241 importssection^.concat(new(pai_section,init(sec_idata5)));
242 if hp2^.is_var then
243 importssection^.concat(new(pai_symbol,initname_global(hp2^.func^,0)))
244 else
245 importssection^.concat(new(pai_label,init(lcode)));
246 if hp2^.name^<>'' then
247 importssection^.concat(new(pai_const_symbol,init_rva(hp2^.lab)))
248 else
249 importssection^.concat(new(pai_const,init_32bit($80000000 or hp2^.ordnr)));
250 { finally the import information }
251 importssection^.concat(new(pai_section,init(sec_idata6)));
252 importssection^.concat(new(pai_label,init(hp2^.lab)));
253 importssection^.concat(new(pai_const,init_16bit(hp2^.ordnr)));
254 importssection^.concat(new(pai_string,init(hp2^.name^+#0)));
255 importssection^.concat(new(pai_align,init_op(2,0)));
256 hp2:=pimported_item(hp2^.next);
257 end;
259 { write final section }
260 importssection^.concat(new(pai_cut,init_end));
261 { end of name references }
262 importssection^.concat(new(pai_section,init(sec_idata4)));
263 importssection^.concat(new(pai_const,init_32bit(0)));
264 { end if addresses }
265 importssection^.concat(new(pai_section,init(sec_idata5)));
266 importssection^.concat(new(pai_const,init_32bit(0)));
267 { dllname }
268 importssection^.concat(new(pai_section,init(sec_idata7)));
269 importssection^.concat(new(pai_label,init(lname)));
270 importssection^.concat(new(pai_string,init(hp1^.dllname^+#0)));
272 hp1:=pimportlist(hp1^.next);
273 end;
274 end;
277 procedure timportlibwin32.generatelib;
279 hp1 : pimportlist;
280 hp2 : pimported_item;
281 l1,l2,l3,l4 : pasmlabel;
282 r : preference;
283 begin
284 hp1:=pimportlist(current_module^.imports^.first);
285 while assigned(hp1) do
286 begin
287 { align codesegment for the jumps }
288 importssection^.concat(new(pai_section,init(sec_code)));
289 importssection^.concat(new(pai_align,init_op(4,$90)));
290 { Get labels for the sections }
291 getlabel(l1);
292 getlabel(l2);
293 getlabel(l3);
294 importssection^.concat(new(pai_section,init(sec_idata2)));
295 { pointer to procedure names }
296 importssection^.concat(new(pai_const_symbol,init_rva(l2)));
297 { two empty entries follow }
298 importssection^.concat(new(pai_const,init_32bit(0)));
299 importssection^.concat(new(pai_const,init_32bit(0)));
300 { pointer to dll name }
301 importssection^.concat(new(pai_const_symbol,init_rva(l1)));
302 { pointer to fixups }
303 importssection^.concat(new(pai_const_symbol,init_rva(l3)));
305 { only create one section for each else it will
306 create a lot of idata* }
308 { first write the name references }
309 importssection^.concat(new(pai_section,init(sec_idata4)));
310 importssection^.concat(new(pai_label,init(l2)));
312 hp2:=pimported_item(hp1^.imported_items^.first);
313 while assigned(hp2) do
314 begin
315 getlabel(pasmlabel(hp2^.lab));
316 if hp2^.name^<>'' then
317 importssection^.concat(new(pai_const_symbol,init_rva(hp2^.lab)))
318 else
319 importssection^.concat(new(pai_const,init_32bit($80000000 or hp2^.ordnr)));
320 hp2:=pimported_item(hp2^.next);
321 end;
322 { finalize the names ... }
323 importssection^.concat(new(pai_const,init_32bit(0)));
325 { then the addresses and create also the indirect jump }
326 importssection^.concat(new(pai_section,init(sec_idata5)));
327 importssection^.concat(new(pai_label,init(l3)));
328 hp2:=pimported_item(hp1^.imported_items^.first);
329 while assigned(hp2) do
330 begin
331 if not hp2^.is_var then
332 begin
333 getlabel(l4);
334 { create indirect jump }
335 new(r);
336 reset_reference(r^);
337 r^.symbol:=l4;
338 { place jump in codesegment }
339 importssection^.concat(new(pai_section,init(sec_code)));
340 importssection^.concat(new(pai_symbol,initname_global(hp2^.func^,0)));
341 importssection^.concat(new(paicpu,op_ref(A_JMP,S_NO,r)));
342 importssection^.concat(new(pai_align,init_op(4,$90)));
343 { add jump field to importsection }
344 importssection^.concat(new(pai_section,init(sec_idata5)));
345 importssection^.concat(new(pai_label,init(l4)));
347 else
348 begin
349 importssection^.concat(new(pai_symbol,initname_global(hp2^.func^,0)));
350 end;
351 importssection^.concat(new(pai_const_symbol,init_rva(hp2^.lab)));
352 hp2:=pimported_item(hp2^.next);
353 end;
354 { finalize the addresses }
355 importssection^.concat(new(pai_const,init_32bit(0)));
357 { finally the import information }
358 importssection^.concat(new(pai_section,init(sec_idata6)));
359 hp2:=pimported_item(hp1^.imported_items^.first);
360 while assigned(hp2) do
361 begin
362 importssection^.concat(new(pai_label,init(hp2^.lab)));
363 { the ordinal number }
364 importssection^.concat(new(pai_const,init_16bit(hp2^.ordnr)));
365 importssection^.concat(new(pai_string,init(hp2^.name^+#0)));
366 importssection^.concat(new(pai_align,init_op(2,0)));
367 hp2:=pimported_item(hp2^.next);
368 end;
369 { create import dll name }
370 importssection^.concat(new(pai_section,init(sec_idata7)));
371 importssection^.concat(new(pai_label,init(l1)));
372 importssection^.concat(new(pai_string,init(hp1^.dllname^+#0)));
374 hp1:=pimportlist(hp1^.next);
375 end;
376 end;
379 {*****************************************************************************
380 TEXPORTLIBWIN32
381 *****************************************************************************}
383 procedure texportlibwin32.preparelib(const s:string);
384 begin
385 if not(assigned(exportssection)) then
386 exportssection:=new(paasmoutput,init);
387 last_index:=0;
388 end;
392 procedure texportlibwin32.exportvar(hp : pexported_item);
393 begin
394 { same code used !! PM }
395 exportprocedure(hp);
396 end;
399 procedure texportlibwin32.exportprocedure(hp : pexported_item);
400 { must be ordered at least for win32 !! }
402 hp2 : pexported_item;
403 begin
404 { first test the index value }
405 if (hp^.options and eo_index)<>0 then
406 begin
407 if (hp^.index<=0) or (hp^.index>$ffff) then
408 begin
409 message1(parser_e_export_invalid_index,tostr(hp^.index));
410 exit;
411 end;
412 if (hp^.index<=last_index) then
413 begin
414 message1(parser_e_export_ordinal_double,tostr(hp^.index));
415 { disregard index value }
416 inc(last_index);
417 hp^.index:=last_index;
418 exit;
420 else
421 begin
422 last_index:=hp^.index;
423 end;
425 else
426 begin
427 inc(last_index);
428 hp^.index:=last_index;
429 end;
430 { use pascal name is none specified }
431 if (hp^.options and eo_name)=0 then
432 begin
433 hp^.name:=stringdup(hp^.sym^.name);
434 hp^.options:=hp^.options or eo_name;
435 end;
436 { now place in correct order }
437 hp2:=pexported_item(current_module^._exports^.first);
438 while assigned(hp2) and
439 (hp^.name^>hp2^.name^) do
440 hp2:=pexported_item(hp2^.next);
441 { insert hp there !! }
442 if assigned(hp2) and (hp2^.name^=hp^.name^) then
443 begin
444 { this is not allowed !! }
445 message1(parser_e_export_name_double,hp^.name^);
446 exit;
447 end;
448 if hp2=pexported_item(current_module^._exports^.first) then
449 current_module^._exports^.insert(hp)
450 else if assigned(hp2) then
451 begin
452 hp^.next:=hp2;
453 hp^.previous:=hp2^.previous;
454 if assigned(hp2^.previous) then
455 hp2^.previous^.next:=hp;
456 hp2^.previous:=hp;
458 else
459 current_module^._exports^.concat(hp);
460 end;
463 procedure texportlibwin32.generatelib;
465 ordinal_base,ordinal_max,ordinal_min : longint;
466 current_index : longint;
467 entries,named_entries : longint;
468 name_label,dll_name_label,export_address_table : pasmlabel;
469 export_name_table_pointers,export_ordinal_table : pasmlabel;
470 hp,hp2 : pexported_item;
471 tempexport : plinkedlist;
472 address_table,name_table_pointers,
473 name_table,ordinal_table : paasmoutput;
474 begin
476 hp:=pexported_item(current_module^._exports^.first);
477 if not assigned(hp) then
478 exit;
480 ordinal_max:=0;
481 ordinal_min:=$7FFFFFFF;
482 entries:=0;
483 named_entries:=0;
484 getlabel(dll_name_label);
485 getlabel(export_address_table);
486 getlabel(export_name_table_pointers);
487 getlabel(export_ordinal_table);
489 { count entries }
490 while assigned(hp) do
491 begin
492 inc(entries);
493 if (hp^.index>ordinal_max) then
494 ordinal_max:=hp^.index;
495 if (hp^.index>0) and (hp^.index<ordinal_min) then
496 ordinal_min:=hp^.index;
497 if assigned(hp^.name) then
498 inc(named_entries);
499 hp:=pexported_item(hp^.next);
500 end;
502 { no support for higher ordinal base yet !! }
503 ordinal_base:=1;
504 current_index:=ordinal_base;
505 { we must also count the holes !! }
506 entries:=ordinal_max-ordinal_base+1;
508 exportssection^.concat(new(pai_section,init(sec_edata)));
509 { export flags }
510 exportssection^.concat(new(pai_const,init_32bit(0)));
511 { date/time stamp }
512 exportssection^.concat(new(pai_const,init_32bit(0)));
513 { major version }
514 exportssection^.concat(new(pai_const,init_16bit(0)));
515 { minor version }
516 exportssection^.concat(new(pai_const,init_16bit(0)));
517 { pointer to dll name }
518 exportssection^.concat(new(pai_const_symbol,init_rva(dll_name_label)));
519 { ordinal base normally set to 1 }
520 exportssection^.concat(new(pai_const,init_32bit(ordinal_base)));
521 { number of entries }
522 exportssection^.concat(new(pai_const,init_32bit(entries)));
523 { number of named entries }
524 exportssection^.concat(new(pai_const,init_32bit(named_entries)));
525 { address of export address table }
526 exportssection^.concat(new(pai_const_symbol,init_rva(export_address_table)));
527 { address of name pointer pointers }
528 exportssection^.concat(new(pai_const_symbol,init_rva(export_name_table_pointers)));
529 { address of ordinal number pointers }
530 exportssection^.concat(new(pai_const_symbol,init_rva(export_ordinal_table)));
531 { the name }
532 exportssection^.concat(new(pai_label,init(dll_name_label)));
533 if st='' then
534 exportssection^.concat(new(pai_string,init(current_module^.modulename^+target_os.sharedlibext+#0)))
535 else
536 exportssection^.concat(new(pai_string,init(st+target_os.sharedlibext+#0)));
538 { export address table }
539 address_table:=new(paasmoutput,init);
540 address_table^.concat(new(pai_align,init_op(4,0)));
541 address_table^.concat(new(pai_label,init(export_address_table)));
542 name_table_pointers:=new(paasmoutput,init);
543 name_table_pointers^.concat(new(pai_align,init_op(4,0)));
544 name_table_pointers^.concat(new(pai_label,init(export_name_table_pointers)));
545 ordinal_table:=new(paasmoutput,init);
546 ordinal_table^.concat(new(pai_align,init_op(4,0)));
547 ordinal_table^.concat(new(pai_label,init(export_ordinal_table)));
548 name_table:=new(paasmoutput,init);
549 name_table^.concat(new(pai_align,init_op(4,0)));
550 { write each address }
551 hp:=pexported_item(current_module^._exports^.first);
552 while assigned(hp) do
553 begin
554 if (hp^.options and eo_name)<>0 then
555 begin
556 getlabel(name_label);
557 name_table_pointers^.concat(new(pai_const_symbol,init_rva(name_label)));
558 ordinal_table^.concat(new(pai_const,init_16bit(hp^.index-ordinal_base)));
559 name_table^.concat(new(pai_align,init_op(2,0)));
560 name_table^.concat(new(pai_label,init(name_label)));
561 name_table^.concat(new(pai_string,init(hp^.name^+#0)));
562 end;
563 hp:=pexported_item(hp^.next);
564 end;
565 { order in increasing ordinal values }
566 { into tempexport list }
567 tempexport:=new(plinkedlist,init);
568 hp:=pexported_item(current_module^._exports^.first);
569 while assigned(hp) do
570 begin
571 current_module^._exports^.remove(hp);
572 hp2:=pexported_item(tempexport^.first);
573 while assigned(hp2) and (hp^.index>hp2^.index) do
574 begin
575 hp2:=pexported_item(hp2^.next);
576 end;
577 if hp2=pexported_item(tempexport^.first) then
578 tempexport^.insert(hp)
579 else
580 begin
581 if assigned(hp2) then
582 begin
583 hp^.next:=hp2;
584 hp^.previous:=hp2^.previous;
585 hp2^.previous:=hp;
586 if assigned(hp^.previous) then
587 hp^.previous^.next:=hp;
589 else
590 tempexport^.concat(hp);
591 end;
592 hp:=pexported_item(current_module^._exports^.first);;
593 end;
595 { write the export adress table }
596 current_index:=ordinal_base;
597 hp:=pexported_item(tempexport^.first);
598 while assigned(hp) do
599 begin
600 { fill missing values }
601 while current_index<hp^.index do
602 begin
603 address_table^.concat(new(pai_const,init_32bit(0)));
604 inc(current_index);
605 end;
606 address_table^.concat(new(pai_const_symbol,initname_rva(hp^.sym^.mangledname)));
607 inc(current_index);
608 hp:=pexported_item(hp^.next);
609 end;
611 exportssection^.concatlist(address_table);
612 exportssection^.concatlist(name_table_pointers);
613 exportssection^.concatlist(ordinal_table);
614 exportssection^.concatlist(name_table);
615 dispose(address_table,done);
616 dispose(name_table_pointers,done);
617 dispose(ordinal_table,done);
618 dispose(name_table,done);
619 dispose(tempexport,done);
620 end;
623 {****************************************************************************
624 TLINKERWIN32
625 ****************************************************************************}
628 Constructor TLinkerWin32.Init;
629 begin
630 Inherited Init;
631 { allow duplicated libs (PM) }
632 SharedLibFiles.doubles:=true;
633 StaticLibFiles.doubles:=true;
634 If not ForceDeffileForExport then
635 UseDeffileForExport:=false;
636 end;
638 Procedure TLinkerWin32.SetDefaultInfo;
639 begin
640 with Info do
641 begin
642 ExeCmd[1]:='ldw $OPT $STRIP $APPTYPE $IMAGEBASE $RELOC -o $EXE $RES';
643 DllCmd[1]:='ldw $OPT $STRIP --dll $APPTYPE $IMAGEBASE $RELOC -o $EXE $RES';
644 if RelocSection or UseDeffileForExport then
645 begin
646 { ExeCmd[2]:='dlltool --as $ASBIN --dllname $EXE --output-exp exp.$$$ $RELOC $DEF';
647 use short forms to avoid 128 char limitation problem }
648 ExeCmd[2]:='dlltool -S $ASBIN -D $EXE -e exp.$$$ $RELOC $DEF';
649 ExeCmd[3]:='ldw $OPT $STRIP $APPTYPE $IMAGEBASE -o $EXE $RES exp.$$$';
650 { DllCmd[2]:='dlltool --as $ASBIN --dllname $EXE --output-exp exp.$$$ $RELOC $DEF'; }
651 DllCmd[2]:='dlltool -S $ASBIN -D $EXE -e exp.$$$ $RELOC $DEF';
652 DllCmd[3]:='ldw $OPT $STRIP --dll $APPTYPE $IMAGEBASE -o $EXE $RES exp.$$$';
653 end;
654 end;
655 end;
657 {$ifndef PAVEL_LINKLIB}
658 Function TLinkerWin32.WriteResponseFile(isdll:boolean) : Boolean;
660 linkres : TLinkRes;
661 i : longint;
662 {$IFDEF NEWST}
663 HPath : PStringItem;
664 {$ELSE}
665 HPath : PStringQueueItem;
666 {$ENDIF NEWST}
667 s,s2 : string;
668 found,linklibc : boolean;
669 begin
670 WriteResponseFile:=False;
672 { Open link.res file }
673 LinkRes.Init(outputexedir+Info.ResName);
675 { Write path to search libraries }
676 HPath:=current_module^.locallibrarysearchpath.First;
677 while assigned(HPath) do
678 begin
679 LinkRes.Add('SEARCH_DIR('+GetShortName(HPath^.Data^)+')');
680 HPath:=HPath^.Next;
681 end;
682 HPath:=LibrarySearchPath.First;
683 while assigned(HPath) do
684 begin
685 LinkRes.Add('SEARCH_DIR('+GetShortName(HPath^.Data^)+')');
686 HPath:=HPath^.Next;
687 end;
689 { add objectfiles, start with prt0 always }
690 LinkRes.Add('INPUT(');
691 if isdll then
692 LinkRes.AddFileName(GetShortName(FindObjectFile('wdllprt0','')))
693 else
694 LinkRes.AddFileName(GetShortName(FindObjectFile('wprt0','')));
695 while not ObjectFiles.Empty do
696 begin
697 s:=ObjectFiles.Get;
698 if s<>'' then
699 LinkRes.AddFileName(GetShortName(s));
700 end;
701 LinkRes.Add(')');
703 { Write staticlibraries }
704 if not StaticLibFiles.Empty then
705 begin
706 LinkRes.Add('GROUP(');
707 While not StaticLibFiles.Empty do
708 begin
709 S:=StaticLibFiles.Get;
710 LinkRes.AddFileName(GetShortName(s));
711 end;
712 LinkRes.Add(')');
713 end;
715 { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
716 here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
717 if not SharedLibFiles.Empty then
718 begin
719 linklibc:=false;
720 LinkRes.Add('INPUT(');
721 While not SharedLibFiles.Empty do
722 begin
723 S:=SharedLibFiles.Get;
724 if pos('.',s)=0 then
725 { we never directly link a DLL
726 its allways through an import library PM }
727 { libraries created by C compilers have .a extensions }
728 s2:=s+'.a'{ target_os.sharedlibext }
729 else
730 s2:=s;
731 s2:=FindLibraryFile(s2,'',found);
732 if found then
733 begin
734 LinkRes.Add(s2);
735 continue;
736 end;
737 if pos(target_os.libprefix,s)=1 then
738 s:=copy(s,length(target_os.libprefix)+1,255);
739 if s<>'c' then
740 begin
741 i:=Pos(target_os.sharedlibext,S);
742 if i>0 then
743 Delete(S,i,255);
744 LinkRes.Add('-l'+s);
746 else
747 begin
748 LinkRes.Add('-l'+s);
749 linklibc:=true;
750 end;
751 end;
752 { be sure that libc is the last lib }
753 if linklibc then
754 LinkRes.Add('-lc');
755 LinkRes.Add(')');
756 end;
757 { Write and Close response }
758 linkres.writetodisk;
759 linkres.done;
761 WriteResponseFile:=True;
762 end;
763 {$else PAVEL_LINKLIB}
764 Function TLinkerWin32.WriteResponseFile(isdll:boolean) : Boolean;
766 linkres : TLinkRes;
767 HPath : {$ifdef NEWST} PStringItem {$else} PStringQueueItem {$endif};
768 s,s2 : string;
769 success : boolean;
770 function ExpandName(const s:string):string;
772 sysdir:string;
773 procedure GetSysDir;
774 begin
775 sysdir:=GetEnv('windir');
776 if sysdir<>''then
777 begin
778 if not(sysdir[length(sysdir)]in['\','/'])then
779 sysdir:=sysdir+dirsep;
780 end;
781 end;
782 function IsFile(d:string;var PathToDll:string):longbool;
784 f:file;
785 attr:word;
786 begin
787 PathToDll:='';
788 if d<>''then
789 if d[length(d)]<>dirsep then
790 d:=d+dirsep;
791 d:=d+s;
792 assign(f,d);
793 GetFattr(f,Attr);
794 if DOSerror<>0 then
795 IsFile:=false
796 else
797 begin
798 if(attr and directory)=0 then
799 begin
800 IsFile:=true;
801 PathToDll:=GetShortName(d);
803 else
804 IsFile:=false;
805 end;
806 end;
808 PathToDll:string;
809 begin
810 if not isFile('',PathToDll)then
811 begin
812 HPath:=LibrarySearchPath.First;
813 while assigned(HPath) do
814 begin
815 if isFile(GetShortName(HPath^.Data^),PathToDll)then
816 break;
817 HPath:=HPath^.Next;
818 end;
819 if PathToDll='' then
820 begin
821 GetSysDir;
822 if not isFile(sysdir,PathToDll)then
823 if not isFile(sysdir+'system32',PathToDll)then
824 if not isFile(sysdir+'system',PathToDll)then
825 begin
826 message1(exec_w_libfile_not_found,S2);
827 PathToDll:=S2;
828 end;
829 end;
830 end;
831 ExpandName:=PathToDll;
832 end;
833 function DotPos(const s:string):longint;
835 i:longint;
836 begin
837 DotPos:=0;
838 for i:=length(s)downto 1 do
839 begin
840 if s[i]in['/','\',':']then
841 exit
842 else if s[i]='.'then
843 begin
844 DotPos:=i;
845 exit;
846 end;
847 end;
848 end;
849 procedure strip(var s:string);
851 d:dirstr;
852 n:namestr;
853 e:extstr;
854 begin
855 fsplit(s,d,n,e);
856 s:=n;
857 end;
858 function do_makedef(const s:string):longbool;
859 begin
860 if cs_link_extern in aktglobalswitches then
861 do_makedef:=DoExec(FindUtil('fpimpdef'),'-o deffile.$$$ -i '+s,false,false)
862 else
863 do_makedef:=makedef(s,'deffile.$$$');
864 end;
865 begin
866 WriteResponseFile:=False;
867 While not SharedLibFiles.Empty do
868 begin
869 S:=SharedLibFiles.Get;
870 if DotPos(s)=0 then
871 s2:=s+target_os.sharedlibext
872 else
873 s2:=s;
874 strip(s);
875 if not do_makedef(ExpandName(s2))then
876 begin
877 Message(exec_w_error_while_linking);
878 aktglobalswitches:=aktglobalswitches+[cs_link_extern];
880 else
881 begin
882 s:=target_os.libprefix+s+target_os.staticlibext;
883 success:=DoExec(FindUtil('dlltool'),'-l '+s+' -D '+s2+' -d deffile.$$$',false,false);
884 ObjectFiles.insert(s);
885 if not success then
886 break;
887 end;
888 end;
890 { Open link.res file }
891 LinkRes.Init(outputexedir+Info.ResName);
893 { Write path to search libraries }
894 HPath:=current_module^.locallibrarysearchpath.First;
895 while assigned(HPath) do
896 begin
897 LinkRes.Add('SEARCH_DIR('+GetShortName(HPath^.Data^)+')');
898 HPath:=HPath^.Next;
899 end;
900 HPath:=LibrarySearchPath.First;
901 while assigned(HPath) do
902 begin
903 LinkRes.Add('SEARCH_DIR('+GetShortName(HPath^.Data^)+')');
904 HPath:=HPath^.Next;
905 end;
907 { add objectfiles, start with prt0 always }
908 LinkRes.Add('INPUT(');
909 if isdll then
910 LinkRes.AddFileName(GetShortName(FindObjectFile('wdllprt0')))
911 else
912 LinkRes.AddFileName(GetShortName(FindObjectFile('wprt0')));
913 while not ObjectFiles.Empty do
914 begin
915 s:=ObjectFiles.Get;
916 if s<>'' then
917 LinkRes.AddFileName(GetShortName(s));
918 end;
919 LinkRes.Add(')');
921 { Write staticlibraries }
922 if not StaticLibFiles.Empty then
923 begin
924 LinkRes.Add('GROUP(');
925 While not StaticLibFiles.Empty do
926 begin
927 S:=StaticLibFiles.Get;
928 LinkRes.AddFileName(GetShortName(s));
929 end;
930 LinkRes.Add(')');
931 end;
933 { Write and Close response }
934 linkres.writetodisk;
935 linkres.done;
937 WriteResponseFile:=True;
938 end;
939 {$endif PAVEL_LINKLIB}
942 function TLinkerWin32.MakeExecutable:boolean;
944 binstr,
945 cmdstr : string;
946 found,
947 success : boolean;
948 i : longint;
949 AsBinStr : string[80];
950 StripStr,
951 RelocStr,
952 AppTypeStr,
953 ImageBaseStr : string[40];
954 begin
955 if not(cs_link_extern in aktglobalswitches) then
956 Message1(exec_i_linking,current_module^.exefilename^);
958 { Create some replacements }
959 RelocStr:='';
960 AppTypeStr:='';
961 ImageBaseStr:='';
962 StripStr:='';
963 AsBinStr:=FindExe('asw',found);
964 if RelocSection then
965 { Using short form to avoid problems with 128 char limitation under Dos. }
966 RelocStr:='-b base.$$$';
967 if apptype=at_gui then
968 AppTypeStr:='--subsystem windows';
969 if assigned(DLLImageBase) then
970 ImageBaseStr:='--image-base=0x'+DLLImageBase^;
971 if (cs_link_strip in aktglobalswitches) then
972 StripStr:='-s';
974 { Write used files and libraries }
975 WriteResponseFile(false);
977 { Call linker }
978 success:=false;
979 for i:=1 to 3 do
980 begin
981 SplitBinCmd(Info.ExeCmd[i],binstr,cmdstr);
982 if binstr<>'' then
983 begin
984 Replace(cmdstr,'$EXE',current_module^.exefilename^);
985 Replace(cmdstr,'$OPT',Info.ExtraOptions);
986 Replace(cmdstr,'$RES',outputexedir+Info.ResName);
987 Replace(cmdstr,'$APPTYPE',AppTypeStr);
988 Replace(cmdstr,'$ASBIN',AsbinStr);
989 Replace(cmdstr,'$RELOC',RelocStr);
990 Replace(cmdstr,'$IMAGEBASE',ImageBaseStr);
991 Replace(cmdstr,'$STRIP',StripStr);
992 if not DefFile.Empty {and UseDefFileForExport} then
993 begin
994 DefFile.WriteFile;
995 Replace(cmdstr,'$DEF','-d '+deffile.fname);
997 else
998 Replace(cmdstr,'$DEF','');
999 success:=DoExec(FindUtil(binstr),cmdstr,(i=1),false);
1000 if not success then
1001 break;
1002 end;
1003 end;
1005 { Post process }
1006 if success then
1007 success:=PostProcessExecutable(current_module^.exefilename^,false);
1009 { Remove ReponseFile }
1010 if (success) and not(cs_link_extern in aktglobalswitches) then
1011 begin
1012 RemoveFile(outputexedir+Info.ResName);
1013 RemoveFile('base.$$$');
1014 RemoveFile('exp.$$$');
1015 RemoveFile('deffile.$$$');
1016 end;
1018 MakeExecutable:=success; { otherwise a recursive call to link method }
1019 end;
1022 Function TLinkerWin32.MakeSharedLibrary:boolean;
1024 binstr,
1025 cmdstr : string;
1026 found,
1027 success : boolean;
1028 i : longint;
1029 AsBinStr : string[80];
1030 StripStr,
1031 RelocStr,
1032 AppTypeStr,
1033 ImageBaseStr : string[40];
1034 begin
1035 MakeSharedLibrary:=false;
1036 if not(cs_link_extern in aktglobalswitches) then
1037 Message1(exec_i_linking,current_module^.sharedlibfilename^);
1039 { Create some replacements }
1040 RelocStr:='';
1041 AppTypeStr:='';
1042 ImageBaseStr:='';
1043 StripStr:='';
1044 AsBinStr:=FindExe('asw',found);
1045 if RelocSection then
1046 { Using short form to avoid problems with 128 char limitation under Dos. }
1047 RelocStr:='-b base.$$$';
1048 if apptype=at_gui then
1049 AppTypeStr:='--subsystem windows';
1050 if assigned(DLLImageBase) then
1051 ImageBaseStr:='--image-base=0x'+DLLImageBase^;
1052 if (cs_link_strip in aktglobalswitches) then
1053 StripStr:='-s';
1055 { Write used files and libraries }
1056 WriteResponseFile(true);
1058 { Call linker }
1059 success:=false;
1060 for i:=1 to 3 do
1061 begin
1062 SplitBinCmd(Info.DllCmd[i],binstr,cmdstr);
1063 if binstr<>'' then
1064 begin
1065 Replace(cmdstr,'$EXE',current_module^.sharedlibfilename^);
1066 Replace(cmdstr,'$OPT',Info.ExtraOptions);
1067 Replace(cmdstr,'$RES',outputexedir+Info.ResName);
1068 Replace(cmdstr,'$APPTYPE',AppTypeStr);
1069 Replace(cmdstr,'$ASBIN',AsbinStr);
1070 Replace(cmdstr,'$RELOC',RelocStr);
1071 Replace(cmdstr,'$IMAGEBASE',ImageBaseStr);
1072 Replace(cmdstr,'$STRIP',StripStr);
1073 if not DefFile.Empty {and UseDefFileForExport} then
1074 begin
1075 DefFile.WriteFile;
1076 Replace(cmdstr,'$DEF','-d '+deffile.fname);
1078 else
1079 Replace(cmdstr,'$DEF','');
1080 success:=DoExec(FindUtil(binstr),cmdstr,(i=1),false);
1081 if not success then
1082 break;
1083 end;
1084 end;
1086 { Post process }
1087 if success then
1088 success:=PostProcessExecutable(current_module^.sharedlibfilename^,true);
1090 { Remove ReponseFile }
1091 if (success) and not(cs_link_extern in aktglobalswitches) then
1092 begin
1093 RemoveFile(outputexedir+Info.ResName);
1094 RemoveFile('base.$$$');
1095 RemoveFile('exp.$$$');
1096 end;
1097 MakeSharedLibrary:=success; { otherwise a recursive call to link method }
1098 end;
1101 function tlinkerwin32.postprocessexecutable(const fn : string;isdll:boolean):boolean;
1102 type
1103 tdosheader = packed record
1104 e_magic : word;
1105 e_cblp : word;
1106 e_cp : word;
1107 e_crlc : word;
1108 e_cparhdr : word;
1109 e_minalloc : word;
1110 e_maxalloc : word;
1111 e_ss : word;
1112 e_sp : word;
1113 e_csum : word;
1114 e_ip : word;
1115 e_cs : word;
1116 e_lfarlc : word;
1117 e_ovno : word;
1118 e_res : array[0..3] of word;
1119 e_oemid : word;
1120 e_oeminfo : word;
1121 e_res2 : array[0..9] of word;
1122 e_lfanew : longint;
1123 end;
1124 tpeheader = packed record
1125 PEMagic : array[0..3] of char;
1126 Machine : word;
1127 NumberOfSections : word;
1128 TimeDateStamp : longint;
1129 PointerToSymbolTable : longint;
1130 NumberOfSymbols : longint;
1131 SizeOfOptionalHeader : word;
1132 Characteristics : word;
1133 Magic : word;
1134 MajorLinkerVersion : byte;
1135 MinorLinkerVersion : byte;
1136 SizeOfCode : longint;
1137 SizeOfInitializedData : longint;
1138 SizeOfUninitializedData : longint;
1139 AddressOfEntryPoint : longint;
1140 BaseOfCode : longint;
1141 BaseOfData : longint;
1142 ImageBase : longint;
1143 SectionAlignment : longint;
1144 FileAlignment : longint;
1145 MajorOperatingSystemVersion : word;
1146 MinorOperatingSystemVersion : word;
1147 MajorImageVersion : word;
1148 MinorImageVersion : word;
1149 MajorSubsystemVersion : word;
1150 MinorSubsystemVersion : word;
1151 Reserved1 : longint;
1152 SizeOfImage : longint;
1153 SizeOfHeaders : longint;
1154 CheckSum : longint;
1155 Subsystem : word;
1156 DllCharacteristics : word;
1157 SizeOfStackReserve : longint;
1158 SizeOfStackCommit : longint;
1159 SizeOfHeapReserve : longint;
1160 SizeOfHeapCommit : longint;
1161 LoaderFlags : longint;
1162 NumberOfRvaAndSizes : longint;
1163 DataDirectory : array[1..$80] of byte;
1164 end;
1165 tcoffsechdr=packed record
1166 name : array[0..7] of char;
1167 vsize : longint;
1168 rvaofs : longint;
1169 datalen : longint;
1170 datapos : longint;
1171 relocpos : longint;
1172 lineno1 : longint;
1173 nrelocs : word;
1174 lineno2 : word;
1175 flags : longint;
1176 end;
1177 psecfill=^tsecfill;
1178 tsecfill=record
1179 fillpos,
1180 fillsize : longint;
1181 next : psecfill;
1182 end;
1184 f : file;
1185 cmdstr : string;
1186 dosheader : tdosheader;
1187 peheader : tpeheader;
1188 firstsecpos,
1189 maxfillsize,
1190 l,peheaderpos : longint;
1191 coffsec : tcoffsechdr;
1192 secroot,hsecroot : psecfill;
1193 zerobuf : pointer;
1194 begin
1195 postprocessexecutable:=false;
1196 { when -s is used or it's a dll then quit }
1197 if (cs_link_extern in aktglobalswitches) then
1198 begin
1199 if apptype=at_gui then
1200 cmdstr:='--subsystem gui'
1201 else if apptype=at_cui then
1202 cmdstr:='--subsystem console';
1203 if dllversion<>'' then
1204 cmdstr:=cmdstr+' --version '+dllversion;
1205 cmdstr:=cmdstr+' --input '+fn;
1206 cmdstr:=cmdstr+' --stack '+tostr(stacksize);
1207 DoExec(FindUtil('postw32'),cmdstr,false,false);
1208 postprocessexecutable:=true;
1209 exit;
1210 end;
1211 { open file }
1212 assign(f,fn);
1213 {$I-}
1214 reset(f,1);
1215 if ioresult<>0 then
1216 Message1(execinfo_f_cant_open_executable,fn);
1217 { read headers }
1218 blockread(f,dosheader,sizeof(tdosheader));
1219 peheaderpos:=dosheader.e_lfanew;
1220 seek(f,peheaderpos);
1221 blockread(f,peheader,sizeof(tpeheader));
1222 { write info }
1223 Message1(execinfo_x_codesize,tostr(peheader.SizeOfCode));
1224 Message1(execinfo_x_initdatasize,tostr(peheader.SizeOfInitializedData));
1225 Message1(execinfo_x_uninitdatasize,tostr(peheader.SizeOfUninitializedData));
1226 { change stack size (PM) }
1227 { I am not sure that the default value is adequate !! }
1228 peheader.SizeOfStackReserve:=stacksize;
1229 { change the header }
1230 { sub system }
1231 { gui=2 }
1232 { cui=3 }
1233 if apptype=at_gui then
1234 peheader.Subsystem:=2
1235 else if apptype=at_cui then
1236 peheader.Subsystem:=3;
1237 if dllversion<>'' then
1238 begin
1239 peheader.MajorImageVersion:=dllmajor;
1240 peheader.MinorImageVersion:=dllminor;
1241 end;
1242 { reset timestamp }
1243 peheader.TimeDateStamp:=0;
1244 { write header back }
1245 seek(f,peheaderpos);
1246 blockwrite(f,peheader,sizeof(tpeheader));
1247 if ioresult<>0 then
1248 Message1(execinfo_f_cant_process_executable,fn);
1249 seek(f,peheaderpos);
1250 blockread(f,peheader,sizeof(tpeheader));
1251 { write the value after the change }
1252 Message1(execinfo_x_stackreserve,tostr(peheader.SizeOfStackReserve));
1253 Message1(execinfo_x_stackcommit,tostr(peheader.SizeOfStackCommit));
1254 { read section info }
1255 maxfillsize:=0;
1256 firstsecpos:=0;
1257 secroot:=nil;
1258 for l:=1 to peheader.NumberOfSections do
1259 begin
1260 blockread(f,coffsec,sizeof(tcoffsechdr));
1261 if coffsec.datapos>0 then
1262 begin
1263 if secroot=nil then
1264 firstsecpos:=coffsec.datapos;
1265 new(hsecroot);
1266 hsecroot^.fillpos:=coffsec.datapos+coffsec.vsize;
1267 hsecroot^.fillsize:=coffsec.datalen-coffsec.vsize;
1268 hsecroot^.next:=secroot;
1269 secroot:=hsecroot;
1270 if secroot^.fillsize>maxfillsize then
1271 maxfillsize:=secroot^.fillsize;
1272 end;
1273 end;
1274 if firstsecpos>0 then
1275 begin
1276 l:=firstsecpos-filepos(f);
1277 if l>maxfillsize then
1278 maxfillsize:=l;
1280 else
1281 l:=0;
1282 { get zero buffer }
1283 getmem(zerobuf,maxfillsize);
1284 fillchar(zerobuf^,maxfillsize,0);
1285 { zero from sectioninfo until first section }
1286 blockwrite(f,zerobuf^,l);
1287 { zero section alignments }
1288 while assigned(secroot) do
1289 begin
1290 seek(f,secroot^.fillpos);
1291 blockwrite(f,zerobuf^,secroot^.fillsize);
1292 hsecroot:=secroot;
1293 secroot:=secroot^.next;
1294 dispose(hsecroot);
1295 end;
1296 freemem(zerobuf,maxfillsize);
1297 close(f);
1298 {$I+}
1299 if ioresult<>0 then;
1300 postprocessexecutable:=true;
1301 end;
1303 end.
1305 $Log$
1306 Revision 1.1 2002/02/19 08:24:13 sasu
1307 Initial revision
1309 Revision 1.1 2000/07/13 06:29:57 michael
1310 + Initial import
1312 Revision 1.25 2000/07/08 20:43:38 peter
1313 * findobjectfile gets extra arg with directory where the unit is found
1314 and the .o should be looked first
1316 Revision 1.24 2000/06/20 12:44:30 pierre
1317 * do not create an empty export section
1319 Revision 1.23 2000/05/23 20:18:25 pierre
1320 + pavel's code integrated, but onyl inside
1321 ifdef pavel_linklib !
1323 Revision 1.22 2000/04/14 11:16:10 pierre
1324 * partial linklib change
1325 I could not use Pavel's code because it broke the current way
1326 linklib is used, which is messy :(
1327 + add postw32 call if external linking on win32
1329 Revision 1.21 2000/03/10 09:14:40 pierre
1330 * dlltool is also needed if we use DefFile
1332 Revision 1.20 2000/02/28 17:23:57 daniel
1333 * Current work of symtable integration committed. The symtable can be
1334 activated by defining 'newst', but doesn't compile yet. Changes in type
1335 checking and oop are completed. What is left is to write a new
1336 symtablestack and adapt the parser to use it.
1338 Revision 1.19 2000/02/24 18:41:39 peter
1339 * removed warnings/notes
1341 Revision 1.18 2000/01/12 10:31:45 peter
1342 * fixed group() writing
1344 Revision 1.17 2000/01/11 09:52:07 peter
1345 * fixed placing of .sl directories
1346 * use -b again for base-file selection
1347 * fixed group writing for linux with smartlinking
1349 Revision 1.16 2000/01/09 00:55:51 pierre
1350 * GROUP of smartlink units put before the C libraries
1351 to allow for smartlinking code that uses C code.
1353 Revision 1.15 2000/01/07 01:14:43 peter
1354 * updated copyright to 2000
1356 Revision 1.14 2000/01/07 00:10:26 peter
1357 * --base-file instead of -b as dlltool 2.9.1 doesn't understand it
1358 * clear timestamp in pe header
1360 Revision 1.13 1999/12/20 23:23:30 pierre
1361 + $description $version
1363 Revision 1.12 1999/12/08 10:40:01 pierre
1364 + allow use of unit var in exports of DLL for win32
1365 by using direct export writing by default instead of use of DEFFILE
1366 that does not allow assembler labels that do not
1367 start with an underscore.
1368 Use -WD to force use of Deffile for Win32 DLL
1370 Revision 1.11 1999/12/06 18:21:04 peter
1371 * support !ENVVAR for long commandlines
1372 * win32/go32v2 write short pathnames to link.res so c:\Program Files\ is
1373 finally supported as installdir.
1375 Revision 1.10 1999/11/24 11:45:36 pierre
1376 * $STRIP was missign in DllCmd[1]
1378 Revision 1.9 1999/11/22 22:20:43 pierre
1379 * Def file syntax for win32 with index corrected
1380 * direct output of .edata leads to same indexes
1381 (index 5 leads to next export being 6 unless otherwise
1382 specified like for enums)
1384 Revision 1.8 1999/11/16 23:39:04 peter
1385 * use outputexedir for link.res location
1387 Revision 1.7 1999/11/15 15:01:56 pierre
1388 + Pavel's changes to support reloc section in exes
1390 Revision 1.6 1999/11/12 11:03:50 peter
1391 * searchpaths changed to stringqueue object
1393 Revision 1.5 1999/11/04 10:55:31 peter
1394 * TSearchPathString for the string type of the searchpaths, which is
1395 ansistring under FPC/Delphi
1397 Revision 1.4 1999/11/02 15:06:58 peter
1398 * import library fixes for win32
1399 * alignment works again
1401 Revision 1.3 1999/10/28 10:33:06 pierre
1402 * Libs can be link serveral times
1404 Revision 1.2 1999/10/22 14:42:40 peter
1405 * reset linklibc
1407 Revision 1.1 1999/10/21 14:29:38 peter
1408 * redesigned linker object
1409 + library support for linux (only procedures can be exported)