fpcmmain.pp 62 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763
  1. {
  2. Copyright (c) 2001 by Peter Vreman
  3. FPCMake - Main module
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {$ifdef fpc}{$mode objfpc}{$endif}
  11. {$H+}
  12. unit fpcmmain;
  13. interface
  14. uses
  15. dos,
  16. {$ifdef Unix}
  17. {$ifdef VER1_0}
  18. {$ifdef linux}
  19. {$ifndef BSD}
  20. linux,
  21. {$endif}
  22. {$endif}
  23. {$ifdef BSD}
  24. Linux,
  25. {$endif}
  26. {$else}
  27. baseunix,
  28. unix,
  29. {$endif}
  30. {$endif}
  31. {$ifdef TEST_FPMKUNIT}
  32. fpmkunit,
  33. {$endif}
  34. sysutils,classes,
  35. fpcmdic;
  36. {$ifdef BEOS}
  37. {$define NO_UNIX_UNIT}
  38. {$endif}
  39. {$ifdef SOLARIS}
  40. {$define NO_UNIX_UNIT}
  41. {$endif}
  42. {$ifdef QNX}
  43. {$define NO_UNIX_UNIT}
  44. {$endif}
  45. {$ifdef OS2}
  46. {$define LIMIT83}
  47. {$endif}
  48. {$ifdef EMX}
  49. {$define LIMIT83}
  50. {$endif}
  51. {$ifdef GO32V2}
  52. {$define LIMIT83}
  53. {$endif}
  54. const
  55. Version='2.0.0';
  56. Title='FPCMake Version '+Version;
  57. {$ifdef REVINC}
  58. DateRevision={$i revision.inc};
  59. {$else}
  60. DateRevision={$I %DATE%}+' no revision';
  61. {$endif}
  62. TitleNoDate=Title;
  63. TitleDate=Title+' '+DateRevision;
  64. type
  65. {$ifdef TEST_FPMKUNIT}
  66. { Please keep this order, see OSCPUSupported below
  67. TCpu=(cpuNone,
  68. i386,m68k,powerpc,sparc,x86_64,arm,powerpc64,avr,armeb,
  69. mips,mipsel,mips64,mips64el,jvm,i8086,aarch64,wasm32,sparc64,riscv32,riscv64,xtensa,z80,loongarch64
  70. );}
  71. TCpu = fpmkunit.TCpu;
  72. { Please keep this order, see OSCPUSupported below
  73. TOS=(osNone,
  74. linux,go32v2,win32,os2,freebsd,beos,netbsd,
  75. amiga,atari, solaris, qnx, netware, openbsd,wdosx,
  76. palmos,macosclassic,darwin,emx,watcom,morphos,netwlibc,
  77. win64,wince,gba,nds,embedded,symbian,haiku,iphonesim,
  78. aix,java,android,nativent,msdos,wii,aros,dragonfly,
  79. win16,freertos,zxspectrum,msxdos,ios,amstradcpc,sinclairql,
  80. wasi
  81. );}
  82. TOS = fpmkunit.TOS;
  83. {$else}
  84. TCpu=(
  85. c_none,i386,m68k,powerpc,sparc,x86_64,arm,powerpc64,avr,
  86. armeb,armel,mips,mipsel,mips64,mips64el,jvm,i8086,aarch64,
  87. wasm32,sparc64,riscv32,riscv64,xtensa,z80,loongarch64
  88. );
  89. TOS=(
  90. o_none,linux,go32v2,win32,os2,freebsd,beos,haiku,netbsd,
  91. amiga,atari, solaris, qnx, netware, openbsd,wdosx,
  92. palmos,macosclassic,darwin,emx,watcom,morphos,netwlibc,
  93. win64,wince,gba,nds,embedded,symbian,nativent,iphonesim,
  94. wii,aix,java,android,msdos,aros,dragonfly,win16,freertos,
  95. zxspectrum,msxdos,ios,amstradcpc,sinclairql,wasi
  96. );
  97. {$endif}
  98. TTargetSet=array[tcpu,tos] of boolean;
  99. const
  100. CpuStr : array[TCpu] of string=(
  101. 'none','i386','m68k','powerpc','sparc','x86_64','arm','powerpc64','avr',
  102. 'armeb', 'armel', 'mips', 'mipsel', 'mips64', 'mips64el', 'jvm','i8086','aarch64',
  103. 'wasm32','sparc64','riscv32','riscv64','xtensa','z80', 'loongarch64'
  104. );
  105. CpuSuffix : array[TCpu] of string=(
  106. '_none','_i386','_m68k','_powerpc','_sparc','_x86_64','_arm','_powerpc64','_avr',
  107. '_armeb', '_armel', '_mips', '_mipsel', '_mips64', '_mips64el', '_jvm','_i8086','_aarch64',
  108. '_wasm32','_sparc64','_riscv32','_riscv64','xtensa','_z80', 'loongarch64'
  109. );
  110. ppcSuffix : array[TCpu] of string=(
  111. 'none','386','68k','ppc','sparc','x64','arm','ppc64','avr',
  112. 'armeb', 'armel', 'mips', 'mipsel', 'mips64', 'mips64el', 'jvm','8086','a64',
  113. 'wasm32','sparc64','rv32','rv64','xtensa','z80', 'loongarch64'
  114. );
  115. OSStr : array[TOS] of string=(
  116. 'none','linux','go32v2','win32','os2','freebsd','beos','haiku','netbsd',
  117. 'amiga','atari','solaris', 'qnx', 'netware','openbsd','wdosx',
  118. 'palmos','macosclassic','darwin','emx','watcom','morphos','netwlibc',
  119. 'win64','wince','gba','nds','embedded','symbian','nativent',
  120. 'iphonesim', 'wii', 'aix', 'java', 'android', 'msdos', 'aros',
  121. 'dragonfly', 'win16', 'freertos', 'zxspectrum', 'msxdos',
  122. 'ios','amstradcpc','sinclairql','wasi'
  123. );
  124. OSSuffix : array[TOS] of string=(
  125. '_none','_linux','_go32v2','_win32','_os2','_freebsd','_beos','_haiku','_netbsd',
  126. '_amiga','_atari','_solaris', '_qnx', '_netware','_openbsd','_wdosx',
  127. '_palmos','_macosclassic','_darwin','_emx','_watcom','_morphos','_netwlibc',
  128. '_win64','_wince','_gba','_nds','_embedded','_symbian','_nativent',
  129. '_iphonesim','_wii','_aix','_java','_android','_msdos','_aros',
  130. '_dragonfly','_win16','_freertos','_zxspectrum','_msxdos',
  131. '_ios','_amstradcpc','_sinclairql','_wasi'
  132. );
  133. { This table is kept OS,Cpu because it is easier to maintain (PFV) }
  134. {$ifdef TEST_FPMKUNIT}
  135. type
  136. TOSCpuPossible = array[TOS,TCpu] of boolean;
  137. var
  138. OSCpuPossible : TOsCpuPossible;
  139. {$else}
  140. OSCpuPossible : array[TOS,TCpu] of boolean =
  141. (
  142. { os none i386 m68k ppc sparc x86_64 arm ppc64 avr armeb armel mips mipsel mips64 misp64el jvm i8086 aarch64 wasm32 sparc64 riscv32 riscv64 xtensa z80 loongarch64 }
  143. { none } ( false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  144. { linux } ( false, true, true, true, true, true, true, true, false, true, false, true, true, true, true, false, false, true, false, true, true, true, true, false, true),
  145. { go32v2 } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  146. { win32 } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  147. { os2 } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  148. { freebsd } ( false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false),
  149. { beos } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  150. { haiku } ( false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  151. { netbsd } ( false, true, true, true, true, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  152. { amiga } ( false, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  153. { atari } ( false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  154. { solaris } ( false, true, false, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  155. { qnx } ( false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  156. { netware } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  157. { openbsd } ( false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  158. { wdosx } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  159. { palmos } ( false, false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  160. { macosclassic } ( false, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  161. { darwin } ( false, true, false, true, false, true, false, true, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false),
  162. { emx } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  163. { watcom } ( false, true, false, false, false ,false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  164. { morphos } ( false, false, false, true, false ,false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  165. { netwlibc }( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  166. { win64 } ( false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false),
  167. { wince }( false, true, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  168. { gba } ( false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  169. { nds } ( false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  170. { embedded }( false, true, true, true, true, true, true, true, true, true , false, false, true , false, false, false, true , true , true, false, true, true, true, true, false),
  171. { symbian } ( false, true, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  172. { nativent }( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  173. { iphonesim }( false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, true , false, false, false, false, false, false, false),
  174. { wii } ( false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  175. { aix } ( false, false, false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  176. { java } ( false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false),
  177. { android } ( false, true, false, false, false, true, true, false, false, false, false, false, true, false, false, true, false, true, false, false, false, false, false, false, false),
  178. { msdos } ( false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true , false, false, false, false, false, false, false, false),
  179. { aros } ( false, true, false, false, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  180. {dragonfly} ( false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  181. { win16 } ( false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true , false, false, false, false, false, false, false, false),
  182. { freertos }( false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, true, false, false),
  183. {zxspectrum}( false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false),
  184. { msxdos} ( false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false),
  185. { ios } ( false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, true , false, false, false, false, false, false, false),
  186. {amstradcpc}( false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false),
  187. {sinclairql}( false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false),
  188. { wasi } ( false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false)
  189. );
  190. {$endif }
  191. type
  192. TKeyValueItem = class(TDictionaryItem)
  193. private
  194. FValue : string;
  195. public
  196. constructor Create(const k,v:string);
  197. property Value:string read FValue write FValue;
  198. end;
  199. TKeyValue = class(TDictionary)
  200. private
  201. function GetKey(const k:string):string;
  202. public
  203. procedure Add(const k,v:String);
  204. property Key[const s:string]:string read GetKey write Add;default;
  205. end;
  206. TFPCMakeSection = class(TDictionaryItem)
  207. private
  208. FList : TStringList;
  209. FDictionary : TKeyValue;
  210. procedure BuildIniDic(p:TDictionaryItem);
  211. procedure BuildMakefileDic(p:TDictionaryItem);
  212. function GetKey(const k:string):string;
  213. public
  214. constructor Create(const n:string);
  215. constructor CreateKeyValue(const n:string);
  216. destructor Destroy;override;
  217. procedure AddLine(const s:string);
  218. procedure AddKey(const k,v:string);
  219. procedure Clear;
  220. procedure ParseIni;
  221. procedure BuildIni;
  222. procedure BuildMakefile;
  223. property Key[const s:string]:string read GetKey;default;
  224. property List:TStringList read FList;
  225. property Dictionary:TKeyValue read FDictionary;
  226. end;
  227. TTargetRequireList = array[tcpu,tos] of TStringList;
  228. TFPCMakeVerbose = (FPCMakeError, FPCMakeInfo, FPCMakeDebug);
  229. { TFPCMake }
  230. TFPCMake = class
  231. private
  232. FStream : TStream;
  233. FFileName : string;
  234. FCommentChars : TSysCharSet;
  235. FEmptyLines : boolean;
  236. FSections : TDictionary;
  237. FPackageSec,
  238. FExportSec : TFPCMakeSection;
  239. FUsesLCL,
  240. FIsPackage : boolean;
  241. FPackageName,
  242. FPackageVersion : string;
  243. FRequireList : TTargetRequireList;
  244. FVariables : TKeyValue;
  245. FIncludeTargets : TTargetSet;
  246. FExtraTargetsFile : String;
  247. procedure Init;
  248. procedure ParseSec(p:TDictionaryItem);
  249. procedure PrintSec(p:TDictionaryItem);
  250. procedure PrintDic(p:TDictionaryItem);
  251. function GetSec(const AName:string):TDictionaryItem;
  252. procedure LoadRequiredPackage(c:TCpu;t:TOS;const ReqName,ReqVersion:string);
  253. procedure LoadRequiredDir(c:TCpu;t:TOS;const MainPack,currdir,subdir:string);
  254. procedure LoadRequires(c:TCpu;t:TOS;FromFPCMake:TFPCMake);
  255. function CopySection(Sec:TFPCMakeSection;Secname:string):TFPCMakeSection;
  256. protected
  257. VerboseIdent : string;
  258. public
  259. constructor Create(const AFileName:string);
  260. constructor CreateFromStream(s:TStream;const AFileName:string);
  261. destructor Destroy;override;
  262. procedure Verbose(lvl:TFPCMakeVerbose;const s:string);virtual;
  263. procedure SetTargets(const s:string);
  264. procedure AddExtraTargets(const aFileName : String; aList : TStrings);
  265. procedure LoadSections;
  266. procedure LoadMakefileFPC;
  267. procedure LoadPackageSection;
  268. procedure LoadRequireSection;
  269. function GetTargetRequires(c:TCpu;t:TOS):TStringList;
  270. function CheckLibcRequire:boolean;
  271. procedure CreateExportSection;
  272. procedure AddFPCDefaultVariables;
  273. procedure AddLCLDefaultVariables;
  274. function SubstVariables(const s:string):string;
  275. function GetVariable(const inivar:string;dosubst:boolean):string;
  276. function GetTargetVariable(c:TCPU;t:TOS;const inivar:string;dosubst:boolean):string;
  277. function HasVariable(const inivar:string):boolean;
  278. function HasTargetVariable(const inivar:string):boolean;
  279. function SetVariable(const inivar,value:string;add:boolean):string;
  280. procedure Print;
  281. property Section[const s:string]:TDictionaryItem read GetSec;default;
  282. property RequireList:TTargetRequireList read FRequireList;
  283. property Variables:TKeyValue read FVariables;
  284. property UsesLCL:boolean read FUsesLCL;
  285. property IsPackage:boolean read FIsPackage;
  286. property PackageName:string read FPackageName;
  287. property PackageVersion:string read FPackageVersion;
  288. property PackageSec:TFPCMakeSection read FPackageSec;
  289. property ExportSec:TFPCMakeSection read FExportSec;
  290. property CommentChars:TSysCharSet read FCommentChars write FCommentChars;
  291. property EmptyLines:Boolean read FEmptyLines write FEmptyLines;
  292. property IncludeTargets:TTargetSet read FIncludeTargets write FIncludeTargets;
  293. Property ExtraTargetsFile : String Read FExtraTargetsFile Write FExtraTargetsFile;
  294. end;
  295. function posidx(const substr,s : string;idx:integer):integer;
  296. function GetToken(var s:string;sep:char):string;
  297. procedure AddToken(var s:string;const tok:string;sep:char);
  298. procedure AddTokenNoDup(var s:string;const s2:string;sep:char);
  299. implementation
  300. resourcestring
  301. s_not_list_sec='Not a list section "%s"';
  302. s_not_key_value_sec='Not a key-value section "%s"';
  303. s_err_section_start='%s:%d: Wrong section start';
  304. s_err_not_key_value='Parse error key=value excepted: "%s"';
  305. s_err_no_section='%s:%d: Entries without section';
  306. s_no_package_name='No package name set';
  307. s_no_package_version='No package version set';
  308. s_err_require_format='Wrong require format "%s"';
  309. s_wrong_package_name='Package name "%s" expected, but "%s" found';
  310. s_wrong_package_version='Package version "%s" expected, but version "%s" found';
  311. s_directory_not_found='Directory "%s" not found';
  312. s_makefilefpc_not_found='No Makefile.fpc found in directory "%s"';
  313. s_package_not_found='Target "%s", package "%s" not found';
  314. s_fpcmake_version_required='FPCMake version "%s" is required';
  315. s_no_targets_set='No targets set';
  316. s_targets_info='Targets: "%s"';
  317. s_globals='Globals:';
  318. {****************************************************************************
  319. Helpers
  320. ****************************************************************************}
  321. Function PathExists ( F : String) : Boolean;
  322. Var
  323. Info : TSearchRec;
  324. begin
  325. if F[Length(f)] in ['/','\'] then
  326. Delete(f,length(f),1);
  327. PathExists:=(findfirst(F,faAnyFile,info)=0) and
  328. ((info.attr and fadirectory)=fadirectory);
  329. findclose(Info);
  330. end;
  331. Function PathOrFileExists ( F : String) : Boolean;
  332. Var
  333. Info : Dos.SearchRec;
  334. begin
  335. if F[Length(f)] in ['/','\'] then
  336. Delete(f,length(f),1);
  337. dos.findfirst(f,fareadonly+faarchive+fahidden+fadirectory,info);
  338. PathOrFileExists:=(Doserror=0);
  339. dos.findclose(Info);
  340. end;
  341. function posidx(const substr,s : string;idx:integer):integer;
  342. var
  343. i,j : integer;
  344. e : boolean;
  345. begin
  346. i:=idx;
  347. j:=0;
  348. e:=(length(SubStr)>0);
  349. while e and (i<=Length(s)-Length(SubStr)) do
  350. begin
  351. inc(i);
  352. if (SubStr[1]=s[i]) and (Substr=Copy(s,i,Length(SubStr))) then
  353. begin
  354. j:=i;
  355. e:=false;
  356. end;
  357. end;
  358. PosIdx:=j;
  359. end;
  360. function GetToken(var s:string;sep:char):string;
  361. var
  362. i : integer;
  363. begin
  364. s:=Trim(s);
  365. i:=pos(sep,s);
  366. if i=0 then
  367. begin
  368. Result:=s;
  369. s:='';
  370. end
  371. else
  372. begin
  373. Result:=Copy(s,1,i-1);
  374. Delete(s,1,i);
  375. end;
  376. end;
  377. procedure AddToken(var s:string;const tok:string;sep:char);
  378. begin
  379. if tok='' then
  380. exit;
  381. if s<>'' then
  382. s:=s+sep+tok
  383. else
  384. s:=tok;
  385. end;
  386. procedure AddTokenNoDup(var s:string;const s2:string;sep:char);
  387. var
  388. i,idx : integer;
  389. again,add : boolean;
  390. begin
  391. add:=false;
  392. idx:=0;
  393. repeat
  394. again:=false;
  395. i:=posidx(s2,s,idx);
  396. if (i=0) then
  397. add:=true
  398. else
  399. if (i=1) then
  400. begin
  401. if (length(s)>length(s2)) and
  402. (s[length(s2)+1]<>sep) then
  403. add:=true;
  404. end
  405. else
  406. if (i>1) and
  407. ((s[i-1]<>sep) or
  408. ((length(s)>=i+length(s2)) and (s[i+length(s2)]<>sep))) then
  409. begin
  410. idx:=i+length(s2);
  411. again:=true;
  412. end;
  413. until not again;
  414. if add then
  415. begin
  416. if s='' then
  417. s:=s2
  418. else
  419. s:=s+sep+s2;
  420. end;
  421. end;
  422. {****************************************************************************
  423. TKeyValueItem
  424. ****************************************************************************}
  425. constructor TKeyValueItem.Create(const k,v:string);
  426. begin
  427. inherited Create(k);
  428. value:=v;
  429. end;
  430. {****************************************************************************
  431. TKeyValue
  432. ****************************************************************************}
  433. function TKeyValue.GetKey(const k:string):string;
  434. var
  435. p : TKeyValueItem;
  436. begin
  437. p:=TKeyValueItem(Search(k));
  438. if p=nil then
  439. GetKey:=''
  440. else
  441. GetKey:=p.Value;
  442. end;
  443. procedure TKeyValue.Add(const k,v:string);
  444. var
  445. p : TKeyValueItem;
  446. begin
  447. p:=TKeyValueItem(Search(k));
  448. if p=nil then
  449. begin
  450. p:=TKeyValueItem.Create(k,v);
  451. Insert(p);
  452. end
  453. else
  454. p.Value:=v;
  455. end;
  456. {****************************************************************************
  457. TFPCMakeSection
  458. ****************************************************************************}
  459. constructor TFPCMakeSection.Create(const n:string);
  460. begin
  461. inherited Create(n);
  462. FList:=TStringList.Create;
  463. FDictionary:=nil;
  464. end;
  465. constructor TFPCMakeSection.CreateKeyValue(const n:string);
  466. begin
  467. inherited Create(n);
  468. FList:=nil;
  469. FDictionary:=TKeyValue.Create;
  470. end;
  471. destructor TFPCMakeSection.Destroy;
  472. begin
  473. inherited Destroy;
  474. FList.Free;
  475. FDictionary.Free;
  476. end;
  477. procedure TFPCMakeSection.Clear;
  478. begin
  479. FList.Free;
  480. FList:=TStringList.Create;
  481. FDictionary.Free;
  482. FDictionary:=nil;
  483. end;
  484. procedure TFPCMakeSection.AddLine(const s:string);
  485. begin
  486. if FList=nil then
  487. raise Exception.Create(Format(s_not_list_sec,[Name]));
  488. FList.Add(s);
  489. end;
  490. procedure TFPCMakeSection.AddKey(const k,v:string);
  491. begin
  492. if FDictionary=nil then
  493. raise Exception.Create(Format(s_not_key_value_sec,[Name]));
  494. { Don't add empty values }
  495. if v<>'' then
  496. FDictionary.Add(k,v);
  497. end;
  498. function TFPCMakeSection.GetKey(const k:string):string;
  499. begin
  500. if FDictionary=nil then
  501. raise Exception.Create(Format(s_not_key_value_sec,[Name]));
  502. GetKey:=FDictionary[k];
  503. end;
  504. procedure TFPCMakeSection.ParseIni;
  505. var
  506. p : TKeyValueItem;
  507. i,j,len,maxi : integer;
  508. s,newkey,value : string;
  509. begin
  510. { If already processed skip }
  511. if assigned(FDictionary) then
  512. exit;
  513. { Don't process rules section }
  514. if (Name='prerules') or (Name='rules') then
  515. exit;
  516. { Parse the section }
  517. FDictionary:=TKeyValue.Create;
  518. { Parse the list }
  519. maxi:=FList.Count;
  520. i:=0;
  521. while (i<maxi) do
  522. begin
  523. s:=Trim(FList[i]);
  524. len:=Length(s);
  525. { Concat lines ending with \ }
  526. while s[len]='\' do
  527. begin
  528. Delete(s,len,1);
  529. if i+1<maxi then
  530. begin
  531. inc(i);
  532. s:=s+Trim(FList[i]);
  533. len:=Length(s);
  534. end;
  535. end;
  536. { Parse key=value line }
  537. j:=0;
  538. while (j<len) and (s[j+1] in ['A'..'Z','a'..'z','0'..'9','_']) do
  539. inc(j);
  540. NewKey:=Copy(s,1,j);
  541. While (j<len) and (s[j+1] in [' ',#9]) do
  542. inc(j);
  543. inc(j);
  544. if s[j]<>'=' then
  545. Raise Exception.Create(Format(s_err_not_key_value,[s]));
  546. While (j<len) and (s[j+1] in [' ',#9]) do
  547. inc(j);
  548. Value:=Copy(s,j+1,len-j);
  549. p:=TKeyValueItem(FDictionary.Search(NewKey));
  550. { Concat values if key already exists }
  551. if assigned(p) then
  552. AddToken(p.FValue,Value,' ')
  553. else
  554. FDictionary.Add(NewKey,Value);
  555. inc(i);
  556. end;
  557. { List is not used anymore }
  558. FList.Free;
  559. FList:=nil;
  560. end;
  561. procedure TFPCMakeSection.BuildIniDic(p:TDictionaryItem);
  562. begin
  563. with TKeyValueItem(p) do
  564. begin
  565. FList.Add(Name+'='+Value);
  566. end;
  567. end;
  568. procedure TFPCMakeSection.BuildIni;
  569. begin
  570. if assigned(FList) then
  571. exit;
  572. FList:=TStringList.Create;
  573. FDictionary.Foreach(@BuildIniDic);
  574. FDictionary.Free;
  575. FDictionary:=nil;
  576. end;
  577. procedure TFPCMakeSection.BuildMakefileDic(p:TDictionaryItem);
  578. begin
  579. FList.Add(Uppercase(Name+'_'+TKeyValueItem(p).Name)+'='+TKeyValueItem(p).Value);
  580. end;
  581. procedure TFPCMakeSection.BuildMakefile;
  582. begin
  583. if assigned(FList) then
  584. exit;
  585. FList:=TStringList.Create;
  586. FDictionary.Foreach(@BuildMakefileDic);
  587. FDictionary.Free;
  588. FDictionary:=nil;
  589. end;
  590. {****************************************************************************
  591. TFPCMake
  592. ****************************************************************************}
  593. constructor TFPCMake.Create(const AFileName:string);
  594. begin
  595. FFileName:=AFileName;
  596. FStream:=nil;
  597. Init;
  598. end;
  599. constructor TFPCMake.CreateFromStream(s:TStream;const AFileName:string);
  600. begin
  601. FFileName:=AFileName;
  602. FStream:=s;
  603. Init;
  604. end;
  605. procedure TFPCMake.Init;
  606. var
  607. t : tos;
  608. c : tcpu;
  609. begin
  610. FSections:=TDictionary.Create;
  611. for c:=succ(low(tcpu)) to high(tcpu) do
  612. for t:=succ(low(tos)) to high(tos) do
  613. FRequireList[c,t]:=TStringList.Create;
  614. FVariables:=TKeyValue.Create;
  615. FCommentChars:=[';','#'];
  616. FEmptyLines:=false;
  617. FIsPackage:=false;
  618. FPackageName:='';
  619. FPackageVersion:='';
  620. FPackageSec:=nil;
  621. FExportSec:=nil;
  622. FillChar(FIncludeTargets,sizeof(FIncludeTargets),true);
  623. VerboseIdent:='';
  624. FUsesLCL:=false;
  625. end;
  626. destructor TFPCMake.Destroy;
  627. var
  628. t : tos;
  629. c : tcpu;
  630. begin
  631. FSections.Free;
  632. for c:=succ(low(tcpu)) to high(tcpu) do
  633. for t:=succ(low(tos)) to high(tos) do
  634. FRequireList[c,t].Free;
  635. FVariables.Free;
  636. end;
  637. procedure TFPCMake.AddExtraTargets(const aFileName : string; aList : TStrings);
  638. var
  639. Xtra : TStringList;
  640. begin
  641. Xtra:=TstringList.Create;
  642. try
  643. Xtra.LoadFromFile(aFileName);
  644. aList.AddStrings(Xtra);
  645. finally
  646. Xtra.Free;
  647. end;
  648. end;
  649. procedure TFPCMake.LoadSections;
  650. var
  651. SLInput, slExtra : TStringList;
  652. i,j,n : integer;
  653. s,
  654. SecName : string;
  655. CurrSec : TFPCMakeSection;
  656. begin
  657. CurrSec:=nil;
  658. slExtra:=Nil;
  659. SLInput:=TStringList.Create;
  660. try
  661. // We do this first
  662. if ExtraTargetsFile<>'' then
  663. begin
  664. slExtra:=TStringList.Create;
  665. AddExtraTargets(ExtraTargetsFile,slExtra);
  666. end;
  667. if assigned(FStream) then
  668. SLInput.LoadFromStream(FStream)
  669. else
  670. SLInput.LoadFromFile(FFileName);
  671. if Assigned(SLExtra) then
  672. begin
  673. slExtra.AddStrings(slInput);
  674. slInput.Free;
  675. slInput:=slExtra;
  676. slExtra:=nil;
  677. end;
  678. { Load Input into sections list }
  679. n:=SLInput.Count;
  680. i:=0;
  681. while (i<n) do
  682. begin
  683. s:=Trim(SLInput[i]);
  684. if (EmptyLines and (s='')) or
  685. ((s<>'') and not(s[1] in FCommentChars)) then
  686. begin
  687. { section start? }
  688. if (s<>'') and (s[1]='[') then
  689. begin
  690. j:=pos(']',s);
  691. if j=0 then
  692. raise Exception.Create(Format(s_err_section_start,[FFileName,i+1]));
  693. SecName:=Copy(s,2,j-2);
  694. CurrSec:=TFPCMakeSection(FSections[SecName]);
  695. if CurrSec=nil then
  696. CurrSec:=TFPCMakeSection(FSections.Insert(TFPCMakeSection.Create(SecName)))
  697. end
  698. else
  699. begin
  700. if CurrSec=nil then
  701. raise Exception.Create(Format(s_err_no_section,[FFileName,i+1]));
  702. { Insert string without spaces stripped }
  703. // Writeln('Appending: ',SLInput[i]);
  704. CurrSec.AddLine(SLInput[i]);
  705. end;
  706. end;
  707. inc(i);
  708. end;
  709. finally
  710. SLInput.Free;
  711. slExtra.Free;
  712. end;
  713. end;
  714. function TFPCMake.CopySection(Sec:TFPCMakeSection;Secname:string):TFPCMakeSection;
  715. begin
  716. Result:=TFPCMakeSection(FSections[SecName]);
  717. if Sec=Nil then
  718. exit;
  719. { Clear old section or if not existing create new }
  720. if assigned(Result) then
  721. Result.Clear
  722. else
  723. Result:=TFPCMakeSection(FSections.Insert(TFPCMakeSection.Create(SecName)));
  724. Sec.BuildIni;
  725. Result.List.AddStrings(Sec.List);
  726. Result.ParseIni;
  727. Sec.ParseIni;
  728. end;
  729. procedure TFPCMake.LoadMakefileFPC;
  730. {$ifdef SupportLCL}
  731. var
  732. s : string;
  733. {$endif SupportLCL}
  734. begin
  735. LoadSections;
  736. { Parse all sections }
  737. FSections.Foreach(@ParseSec);
  738. { Load package section }
  739. LoadPackageSection;
  740. { Add some default variables like FPCDIR, UNITSDIR }
  741. AddFPCDefaultVariables;
  742. { Load LCL code ? }
  743. {$ifdef SupportLCL}
  744. s:=GetVariable('require_packages',true);
  745. if (pos('lcl',s)>0) or (PackageName='lcl') then
  746. begin
  747. FUsesLCL:=true;
  748. AddLCLDefaultVariables;
  749. end;
  750. {$endif SupportLCL}
  751. { Show globals }
  752. Verbose(FPCMakeDebug,s_globals);
  753. Variables.Foreach(@PrintDic);
  754. { Load required packages }
  755. LoadRequireSection;
  756. end;
  757. procedure TFPCMake.Verbose(lvl:TFPCMakeVerbose;const s:string);
  758. begin
  759. writeln(VerboseIdent,s);
  760. end;
  761. procedure TFPCMake.SetTargets(const s:string);
  762. var
  763. hslst : string;
  764. hs : string;
  765. hcpu,htarget : string;
  766. t : TOs;
  767. c : TCpu;
  768. i : integer;
  769. targetset : boolean;
  770. begin
  771. FillChar(FIncludeTargets,sizeof(FIncludeTargets),0);
  772. targetset:=false;
  773. hslst:=s;
  774. repeat
  775. hs:=LowerCase(GetToken(hslst,','));
  776. if hs='' then
  777. break;
  778. { target 'all' includes all targets }
  779. if hs='all' then
  780. begin
  781. for c:=succ(low(TCpu)) to high(TCpu) do
  782. for t:=succ(low(TOs)) to high(TOs) do
  783. if OSCpuPossible[t,c] then
  784. FIncludeTargets[c,t]:=true;
  785. targetset:=true;
  786. break;
  787. end;
  788. { full cpu-target specified? }
  789. i:=pos('-',hs);
  790. if i>0 then
  791. begin
  792. hcpu:=copy(hs,1,i-1);
  793. htarget:=copy(hs,i+1,length(hs)-i);
  794. for c:=succ(low(TCpu)) to high(TCpu) do
  795. begin
  796. if hcpu=CpuStr[c] then
  797. begin
  798. for t:=succ(low(TOs)) to high(TOs) do
  799. begin
  800. if htarget=OSStr[t] then
  801. begin
  802. if OSCpuPossible[t,c] then
  803. begin
  804. FIncludeTargets[c,t]:=true;
  805. targetset:=true;
  806. end;
  807. break;
  808. end;
  809. end;
  810. break;
  811. end;
  812. end;
  813. end
  814. else
  815. begin
  816. for c:=succ(low(TCpu)) to high(TCpu) do
  817. begin
  818. for t:=succ(low(TOS)) to high(TOS) do
  819. begin
  820. if hs=OSStr[t] then
  821. begin
  822. if OSCpuPossible[t,c] then
  823. begin
  824. FIncludeTargets[c,t]:=true;
  825. targetset:=true;
  826. end;
  827. break;
  828. end;
  829. end;
  830. end;
  831. end;
  832. until false;
  833. if not targetset then
  834. raise Exception.Create(s_no_targets_set)
  835. else
  836. begin
  837. hs:='';
  838. for c:=succ(low(TCpu)) to high(TCpu) do
  839. for t:=succ(low(TOs)) to high(TOs) do
  840. if FIncludeTargets[c,t] then
  841. AddToken(hs,CpuStr[c]+'-'+OSStr[t],' ');
  842. Verbose(FPCMakeDebug,Format(s_targets_info,[hs]));
  843. end;
  844. end;
  845. procedure TFPCMake.LoadPackageSection;
  846. var
  847. s : string;
  848. begin
  849. { Get package info from package section }
  850. FPackageSec:=TFPCMakeSection(FSections['package']);
  851. if FPackageSec=nil then
  852. exit;
  853. { Parse the section to key=value pairs }
  854. FPackageSec.ParseIni;
  855. { Are we a subpart of a package, then load that package }
  856. s:=FPackageSec['main'];
  857. if s<>'' then
  858. begin
  859. SetVariable('package_name',s,false);
  860. FPackageName:=s;
  861. end
  862. else
  863. begin
  864. { mandatory name }
  865. FPackageName:=FPackageSec['name'];
  866. if FPackageName='' then
  867. Raise Exception.Create(s_no_package_name);
  868. { mandatory version }
  869. FPackageVersion:=FPackageSec['version'];
  870. if FPackageVersion='' then
  871. Raise Exception.Create(s_no_package_version);
  872. FIsPackage:=true;
  873. { Set the ExportSec }
  874. FExportSec:=TFPCMakeSection(FSections[Lowercase(FPackageName)]);
  875. end;
  876. end;
  877. procedure TFPCMake.CreateExportSection;
  878. var
  879. t : TOS;
  880. c : TCpu;
  881. begin
  882. { Don't create a section twice }
  883. if FExportSec<>nil then
  884. exit;
  885. { Look if we've already an own section, else create a new
  886. key-value section }
  887. FExportSec:=TFPCMakeSection(FSections[LowerCase(FPackageName)]);
  888. if FExportSec=nil then
  889. FExportSec:=TFPCMakeSection(FSections.Insert(TFPCMakeSection.CreateKeyValue(LowerCase(FPackageName))));
  890. { Add default the values to the export section }
  891. FExportSec.AddKey('name',FPackageName);
  892. FExportSec.AddKey('version',FPackageVersion);
  893. { Add required packages }
  894. for c:=succ(low(TCpu)) to high(TCpu) do
  895. for t:=succ(low(TOS)) to high(TOS) do
  896. FExportSec.AddKey('require'+CpuSuffix[c]+OSSuffix[t],FPackageSec['require'+CpuSuffix[c]+OSSuffix[t]]);
  897. { Unit dir }
  898. {FExportSec.AddKey('unitdir','$(UNITSDIR)/'+Lowercase(PackageName));}
  899. end;
  900. procedure TFPCMake.LoadRequiredPackage(c:TCpu;t:TOS;const ReqName,ReqVersion:string);
  901. function TryFile(const fn:string):boolean;
  902. var
  903. ReqFPCMake : TFPCMake;
  904. begin
  905. TryFile:=false;
  906. if FileExists(fn) then
  907. begin
  908. VerboseIdent:=VerboseIdent+' ';
  909. Verbose(FPCMakeDebug,'Package '+ReqName+': '+fn);
  910. ReqFPCMake:=TFPCMake.Create(fn);
  911. ReqFPCMake.LoadSections;
  912. ReqFPCMake.LoadPackageSection;
  913. { Check package name and version }
  914. if LowerCase(ReqFPCMake.PackageName)<>ExtractFileName(ReqName) then
  915. raise Exception.Create(Format(s_wrong_package_name,[ReqName,LowerCase(ReqFPCMake.PackageName)]));
  916. if (ReqVersion<>'') and (ReqFPCMake.PackageVersion<ReqVersion) then
  917. raise Exception.Create(Format(s_wrong_package_version,[ReqVersion,ReqFPCMake.PackageVersion]));
  918. { First load the requirements of this package }
  919. LoadRequires(c,t,ReqFPCMake);
  920. { Get a copy of the package section }
  921. CopySection(ReqFPCMake.PackageSec,ReqName+'_package');
  922. { Get a copy of the export section }
  923. CopySection(ReqFPCMake.ExportSec,ReqName);
  924. { Get a copy of the require section }
  925. CopySection(TFPCMakeSection(ReqFPCMake['require']),ReqName+'_require');
  926. { Free }
  927. ReqFPCMake.Free;
  928. Delete(VerboseIdent,1,2);
  929. TryFile:=true;
  930. end;
  931. end;
  932. var
  933. s : string;
  934. begin
  935. { Force the current target }
  936. SetVariable('OSTARGET',OSStr[t],false);
  937. SetVariable('CPUTARGET',CpuStr[c],false);
  938. {$ifdef LIMIT83}
  939. SetVariable('FULLTARGET',OSStr[t],false);
  940. {$else}
  941. SetVariable('FULLTARGET',CpuStr[c]+'-'+OSStr[t],false);
  942. {$endif}
  943. { Check for Makefile.fpc }
  944. s:=SubstVariables('$(addsuffix /'+ReqName+'/Makefile.fpc,$(FPCDIR)) $(addsuffix /'+ReqName+'/Makefile.fpc,$(PACKAGESDIR)) $(addsuffix /'+ReqName+'/Makefile.fpc,$(REQUIRE_PACKAGESDIR))');
  945. Verbose(FPCMakeDebug,'Package "'+ReqName+'": Looking for Makefile.fpc: "'+s+'"');
  946. s:=SubstVariables('$(firstword $(wildcard '+s+'))');
  947. if TryFile(s) then
  948. exit;
  949. { Check for Package.fpc }
  950. s:=SubstVariables('$(addsuffix /'+ReqName+'/Package.fpc,$(FPCDIR)) $(addsuffix /'+ReqName+'/Package.fpc,$(UNITSDIR)) $(addsuffix /'+ReqName+'/Package.fpc,$(REQUIRE_UNITSDIR))');
  951. Verbose(FPCMakeDebug,'Package "'+ReqName+'": Looking for Package.fpc: "'+s+'"');
  952. s:=SubstVariables('$(firstword $(wildcard '+s+'))');
  953. if TryFile(s) then
  954. exit;
  955. { Check for Makefile }
  956. s:=SubstVariables('$(addsuffix /'+ReqName+'/Makefile,$(FPCDIR)) $(addsuffix /'+ReqName+'/Makefile,$(PACKAGESDIR)) $(addsuffix /'+ReqName+'/Makefile,$(REQUIRE_PACKAGESDIR))');
  957. Verbose(FPCMakeDebug,'Package "'+ReqName+'": Looking for Makefile+fpmake: "'+s+'"');
  958. s:=SubstVariables('$(firstword $(wildcard '+s+'))');
  959. if FileExists(s) then
  960. exit;
  961. Raise Exception.Create(Format(s_package_not_found,[OSStr[t],Reqname]));
  962. end;
  963. procedure TFPCMake.LoadRequiredDir(c:TCpu;t:TOS;const MainPack,currdir,subdir:string);
  964. var
  965. ReqFPCMake : TFPCMake;
  966. s : string;
  967. begin
  968. VerboseIdent:=VerboseIdent+' ';
  969. s:=currdir+subdir;
  970. Verbose(FPCMakeDebug,'Subdir: '+s+'/Makefile.fpc');
  971. if not FileExists(s+'/Makefile.fpc') then
  972. begin
  973. { give better error what is wrong }
  974. if not PathExists(s) then
  975. Raise Exception.Create(Format(s_directory_not_found,[s]))
  976. // packages may no longer have 'Makefile.fpc', but they will have a Makefile.
  977. // for such cases, the top Makefile.fpc must simply specify all dependencies recursively.
  978. else if not FileExists(s+'/Makefile') then
  979. Raise Exception.Create(Format(s_makefilefpc_not_found,[s]))
  980. else
  981. exit;
  982. end;
  983. { Process Makefile.fpc }
  984. ReqFPCMake:=TFPCMake.Create(currdir+subdir+'/Makefile.fpc');
  985. ReqFPCMake.LoadSections;
  986. ReqFPCMake.LoadPackageSection;
  987. { Are we a subpackage? }
  988. if (ReqFPCMake.GetVariable('package_name',false)<>MainPack) then
  989. begin
  990. ReqFPCMake.Free;
  991. Delete(VerboseIdent,1,2);
  992. exit;
  993. end;
  994. { Load the requirements of this package }
  995. LoadRequires(c,t,ReqFPCMake);
  996. { Add the current requirements to our parents requirements }
  997. s:=ReqFPCMake.GetTargetVariable(c,t,'require_packages',true);
  998. SetVariable('require_packages'+OSSuffix[t]+cpusuffix[c],s,true);
  999. if ReqFPCMake.GetVariable('require_libc',false)<>'' then
  1000. SetVariable('require_libc','y',false);
  1001. { Free }
  1002. ReqFPCMake.Free;
  1003. Delete(VerboseIdent,1,2);
  1004. end;
  1005. procedure TFPCMake.LoadRequires(c:TCpu;t:TOS;FromFPCMake:TFPCMake);
  1006. var
  1007. s,
  1008. ReqDir,
  1009. ReqName,
  1010. ReqVersion : string;
  1011. i,j : integer;
  1012. begin
  1013. { packages }
  1014. s:=FromFPCMake.GetTargetVariable(c,t,'require_packages',true);
  1015. Verbose(FPCMakeDebug,'Required packages for '+OSStr[t]+'-'+CpuStr[c]+': '+s);
  1016. repeat
  1017. reqname:=GetToken(s,' ');
  1018. if reqname='' then
  1019. break;
  1020. i:=Pos('(',ReqName);
  1021. if i>0 then
  1022. begin
  1023. j:=Pos(')',ReqName);
  1024. if (i=1) or (j=0) then
  1025. Raise Exception.Create(Format(s_err_require_format,[ReqName]));
  1026. ReqVersion:=Copy(ReqName,i+1,j-i-1);
  1027. ReqName:=Copy(ReqName,1,i-1);
  1028. end
  1029. else
  1030. ReqVersion:='';
  1031. { We only use lowercase names }
  1032. ReqName:=Lowercase(ReqName);
  1033. { Already loaded ? }
  1034. if (RequireList[c,t].IndexOf(ReqName)=-1) then
  1035. begin
  1036. LoadRequiredPackage(c,t,ReqName,ReqVersion);
  1037. RequireList[c,t].Add(ReqName);
  1038. end;
  1039. until false;
  1040. { sub dirs }
  1041. s:=FromFPCMake.GetTargetVariable(c,t,'target_dirs',true);
  1042. Verbose(FPCMakeDebug,'Required dirs for '+CpuStr[c]+'-'+OSStr[t]+': '+s);
  1043. repeat
  1044. reqdir:=GetToken(s,' ');
  1045. if reqdir='' then
  1046. break;
  1047. LoadRequiredDir(c,t,FromFPCMake.FPackageName,ExtractFilePath(FromFPCMake.FFileName),ReqDir)
  1048. until false;
  1049. end;
  1050. procedure TFPCMake.LoadRequireSection;
  1051. var
  1052. s : string;
  1053. t : tos;
  1054. c : tcpu;
  1055. begin
  1056. { Check FPCMake version }
  1057. s:=GetVariable('require_fpcmake',false);
  1058. if (s>version) then
  1059. raise Exception.Create(Format(s_fpcmake_version_required,[s]));
  1060. { Maybe add an implicit rtl dependency if there is something
  1061. to compile }
  1062. s:=GetVariable('require_packages',false);
  1063. if (GetVariable('require_nortl',false)='') and
  1064. (HasTargetVariable('target_programs') or
  1065. HasTargetVariable('target_units') or
  1066. HasTargetVariable('target_examples')) and
  1067. (Pos('rtl(',s)=0) and (getvariable('package_name',false)<>'rtl') then
  1068. begin
  1069. s:='rtl '+s;
  1070. SetVariable('require_packages',s,false);
  1071. end;
  1072. { Load recursively all required packages starting with this Makefile.fpc }
  1073. for c:=succ(low(TCpu)) to high(TCpu) do
  1074. for t:=succ(low(Tos)) to high(Tos) do
  1075. if FIncludeTargets[c,t] then
  1076. LoadRequires(c,t,self);
  1077. end;
  1078. function TFPCMake.GetTargetRequires(c: TCpu; t: TOS): TStringList;
  1079. var
  1080. ReqSec : TFPCMakeSection;
  1081. ReqList : TStringList;
  1082. procedure AddReqSec(c:TCpu;t:Tos;Sec:TFPCMakeSection);
  1083. var
  1084. s,
  1085. ReqName : string;
  1086. RSec : TFPCMakeSection;
  1087. i : integer;
  1088. begin
  1089. s:=Sec['packages']+' '+
  1090. Sec['packages'+CpuSuffix[c]]+' '+
  1091. Sec['packages'+OSSuffix[t]]+' '+
  1092. Sec['packages'+OSSuffix[t]+CpuSuffix[c]];
  1093. repeat
  1094. ReqName:=GetToken(s,' ');
  1095. if ReqName='' then
  1096. break;
  1097. i:=Pos('(',ReqName);
  1098. if i>0 then
  1099. ReqName:=Copy(ReqName,1,i-1);
  1100. { We only use lowercase names }
  1101. ReqName:=Lowercase(ReqName);
  1102. { Already loaded ? }
  1103. if (ReqList.IndexOf(ReqName)=-1) then
  1104. begin
  1105. RSec:=TFPCMakeSection(FSections[ReqName+'_require']);
  1106. if assigned(RSec) then
  1107. AddReqSec(c,t,RSec);
  1108. ReqList.Add(ReqName);
  1109. end;
  1110. until false;
  1111. end;
  1112. begin
  1113. ReqList:=TStringList.Create;
  1114. ReqSec:=TFPCMakeSection(FSections['require']);
  1115. { Building fpmake itself always requires the rtl }
  1116. if HasTargetVariable('target_fpmake') then
  1117. ReqList.Add('rtl');
  1118. if assigned(ReqSec) then
  1119. AddReqSec(c,t,ReqSec);
  1120. GetTargetRequires:=ReqList;
  1121. end;
  1122. function TFPCMake.CheckLibcRequire:boolean;
  1123. var
  1124. i : integer;
  1125. RSec : TFPCMakeSection;
  1126. t : tos;
  1127. c : tcpu;
  1128. begin
  1129. Result:=false;
  1130. if GetVariable('require_libc',false)<>'' then
  1131. begin
  1132. Result:=true;
  1133. exit;
  1134. end;
  1135. { for LLVM compiler support, and dwarf eh }
  1136. for c:=succ(low(tcpu)) to high(tcpu) do
  1137. if FIncludeTargets[c,linux] then
  1138. begin
  1139. Result:=true;
  1140. exit;
  1141. end;
  1142. for c:=succ(low(tcpu)) to high(tcpu) do
  1143. for t:=succ(low(tos)) to high(tos) do
  1144. if FIncludeTargets[c,t] then
  1145. begin
  1146. for i:=0 to RequireList[c,t].Count-1 do
  1147. begin
  1148. RSec:=TFPCMakeSection(FSections[RequireList[c,t][i]+'_require']);
  1149. if assigned(RSec) then
  1150. begin
  1151. if RSec['libc']<>'' then
  1152. begin
  1153. Result:=true;
  1154. exit;
  1155. end;
  1156. end;
  1157. end;
  1158. end;
  1159. end;
  1160. procedure TFPCMake.AddFPCDefaultVariables;
  1161. var
  1162. cpu : TCpu;
  1163. hs,s : string;
  1164. begin
  1165. { Already set FPCDIR }
  1166. hs:='';
  1167. s:=GetVariable('FPCDIR',false);
  1168. if s<>'' then
  1169. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  1170. { Load from environment }
  1171. if hs='' then
  1172. begin
  1173. s:=GetEnv('FPCDIR');
  1174. if s<>'' then
  1175. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  1176. end;
  1177. { default_fpcdir }
  1178. if hs='' then
  1179. begin
  1180. s:=GetVariable('default_fpcdir',true);
  1181. { add the current subdir to relative paths }
  1182. if s<>'' then
  1183. begin
  1184. {$ifdef UNIX}
  1185. if (s[1]<>'/') then
  1186. {$else}
  1187. if ((length(s)>2) and (s[2]<>':')) or (length(s)<=2) then
  1188. {$endif}
  1189. s:=ExtractFilePath(FFileName)+s;
  1190. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  1191. end
  1192. end;
  1193. { OS defaults }
  1194. if hs='' then
  1195. begin
  1196. {$ifdef UNIX}
  1197. {$ifndef NO_UNIX_UNIT}
  1198. cpu := succ(low(TCpu));
  1199. while(cpuStr[cpu] <> {$I %FPCTARGETCPU%}) do begin
  1200. Inc(cpu);
  1201. if cpu > high(TCpu) then
  1202. raise Exception.Create('Internal error');
  1203. end;
  1204. if FileExists('/usr/local/bin/ppc' + ppcSuffix[cpu]) then
  1205. begin
  1206. s:=ExtractFilePath({$ifdef ver1_0}ReadLink{$else}fpReadlink{$endif}('/usr/local/bin/ppc' + ppcSuffix[cpu]));
  1207. if s<>'' then
  1208. begin
  1209. if s[length(s)]='/' then
  1210. delete(s,length(s),1);
  1211. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  1212. end;
  1213. end;
  1214. if hs='' then
  1215. begin
  1216. if FileExists('/usr/bin/ppc' + ppcSuffix[cpu]) then
  1217. begin
  1218. s:=ExtractFilePath({$ifdef ver1_0}ReadLink{$else}fpReadLink{$endif}('/usr/bin/ppc' + ppcSuffix[cpu]));
  1219. if s<>'' then
  1220. begin
  1221. if s[length(s)]='/' then
  1222. delete(s,length(s),1);
  1223. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  1224. end;
  1225. end;
  1226. end;
  1227. {$endif}
  1228. {$else UNIX}
  1229. hs:=ExtractFilePath(FSearch('ppc386.exe',getenv('PATH')));
  1230. if hs<>'' then
  1231. begin
  1232. s:=hs+'/..';
  1233. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  1234. if hs='' then
  1235. begin
  1236. s:=s+'/..';
  1237. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  1238. end;
  1239. end;
  1240. if hs='' then
  1241. s:='c:/pp';
  1242. {$endif UNIX}
  1243. end;
  1244. SetVariable('FPCDIR',s,false);
  1245. { PACKAGESDIR }
  1246. if GetVariable('PACKAGESDIR',false)='' then
  1247. SetVariable('PACKAGESDIR','$(FPCDIR) $(FPCDIR)/packages',false);
  1248. { UNITSDIR }
  1249. if GetVariable('UNITSDIR',false)='' then
  1250. SetVariable('UNITSDIR','$(FPCDIR)/units/$(FULLTARGET)',false);
  1251. { BASEDIR }
  1252. SetVariable('BASEDIR',GetCurrentDir,false);
  1253. end;
  1254. procedure TFPCMake.AddLCLDefaultVariables;
  1255. var
  1256. hs,s : string;
  1257. begin
  1258. { Already set LCLDIR }
  1259. hs:=SubstVariables('$(wildcard $(LCLDIR)/units)');
  1260. { Load from environment }
  1261. if hs='' then
  1262. begin
  1263. SetVariable('LCLDIR',GetEnv('LCLDIR'),false);
  1264. hs:=SubstVariables('$(wildcard $(LCLDIR)/units)');
  1265. end;
  1266. { default_lcldir }
  1267. if hs='' then
  1268. begin
  1269. s:=GetVariable('default_lcldir',true);
  1270. { add the current subdir to relative paths }
  1271. if s<>'' then
  1272. begin
  1273. {$ifdef UNIX}
  1274. if (s[1]<>'/') then
  1275. {$else}
  1276. if ((length(s)>2) and (s[2]<>':')) or (length(s)<=2) then
  1277. {$endif}
  1278. s:=ExtractFilePath(FFileName)+s;
  1279. SetVariable('LCLDIR',s,false);
  1280. hs:=SubstVariables('$(wildcard $(LCLDIR)/units)');
  1281. end
  1282. end;
  1283. { OS defaults }
  1284. if hs='' then
  1285. begin
  1286. hs:=SubstVariables('$(subst /units,,$(firstword $(wildcard $(addsuffix /units,$(BASEDIR)/lcl $(BASEDIR)))))');
  1287. if hs<>'' then
  1288. SetVariable('LCLDIR',hs,false);
  1289. end;
  1290. {$ifdef UNIX}
  1291. if hs='' then
  1292. begin
  1293. hs:=SubstVariables('$(subst /units,,$(firstword $(wildcard $(addsuffix /lib/lazarus/units,/usr/local /usr))))');
  1294. if hs<>'' then
  1295. SetVariable('LCLDIR',hs,false);
  1296. end;
  1297. {$endif UNIX}
  1298. { Add components to PACKAGESDIR }
  1299. SetVariable('PACKAGESDIR',SubstVariables('$(wildcard $(LCLDIR)/.. $(LCLDIR)/../components $(LCLDIR)/components)'),true);
  1300. end;
  1301. function TFPCMake.SubstVariables(const s:string):string;
  1302. function Expect(var s:string;c:char):boolean;
  1303. begin
  1304. if (s<>'') and (s[1]=c) then
  1305. begin
  1306. Delete(s,1,1);
  1307. Result:=true;
  1308. end
  1309. else
  1310. begin
  1311. Verbose(FPCMakeError,'Error "'+c+'" expected');
  1312. Result:=false;
  1313. end;
  1314. end;
  1315. function GetVar(var s:string;untilc:char):string;
  1316. var
  1317. i,j,k : integer;
  1318. first : boolean;
  1319. func,
  1320. tok,s1,s2,s3 : string;
  1321. Sec : TFPCMakeSection;
  1322. begin
  1323. Result:='';
  1324. repeat
  1325. j:=Pos(untilc,s);
  1326. if j=0 then
  1327. j:=Length(s)+1;
  1328. i:=Pos('$(',s);
  1329. if (j<i) or (i=0) then
  1330. break;
  1331. Result:=Result+Copy(s,1,i-1);
  1332. Delete(s,1,i+1);
  1333. { Maybe Function ? }
  1334. j:=Pos(')',s);
  1335. if j=0 then
  1336. j:=Length(s)+1;
  1337. i:=Pos(' ',s);
  1338. if i=0 then
  1339. i:=Length(s)+1;
  1340. if i<j then
  1341. begin
  1342. { It's a function }
  1343. Func:=Copy(s,1,i-1);
  1344. //writeln('func: ',func);
  1345. { $(wildcard <list>) }
  1346. if Func='wildcard' then
  1347. begin
  1348. Delete(s,1,9);
  1349. s1:=GetVar(s,')');
  1350. Expect(s,')');
  1351. first:=true;
  1352. repeat
  1353. tok:=GetToken(s1,' ');
  1354. if tok='' then
  1355. break;
  1356. if PathOrFileExists(tok) then
  1357. begin
  1358. if not first then
  1359. Result:=Result+' '
  1360. else
  1361. first:=false;
  1362. Result:=Result+tok;
  1363. end;
  1364. until false;
  1365. end
  1366. { $(addprefix <suffix>,<list>) }
  1367. else if Func='addprefix' then
  1368. begin
  1369. Delete(s,1,10);
  1370. s1:=GetVar(s,',');
  1371. if Expect(s,',') then
  1372. begin
  1373. s2:=GetVar(s,')');
  1374. Expect(s,')');
  1375. end;
  1376. first:=true;
  1377. repeat
  1378. tok:=GetToken(s2,' ');
  1379. if tok='' then
  1380. break;
  1381. if not first then
  1382. Result:=Result+' '
  1383. else
  1384. first:=false;
  1385. Result:=Result+s1+tok;
  1386. until false;
  1387. end
  1388. { $(addsuffix <suffix>,<list>) }
  1389. else if Func='addsuffix' then
  1390. begin
  1391. Delete(s,1,10);
  1392. s1:=GetVar(s,',');
  1393. if Expect(s,',') then
  1394. begin
  1395. s2:=GetVar(s,')');
  1396. Expect(s,')');
  1397. end;
  1398. first:=true;
  1399. repeat
  1400. tok:=GetToken(s2,' ');
  1401. if tok='' then
  1402. break;
  1403. if not first then
  1404. Result:=Result+' '
  1405. else
  1406. first:=false;
  1407. Result:=Result+tok+s1;
  1408. until false;
  1409. end
  1410. { $(firstword <list>) }
  1411. else if Func='firstword' then
  1412. begin
  1413. Delete(s,1,10);
  1414. s1:=GetVar(s,')');
  1415. Expect(s,')');
  1416. Result:=GetToken(s1,' ');
  1417. end
  1418. { $(subst <oldpat>,<newpat>,<string>) }
  1419. else if Func='subst' then
  1420. begin
  1421. Delete(s,1,6);
  1422. s1:=GetVar(s,',');
  1423. if Expect(s,',') then
  1424. begin
  1425. s2:=GetVar(s,',');
  1426. if Expect(s,',') then
  1427. begin
  1428. s3:=GetVar(s,')');
  1429. Expect(s,')');
  1430. end;
  1431. end;
  1432. Result:=StringReplace(s3,s1,s2,[rfReplaceAll]);
  1433. end;
  1434. end
  1435. else
  1436. begin
  1437. s2:=Copy(s,1,j-1);
  1438. Delete(s,1,j);
  1439. k:=pos('_',s2);
  1440. if k>0 then
  1441. begin
  1442. s3:=LowerCase(Copy(s2,k+1,Length(s2)-k));
  1443. s2:=LowerCase(Copy(s2,1,k-1));
  1444. Sec:=TFPCMakeSection(Section[s2]);
  1445. if assigned(Sec) then
  1446. s2:=Sec[s3]
  1447. else
  1448. s2:='';
  1449. end
  1450. else
  1451. s2:=Variables[s2];
  1452. Insert(s2,s,1);
  1453. end;
  1454. until false;
  1455. Result:=Result+Copy(s,1,j-1);
  1456. Delete(s,1,j-1);
  1457. end;
  1458. var
  1459. s1 : string;
  1460. begin
  1461. //writeln('S: ',s);
  1462. s1:=s;
  1463. Result:=GetVar(s1,#0);
  1464. //writeln('R: ',result);
  1465. end;
  1466. function TFPCMake.GetVariable(const inivar:string;dosubst:boolean):string;
  1467. var
  1468. Sec : TFPCMakeSection;
  1469. Dic : TKeyValue;
  1470. i : integer;
  1471. begin
  1472. Result:='';
  1473. i:=Pos('_',inivar);
  1474. if i<>0 then
  1475. begin
  1476. Sec:=TFPCMakeSection(FSections[Copy(Inivar,1,i-1)]);
  1477. if assigned(Sec) then
  1478. begin
  1479. if not assigned(Sec.Dictionary) then
  1480. Sec.ParseIni;
  1481. Dic:=TKeyValue(Sec.Dictionary);
  1482. Result:=Dic[Copy(IniVar,i+1,Length(IniVar)-i)];
  1483. end
  1484. else
  1485. exit;
  1486. end
  1487. else
  1488. Result:=Variables[IniVar];
  1489. { Substition asked ? }
  1490. if dosubst then
  1491. Result:=SubstVariables(Result);
  1492. end;
  1493. function TFPCMake.GetTargetVariable(c:TCPU;t:TOS;const inivar:string;dosubst:boolean):string;
  1494. begin
  1495. result:=Trim(GetVariable(inivar,dosubst)+' '+
  1496. GetVariable(inivar+cpusuffix[c],dosubst)+' '+
  1497. GetVariable(inivar+OSSuffix[t],dosubst)+' '+
  1498. GetVariable(inivar+CpuSuffix[c]+OSSuffix[t],dosubst)+' '+
  1499. GetVariable(inivar+OSSuffix[t]+cpusuffix[c],dosubst));
  1500. end;
  1501. function TFPCMake.HasVariable(const inivar:string):boolean;
  1502. begin
  1503. Result:=(GetVariable(IniVar,false)<>'');
  1504. end;
  1505. function TFPCMake.HasTargetVariable(const inivar:string):boolean;
  1506. var
  1507. c:TCPU;
  1508. t:TOS;
  1509. begin
  1510. result:=false;
  1511. for c:=succ(low(tcpu)) to high(tcpu) do
  1512. for t:=succ(low(tos)) to high(tos) do
  1513. if FIncludeTargets[c,t] then
  1514. begin
  1515. if (GetVariable(inivar,false)<>'') or
  1516. (GetVariable(inivar+cpusuffix[c],false)<>'') or
  1517. (GetVariable(inivar+OSSuffix[t],false)<>'') or
  1518. (GetVariable(inivar+CpuSuffix[c]+OSSuffix[t],false)<>'') or
  1519. (GetVariable(inivar+OSSuffix[t]+cpusuffix[c],false)<>'') then
  1520. begin
  1521. result:=true;
  1522. exit;
  1523. end;
  1524. end;
  1525. end;
  1526. function TFPCMake.SetVariable(const inivar,value:string;add:boolean):string;
  1527. var
  1528. Sec : TFPCMakeSection;
  1529. P : TKeyValueItem;
  1530. i : integer;
  1531. tempval,key : string;
  1532. begin
  1533. Result:='';
  1534. i:=Pos('_',inivar);
  1535. if i<>0 then
  1536. begin
  1537. Sec:=TFPCMakeSection(FSections[Copy(Inivar,1,i-1)]);
  1538. if Sec=nil then
  1539. Sec:=TFPCMakeSection(FSections.Insert(TFPCMakeSection.CreateKeyValue(Copy(Inivar,1,i-1))));
  1540. key:=Copy(IniVar,i+1,Length(IniVar)-i);
  1541. p:=TKeyValueItem(Sec.Dictionary.Search(Key));
  1542. if assigned(p) then
  1543. begin
  1544. if Add then
  1545. AddToken(p.FValue,Value,' ')
  1546. else
  1547. p.Value:=Value;
  1548. end
  1549. else
  1550. TKeyValue(Sec.Dictionary).Add(key,value);
  1551. end
  1552. else
  1553. begin
  1554. if Add then
  1555. begin
  1556. tempval:=Variables[IniVar];
  1557. AddToken(tempval,Value,' ');
  1558. Variables[IniVar]:=tempval;
  1559. end
  1560. else
  1561. Variables[IniVar]:=Value;
  1562. end;
  1563. end;
  1564. procedure TFPCMake.ParseSec(p:TDictionaryItem);
  1565. begin
  1566. TFPCMakeSection(p).ParseIni;
  1567. end;
  1568. procedure TFPCMake.PrintSec(p:TDictionaryItem);
  1569. var
  1570. i : integer;
  1571. begin
  1572. with TFPCMakeSection(p) do
  1573. begin
  1574. Verbose(FPCMakeDebug,'['+Name+']');
  1575. if assigned(FList) then
  1576. begin
  1577. Verbose(FPCMakeDebug,' List:');
  1578. for i:=0 to FList.Count-1 do
  1579. Verbose(FPCMakeDebug,' "'+FList[i]+'"');
  1580. if assigned(FDictionary) then
  1581. Verbose(FPCMakeDebug,'');
  1582. end;
  1583. if assigned(FDictionary) then
  1584. begin
  1585. Verbose(FPCMakeDebug,' Dictionary:');
  1586. FDictionary.Foreach(@PrintDic);
  1587. end;
  1588. end;
  1589. end;
  1590. procedure TFPCMake.PrintDic(p:TDictionaryItem);
  1591. begin
  1592. with TKeyValueItem(p) do
  1593. begin
  1594. Verbose(FPCMakeDebug,' '+name+' = "'+value+'"');
  1595. end;
  1596. end;
  1597. procedure TFPCMake.Print;
  1598. begin
  1599. { global variables }
  1600. Verbose(FPCMakeDebug,'[global variables]');
  1601. Verbose(FPCMakeDebug,' Dictionary:');
  1602. Variables.Foreach(@PrintDic);
  1603. { sections }
  1604. FSections.Foreach(@PrintSec);
  1605. end;
  1606. function TFPCMake.GetSec(const AName:string):TDictionaryItem;
  1607. begin
  1608. GetSec:=FSections.Search(AName);
  1609. end;
  1610. {$ifdef TEST_FPMKUNIT}
  1611. begin
  1612. OSCpuPossible := TOSCpuPossible(fpmkunit.OSCPUSupported);
  1613. {$endif}
  1614. end.