pkgfpmake.pp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. unit pkgfpmake;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes,SysUtils,DateUtils,
  6. pkghandler;
  7. implementation
  8. uses
  9. fprepos,
  10. pkgoptions,
  11. pkgglobals,
  12. pkgmessages,
  13. pkgrepos;
  14. type
  15. { TFPMakeCompiler }
  16. TFPMakeCompiler = Class(TPackagehandler)
  17. Public
  18. Procedure Execute;override;
  19. end;
  20. { TFPMakeRunner }
  21. TFPMakeRunner = Class(TPackagehandler)
  22. Protected
  23. Function RunFPMake(const Command:string):Integer;
  24. end;
  25. { TFPMakeRunnerCompile }
  26. TFPMakeRunnerCompile = Class(TFPMakeRunner)
  27. Public
  28. Procedure Execute;override;
  29. end;
  30. { TFPMakeRunnerBuild }
  31. TFPMakeRunnerBuild = Class(TFPMakeRunner)
  32. Public
  33. Procedure Execute;override;
  34. end;
  35. { TFPMakeRunnerInstall }
  36. TFPMakeRunnerInstall = Class(TFPMakeRunner)
  37. Public
  38. Procedure Execute;override;
  39. end;
  40. { TFPMakeRunnerClean }
  41. TFPMakeRunnerClean = Class(TFPMakeRunner)
  42. Public
  43. Procedure Execute;override;
  44. end;
  45. { TFPMakeRunnerManifest }
  46. TFPMakeRunnerManifest = Class(TFPMakeRunner)
  47. Public
  48. Procedure Execute;override;
  49. end;
  50. { TFPMakeRunnerArchive }
  51. TFPMakeRunnerArchive = Class(TFPMakeRunner)
  52. Public
  53. Procedure Execute;override;
  54. end;
  55. TMyMemoryStream=class(TMemoryStream)
  56. public
  57. constructor Create(p:pointer;mysize:integer);
  58. end;
  59. {
  60. Generated from fpmkunit.pp, using data2inc:
  61. data2inc -b -s fpmkunit.pp fpmkunitsrc.inc fpmkunitsrc
  62. }
  63. {$i fpmkunitsrc.inc}
  64. procedure CreateFPMKUnitSource(const AFileName:string);
  65. var
  66. InStream,
  67. OutStream : TStream;
  68. pend : pchar;
  69. begin
  70. try
  71. // Don't write trailing #0
  72. pend:=pchar(@fpmkunitsrc)+sizeof(fpmkunitsrc)-1;
  73. while pend^=#0 do
  74. dec(pend);
  75. InStream:=TMyMemoryStream.Create(@fpmkunitsrc,pend-pchar(@fpmkunitsrc));
  76. OutStream:=TFileStream.Create(AFileName,fmCreate);
  77. OutStream.CopyFrom(InStream,InStream.Size);
  78. finally
  79. InStream.Destroy;
  80. OutStream.Destroy;
  81. end;
  82. end;
  83. {*****************************************************************************
  84. TMyMemoryStream
  85. *****************************************************************************}
  86. constructor TMyMemoryStream.Create(p:pointer;mysize:integer);
  87. begin
  88. inherited Create;
  89. SetPointer(p,mysize);
  90. end;
  91. { TFPMakeCompiler }
  92. Procedure TFPMakeCompiler.Execute;
  93. var
  94. OOptions : string;
  95. function CheckUnitDir(const AUnitName:string;Out AUnitDir:string):boolean;
  96. begin
  97. Result:=false;
  98. if FPMakeCompilerOptions.LocalUnitDir<>'' then
  99. begin
  100. AUnitDir:=IncludeTrailingPathDelimiter(FPMakeCompilerOptions.LocalUnitDir+AUnitName);
  101. if DirectoryExistsLog(AUnitDir) then
  102. begin
  103. Result:=true;
  104. exit;
  105. end;
  106. end;
  107. AUnitDir:=IncludeTrailingPathDelimiter(FPMakeCompilerOptions.GlobalUnitDir+AUnitName);
  108. if DirectoryExistsLog(AUnitDir) then
  109. begin
  110. Result:=true;
  111. exit;
  112. end;
  113. AUnitDir:='';
  114. end;
  115. procedure AddOption(const s:string);
  116. begin
  117. if OOptions<>'' then
  118. OOptions:=OOptions+' ';
  119. OOptions:=OOptions+maybequoted(s);
  120. end;
  121. Var
  122. i : Integer;
  123. TempBuildDir,
  124. DepDir,
  125. FPMakeBin,
  126. FPMakeSrc : string;
  127. NeedFPMKUnitSource,
  128. HaveFpmake : boolean;
  129. P : TFPPackage;
  130. begin
  131. P:=AvailableRepository.PackageByName(PackageName);
  132. NeedFPMKUnitSource:=false;
  133. OOptions:='';
  134. SetCurrentDir(PackageBuildPath(P));
  135. // Generate random name for build path
  136. TempBuildDir:='build_fpmake_'+HexStr(DateTimeToUnix(Now),8)+HexStr(GetProcessId,4);
  137. // Check for fpmake source
  138. FPMakeBin:='fpmake'+ExeExt;
  139. FPMakeSrc:='fpmake.pp';
  140. HaveFpmake:=FileExists(FPMakeSrc);
  141. If Not HaveFPMake then
  142. begin
  143. HaveFPMake:=FileExists('fpmake.pas');
  144. If HaveFPMake then
  145. FPMakeSrc:='fpmake.pas';
  146. end;
  147. // Need to compile fpmake executable?
  148. if not FileExists(FPMakeBin) or
  149. (FileAge(FPMakeBin)<FileAge(FPMakeSrc)) then
  150. begin
  151. if Not HaveFPMake then
  152. Error(SErrMissingFPMake);
  153. AddOption('-n');
  154. AddOption('-dCOMPILED_BY_FPPKG');
  155. for i:=0 to high(FPMKUnitDeps) do
  156. begin
  157. if FPMKUnitDeps[i].available then
  158. begin
  159. if CheckUnitDir(FPMKUnitDeps[i].package,DepDir) then
  160. AddOption('-Fu'+DepDir)
  161. else
  162. Error(SErrMissingInstallPackage,[FPMKUnitDeps[i].package]);
  163. if FPMKUnitDeps[i].def<>'' then
  164. AddOption('-d'+FPMKUnitDeps[i].def);
  165. end
  166. else
  167. begin
  168. // If fpmkunit is not installed, we use the internal fpmkunit source
  169. if FPMKUnitDeps[i].package='fpmkunit' then
  170. begin
  171. NeedFPMKUnitSource:=true;
  172. AddOption('-Fu'+TempBuildDir);
  173. end;
  174. if FPMKUnitDeps[i].undef<>'' then
  175. AddOption('-d'+FPMKUnitDeps[i].undef);
  176. end;
  177. end;
  178. // Add RTL unit dir
  179. if not CheckUnitDir('rtl',DepDir) then
  180. Error(SErrMissingInstallPackage,['rtl']);
  181. AddOption('-Fu'+DepDir);
  182. // Units in a directory for easy cleaning
  183. DeleteDir(TempBuildDir);
  184. ForceDirectories(TempBuildDir);
  185. AddOption('-FU'+TempBuildDir);
  186. // Compile options
  187. // -- default is to optimize, smartlink and strip to reduce
  188. // the executable size (there can be 100's of fpmake's on a system)
  189. if vlInfo in LogLevels then
  190. AddOption('-vi');
  191. AddOption('-O2');
  192. AddOption('-XXs');
  193. // Create fpmkunit.pp if needed
  194. if NeedFPMKUnitSource then
  195. CreateFPMKUnitSource(TempBuildDir+PathDelim+'fpmkunit.pp');
  196. // Call compiler
  197. If ExecuteProcess(FPMakeCompilerOptions.Compiler,OOptions+' '+FPmakeSrc)<>0 then
  198. begin
  199. if not GlobalOptions.RecoveryMode then
  200. Error(SErrCompileFailureFPMakeTryRecovery)
  201. else
  202. Error(SErrCompileFailureFPMake);
  203. end;
  204. // Cleanup units
  205. DeleteDir(TempBuildDir);
  206. end
  207. else
  208. Log(vlCommands,SLogNotCompilingFPMake);
  209. end;
  210. { TFPMakeRunner }
  211. Function TFPMakeRunner.RunFPMake(const Command:string) : Integer;
  212. Var
  213. ManifestPackage,
  214. P : TFPPackage;
  215. FPMakeBin,
  216. OOptions : string;
  217. procedure AddOption(const s:string);
  218. begin
  219. if OOptions<>'' then
  220. OOptions:=OOptions+' ';
  221. OOptions:=OOptions+maybequoted(s);
  222. end;
  223. procedure CondAddOption(const Name,Value:string);
  224. begin
  225. if Value<>'' then
  226. AddOption(Name+'='+Value);
  227. end;
  228. begin
  229. OOptions:='';
  230. // Does the current package support this CPU-OS?
  231. if PackageName<>'' then
  232. begin
  233. P:=AvailableRepository.PackageByName(PackageName);
  234. if (PackageName=CurrentDirPackageName) and (FileExists(ManifestFileName)) then
  235. begin
  236. ManifestPackage:=LoadManifestFromFile(ManifestFileName);
  237. P.OSes:=ManifestPackage.OSes;
  238. P.CPUs:=ManifestPackage.CPUs;
  239. ManifestPackage.Free;
  240. end;
  241. end
  242. else
  243. P:=nil;
  244. if assigned(P) then
  245. begin
  246. if (command<>'archive') and (command<>'manifest') and
  247. (not(CompilerOptions.CompilerOS in P.OSes) or
  248. not(CompilerOptions.CompilerCPU in P.CPUs)) then
  249. Error(SErrPackageDoesNotSupportTarget,[P.Name,MakeTargetString(CompilerOptions.CompilerCPU,CompilerOptions.CompilerOS)]);
  250. end;
  251. { Maybe compile fpmake executable? }
  252. ExecuteAction(PackageName,'compilefpmake');
  253. { Create options }
  254. if vlDebug in LogLevels then
  255. AddOption('--debug')
  256. else if vlInfo in LogLevels then
  257. AddOption('--verbose');
  258. if P.RecompileBroken and
  259. (P.FPMakeOptionsString<>'') then // Check for a empty FPMakeOptionString for packages being installed with an old fpmkunit
  260. begin
  261. // When the package is being reinstalled because of broken dependencies, use the same fpmake-options
  262. // as were used to compile the package in the first place.
  263. OOptions:=P.FPMakeOptionsString;
  264. end
  265. else
  266. begin
  267. AddOption('--nofpccfg');
  268. AddOption('--compiler='+CompilerOptions.Compiler);
  269. AddOption('--cpu='+CPUToString(CompilerOptions.CompilerCPU));
  270. AddOption('--os='+OSToString(CompilerOptions.CompilerOS));
  271. if CompilerOptions.HasOptions then
  272. AddOption('--options='+CompilerOptions.Options.DelimitedText);
  273. if IsSuperUser or GlobalOptions.InstallGlobal then
  274. begin
  275. CondAddOption('--prefix',CompilerOptions.GlobalPrefix);
  276. CondAddOption('--baseinstalldir',CompilerOptions.GlobalInstallDir);
  277. end
  278. else
  279. begin
  280. CondAddOption('--prefix',CompilerOptions.LocalPrefix);
  281. CondAddOption('--baseinstalldir',CompilerOptions.LocalInstallDir);
  282. end;
  283. CondAddOption('--localunitdir',CompilerOptions.LocalUnitDir);
  284. CondAddOption('--globalunitdir',CompilerOptions.GlobalUnitDir);
  285. if GlobalOptions.CustomFPMakeOptions<>'' then
  286. begin
  287. AddOption('--ignoreinvalidoption');
  288. AddOption(GlobalOptions.CustomFPMakeOptions);
  289. end;
  290. end;
  291. { Run FPMake }
  292. FPMakeBin:='fpmake'+ExeExt;
  293. SetCurrentDir(PackageBuildPath(P));
  294. Result:=ExecuteProcess(FPMakeBin,Command+' '+OOptions);
  295. if Result<>0 then
  296. Error(SErrExecutionFPMake,[Command]);
  297. end;
  298. procedure TFPMakeRunnerCompile.Execute;
  299. begin
  300. RunFPMake('compile');
  301. end;
  302. procedure TFPMakeRunnerBuild.Execute;
  303. begin
  304. RunFPMake('build');
  305. end;
  306. procedure TFPMakeRunnerInstall.Execute;
  307. begin
  308. RunFPMake('install');
  309. end;
  310. procedure TFPMakeRunnerClean.Execute;
  311. begin
  312. RunFPMake('clean');
  313. end;
  314. procedure TFPMakeRunnerManifest.Execute;
  315. begin
  316. RunFPMake('manifest');
  317. end;
  318. procedure TFPMakeRunnerArchive.Execute;
  319. begin
  320. RunFPMake('archive');
  321. end;
  322. initialization
  323. RegisterPkgHandler('compilefpmake',TFPMakeCompiler);
  324. RegisterPkgHandler('fpmakecompile',TFPMakeRunnerCompile);
  325. RegisterPkgHandler('fpmakebuild',TFPMakeRunnerBuild);
  326. RegisterPkgHandler('fpmakeinstall',TFPMakeRunnerInstall);
  327. RegisterPkgHandler('fpmakeclean',TFPMakeRunnerClean);
  328. RegisterPkgHandler('fpmakemanifest',TFPMakeRunnerManifest);
  329. RegisterPkgHandler('fpmakearchive',TFPMakeRunnerArchive);
  330. end.