fpcmmain.pp 63 KB

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