fpcmmain.pp 63 KB

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