2
0

fpcmmain.pp 63 KB

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