ppumove.pp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. {
  2. $Id$
  3. Copyright (c) 1998 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. {$ifdef TP}
  18. {$N+,E+}
  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-99 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,
  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. { Already a lib? }
  239. if (inppu^.header.flags and uf_in_library)<>0 then
  240. begin
  241. dispose(inppu,done);
  242. Error('Error: PPU is already in a library : '+PPUFn,false);
  243. Exit;
  244. end;
  245. { We need a static linked unit }
  246. if (inppu^.header.flags and uf_static_linked)=0 then
  247. begin
  248. dispose(inppu,done);
  249. Error('Error: PPU is not static linked : '+PPUFn,false);
  250. Exit;
  251. end;
  252. { Create the new ppu }
  253. if PPUFn=PPLFn then
  254. outppu:=new(pppufile,init('ppumove.$$$'))
  255. else
  256. outppu:=new(pppufile,init(PPLFn));
  257. outppu^.create;
  258. { Create new header, with the new flags }
  259. outppu^.header:=inppu^.header;
  260. outppu^.header.flags:=outppu^.header.flags or uf_in_library;
  261. if MakeStatic then
  262. outppu^.header.flags:=outppu^.header.flags or uf_static_linked
  263. else
  264. outppu^.header.flags:=outppu^.header.flags or uf_shared_linked;
  265. { read until the object files are found }
  266. untilb:=iblinkunitofiles;
  267. repeat
  268. b:=inppu^.readentry;
  269. if b in [ibendinterface,ibend] then
  270. begin
  271. dispose(inppu,done);
  272. dispose(outppu,done);
  273. Error('Error: No files to be linked found : '+PPUFn,false);
  274. Exit;
  275. end;
  276. if b<>untilb then
  277. begin
  278. repeat
  279. inppu^.getdatabuf(buffer^,bufsize,l);
  280. outppu^.putdata(buffer^,l);
  281. until l<bufsize;
  282. outppu^.writeentry(b);
  283. end;
  284. until (b=untilb);
  285. { we have now reached the section for the files which need to be added,
  286. now add them to the list }
  287. case b of
  288. iblinkunitofiles :
  289. begin
  290. { add all o files, and save the entry when not creating a static
  291. library to keep staticlinking possible }
  292. while not inppu^.endofentry do
  293. begin
  294. s:=inppu^.getstring;
  295. m:=inppu^.getlongint;
  296. if not MakeStatic then
  297. begin
  298. outppu^.putstring(s);
  299. outppu^.putlongint(m);
  300. end;
  301. AddToLinkFiles(s);
  302. end;
  303. if not MakeStatic then
  304. outppu^.writeentry(b);
  305. end;
  306. { iblinkunitstaticlibs :
  307. begin
  308. AddToLinkFiles(ExtractLib(inppu^.getstring));
  309. if not inppu^.endofentry then
  310. begin
  311. repeat
  312. inppu^.getdatabuf(buffer^,bufsize,l);
  313. outppu^.putdata(buffer^,l);
  314. until l<bufsize;
  315. outppu^.writeentry(b);
  316. end;
  317. end; }
  318. end;
  319. { just add a new entry with the new lib }
  320. if MakeStatic then
  321. begin
  322. outppu^.putstring(outputfile);
  323. outppu^.putlongint(link_static);
  324. outppu^.writeentry(iblinkunitstaticlibs)
  325. end
  326. else
  327. begin
  328. outppu^.putstring(outputfile);
  329. outppu^.putlongint(link_shared);
  330. outppu^.writeentry(iblinkunitsharedlibs);
  331. end;
  332. { read all entries until the end and write them also to the new ppu }
  333. repeat
  334. b:=inppu^.readentry;
  335. { don't write ibend, that's written automaticly }
  336. if b<>ibend then
  337. begin
  338. repeat
  339. inppu^.getdatabuf(buffer^,bufsize,l);
  340. outppu^.putdata(buffer^,l);
  341. until l<bufsize;
  342. outppu^.writeentry(b);
  343. end;
  344. until b=ibend;
  345. { write the last stuff and close }
  346. outppu^.flush;
  347. outppu^.writeheader;
  348. dispose(outppu,done);
  349. dispose(inppu,done);
  350. { rename }
  351. if PPUFn=PPLFn then
  352. begin
  353. {$I-}
  354. assign(f,PPUFn);
  355. erase(f);
  356. assign(f,'ppumove.$$$');
  357. rename(f,PPUFn);
  358. {$I+}
  359. i:=ioresult;
  360. end;
  361. { the end }
  362. If Not Quiet then
  363. Writeln (' Done.');
  364. DoPPU:=True;
  365. end;
  366. Function DoFile(const FileName:String):Boolean;
  367. {
  368. Process a file, mainly here for wildcard support under Dos
  369. }
  370. {$ifndef linux}
  371. var
  372. dir : searchrec;
  373. {$endif}
  374. begin
  375. {$ifdef linux}
  376. DoFile:=DoPPU(FileName,ForceExtension(FileName,PPLExt));
  377. {$else}
  378. DoFile:=false;
  379. findfirst(filename,$20,dir);
  380. while doserror=0 do
  381. begin
  382. if not DoPPU(Dir.Name,ForceExtension(Dir.Name,PPLExt)) then
  383. exit;
  384. findnext(dir);
  385. end;
  386. findclose(dir);
  387. DoFile:=true;
  388. {$endif}
  389. end;
  390. Procedure DoLink;
  391. {
  392. Link the object files together to form a (shared) library, the only
  393. problem here is the 255 char limit of Names
  394. }
  395. Var
  396. Names : String;
  397. f : file;
  398. Err : boolean;
  399. P : PLinkOEnt;
  400. begin
  401. if not Quiet then
  402. Write ('Linking ');
  403. P:=ObjFiles;
  404. names:='';
  405. While p<>nil do
  406. begin
  407. if Names<>'' then
  408. Names:=Names+' '+P^.name
  409. else
  410. Names:=p^.Name;
  411. p:=p^.next;
  412. end;
  413. if Names='' then
  414. begin
  415. If not Quiet then
  416. Writeln('Error: no files found to be linked');
  417. exit;
  418. end;
  419. If not Quiet then
  420. WriteLn(names);
  421. { Run ar or ld to create the lib }
  422. If MakeStatic then
  423. Err:=Shell(arbin+' rs '+outputfile+' '+names)<>0
  424. else
  425. Err:=Shell(ldbin+' -shared -o '+OutputFile+' '+names)<>0;
  426. If Err then
  427. Error('Fatal: Library building stage failed.',true);
  428. { Rename to the destpath }
  429. if DestPath<>'' then
  430. begin
  431. Assign(F, OutputFile);
  432. Rename(F,DestPath+'/'+OutputFile);
  433. end;
  434. end;
  435. Procedure usage;
  436. {
  437. Print usage and exit.
  438. }
  439. begin
  440. Writeln(paramstr(0),': [-qhwvbs] [-e ext] [-o name] [-d path] file [file ...]');
  441. Halt(0);
  442. end;
  443. Procedure processopts;
  444. {
  445. Process command line opions, and checks if command line options OK.
  446. }
  447. var
  448. C : char;
  449. begin
  450. if paramcount=0 then
  451. usage;
  452. { Reset }
  453. ObjFiles:=Nil;
  454. Quiet:=False;
  455. Batch:=False;
  456. OutputFile:='';
  457. PPLExt:='ppu';
  458. ArBin:='ar';
  459. LdBin:='ld';
  460. repeat
  461. c:=Getopt (ShortOpts);
  462. Case C of
  463. EndOfOptions : break;
  464. 's' : MakeStatic:=True;
  465. 'o' : OutputFile:=OptArg;
  466. 'd' : DestPath:=OptArg;
  467. 'e' : PPLext:=OptArg;
  468. 'q' : Quiet:=True;
  469. 'w' : begin
  470. ArBin:='arw';
  471. LdBin:='ldw';
  472. end;
  473. 'b' : Batch:=true;
  474. '?' : Usage;
  475. 'h' : Usage;
  476. end;
  477. until false;
  478. { Test filenames on the commandline }
  479. if (OptInd>Paramcount) then
  480. Error('Error: no input files',true);
  481. if (OptInd<ParamCount) and (OutputFile='') then
  482. Error('Error: when moving multiple units, specify an output name.',true);
  483. { alloc a buffer }
  484. GetMem (Buffer,Bufsize);
  485. If Buffer=Nil then
  486. Error('Error: could not allocate memory for buffer.',true);
  487. { fix filename }
  488. {$ifdef linux}
  489. if Copy(OutputFile,1,3)<>'lib' then
  490. OutputFile:='lib'+OutputFile;
  491. {$endif}
  492. end;
  493. var
  494. i : longint;
  495. begin
  496. ProcessOpts;
  497. { Write Header }
  498. if not Quiet then
  499. begin
  500. Writeln(Title+' '+Version);
  501. Writeln(Copyright);
  502. Writeln;
  503. end;
  504. { Check if shared is allowed }
  505. {$ifndef linux}
  506. if arbin<>'arw' then
  507. begin
  508. Writeln('Warning: shared library not supported for Go32, switching to static library');
  509. MakeStatic:=true;
  510. end;
  511. {$endif}
  512. { fix the libext and outputfilename }
  513. if Makestatic then
  514. LibExt:=StaticLibExt
  515. else
  516. LibExt:=SharedLibExt;
  517. if OutputFile='' then
  518. OutPutFile:=Paramstr(OptInd);
  519. OutputFile:=ForceExtension(OutputFile,LibExt);
  520. { Open BatchFile }
  521. if Batch then
  522. begin
  523. Assign(BatchFile,'pmove'+BatchExt);
  524. Rewrite(BatchFile);
  525. end;
  526. { Process Files }
  527. i:=OptInd;
  528. While (i<=ParamCount) and Dofile(AddExtension(Paramstr(i),PPUExt)) do
  529. Inc(i);
  530. { Do Linking stage }
  531. DoLink;
  532. { Close BatchFile }
  533. if Batch then
  534. begin
  535. if Not Quiet then
  536. Writeln('Writing pmove'+BatchExt);
  537. Close(BatchFile);
  538. {$ifdef Linux}
  539. ChMod('pmove'+BatchExt,493);
  540. {$endif}
  541. end;
  542. { The End }
  543. if Not Quiet then
  544. Writeln('Done.');
  545. end.
  546. {
  547. $Log$
  548. Revision 1.5 1999-07-29 01:40:21 peter
  549. * fsplit var type fixes
  550. Revision 1.4 1999/07/28 16:53:58 peter
  551. * updated for new linking, but still doesn't work because ld-linux.so.2
  552. requires some more crt*.o files
  553. Revision 1.3 1999/07/06 11:32:54 peter
  554. * updated for new ppu.pas
  555. Revision 1.2 1999/06/08 22:16:07 peter
  556. * version 0.99.12
  557. Revision 1.1 1999/05/12 16:11:39 peter
  558. * moved
  559. Revision 1.3 1998/08/17 10:26:30 peter
  560. * updated for new shared/static style
  561. Revision 1.2 1998/06/18 10:47:55 peter
  562. * new for v15
  563. }