fpcmmain.pp 63 KB

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