fpcmmain.pp 59 KB

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