ppumove.pp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  1. {
  2. $Id$
  3. Copyright (c) 1999-2000 by the FPC Development Team
  4. Add multiple FPC units into a static/shared library
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************}
  17. {$ifndef TP}
  18. {$H+}
  19. {$endif}
  20. Program ppumove;
  21. uses
  22. {$ifdef linux}
  23. linux,
  24. {$else linux}
  25. dos,
  26. {$endif linux}
  27. ppu,
  28. getopts;
  29. const
  30. Version = 'Version 0.99.13';
  31. Title = 'PPU-Mover';
  32. Copyright = 'Copyright (c) 1998-2000 by the Free Pascal Development Team';
  33. ShortOpts = 'o:e:d:qhsvbw';
  34. BufSize = 4096;
  35. PPUExt = 'ppu';
  36. ObjExt = 'o';
  37. StaticLibExt ='a';
  38. {$ifdef Linux}
  39. SharedLibExt ='so';
  40. BatchExt ='.sh';
  41. {$else}
  42. SharedLibExt ='dll';
  43. BatchExt ='.bat';
  44. {$endif Linux}
  45. { link options }
  46. link_none = $0;
  47. link_allways = $1;
  48. link_static = $2;
  49. link_smart = $4;
  50. link_shared = $8;
  51. Type
  52. PLinkOEnt = ^TLinkOEnt;
  53. TLinkOEnt = record
  54. Name : string;
  55. Next : PLinkOEnt;
  56. end;
  57. Var
  58. ArBin,LDBin,StripBin,
  59. OutputFile,
  60. DestPath,
  61. PPLExt,
  62. LibExt : string;
  63. Batch,
  64. Quiet,
  65. MakeStatic : boolean;
  66. Buffer : Pointer;
  67. ObjFiles : PLinkOEnt;
  68. BatchFile : Text;
  69. {*****************************************************************************
  70. Helpers
  71. *****************************************************************************}
  72. Procedure Error(const s:string;stop:boolean);
  73. {
  74. Write an error message to stderr
  75. }
  76. begin
  77. {$ifdef FPC}
  78. writeln(stderr,s);
  79. {$else}
  80. writeln(s);
  81. {$endif}
  82. if stop then
  83. halt(1);
  84. end;
  85. function Shell(const s:string):longint;
  86. {
  87. Run a shell commnad and return the exitcode
  88. }
  89. begin
  90. if Batch then
  91. begin
  92. Writeln(BatchFile,s);
  93. Shell:=0;
  94. exit;
  95. end;
  96. {$ifdef Linux}
  97. Shell:=Linux.shell(s);
  98. {$else}
  99. exec(getenv('COMSPEC'),'/C '+s);
  100. Shell:=DosExitCode;
  101. {$endif}
  102. end;
  103. Function FileExists (Const F : String) : Boolean;
  104. {
  105. Returns True if the file exists, False if not.
  106. }
  107. Var
  108. {$ifdef linux}
  109. info : Stat;
  110. {$else}
  111. info : searchrec;
  112. {$endif}
  113. begin
  114. {$ifdef linux}
  115. FileExists:=FStat (F,Info);
  116. {$else}
  117. FindFirst (F,anyfile,Info);
  118. FileExists:=DosError=0;
  119. {$endif}
  120. end;
  121. Function AddExtension(Const HStr,ext:String):String;
  122. {
  123. Return a filename which will have extension ext added if no
  124. extension is found
  125. }
  126. var
  127. j : longint;
  128. begin
  129. j:=length(Hstr);
  130. while (j>0) and (Hstr[j]<>'.') do
  131. dec(j);
  132. if j=0 then
  133. AddExtension:=Hstr+'.'+Ext
  134. else
  135. AddExtension:=HStr;
  136. end;
  137. Function ForceExtension(Const HStr,ext:String):String;
  138. {
  139. Return a filename which certainly has the extension ext
  140. }
  141. var
  142. j : longint;
  143. begin
  144. j:=length(Hstr);
  145. while (j>0) and (Hstr[j]<>'.') do
  146. dec(j);
  147. if j=0 then
  148. j:=255;
  149. ForceExtension:=Copy(Hstr,1,j-1)+'.'+Ext;
  150. end;
  151. Procedure AddToLinkFiles(const S : String);
  152. {
  153. Adds a filename to a list of object files to link to.
  154. No duplicates allowed.
  155. }
  156. Var
  157. P : PLinKOEnt;
  158. begin
  159. P:=ObjFiles;
  160. { Don't add files twice }
  161. While (P<>nil) and (p^.name<>s) do
  162. p:=p^.next;
  163. if p=nil then
  164. begin
  165. new(p);
  166. p^.next:=ObjFiles;
  167. p^.name:=s;
  168. ObjFiles:=P;
  169. end;
  170. end;
  171. Function ExtractLib(const libfn:string):string;
  172. {
  173. Extract a static library libfn and return the files with a
  174. wildcard
  175. }
  176. var
  177. n : namestr;
  178. d : dirstr;
  179. e : extstr;
  180. i : word;
  181. begin
  182. { create the temp dir first }
  183. fsplit(libfn,d,n,e);
  184. {$I-}
  185. mkdir(n+'.sl');
  186. {$I+}
  187. i:=ioresult;
  188. { Extract }
  189. if Shell(arbin+' x '+libfn)<>0 then
  190. Error('Fatal: Error running '+arbin,true);
  191. { Remove the lib file, it's extracted so it can be created with ease }
  192. if PPLExt=PPUExt then
  193. Shell('rm '+libfn);
  194. {$ifdef linux}
  195. ExtractLib:=n+'.sl/*';
  196. {$else}
  197. ExtractLib:=n+'.sl\*';
  198. {$endif}
  199. end;
  200. Function DoPPU(const PPUFn,PPLFn:String):Boolean;
  201. {
  202. Convert one file (in Filename) to library format.
  203. Return true if successful, false otherwise.
  204. }
  205. Var
  206. inppu,
  207. outppu : pppufile;
  208. b,
  209. untilb : byte;
  210. l,m : longint;
  211. i : word;
  212. f : file;
  213. s : string;
  214. begin
  215. DoPPU:=false;
  216. If Not Quiet then
  217. Write ('Processing ',PPUFn,'...');
  218. inppu:=new(pppufile,init(PPUFn));
  219. if not inppu^.open then
  220. begin
  221. dispose(inppu,done);
  222. Error('Error: Could not open : '+PPUFn,false);
  223. Exit;
  224. end;
  225. { Check the ppufile }
  226. if not inppu^.CheckPPUId then
  227. begin
  228. dispose(inppu,done);
  229. Error('Error: Not a PPU File : '+PPUFn,false);
  230. Exit;
  231. end;
  232. if inppu^.GetPPUVersion<CurrentPPUVersion then
  233. begin
  234. dispose(inppu,done);
  235. Error('Error: Wrong PPU Version : '+PPUFn,false);
  236. Exit;
  237. end;
  238. { No .o file generated for this ppu, just skip }
  239. if (inppu^.header.flags and uf_no_link)<>0 then
  240. begin
  241. dispose(inppu,done);
  242. If Not Quiet then
  243. Writeln (' No files.');
  244. DoPPU:=true;
  245. Exit;
  246. end;
  247. { Already a lib? }
  248. if (inppu^.header.flags and uf_in_library)<>0 then
  249. begin
  250. dispose(inppu,done);
  251. Error('Error: PPU is already in a library : '+PPUFn,false);
  252. Exit;
  253. end;
  254. { We need a static linked unit }
  255. if (inppu^.header.flags and uf_static_linked)=0 then
  256. begin
  257. dispose(inppu,done);
  258. Error('Error: PPU is not static linked : '+PPUFn,false);
  259. Exit;
  260. end;
  261. { Create the new ppu }
  262. if PPUFn=PPLFn then
  263. outppu:=new(pppufile,init('ppumove.$$$'))
  264. else
  265. outppu:=new(pppufile,init(PPLFn));
  266. outppu^.create;
  267. { Create new header, with the new flags }
  268. outppu^.header:=inppu^.header;
  269. outppu^.header.flags:=outppu^.header.flags or uf_in_library;
  270. if MakeStatic then
  271. outppu^.header.flags:=outppu^.header.flags or uf_static_linked
  272. else
  273. outppu^.header.flags:=outppu^.header.flags or uf_shared_linked;
  274. { read until the object files are found }
  275. untilb:=iblinkunitofiles;
  276. repeat
  277. b:=inppu^.readentry;
  278. if b in [ibendinterface,ibend] then
  279. begin
  280. dispose(inppu,done);
  281. dispose(outppu,done);
  282. Error('Error: No files to be linked found : '+PPUFn,false);
  283. Exit;
  284. end;
  285. if b<>untilb then
  286. begin
  287. repeat
  288. inppu^.getdatabuf(buffer^,bufsize,l);
  289. outppu^.putdata(buffer^,l);
  290. until l<bufsize;
  291. outppu^.writeentry(b);
  292. end;
  293. until (b=untilb);
  294. { we have now reached the section for the files which need to be added,
  295. now add them to the list }
  296. case b of
  297. iblinkunitofiles :
  298. begin
  299. { add all o files, and save the entry when not creating a static
  300. library to keep staticlinking possible }
  301. while not inppu^.endofentry do
  302. begin
  303. s:=inppu^.getstring;
  304. m:=inppu^.getlongint;
  305. if not MakeStatic then
  306. begin
  307. outppu^.putstring(s);
  308. outppu^.putlongint(m);
  309. end;
  310. AddToLinkFiles(s);
  311. end;
  312. if not MakeStatic then
  313. outppu^.writeentry(b);
  314. end;
  315. { iblinkunitstaticlibs :
  316. begin
  317. AddToLinkFiles(ExtractLib(inppu^.getstring));
  318. if not inppu^.endofentry then
  319. begin
  320. repeat
  321. inppu^.getdatabuf(buffer^,bufsize,l);
  322. outppu^.putdata(buffer^,l);
  323. until l<bufsize;
  324. outppu^.writeentry(b);
  325. end;
  326. end; }
  327. end;
  328. { just add a new entry with the new lib }
  329. if MakeStatic then
  330. begin
  331. outppu^.putstring(outputfile);
  332. outppu^.putlongint(link_static);
  333. outppu^.writeentry(iblinkunitstaticlibs)
  334. end
  335. else
  336. begin
  337. outppu^.putstring(outputfile);
  338. outppu^.putlongint(link_shared);
  339. outppu^.writeentry(iblinkunitsharedlibs);
  340. end;
  341. { read all entries until the end and write them also to the new ppu }
  342. repeat
  343. b:=inppu^.readentry;
  344. { don't write ibend, that's written automaticly }
  345. if b<>ibend then
  346. begin
  347. repeat
  348. inppu^.getdatabuf(buffer^,bufsize,l);
  349. outppu^.putdata(buffer^,l);
  350. until l<bufsize;
  351. outppu^.writeentry(b);
  352. end;
  353. until b=ibend;
  354. { write the last stuff and close }
  355. outppu^.flush;
  356. outppu^.writeheader;
  357. dispose(outppu,done);
  358. dispose(inppu,done);
  359. { rename }
  360. if PPUFn=PPLFn then
  361. begin
  362. {$I-}
  363. assign(f,PPUFn);
  364. erase(f);
  365. assign(f,'ppumove.$$$');
  366. rename(f,PPUFn);
  367. {$I+}
  368. i:=ioresult;
  369. end;
  370. { the end }
  371. If Not Quiet then
  372. Writeln (' Done.');
  373. DoPPU:=True;
  374. end;
  375. Function DoFile(const FileName:String):Boolean;
  376. {
  377. Process a file, mainly here for wildcard support under Dos
  378. }
  379. {$ifndef linux}
  380. var
  381. dir : searchrec;
  382. {$endif}
  383. begin
  384. {$ifdef linux}
  385. DoFile:=DoPPU(FileName,ForceExtension(FileName,PPLExt));
  386. {$else}
  387. DoFile:=false;
  388. findfirst(filename,$20,dir);
  389. while doserror=0 do
  390. begin
  391. if not DoPPU(Dir.Name,ForceExtension(Dir.Name,PPLExt)) then
  392. exit;
  393. findnext(dir);
  394. end;
  395. findclose(dir);
  396. DoFile:=true;
  397. {$endif}
  398. end;
  399. Procedure DoLink;
  400. {
  401. Link the object files together to form a (shared) library, the only
  402. problem here is the 255 char limit of Names
  403. }
  404. Var
  405. Names : String;
  406. f : file;
  407. Err : boolean;
  408. P : PLinkOEnt;
  409. begin
  410. if not Quiet then
  411. Write ('Linking ');
  412. P:=ObjFiles;
  413. names:='';
  414. While p<>nil do
  415. begin
  416. if Names<>'' then
  417. Names:=Names+' '+P^.name
  418. else
  419. Names:=p^.Name;
  420. p:=p^.next;
  421. end;
  422. if Names='' then
  423. begin
  424. If not Quiet then
  425. Writeln('Error: no files found to be linked');
  426. exit;
  427. end;
  428. If not Quiet then
  429. WriteLn(names);
  430. { Run ar or ld to create the lib }
  431. If MakeStatic then
  432. Err:=Shell(arbin+' rs '+outputfile+' '+names)<>0
  433. else
  434. begin
  435. Err:=Shell(ldbin+' -shared -o '+OutputFile+' '+names)<>0;
  436. if not Err then
  437. Shell(stripbin+' --strip-unneeded '+OutputFile);
  438. end;
  439. If Err then
  440. Error('Fatal: Library building stage failed.',true);
  441. { Rename to the destpath }
  442. if DestPath<>'' then
  443. begin
  444. Assign(F, OutputFile);
  445. Rename(F,DestPath+'/'+OutputFile);
  446. end;
  447. end;
  448. Procedure usage;
  449. {
  450. Print usage and exit.
  451. }
  452. begin
  453. Writeln(paramstr(0),': [-qhwvbs] [-e ext] [-o name] [-d path] file [file ...]');
  454. Halt(0);
  455. end;
  456. Procedure processopts;
  457. {
  458. Process command line opions, and checks if command line options OK.
  459. }
  460. var
  461. C : char;
  462. begin
  463. if paramcount=0 then
  464. usage;
  465. { Reset }
  466. ObjFiles:=Nil;
  467. Quiet:=False;
  468. Batch:=False;
  469. OutputFile:='';
  470. PPLExt:='ppu';
  471. ArBin:='ar';
  472. LdBin:='ld';
  473. StripBin:='strip';
  474. repeat
  475. c:=Getopt (ShortOpts);
  476. Case C of
  477. EndOfOptions : break;
  478. 's' : MakeStatic:=True;
  479. 'o' : OutputFile:=OptArg;
  480. 'd' : DestPath:=OptArg;
  481. 'e' : PPLext:=OptArg;
  482. 'q' : Quiet:=True;
  483. 'w' : begin
  484. ArBin:='arw';
  485. LdBin:='ldw';
  486. end;
  487. 'b' : Batch:=true;
  488. '?' : Usage;
  489. 'h' : Usage;
  490. end;
  491. until false;
  492. { Test filenames on the commandline }
  493. if (OptInd>Paramcount) then
  494. Error('Error: no input files',true);
  495. if (OptInd<ParamCount) and (OutputFile='') then
  496. Error('Error: when moving multiple units, specify an output name.',true);
  497. { alloc a buffer }
  498. GetMem (Buffer,Bufsize);
  499. If Buffer=Nil then
  500. Error('Error: could not allocate memory for buffer.',true);
  501. { fix filename }
  502. {$ifdef linux}
  503. if Copy(OutputFile,1,3)<>'lib' then
  504. OutputFile:='lib'+OutputFile;
  505. {$endif}
  506. end;
  507. var
  508. i : longint;
  509. begin
  510. ProcessOpts;
  511. { Write Header }
  512. if not Quiet then
  513. begin
  514. Writeln(Title+' '+Version);
  515. Writeln(Copyright);
  516. Writeln;
  517. end;
  518. { Check if shared is allowed }
  519. {$ifndef linux}
  520. if arbin<>'arw' then
  521. begin
  522. Writeln('Warning: shared library not supported for Go32, switching to static library');
  523. MakeStatic:=true;
  524. end;
  525. {$endif}
  526. { fix the libext and outputfilename }
  527. if Makestatic then
  528. LibExt:=StaticLibExt
  529. else
  530. LibExt:=SharedLibExt;
  531. if OutputFile='' then
  532. OutPutFile:=Paramstr(OptInd);
  533. OutputFile:=ForceExtension(OutputFile,LibExt);
  534. { Open BatchFile }
  535. if Batch then
  536. begin
  537. Assign(BatchFile,'pmove'+BatchExt);
  538. Rewrite(BatchFile);
  539. end;
  540. { Process Files }
  541. i:=OptInd;
  542. While (i<=ParamCount) and Dofile(AddExtension(Paramstr(i),PPUExt)) do
  543. Inc(i);
  544. { Do Linking stage }
  545. DoLink;
  546. { Close BatchFile }
  547. if Batch then
  548. begin
  549. if Not Quiet then
  550. Writeln('Writing pmove'+BatchExt);
  551. Close(BatchFile);
  552. {$ifdef Linux}
  553. ChMod('pmove'+BatchExt,493);
  554. {$endif}
  555. end;
  556. { The End }
  557. if Not Quiet then
  558. Writeln('Done.');
  559. end.
  560. {
  561. $Log$
  562. Revision 1.9 2000-02-09 16:44:15 peter
  563. * log truncated
  564. Revision 1.8 2000/01/07 16:46:04 daniel
  565. * copyright 2000
  566. Revision 1.7 1999/11/25 00:00:39 peter
  567. * strip created .so file with strip --strip-unneeded
  568. Revision 1.6 1999/11/23 09:44:15 peter
  569. * updated
  570. Revision 1.5 1999/07/29 01:40:21 peter
  571. * fsplit var type fixes
  572. Revision 1.4 1999/07/28 16:53:58 peter
  573. * updated for new linking, but still doesn't work because ld-linux.so.2
  574. requires some more crt*.o files
  575. }