fpcmmain.pp 64 KB

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