2
0

ppumove.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  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.12';
  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. Type
  46. PLinkOEnt = ^TLinkOEnt;
  47. TLinkOEnt = record
  48. Name : string;
  49. Next : PLinkOEnt;
  50. end;
  51. Var
  52. ArBin,LDBin,
  53. OutputFile,
  54. DestPath,
  55. PPLExt,
  56. LibExt : string;
  57. Batch,
  58. Quiet,
  59. MakeStatic : boolean;
  60. Buffer : Pointer;
  61. ObjFiles : PLinkOEnt;
  62. BatchFile : Text;
  63. {*****************************************************************************
  64. Helpers
  65. *****************************************************************************}
  66. Procedure Error(const s:string;stop:boolean);
  67. {
  68. Write an error message to stderr
  69. }
  70. begin
  71. {$ifdef FPC}
  72. writeln(stderr,s);
  73. flush(stderr);
  74. {$else}
  75. writeln(s);
  76. {$endif}
  77. if stop then
  78. halt(1);
  79. end;
  80. function Shell(const s:string):longint;
  81. {
  82. Run a shell commnad and return the exitcode
  83. }
  84. begin
  85. if Batch then
  86. begin
  87. Writeln(BatchFile,s);
  88. Shell:=0;
  89. exit;
  90. end;
  91. {$ifdef Linux}
  92. Shell:=Linux.shell(s);
  93. {$else}
  94. exec(getenv('COMSPEC'),'/C '+s);
  95. Shell:=DosExitCode;
  96. {$endif}
  97. end;
  98. Function FileExists (Const F : String) : Boolean;
  99. {
  100. Returns True if the file exists, False if not.
  101. }
  102. Var
  103. {$ifdef linux}
  104. info : Stat;
  105. {$else}
  106. info : searchrec;
  107. {$endif}
  108. begin
  109. {$ifdef linux}
  110. FileExists:=FStat (F,Info);
  111. {$else}
  112. FindFirst (F,anyfile,Info);
  113. FileExists:=DosError=0;
  114. {$endif}
  115. end;
  116. Function AddExtension(Const HStr,ext:String):String;
  117. {
  118. Return a filename which will have extension ext added if no
  119. extension is found
  120. }
  121. var
  122. j : longint;
  123. begin
  124. j:=length(Hstr);
  125. while (j>0) and (Hstr[j]<>'.') do
  126. dec(j);
  127. if j=0 then
  128. AddExtension:=Hstr+'.'+Ext
  129. else
  130. AddExtension:=HStr;
  131. end;
  132. Function ForceExtension(Const HStr,ext:String):String;
  133. {
  134. Return a filename which certainly has the extension ext
  135. }
  136. var
  137. j : longint;
  138. begin
  139. j:=length(Hstr);
  140. while (j>0) and (Hstr[j]<>'.') do
  141. dec(j);
  142. if j=0 then
  143. j:=255;
  144. ForceExtension:=Copy(Hstr,1,j-1)+'.'+Ext;
  145. end;
  146. Procedure AddToLinkFiles(const S : String);
  147. {
  148. Adds a filename to a list of object files to link to.
  149. No duplicates allowed.
  150. }
  151. Var
  152. P : PLinKOEnt;
  153. begin
  154. P:=ObjFiles;
  155. { Don't add files twice }
  156. While (P<>nil) and (p^.name<>s) do
  157. p:=p^.next;
  158. if p=nil then
  159. begin
  160. new(p);
  161. p^.next:=ObjFiles;
  162. p^.name:=s;
  163. ObjFiles:=P;
  164. end;
  165. end;
  166. Function ExtractLib(const libfn:string):string;
  167. {
  168. Extract a static library libfn and return the files with a
  169. wildcard
  170. }
  171. var
  172. n,d,e : string;
  173. i : word;
  174. begin
  175. { create the temp dir first }
  176. fsplit(libfn,d,n,e);
  177. {$I-}
  178. mkdir(n+'.sl');
  179. {$I+}
  180. i:=ioresult;
  181. { Extract }
  182. if Shell(arbin+' x '+libfn)<>0 then
  183. Error('Fatal: Error running '+arbin,true);
  184. { Remove the lib file, it's extracted so it can be created with ease }
  185. if PPLExt=PPUExt then
  186. Shell('rm '+libfn);
  187. {$ifdef linux}
  188. ExtractLib:=n+'.sl/*';
  189. {$else}
  190. ExtractLib:=n+'.sl\*';
  191. {$endif}
  192. end;
  193. Function DoPPU(const PPUFn,PPLFn:String):Boolean;
  194. {
  195. Convert one file (in Filename) to library format.
  196. Return true if successful, false otherwise.
  197. }
  198. Var
  199. inppu,
  200. outppu : pppufile;
  201. b,
  202. untilb : byte;
  203. l : longint;
  204. i : word;
  205. f : file;
  206. isstaticlinked : boolean;
  207. begin
  208. DoPPU:=false;
  209. If Not Quiet then
  210. Write ('Processing ',PPUFn,'...');
  211. inppu:=new(pppufile,init(PPUFn));
  212. if not inppu^.open then
  213. begin
  214. dispose(inppu,done);
  215. Error('Error: Could not open : '+PPUFn,false);
  216. Exit;
  217. end;
  218. { Check the ppufile }
  219. if not inppu^.CheckPPUId then
  220. begin
  221. dispose(inppu,done);
  222. Error('Error: Not a PPU File : '+PPUFn,false);
  223. Exit;
  224. end;
  225. if inppu^.GetPPUVersion<15 then
  226. begin
  227. dispose(inppu,done);
  228. Error('Error: Wrong PPU Version : '+PPUFn,false);
  229. Exit;
  230. end;
  231. { Already a lib? }
  232. if (inppu^.header.flags and uf_in_library)<>0 then
  233. begin
  234. dispose(inppu,done);
  235. Error('Error: PPU is already in a library : '+PPUFn,false);
  236. Exit;
  237. end;
  238. { Create the new ppu }
  239. if PPUFn=PPLFn then
  240. outppu:=new(pppufile,init('ppumove.$$$'))
  241. else
  242. outppu:=new(pppufile,init(PPLFn));
  243. outppu^.create;
  244. { Create new header, with the new flags }
  245. outppu^.header:=inppu^.header;
  246. outppu^.header.flags:=outppu^.header.flags or uf_in_library;
  247. if MakeStatic then
  248. outppu^.header.flags:=outppu^.header.flags or uf_static_linked
  249. else
  250. outppu^.header.flags:=outppu^.header.flags or uf_shared_linked;
  251. { Is the until smartlinked ? }
  252. IsStaticLinked:=(inppu^.header.flags and uf_static_linked)<>0;
  253. { read until the object files are found }
  254. if IsStaticLinked then
  255. untilb:=iblinkstaticlibs
  256. else
  257. untilb:=iblinkunitfiles;
  258. repeat
  259. b:=inppu^.readentry;
  260. if b in [ibendinterface,ibend] then
  261. begin
  262. dispose(inppu,done);
  263. dispose(outppu,done);
  264. Error('Error: No files to be linked found : '+PPUFn,false);
  265. Exit;
  266. end;
  267. if b<>untilb then
  268. begin
  269. repeat
  270. inppu^.getdatabuf(buffer^,bufsize,l);
  271. outppu^.putdata(buffer^,l);
  272. until l<bufsize;
  273. outppu^.writeentry(b);
  274. end;
  275. until (b=untilb);
  276. { we have now reached the section for the files which need to be added,
  277. now add them to the list }
  278. case b of
  279. iblinkunitfiles : begin
  280. while not inppu^.endofentry do
  281. AddToLinkFiles(inppu^.getstring);
  282. end;
  283. iblinkstaticlibs : begin
  284. AddToLinkFiles(ExtractLib(inppu^.getstring));
  285. if not inppu^.endofentry 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. end;
  294. end;
  295. { just add a new entry with the new lib }
  296. outppu^.putstring(outputfile);
  297. if MakeStatic then
  298. outppu^.writeentry(iblinkstaticlibs)
  299. else
  300. outppu^.writeentry(iblinksharedlibs);
  301. { read all entries until the end and write them also to the new ppu }
  302. repeat
  303. b:=inppu^.readentry;
  304. { don't write ibend, that's written automaticly }
  305. if b<>ibend then
  306. begin
  307. repeat
  308. inppu^.getdatabuf(buffer^,bufsize,l);
  309. outppu^.putdata(buffer^,l);
  310. until l<bufsize;
  311. outppu^.writeentry(b);
  312. end;
  313. until b=ibend;
  314. { write the last stuff and close }
  315. outppu^.flush;
  316. outppu^.writeheader;
  317. dispose(outppu,done);
  318. dispose(inppu,done);
  319. { rename }
  320. if PPUFn=PPLFn then
  321. begin
  322. {$I-}
  323. assign(f,PPUFn);
  324. erase(f);
  325. assign(f,'ppumove.$$$');
  326. rename(f,PPUFn);
  327. {$I+}
  328. i:=ioresult;
  329. end;
  330. { the end }
  331. If Not Quiet then
  332. Writeln (' Done.');
  333. DoPPU:=True;
  334. end;
  335. Function DoFile(const FileName:String):Boolean;
  336. {
  337. Process a file, mainly here for wildcard support under Dos
  338. }
  339. {$ifndef linux}
  340. var
  341. dir : searchrec;
  342. {$endif}
  343. begin
  344. {$ifdef linux}
  345. DoFile:=DoPPU(FileName,ForceExtension(FileName,PPLExt));
  346. {$else}
  347. DoFile:=false;
  348. findfirst(filename,$20,dir);
  349. while doserror=0 do
  350. begin
  351. if not DoPPU(Dir.Name,ForceExtension(Dir.Name,PPLExt)) then
  352. exit;
  353. findnext(dir);
  354. end;
  355. DoFile:=true;
  356. {$endif}
  357. end;
  358. Procedure DoLink;
  359. {
  360. Link the object files together to form a (shared) library, the only
  361. problem here is the 255 char limit of Names
  362. }
  363. Var
  364. Names : String;
  365. f : file;
  366. Err : boolean;
  367. P : PLinkOEnt;
  368. begin
  369. if not Quiet then
  370. Write ('Linking ');
  371. P:=ObjFiles;
  372. names:='';
  373. While p<>nil do
  374. begin
  375. if Names<>'' then
  376. Names:=Names+' '+P^.name
  377. else
  378. Names:=p^.Name;
  379. p:=p^.next;
  380. end;
  381. if Names='' then
  382. begin
  383. If not Quiet then
  384. Writeln('Error: no files found to be linked');
  385. exit;
  386. end;
  387. If not Quiet then
  388. WriteLn(names);
  389. { Run ar or ld to create the lib }
  390. If MakeStatic then
  391. Err:=Shell(arbin+' rs '+outputfile+' '+names)<>0
  392. else
  393. Err:=Shell(ldbin+' -shared -o '+OutputFile+' '+names)<>0;
  394. If Err then
  395. Error('Fatal: Library building stage failed.',true);
  396. { Remove the .o files }
  397. if PPLExt=PPUExt then
  398. begin
  399. while pos('*',names)>0 do
  400. Delete(names,pos('*',names),1);
  401. Shell('rm -rf '+names);
  402. end;
  403. { Rename to the destpath }
  404. if DestPath<>'' then
  405. begin
  406. Assign(F, OutputFile);
  407. Rename(F,DestPath+'/'+OutputFile);
  408. end;
  409. end;
  410. Procedure usage;
  411. {
  412. Print usage and exit.
  413. }
  414. begin
  415. Writeln(paramstr(0),': [-qhwvbs] [-e ext] [-o name] [-d path] file [file ...]');
  416. Halt(0);
  417. end;
  418. Procedure processopts;
  419. {
  420. Process command line opions, and checks if command line options OK.
  421. }
  422. var
  423. C : char;
  424. begin
  425. if paramcount=0 then
  426. usage;
  427. { Reset }
  428. ObjFiles:=Nil;
  429. Quiet:=False;
  430. Batch:=False;
  431. OutputFile:='';
  432. PPLExt:='ppu';
  433. ArBin:='ar';
  434. LdBin:='ld';
  435. repeat
  436. c:=Getopt (ShortOpts);
  437. Case C of
  438. EndOfOptions : break;
  439. 's' : MakeStatic:=True;
  440. 'o' : OutputFile:=OptArg;
  441. 'd' : DestPath:=OptArg;
  442. 'e' : PPLext:=OptArg;
  443. 'q' : Quiet:=True;
  444. 'w' : begin
  445. ArBin:='arw';
  446. LdBin:='ldw';
  447. end;
  448. 'b' : Batch:=true;
  449. '?' : Usage;
  450. 'h' : Usage;
  451. end;
  452. until false;
  453. { Test filenames on the commandline }
  454. if (OptInd>Paramcount) then
  455. Error('Error: no input files',true);
  456. if (OptInd<ParamCount) and (OutputFile='') then
  457. Error('Error: when moving multiple units, specify an output name.',true);
  458. { alloc a buffer }
  459. GetMem (Buffer,Bufsize);
  460. If Buffer=Nil then
  461. Error('Error: could not allocate memory for buffer.',true);
  462. { fix filename }
  463. {$ifdef linux}
  464. if Copy(OutputFile,1,3)<>'lib' then
  465. OutputFile:='lib'+OutputFile;
  466. {$endif}
  467. end;
  468. var
  469. i : longint;
  470. begin
  471. ProcessOpts;
  472. { Write Header }
  473. if not Quiet then
  474. begin
  475. Writeln(Title+' '+Version);
  476. Writeln(Copyright);
  477. Writeln;
  478. end;
  479. { Check if shared is allowed }
  480. {$ifndef linux}
  481. if arbin<>'arw' then
  482. begin
  483. Writeln('Warning: shared library not supported for Go32, switching to static library');
  484. MakeStatic:=true;
  485. end;
  486. {$endif}
  487. { fix the libext and outputfilename }
  488. if Makestatic then
  489. LibExt:=StaticLibExt
  490. else
  491. LibExt:=SharedLibExt;
  492. if OutputFile='' then
  493. OutPutFile:=Paramstr(OptInd);
  494. OutputFile:=ForceExtension(OutputFile,LibExt);
  495. { Open BatchFile }
  496. if Batch then
  497. begin
  498. Assign(BatchFile,'pmove'+BatchExt);
  499. Rewrite(BatchFile);
  500. end;
  501. { Process Files }
  502. i:=OptInd;
  503. While (i<=ParamCount) and Dofile(AddExtension(Paramstr(i),PPUExt)) do
  504. Inc(i);
  505. { Do Linking stage }
  506. DoLink;
  507. { Close BatchFile }
  508. if Batch then
  509. begin
  510. if Not Quiet then
  511. Writeln('Writing pmove'+BatchExt);
  512. Close(BatchFile);
  513. {$ifdef Linux}
  514. ChMod('pmove'+BatchExt,493);
  515. {$endif}
  516. end;
  517. { The End }
  518. if Not Quiet then
  519. Writeln('Done.');
  520. end.
  521. {
  522. $Log$
  523. Revision 1.2 1999-06-08 22:16:07 peter
  524. * version 0.99.12
  525. Revision 1.1 1999/05/12 16:11:39 peter
  526. * moved
  527. Revision 1.3 1998/08/17 10:26:30 peter
  528. * updated for new shared/static style
  529. Revision 1.2 1998/06/18 10:47:55 peter
  530. * new for v15
  531. }