cmMakefile.cxx 129 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmConfigure.h" // IWYU pragma: keep
  4. #include "cmMakefile.h"
  5. #include <algorithm>
  6. #include <cassert>
  7. #include <cctype>
  8. #include <cstdio>
  9. #include <cstdlib>
  10. #include <cstring>
  11. #include <sstream>
  12. #include <utility>
  13. #include <cm/iterator>
  14. #include <cm/memory>
  15. #include <cm/optional>
  16. #include <cm/type_traits> // IWYU pragma: keep
  17. #include <cm/vector>
  18. #include <cmext/algorithm>
  19. #include <cmext/string_view>
  20. #ifndef CMAKE_BOOTSTRAP
  21. # include <cm3p/json/value.h>
  22. # include <cm3p/json/writer.h>
  23. #endif
  24. #include "cmsys/FStream.hxx"
  25. #include "cmsys/RegularExpression.hxx"
  26. #include "cmCustomCommand.h"
  27. #include "cmCustomCommandLines.h"
  28. #include "cmCustomCommandTypes.h"
  29. #include "cmExecutionStatus.h"
  30. #include "cmExpandedCommandArgument.h" // IWYU pragma: keep
  31. #include "cmExportBuildFileGenerator.h"
  32. #include "cmFileLockPool.h"
  33. #include "cmFunctionBlocker.h"
  34. #include "cmGeneratedFileStream.h"
  35. #include "cmGeneratorExpression.h"
  36. #include "cmGeneratorExpressionEvaluationFile.h"
  37. #include "cmGlobalGenerator.h"
  38. #include "cmInstallGenerator.h" // IWYU pragma: keep
  39. #include "cmInstallSubdirectoryGenerator.h"
  40. #include "cmList.h"
  41. #include "cmListFileCache.h"
  42. #include "cmLocalGenerator.h"
  43. #include "cmMessageType.h"
  44. #include "cmRange.h"
  45. #include "cmSourceFile.h"
  46. #include "cmSourceFileLocation.h"
  47. #include "cmState.h"
  48. #include "cmStateDirectory.h"
  49. #include "cmStateTypes.h"
  50. #include "cmStringAlgorithms.h"
  51. #include "cmSystemTools.h"
  52. #include "cmTarget.h"
  53. #include "cmTargetLinkLibraryType.h"
  54. #include "cmTest.h"
  55. #include "cmTestGenerator.h" // IWYU pragma: keep
  56. #include "cmVersion.h"
  57. #include "cmWorkingDirectory.h"
  58. #include "cmake.h"
  59. #ifndef CMAKE_BOOTSTRAP
  60. # include "cmMakefileProfilingData.h"
  61. # include "cmVariableWatch.h"
  62. #endif
  63. #ifdef CMake_ENABLE_DEBUGGER
  64. # include "cmDebuggerAdapter.h"
  65. #endif
  66. #ifndef __has_feature
  67. # define __has_feature(x) 0
  68. #endif
  69. // Select a recursion limit that fits within the stack size.
  70. // See stack size flags in '../CompileFlags.cmake'.
  71. #ifndef CMake_DEFAULT_RECURSION_LIMIT
  72. # if __has_feature(address_sanitizer)
  73. # define CMake_DEFAULT_RECURSION_LIMIT 400
  74. # elif defined(_MSC_VER) && defined(_DEBUG)
  75. # define CMake_DEFAULT_RECURSION_LIMIT 600
  76. # elif defined(__ibmxl__) && defined(__linux)
  77. # define CMake_DEFAULT_RECURSION_LIMIT 600
  78. # else
  79. # define CMake_DEFAULT_RECURSION_LIMIT 1000
  80. # endif
  81. #endif
  82. class cmMessenger;
  83. cmDirectoryId::cmDirectoryId(std::string s)
  84. : String(std::move(s))
  85. {
  86. }
  87. // default is not to be building executables
  88. cmMakefile::cmMakefile(cmGlobalGenerator* globalGenerator,
  89. cmStateSnapshot const& snapshot)
  90. : GlobalGenerator(globalGenerator)
  91. , StateSnapshot(snapshot)
  92. {
  93. this->IsSourceFileTryCompile = false;
  94. this->CheckSystemVars = this->GetCMakeInstance()->GetCheckSystemVars();
  95. // Setup the default include complaint regular expression (match nothing).
  96. this->ComplainFileRegularExpression = "^$";
  97. this->DefineFlags = " ";
  98. this->cmDefineRegex.compile("#([ \t]*)cmakedefine[ \t]+([A-Za-z_0-9]*)");
  99. this->cmDefine01Regex.compile("#([ \t]*)cmakedefine01[ \t]+([A-Za-z_0-9]*)");
  100. this->cmNamedCurly.compile("^[A-Za-z0-9/_.+-]+{");
  101. this->StateSnapshot =
  102. this->StateSnapshot.GetState()->CreatePolicyScopeSnapshot(
  103. this->StateSnapshot);
  104. // Enter a policy level for this directory.
  105. this->PushPolicy();
  106. // push empty loop block
  107. this->PushLoopBlockBarrier();
  108. // By default the check is not done. It is enabled by
  109. // cmMakefile::Configure in the top level if necessary.
  110. this->CheckCMP0000 = false;
  111. #if !defined(CMAKE_BOOTSTRAP)
  112. this->AddSourceGroup("", "^.*$");
  113. this->AddSourceGroup("Source Files", CM_SOURCE_REGEX);
  114. this->AddSourceGroup("Header Files", CM_HEADER_REGEX);
  115. this->AddSourceGroup("Precompile Header File", CM_PCH_REGEX);
  116. this->AddSourceGroup("CMake Rules", "\\.rule$");
  117. this->AddSourceGroup("Resources", CM_RESOURCE_REGEX);
  118. this->AddSourceGroup("Object Files", "\\.(lo|o|obj)$");
  119. this->ObjectLibrariesSourceGroupIndex = this->SourceGroups.size();
  120. this->SourceGroups.emplace_back("Object Libraries", "^MATCH_NO_SOURCES$");
  121. #endif
  122. }
  123. cmMakefile::~cmMakefile() = default;
  124. cmDirectoryId cmMakefile::GetDirectoryId() const
  125. {
  126. // Use the instance pointer value to uniquely identify this directory.
  127. // If we ever need to expose this to CMake language code we should
  128. // add a read-only property in cmMakefile::GetProperty.
  129. char buf[32];
  130. snprintf(buf, sizeof(buf), "(%p)",
  131. static_cast<void const*>(this)); // cast avoids format warning
  132. return std::string(buf);
  133. }
  134. void cmMakefile::IssueMessage(MessageType t, std::string const& text) const
  135. {
  136. if (!this->ExecutionStatusStack.empty()) {
  137. if ((t == MessageType::FATAL_ERROR) ||
  138. (t == MessageType::INTERNAL_ERROR)) {
  139. this->ExecutionStatusStack.back()->SetNestedError();
  140. }
  141. }
  142. this->GetCMakeInstance()->IssueMessage(t, text, this->Backtrace);
  143. }
  144. Message::LogLevel cmMakefile::GetCurrentLogLevel() const
  145. {
  146. cmake const* cmakeInstance = this->GetCMakeInstance();
  147. Message::LogLevel const logLevelCliOrDefault = cmakeInstance->GetLogLevel();
  148. assert("Expected a valid log level here" &&
  149. logLevelCliOrDefault != Message::LogLevel::LOG_UNDEFINED);
  150. Message::LogLevel result = logLevelCliOrDefault;
  151. // If the log-level was set via the command line option, it takes precedence
  152. // over the CMAKE_MESSAGE_LOG_LEVEL variable.
  153. if (!cmakeInstance->WasLogLevelSetViaCLI()) {
  154. Message::LogLevel const logLevelFromVar = cmake::StringToLogLevel(
  155. this->GetSafeDefinition("CMAKE_MESSAGE_LOG_LEVEL"));
  156. if (logLevelFromVar != Message::LogLevel::LOG_UNDEFINED) {
  157. result = logLevelFromVar;
  158. }
  159. }
  160. return result;
  161. }
  162. void cmMakefile::IssueInvalidTargetNameError(
  163. std::string const& targetName) const
  164. {
  165. this->IssueMessage(
  166. MessageType::FATAL_ERROR,
  167. cmStrCat("The target name \"", targetName,
  168. "\" is reserved or not valid for certain "
  169. "CMake features, such as generator expressions, and may result "
  170. "in undefined behavior."));
  171. }
  172. void cmMakefile::MaybeWarnCMP0074(std::string const& rootVar, cmValue rootDef,
  173. cm::optional<std::string> const& rootEnv)
  174. {
  175. // Warn if a <PackageName>_ROOT variable we may use is set.
  176. if ((rootDef || rootEnv) && this->WarnedCMP0074.insert(rootVar).second) {
  177. auto e = cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0074), '\n');
  178. if (rootDef) {
  179. e += cmStrCat("CMake variable ", rootVar, " is set to:\n ", *rootDef,
  180. '\n');
  181. }
  182. if (rootEnv) {
  183. e += cmStrCat("Environment variable ", rootVar, " is set to:\n ",
  184. *rootEnv, '\n');
  185. }
  186. e += "For compatibility, CMake is ignoring the variable.";
  187. this->IssueMessage(MessageType::AUTHOR_WARNING, e);
  188. }
  189. }
  190. void cmMakefile::MaybeWarnCMP0144(std::string const& rootVar, cmValue rootDef,
  191. cm::optional<std::string> const& rootEnv)
  192. {
  193. // Warn if a <PACKAGENAME>_ROOT variable we may use is set.
  194. if ((rootDef || rootEnv) && this->WarnedCMP0144.insert(rootVar).second) {
  195. auto e = cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0144), '\n');
  196. if (rootDef) {
  197. e += cmStrCat("CMake variable ", rootVar, " is set to:\n ", *rootDef,
  198. '\n');
  199. }
  200. if (rootEnv) {
  201. e += cmStrCat("Environment variable ", rootVar, " is set to:\n ",
  202. *rootEnv, '\n');
  203. }
  204. e += "For compatibility, find_package is ignoring the variable, but "
  205. "code in a .cmake module might still use it.";
  206. this->IssueMessage(MessageType::AUTHOR_WARNING, e);
  207. }
  208. }
  209. cmBTStringRange cmMakefile::GetIncludeDirectoriesEntries() const
  210. {
  211. return this->StateSnapshot.GetDirectory().GetIncludeDirectoriesEntries();
  212. }
  213. cmBTStringRange cmMakefile::GetCompileOptionsEntries() const
  214. {
  215. return this->StateSnapshot.GetDirectory().GetCompileOptionsEntries();
  216. }
  217. cmBTStringRange cmMakefile::GetCompileDefinitionsEntries() const
  218. {
  219. return this->StateSnapshot.GetDirectory().GetCompileDefinitionsEntries();
  220. }
  221. cmBTStringRange cmMakefile::GetLinkOptionsEntries() const
  222. {
  223. return this->StateSnapshot.GetDirectory().GetLinkOptionsEntries();
  224. }
  225. cmBTStringRange cmMakefile::GetLinkDirectoriesEntries() const
  226. {
  227. return this->StateSnapshot.GetDirectory().GetLinkDirectoriesEntries();
  228. }
  229. cmListFileBacktrace cmMakefile::GetBacktrace() const
  230. {
  231. return this->Backtrace;
  232. }
  233. cmFindPackageStack cmMakefile::GetFindPackageStack() const
  234. {
  235. return this->FindPackageStack;
  236. }
  237. void cmMakefile::PrintCommandTrace(cmListFileFunction const& lff,
  238. cmListFileBacktrace const& bt,
  239. CommandMissingFromStack missing) const
  240. {
  241. // Check if current file in the list of requested to trace...
  242. std::vector<std::string> const& trace_only_this_files =
  243. this->GetCMakeInstance()->GetTraceSources();
  244. std::string const& full_path = bt.Top().FilePath;
  245. std::string const& only_filename = cmSystemTools::GetFilenameName(full_path);
  246. bool trace = trace_only_this_files.empty();
  247. if (!trace) {
  248. for (std::string const& file : trace_only_this_files) {
  249. std::string::size_type const pos = full_path.rfind(file);
  250. trace = (pos != std::string::npos) &&
  251. ((pos + file.size()) == full_path.size()) &&
  252. (only_filename == cmSystemTools::GetFilenameName(file));
  253. if (trace) {
  254. break;
  255. }
  256. }
  257. // Do nothing if current file wasn't requested for trace...
  258. if (!trace) {
  259. return;
  260. }
  261. }
  262. std::vector<std::string> args;
  263. std::string temp;
  264. bool expand = this->GetCMakeInstance()->GetTraceExpand();
  265. args.reserve(lff.Arguments().size());
  266. for (cmListFileArgument const& arg : lff.Arguments()) {
  267. if (expand && arg.Delim != cmListFileArgument::Bracket) {
  268. temp = arg.Value;
  269. this->ExpandVariablesInString(temp);
  270. args.push_back(temp);
  271. } else {
  272. args.push_back(arg.Value);
  273. }
  274. }
  275. cm::optional<std::string> const& deferId = bt.Top().DeferId;
  276. std::ostringstream msg;
  277. switch (this->GetCMakeInstance()->GetTraceFormat()) {
  278. case cmake::TraceFormat::JSONv1: {
  279. #ifndef CMAKE_BOOTSTRAP
  280. Json::Value val;
  281. Json::StreamWriterBuilder builder;
  282. builder["indentation"] = "";
  283. val["file"] = full_path;
  284. val["line"] = static_cast<Json::Value::Int64>(lff.Line());
  285. if (lff.Line() != lff.LineEnd()) {
  286. val["line_end"] = static_cast<Json::Value::Int64>(lff.LineEnd());
  287. }
  288. if (deferId) {
  289. val["defer"] = *deferId;
  290. }
  291. val["cmd"] = lff.OriginalName();
  292. val["args"] = Json::Value(Json::arrayValue);
  293. for (std::string const& arg : args) {
  294. val["args"].append(arg);
  295. }
  296. val["time"] = cmSystemTools::GetTime();
  297. val["frame"] = int(missing == CommandMissingFromStack::Yes) +
  298. static_cast<Json::Value::UInt64>(this->ExecutionStatusStack.size());
  299. val["global_frame"] = int(missing == CommandMissingFromStack::Yes) +
  300. static_cast<Json::Value::UInt64>(this->RecursionDepth);
  301. msg << Json::writeString(builder, val);
  302. #endif
  303. break;
  304. }
  305. case cmake::TraceFormat::Human:
  306. msg << full_path << '(' << lff.Line() << "):";
  307. if (deferId) {
  308. msg << "DEFERRED:" << *deferId << ':';
  309. }
  310. msg << " " << lff.OriginalName() << '(';
  311. for (std::string const& arg : args) {
  312. msg << arg << ' ';
  313. }
  314. msg << ')';
  315. break;
  316. case cmake::TraceFormat::Undefined:
  317. msg << "INTERNAL ERROR: Trace format is Undefined";
  318. break;
  319. }
  320. auto& f = this->GetCMakeInstance()->GetTraceFile();
  321. if (f) {
  322. f << msg.str() << '\n';
  323. } else {
  324. cmSystemTools::Message(msg.str());
  325. }
  326. }
  327. cmMakefile::CallRAII::CallRAII(cmMakefile* mf, std::string const& file,
  328. cmExecutionStatus& status)
  329. : CallRAII(mf, cmListFileContext::FromListFilePath(file), status)
  330. {
  331. }
  332. cmMakefile::CallRAII::CallRAII(cmMakefile* mf, cmListFileContext const& lfc,
  333. cmExecutionStatus& status)
  334. : Makefile{ mf }
  335. {
  336. this->Makefile->Backtrace = this->Makefile->Backtrace.Push(lfc);
  337. ++this->Makefile->RecursionDepth;
  338. this->Makefile->ExecutionStatusStack.push_back(&status);
  339. }
  340. cmMakefile::CallRAII::~CallRAII()
  341. {
  342. if (this->Makefile) {
  343. this->Detach();
  344. }
  345. }
  346. cmMakefile* cmMakefile::CallRAII::Detach()
  347. {
  348. assert(this->Makefile);
  349. this->Makefile->ExecutionStatusStack.pop_back();
  350. --this->Makefile->RecursionDepth;
  351. this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
  352. auto* const mf = this->Makefile;
  353. this->Makefile = nullptr;
  354. return mf;
  355. }
  356. // Helper class to make sure the call stack is valid.
  357. class cmMakefile::CallScope : public CallRAII
  358. {
  359. public:
  360. CallScope(cmMakefile* mf, cmListFileFunction const& lff,
  361. cm::optional<std::string> deferId, cmExecutionStatus& status)
  362. : CallScope{ mf, lff,
  363. cmListFileContext::FromListFileFunction(
  364. lff, mf->StateSnapshot.GetExecutionListFile(),
  365. std::move(deferId)),
  366. status }
  367. {
  368. }
  369. CallScope(cmMakefile* mf, cmListFileFunction const& lff,
  370. cmListFileContext const& lfc, cmExecutionStatus& status)
  371. : CallRAII{ mf, lfc, status }
  372. {
  373. #if !defined(CMAKE_BOOTSTRAP)
  374. this->ProfilingDataRAII =
  375. this->Makefile->GetCMakeInstance()->CreateProfilingEntry(
  376. "script", lff.LowerCaseName(), [&lff, &lfc]() -> Json::Value {
  377. Json::Value argsValue = Json::objectValue;
  378. if (!lff.Arguments().empty()) {
  379. std::string args;
  380. for (auto const& a : lff.Arguments()) {
  381. args = cmStrCat(args, args.empty() ? "" : " ", a.Value);
  382. }
  383. argsValue["functionArgs"] = args;
  384. }
  385. argsValue["location"] = cmStrCat(lfc.FilePath, ':', lfc.Line);
  386. return argsValue;
  387. });
  388. #endif
  389. #ifdef CMake_ENABLE_DEBUGGER
  390. if (this->Makefile->GetCMakeInstance()->GetDebugAdapter()) {
  391. this->Makefile->GetCMakeInstance()
  392. ->GetDebugAdapter()
  393. ->OnBeginFunctionCall(mf, lfc.FilePath, lff);
  394. }
  395. #endif
  396. }
  397. ~CallScope()
  398. {
  399. #if !defined(CMAKE_BOOTSTRAP)
  400. this->ProfilingDataRAII.reset();
  401. #endif
  402. auto* const mf = this->Detach();
  403. #ifdef CMake_ENABLE_DEBUGGER
  404. if (mf->GetCMakeInstance()->GetDebugAdapter()) {
  405. mf->GetCMakeInstance()->GetDebugAdapter()->OnEndFunctionCall();
  406. }
  407. #else
  408. static_cast<void>(mf);
  409. #endif
  410. }
  411. CallScope(CallScope const&) = delete;
  412. CallScope& operator=(CallScope const&) = delete;
  413. private:
  414. #if !defined(CMAKE_BOOTSTRAP)
  415. cm::optional<cmMakefileProfilingData::RAII> ProfilingDataRAII;
  416. #endif
  417. };
  418. void cmMakefile::OnExecuteCommand(std::function<void()> callback)
  419. {
  420. this->ExecuteCommandCallback = std::move(callback);
  421. }
  422. bool cmMakefile::ExecuteCommand(cmListFileFunction const& lff,
  423. cmExecutionStatus& status,
  424. cm::optional<std::string> deferId)
  425. {
  426. bool result = true;
  427. // quick return if blocked
  428. if (this->IsFunctionBlocked(lff, status)) {
  429. // No error.
  430. return result;
  431. }
  432. // Place this call on the call stack.
  433. CallScope stack_manager(this, lff, std::move(deferId), status);
  434. static_cast<void>(stack_manager);
  435. // Check for maximum recursion depth.
  436. size_t depthLimit = this->GetRecursionDepthLimit();
  437. if (this->RecursionDepth > depthLimit) {
  438. this->IssueMessage(
  439. MessageType::FATAL_ERROR,
  440. cmStrCat("Maximum recursion depth of ", depthLimit, " exceeded"));
  441. cmSystemTools::SetFatalErrorOccurred();
  442. return false;
  443. }
  444. // Lookup the command prototype.
  445. if (cmState::Command command =
  446. this->GetState()->GetCommandByExactName(lff.LowerCaseName())) {
  447. // Decide whether to invoke the command.
  448. if (!cmSystemTools::GetFatalErrorOccurred()) {
  449. // if trace is enabled, print out invoke information
  450. if (this->GetCMakeInstance()->GetTrace()) {
  451. this->PrintCommandTrace(lff, this->Backtrace);
  452. }
  453. // Try invoking the command.
  454. bool invokeSucceeded = command(lff.Arguments(), status);
  455. bool hadNestedError = status.GetNestedError();
  456. if (!invokeSucceeded || hadNestedError) {
  457. if (!hadNestedError) {
  458. // The command invocation requested that we report an error.
  459. std::string const error =
  460. cmStrCat(lff.OriginalName(), ' ', status.GetError());
  461. this->IssueMessage(MessageType::FATAL_ERROR, error);
  462. }
  463. result = false;
  464. if (this->GetCMakeInstance()->GetWorkingMode() != cmake::NORMAL_MODE) {
  465. cmSystemTools::SetFatalErrorOccurred();
  466. }
  467. }
  468. if (this->GetCMakeInstance()->HasScriptModeExitCode() &&
  469. this->GetCMakeInstance()->GetWorkingMode() == cmake::SCRIPT_MODE) {
  470. // pass-through the exit code from inner cmake_language(EXIT) ,
  471. // possibly from include() or similar command...
  472. status.SetExitCode(this->GetCMakeInstance()->GetScriptModeExitCode());
  473. }
  474. }
  475. } else {
  476. if (!cmSystemTools::GetFatalErrorOccurred()) {
  477. std::string error =
  478. cmStrCat("Unknown CMake command \"", lff.OriginalName(), "\".");
  479. this->IssueMessage(MessageType::FATAL_ERROR, error);
  480. result = false;
  481. cmSystemTools::SetFatalErrorOccurred();
  482. }
  483. }
  484. if (this->ExecuteCommandCallback) {
  485. this->ExecuteCommandCallback();
  486. }
  487. return result;
  488. }
  489. bool cmMakefile::IsImportedTargetGlobalScope() const
  490. {
  491. return this->CurrentImportedTargetScope == ImportedTargetScope::Global;
  492. }
  493. class cmMakefile::IncludeScope
  494. {
  495. public:
  496. IncludeScope(cmMakefile* mf, std::string const& filenametoread,
  497. bool noPolicyScope);
  498. ~IncludeScope();
  499. void Quiet() { this->ReportError = false; }
  500. IncludeScope(IncludeScope const&) = delete;
  501. IncludeScope& operator=(IncludeScope const&) = delete;
  502. private:
  503. cmMakefile* Makefile;
  504. bool NoPolicyScope;
  505. bool ReportError = true;
  506. };
  507. cmMakefile::IncludeScope::IncludeScope(cmMakefile* mf,
  508. std::string const& filenametoread,
  509. bool noPolicyScope)
  510. : Makefile(mf)
  511. , NoPolicyScope(noPolicyScope)
  512. {
  513. this->Makefile->Backtrace = this->Makefile->Backtrace.Push(
  514. cmListFileContext::FromListFilePath(filenametoread));
  515. this->Makefile->PushFunctionBlockerBarrier();
  516. this->Makefile->StateSnapshot =
  517. this->Makefile->GetState()->CreateIncludeFileSnapshot(
  518. this->Makefile->StateSnapshot, filenametoread);
  519. if (!this->NoPolicyScope) {
  520. this->Makefile->PushPolicy();
  521. }
  522. }
  523. cmMakefile::IncludeScope::~IncludeScope()
  524. {
  525. if (!this->NoPolicyScope) {
  526. // Pop the scope we pushed for the script.
  527. this->Makefile->PopPolicy();
  528. }
  529. this->Makefile->PopSnapshot(this->ReportError);
  530. this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
  531. this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
  532. }
  533. bool cmMakefile::ReadDependentFile(std::string const& filename,
  534. bool noPolicyScope)
  535. {
  536. if (cmValue def = this->GetDefinition("CMAKE_CURRENT_LIST_FILE")) {
  537. this->AddDefinition("CMAKE_PARENT_LIST_FILE", *def);
  538. }
  539. std::string filenametoread = cmSystemTools::CollapseFullPath(
  540. filename, this->GetCurrentSourceDirectory());
  541. IncludeScope incScope(this, filenametoread, noPolicyScope);
  542. #ifdef CMake_ENABLE_DEBUGGER
  543. if (this->GetCMakeInstance()->GetDebugAdapter()) {
  544. this->GetCMakeInstance()->GetDebugAdapter()->OnBeginFileParse(
  545. this, filenametoread);
  546. }
  547. #endif
  548. cmListFile listFile;
  549. if (!listFile.ParseFile(filenametoread.c_str(), this->GetMessenger(),
  550. this->Backtrace)) {
  551. #ifdef CMake_ENABLE_DEBUGGER
  552. if (this->GetCMakeInstance()->GetDebugAdapter()) {
  553. this->GetCMakeInstance()->GetDebugAdapter()->OnEndFileParse();
  554. }
  555. #endif
  556. return false;
  557. }
  558. #ifdef CMake_ENABLE_DEBUGGER
  559. if (this->GetCMakeInstance()->GetDebugAdapter()) {
  560. this->GetCMakeInstance()->GetDebugAdapter()->OnEndFileParse();
  561. this->GetCMakeInstance()->GetDebugAdapter()->OnFileParsedSuccessfully(
  562. filenametoread, listFile.Functions);
  563. }
  564. #endif
  565. this->RunListFile(listFile, filenametoread);
  566. if (cmSystemTools::GetFatalErrorOccurred()) {
  567. incScope.Quiet();
  568. }
  569. return true;
  570. }
  571. class cmMakefile::ListFileScope
  572. {
  573. public:
  574. ListFileScope(cmMakefile* mf, std::string const& filenametoread)
  575. : Makefile(mf)
  576. {
  577. this->Makefile->Backtrace = this->Makefile->Backtrace.Push(
  578. cmListFileContext::FromListFilePath(filenametoread));
  579. this->Makefile->StateSnapshot =
  580. this->Makefile->GetState()->CreateInlineListFileSnapshot(
  581. this->Makefile->StateSnapshot, filenametoread);
  582. assert(this->Makefile->StateSnapshot.IsValid());
  583. this->Makefile->PushFunctionBlockerBarrier();
  584. }
  585. ~ListFileScope()
  586. {
  587. this->Makefile->PopSnapshot(this->ReportError);
  588. this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
  589. this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
  590. }
  591. void Quiet() { this->ReportError = false; }
  592. ListFileScope(ListFileScope const&) = delete;
  593. ListFileScope& operator=(ListFileScope const&) = delete;
  594. private:
  595. cmMakefile* Makefile;
  596. bool ReportError = true;
  597. };
  598. class cmMakefile::DeferScope
  599. {
  600. public:
  601. DeferScope(cmMakefile* mf, std::string const& deferredInFile)
  602. : Makefile(mf)
  603. {
  604. cmListFileContext lfc;
  605. lfc.Line = cmListFileContext::DeferPlaceholderLine;
  606. lfc.FilePath = deferredInFile;
  607. this->Makefile->Backtrace = this->Makefile->Backtrace.Push(lfc);
  608. this->Makefile->DeferRunning = true;
  609. }
  610. ~DeferScope()
  611. {
  612. this->Makefile->DeferRunning = false;
  613. this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
  614. }
  615. DeferScope(DeferScope const&) = delete;
  616. DeferScope& operator=(DeferScope const&) = delete;
  617. private:
  618. cmMakefile* Makefile;
  619. };
  620. class cmMakefile::DeferCallScope
  621. {
  622. public:
  623. DeferCallScope(cmMakefile* mf, std::string const& deferredFromFile)
  624. : Makefile(mf)
  625. {
  626. this->Makefile->StateSnapshot =
  627. this->Makefile->GetState()->CreateDeferCallSnapshot(
  628. this->Makefile->StateSnapshot, deferredFromFile);
  629. assert(this->Makefile->StateSnapshot.IsValid());
  630. }
  631. ~DeferCallScope() { this->Makefile->PopSnapshot(); }
  632. DeferCallScope(DeferCallScope const&) = delete;
  633. DeferCallScope& operator=(DeferCallScope const&) = delete;
  634. private:
  635. cmMakefile* Makefile;
  636. };
  637. bool cmMakefile::ReadListFile(std::string const& filename)
  638. {
  639. std::string filenametoread = cmSystemTools::CollapseFullPath(
  640. filename, this->GetCurrentSourceDirectory());
  641. ListFileScope scope(this, filenametoread);
  642. #ifdef CMake_ENABLE_DEBUGGER
  643. if (this->GetCMakeInstance()->GetDebugAdapter()) {
  644. this->GetCMakeInstance()->GetDebugAdapter()->OnBeginFileParse(
  645. this, filenametoread);
  646. }
  647. #endif
  648. cmListFile listFile;
  649. if (!listFile.ParseFile(filenametoread.c_str(), this->GetMessenger(),
  650. this->Backtrace)) {
  651. #ifdef CMake_ENABLE_DEBUGGER
  652. if (this->GetCMakeInstance()->GetDebugAdapter()) {
  653. this->GetCMakeInstance()->GetDebugAdapter()->OnEndFileParse();
  654. }
  655. #endif
  656. return false;
  657. }
  658. #ifdef CMake_ENABLE_DEBUGGER
  659. if (this->GetCMakeInstance()->GetDebugAdapter()) {
  660. this->GetCMakeInstance()->GetDebugAdapter()->OnEndFileParse();
  661. this->GetCMakeInstance()->GetDebugAdapter()->OnFileParsedSuccessfully(
  662. filenametoread, listFile.Functions);
  663. }
  664. #endif
  665. this->RunListFile(listFile, filenametoread);
  666. if (cmSystemTools::GetFatalErrorOccurred()) {
  667. scope.Quiet();
  668. }
  669. return true;
  670. }
  671. bool cmMakefile::ReadListFileAsString(std::string const& content,
  672. std::string const& virtualFileName)
  673. {
  674. std::string filenametoread = cmSystemTools::CollapseFullPath(
  675. virtualFileName, this->GetCurrentSourceDirectory());
  676. ListFileScope scope(this, filenametoread);
  677. cmListFile listFile;
  678. if (!listFile.ParseString(content.c_str(), virtualFileName.c_str(),
  679. this->GetMessenger(), this->Backtrace)) {
  680. return false;
  681. }
  682. #ifdef CMake_ENABLE_DEBUGGER
  683. if (this->GetCMakeInstance()->GetDebugAdapter()) {
  684. this->GetCMakeInstance()->GetDebugAdapter()->OnFileParsedSuccessfully(
  685. filenametoread, listFile.Functions);
  686. }
  687. #endif
  688. this->RunListFile(listFile, filenametoread);
  689. if (cmSystemTools::GetFatalErrorOccurred()) {
  690. scope.Quiet();
  691. }
  692. return true;
  693. }
  694. void cmMakefile::RunListFile(cmListFile const& listFile,
  695. std::string const& filenametoread,
  696. DeferCommands* defer)
  697. {
  698. // add this list file to the list of dependencies
  699. this->ListFiles.push_back(filenametoread);
  700. std::string currentParentFile =
  701. this->GetSafeDefinition("CMAKE_PARENT_LIST_FILE");
  702. std::string currentFile = this->GetSafeDefinition("CMAKE_CURRENT_LIST_FILE");
  703. this->AddDefinition("CMAKE_CURRENT_LIST_FILE", filenametoread);
  704. this->AddDefinition("CMAKE_CURRENT_LIST_DIR",
  705. cmSystemTools::GetFilenamePath(filenametoread));
  706. this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE");
  707. this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE");
  708. this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR");
  709. // Run the parsed commands.
  710. size_t const numberFunctions = listFile.Functions.size();
  711. for (size_t i = 0; i < numberFunctions; ++i) {
  712. cmExecutionStatus status(*this);
  713. this->ExecuteCommand(listFile.Functions[i], status);
  714. if (cmSystemTools::GetFatalErrorOccurred()) {
  715. break;
  716. }
  717. if (status.HasExitCode()) {
  718. // cmake_language EXIT was requested, early break.
  719. this->GetCMakeInstance()->SetScriptModeExitCode(status.GetExitCode());
  720. break;
  721. }
  722. if (status.GetReturnInvoked()) {
  723. this->RaiseScope(status.GetReturnVariables());
  724. // Exit early due to return command.
  725. break;
  726. }
  727. }
  728. // Run any deferred commands.
  729. if (defer) {
  730. // Add a backtrace level indicating calls are deferred.
  731. DeferScope scope(this, filenametoread);
  732. // Iterate by index in case one deferred call schedules another.
  733. // NOLINTNEXTLINE(modernize-loop-convert)
  734. for (size_t i = 0; i < defer->Commands.size(); ++i) {
  735. DeferCommand& d = defer->Commands[i];
  736. if (d.Id.empty()) {
  737. // Canceled.
  738. continue;
  739. }
  740. // Mark as executed.
  741. std::string id = std::move(d.Id);
  742. // The deferred call may have come from another file.
  743. DeferCallScope callScope(this, d.FilePath);
  744. cmExecutionStatus status(*this);
  745. this->ExecuteCommand(d.Command, status, std::move(id));
  746. if (cmSystemTools::GetFatalErrorOccurred()) {
  747. break;
  748. }
  749. }
  750. }
  751. this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentParentFile);
  752. this->AddDefinition("CMAKE_CURRENT_LIST_FILE", currentFile);
  753. this->AddDefinition("CMAKE_CURRENT_LIST_DIR",
  754. cmSystemTools::GetFilenamePath(currentFile));
  755. this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE");
  756. this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE");
  757. this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR");
  758. }
  759. void cmMakefile::EnforceDirectoryLevelRules() const
  760. {
  761. // Diagnose a violation of CMP0000 if necessary.
  762. if (this->CheckCMP0000) {
  763. std::string e =
  764. cmStrCat("No cmake_minimum_required command is present. "
  765. "A line of code such as\n"
  766. " cmake_minimum_required(VERSION ",
  767. cmVersion::GetMajorVersion(), '.', cmVersion::GetMinorVersion(),
  768. ")\n"
  769. "should be added at the top of the file. "
  770. "The version specified may be lower if you wish to "
  771. "support older CMake versions for this project. "
  772. "For more information run "
  773. "\"cmake --help-policy CMP0000\".");
  774. this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e,
  775. this->Backtrace);
  776. cmSystemTools::SetFatalErrorOccurred();
  777. }
  778. }
  779. void cmMakefile::AddEvaluationFile(
  780. std::string const& inputFile, std::string const& targetName,
  781. std::unique_ptr<cmCompiledGeneratorExpression> outputName,
  782. std::unique_ptr<cmCompiledGeneratorExpression> condition,
  783. std::string const& newLineCharacter, mode_t permissions, bool inputIsContent)
  784. {
  785. this->EvaluationFiles.push_back(
  786. cm::make_unique<cmGeneratorExpressionEvaluationFile>(
  787. inputFile, targetName, std::move(outputName), std::move(condition),
  788. inputIsContent, newLineCharacter, permissions,
  789. this->GetPolicyStatus(cmPolicies::CMP0070)));
  790. }
  791. std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>> const&
  792. cmMakefile::GetEvaluationFiles() const
  793. {
  794. return this->EvaluationFiles;
  795. }
  796. std::vector<std::unique_ptr<cmExportBuildFileGenerator>> const&
  797. cmMakefile::GetExportBuildFileGenerators() const
  798. {
  799. return this->ExportBuildFileGenerators;
  800. }
  801. void cmMakefile::AddExportBuildFileGenerator(
  802. std::unique_ptr<cmExportBuildFileGenerator> gen)
  803. {
  804. this->ExportBuildFileGenerators.emplace_back(std::move(gen));
  805. }
  806. namespace {
  807. struct file_not_persistent
  808. {
  809. bool operator()(std::string const& path) const
  810. {
  811. return !(path.find("CMakeTmp") == std::string::npos &&
  812. cmSystemTools::FileExists(path));
  813. }
  814. };
  815. }
  816. void cmMakefile::AddGeneratorAction(GeneratorAction&& action)
  817. {
  818. assert(!this->GeneratorActionsInvoked);
  819. this->GeneratorActions.emplace_back(std::move(action), this->Backtrace);
  820. }
  821. void cmMakefile::GeneratorAction::operator()(cmLocalGenerator& lg,
  822. cmListFileBacktrace const& lfbt,
  823. GeneratorActionWhen when)
  824. {
  825. if (this->When != when) {
  826. return;
  827. }
  828. if (cc) {
  829. CCAction(lg, lfbt, std::move(cc));
  830. } else {
  831. assert(Action);
  832. Action(lg, lfbt);
  833. }
  834. }
  835. void cmMakefile::DoGenerate(cmLocalGenerator& lg)
  836. {
  837. // give all the commands a chance to do something
  838. // after the file has been parsed before generation
  839. for (auto& action : this->GeneratorActions) {
  840. action.Value(lg, action.Backtrace, GeneratorActionWhen::AfterConfigure);
  841. }
  842. this->GeneratorActionsInvoked = true;
  843. // go through all configured files and see which ones still exist.
  844. // we don't want cmake to re-run if a configured file is created and deleted
  845. // during processing as that would make it a transient file that can't
  846. // influence the build process
  847. cm::erase_if(this->OutputFiles, file_not_persistent());
  848. // if a configured file is used as input for another configured file,
  849. // and then deleted it will show up in the input list files so we
  850. // need to scan those too
  851. cm::erase_if(this->ListFiles, file_not_persistent());
  852. }
  853. // Generate the output file
  854. void cmMakefile::Generate(cmLocalGenerator& lg)
  855. {
  856. this->DoGenerate(lg);
  857. cmValue oldValue = this->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY");
  858. if (oldValue &&
  859. cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, *oldValue,
  860. "2.4")) {
  861. this->GetCMakeInstance()->IssueMessage(
  862. MessageType::FATAL_ERROR,
  863. "You have set CMAKE_BACKWARDS_COMPATIBILITY to a CMake version less "
  864. "than 2.4. This version of CMake only supports backwards compatibility "
  865. "with CMake 2.4 or later. For compatibility with older versions please "
  866. "use any CMake 2.8.x release or lower.",
  867. this->Backtrace);
  868. }
  869. }
  870. void cmMakefile::GenerateAfterGeneratorTargets(cmLocalGenerator& lg)
  871. {
  872. for (auto& action : this->GeneratorActions) {
  873. action.Value(lg, action.Backtrace,
  874. GeneratorActionWhen::AfterGeneratorTargets);
  875. }
  876. }
  877. namespace {
  878. // There are still too many implicit backtraces through cmMakefile. As a
  879. // workaround we reset the backtrace temporarily.
  880. struct BacktraceGuard
  881. {
  882. BacktraceGuard(cmListFileBacktrace& lfbt, cmListFileBacktrace current)
  883. : Backtrace(lfbt)
  884. , Previous(lfbt)
  885. {
  886. this->Backtrace = std::move(current);
  887. }
  888. ~BacktraceGuard() { this->Backtrace = std::move(this->Previous); }
  889. private:
  890. cmListFileBacktrace& Backtrace;
  891. cmListFileBacktrace Previous;
  892. };
  893. }
  894. bool cmMakefile::ValidateCustomCommand(
  895. cmCustomCommandLines const& commandLines) const
  896. {
  897. // TODO: More strict?
  898. auto const it =
  899. std::find_if(commandLines.begin(), commandLines.end(),
  900. [](cmCustomCommandLine const& cl) {
  901. return !cl.empty() && !cl[0].empty() && cl[0][0] == '"';
  902. });
  903. if (it != commandLines.end()) {
  904. this->IssueMessage(
  905. MessageType::FATAL_ERROR,
  906. cmStrCat("COMMAND may not contain literal quotes:\n ", (*it)[0], '\n'));
  907. return false;
  908. }
  909. return true;
  910. }
  911. cmTarget* cmMakefile::GetCustomCommandTarget(
  912. std::string const& target, cmObjectLibraryCommands objLibCommands,
  913. cmListFileBacktrace const& lfbt) const
  914. {
  915. auto realTarget = target;
  916. auto ai = this->AliasTargets.find(target);
  917. if (ai != this->AliasTargets.end()) {
  918. realTarget = ai->second;
  919. }
  920. // Find the target to which to add the custom command.
  921. auto ti = this->Targets.find(realTarget);
  922. if (ti == this->Targets.end()) {
  923. std::string e;
  924. if (cmTarget const* t = this->FindTargetToUse(target)) {
  925. if (t->IsImported()) {
  926. e += cmStrCat("TARGET '", target,
  927. "' is IMPORTED and does not build here.");
  928. } else {
  929. e +=
  930. cmStrCat("TARGET '", target, "' was not created in this directory.");
  931. }
  932. } else {
  933. e += cmStrCat("No TARGET '", target,
  934. "' has been created in this directory.");
  935. }
  936. this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e, lfbt);
  937. return nullptr;
  938. }
  939. cmTarget* t = &ti->second;
  940. if (objLibCommands == cmObjectLibraryCommands::Reject &&
  941. t->GetType() == cmStateEnums::OBJECT_LIBRARY) {
  942. auto e = cmStrCat(
  943. "Target \"", target,
  944. "\" is an OBJECT library "
  945. "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands.");
  946. this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e, lfbt);
  947. return nullptr;
  948. }
  949. if (t->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
  950. auto e = cmStrCat(
  951. "Target \"", target,
  952. "\" is an INTERFACE library "
  953. "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands.");
  954. this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e, lfbt);
  955. return nullptr;
  956. }
  957. return t;
  958. }
  959. cmTarget* cmMakefile::AddCustomCommandToTarget(
  960. std::string const& target, cmCustomCommandType type,
  961. std::unique_ptr<cmCustomCommand> cc)
  962. {
  963. auto const& byproducts = cc->GetByproducts();
  964. auto const& commandLines = cc->GetCommandLines();
  965. cmTarget* t = this->GetCustomCommandTarget(
  966. target, cmObjectLibraryCommands::Reject, this->Backtrace);
  967. // Validate custom commands.
  968. if (!t || !this->ValidateCustomCommand(commandLines)) {
  969. return t;
  970. }
  971. // Always create the byproduct sources and mark them generated.
  972. this->CreateGeneratedOutputs(byproducts);
  973. cc->RecordPolicyValues(this->GetStateSnapshot());
  974. // Dispatch command creation to allow generator expressions in outputs.
  975. this->AddGeneratorAction(
  976. std::move(cc),
  977. [this, t, type](cmLocalGenerator& lg, cmListFileBacktrace const& lfbt,
  978. std::unique_ptr<cmCustomCommand> tcc) {
  979. BacktraceGuard guard(this->Backtrace, lfbt);
  980. tcc->SetBacktrace(lfbt);
  981. detail::AddCustomCommandToTarget(lg, cmCommandOrigin::Project, t, type,
  982. std::move(tcc));
  983. });
  984. return t;
  985. }
  986. void cmMakefile::AddCustomCommandToOutput(
  987. std::unique_ptr<cmCustomCommand> cc, CommandSourceCallback const& callback,
  988. bool replace)
  989. {
  990. auto const& outputs = cc->GetOutputs();
  991. auto const& byproducts = cc->GetByproducts();
  992. auto const& commandLines = cc->GetCommandLines();
  993. // Make sure there is at least one output.
  994. if (outputs.empty()) {
  995. cmSystemTools::Error("Attempt to add a custom rule with no output!");
  996. return;
  997. }
  998. // Validate custom commands.
  999. if (!this->ValidateCustomCommand(commandLines)) {
  1000. return;
  1001. }
  1002. // Always create the output sources and mark them generated.
  1003. this->CreateGeneratedOutputs(outputs);
  1004. this->CreateGeneratedOutputs(byproducts);
  1005. cc->RecordPolicyValues(this->GetStateSnapshot());
  1006. // Dispatch command creation to allow generator expressions in outputs.
  1007. this->AddGeneratorAction(
  1008. std::move(cc),
  1009. [this, replace, callback](cmLocalGenerator& lg,
  1010. cmListFileBacktrace const& lfbt,
  1011. std::unique_ptr<cmCustomCommand> tcc) {
  1012. BacktraceGuard guard(this->Backtrace, lfbt);
  1013. tcc->SetBacktrace(lfbt);
  1014. cmSourceFile* sf = detail::AddCustomCommandToOutput(
  1015. lg, cmCommandOrigin::Project, std::move(tcc), replace);
  1016. if (callback && sf) {
  1017. callback(sf);
  1018. }
  1019. });
  1020. }
  1021. void cmMakefile::AppendCustomCommandToOutput(
  1022. std::string const& output, std::vector<std::string> const& depends,
  1023. cmImplicitDependsList const& implicit_depends,
  1024. cmCustomCommandLines const& commandLines)
  1025. {
  1026. // Validate custom commands.
  1027. if (this->ValidateCustomCommand(commandLines)) {
  1028. // Dispatch command creation to allow generator expressions in outputs.
  1029. this->AddGeneratorAction(
  1030. [this, output, depends, implicit_depends,
  1031. commandLines](cmLocalGenerator& lg, cmListFileBacktrace const& lfbt) {
  1032. BacktraceGuard guard(this->Backtrace, lfbt);
  1033. detail::AppendCustomCommandToOutput(lg, lfbt, output, depends,
  1034. implicit_depends, commandLines);
  1035. });
  1036. }
  1037. }
  1038. cmTarget* cmMakefile::AddUtilityCommand(std::string const& utilityName,
  1039. bool excludeFromAll,
  1040. std::unique_ptr<cmCustomCommand> cc)
  1041. {
  1042. auto const& depends = cc->GetDepends();
  1043. auto const& byproducts = cc->GetByproducts();
  1044. auto const& commandLines = cc->GetCommandLines();
  1045. cmTarget* target = this->AddNewUtilityTarget(utilityName, excludeFromAll);
  1046. // Validate custom commands.
  1047. if ((commandLines.empty() && depends.empty()) ||
  1048. !this->ValidateCustomCommand(commandLines)) {
  1049. return target;
  1050. }
  1051. // Always create the byproduct sources and mark them generated.
  1052. this->CreateGeneratedOutputs(byproducts);
  1053. cc->RecordPolicyValues(this->GetStateSnapshot());
  1054. // Dispatch command creation to allow generator expressions in outputs.
  1055. this->AddGeneratorAction(
  1056. std::move(cc),
  1057. [this, target](cmLocalGenerator& lg, cmListFileBacktrace const& lfbt,
  1058. std::unique_ptr<cmCustomCommand> tcc) {
  1059. BacktraceGuard guard(this->Backtrace, lfbt);
  1060. tcc->SetBacktrace(lfbt);
  1061. detail::AddUtilityCommand(lg, cmCommandOrigin::Project, target,
  1062. std::move(tcc));
  1063. });
  1064. return target;
  1065. }
  1066. static void s_AddDefineFlag(std::string const& flag, std::string& dflags)
  1067. {
  1068. // remove any \n\r
  1069. std::string::size_type initSize = dflags.size();
  1070. dflags += ' ';
  1071. dflags += flag;
  1072. std::string::iterator flagStart = dflags.begin() + initSize + 1;
  1073. std::replace(flagStart, dflags.end(), '\n', ' ');
  1074. std::replace(flagStart, dflags.end(), '\r', ' ');
  1075. }
  1076. void cmMakefile::AddDefineFlag(std::string const& flag)
  1077. {
  1078. if (flag.empty()) {
  1079. return;
  1080. }
  1081. // If this is really a definition, update COMPILE_DEFINITIONS.
  1082. if (this->ParseDefineFlag(flag, false)) {
  1083. return;
  1084. }
  1085. // Add this flag that does not look like a definition.
  1086. s_AddDefineFlag(flag, this->DefineFlags);
  1087. }
  1088. static void s_RemoveDefineFlag(std::string const& flag, std::string& dflags)
  1089. {
  1090. std::string::size_type const len = flag.length();
  1091. // Remove all instances of the flag that are surrounded by
  1092. // whitespace or the beginning/end of the string.
  1093. for (std::string::size_type lpos = dflags.find(flag, 0);
  1094. lpos != std::string::npos; lpos = dflags.find(flag, lpos)) {
  1095. std::string::size_type rpos = lpos + len;
  1096. if ((lpos <= 0 || cmIsSpace(dflags[lpos - 1])) &&
  1097. (rpos >= dflags.size() || cmIsSpace(dflags[rpos]))) {
  1098. dflags.erase(lpos, len);
  1099. } else {
  1100. ++lpos;
  1101. }
  1102. }
  1103. }
  1104. void cmMakefile::RemoveDefineFlag(std::string const& flag)
  1105. {
  1106. // Check the length of the flag to remove.
  1107. if (flag.empty()) {
  1108. return;
  1109. }
  1110. // If this is really a definition, update COMPILE_DEFINITIONS.
  1111. if (this->ParseDefineFlag(flag, true)) {
  1112. return;
  1113. }
  1114. // Remove this flag that does not look like a definition.
  1115. s_RemoveDefineFlag(flag, this->DefineFlags);
  1116. }
  1117. void cmMakefile::AddCompileDefinition(std::string const& option)
  1118. {
  1119. this->AppendProperty("COMPILE_DEFINITIONS", option);
  1120. }
  1121. void cmMakefile::AddCompileOption(std::string const& option)
  1122. {
  1123. this->AppendProperty("COMPILE_OPTIONS", option);
  1124. }
  1125. void cmMakefile::AddLinkOption(std::string const& option)
  1126. {
  1127. this->AppendProperty("LINK_OPTIONS", option);
  1128. }
  1129. void cmMakefile::AddLinkDirectory(std::string const& directory, bool before)
  1130. {
  1131. if (before) {
  1132. this->StateSnapshot.GetDirectory().PrependLinkDirectoriesEntry(
  1133. BT<std::string>(directory, this->Backtrace));
  1134. } else {
  1135. this->StateSnapshot.GetDirectory().AppendLinkDirectoriesEntry(
  1136. BT<std::string>(directory, this->Backtrace));
  1137. }
  1138. }
  1139. bool cmMakefile::ParseDefineFlag(std::string const& def, bool remove)
  1140. {
  1141. // Create a regular expression to match valid definitions.
  1142. static cmsys::RegularExpression valid("^[-/]D[A-Za-z_][A-Za-z0-9_]*(=.*)?$");
  1143. // Make sure the definition matches.
  1144. if (!valid.find(def)) {
  1145. return false;
  1146. }
  1147. // Get the definition part after the flag.
  1148. char const* define = def.c_str() + 2;
  1149. if (remove) {
  1150. if (cmValue cdefs = this->GetProperty("COMPILE_DEFINITIONS")) {
  1151. // Expand the list.
  1152. cmList defs{ *cdefs };
  1153. // Recompose the list without the definition.
  1154. defs.remove_items({ define });
  1155. // Store the new list.
  1156. this->SetProperty("COMPILE_DEFINITIONS", defs.to_string());
  1157. }
  1158. } else {
  1159. // Append the definition to the directory property.
  1160. this->AppendProperty("COMPILE_DEFINITIONS", define);
  1161. }
  1162. return true;
  1163. }
  1164. void cmMakefile::InitializeFromParent(cmMakefile* parent)
  1165. {
  1166. this->SystemIncludeDirectories = parent->SystemIncludeDirectories;
  1167. // define flags
  1168. this->DefineFlags = parent->DefineFlags;
  1169. // Include transform property. There is no per-config version.
  1170. {
  1171. char const* prop = "IMPLICIT_DEPENDS_INCLUDE_TRANSFORM";
  1172. this->SetProperty(prop, parent->GetProperty(prop));
  1173. }
  1174. // labels
  1175. this->SetProperty("LABELS", parent->GetProperty("LABELS"));
  1176. // link libraries
  1177. this->SetProperty("LINK_LIBRARIES", parent->GetProperty("LINK_LIBRARIES"));
  1178. // the initial project name
  1179. this->StateSnapshot.SetProjectName(parent->StateSnapshot.GetProjectName());
  1180. // Copy include regular expressions.
  1181. this->ComplainFileRegularExpression = parent->ComplainFileRegularExpression;
  1182. // Imported targets.
  1183. this->ImportedTargets = parent->ImportedTargets;
  1184. // Non-global Alias targets.
  1185. this->AliasTargets = parent->AliasTargets;
  1186. // Recursion depth.
  1187. this->RecursionDepth = parent->RecursionDepth;
  1188. }
  1189. void cmMakefile::AddInstallGenerator(std::unique_ptr<cmInstallGenerator> g)
  1190. {
  1191. if (g) {
  1192. this->InstallGenerators.push_back(std::move(g));
  1193. }
  1194. }
  1195. void cmMakefile::AddTestGenerator(std::unique_ptr<cmTestGenerator> g)
  1196. {
  1197. if (g) {
  1198. this->TestGenerators.push_back(std::move(g));
  1199. }
  1200. }
  1201. void cmMakefile::PushFunctionScope(std::string const& fileName,
  1202. cmPolicies::PolicyMap const& pm)
  1203. {
  1204. this->StateSnapshot = this->GetState()->CreateFunctionCallSnapshot(
  1205. this->StateSnapshot, fileName);
  1206. assert(this->StateSnapshot.IsValid());
  1207. this->PushLoopBlockBarrier();
  1208. #if !defined(CMAKE_BOOTSTRAP)
  1209. this->GetGlobalGenerator()->GetFileLockPool().PushFunctionScope();
  1210. #endif
  1211. this->PushFunctionBlockerBarrier();
  1212. this->PushPolicy(true, pm);
  1213. }
  1214. void cmMakefile::PopFunctionScope(bool reportError)
  1215. {
  1216. this->PopPolicy();
  1217. this->PopSnapshot(reportError);
  1218. this->PopFunctionBlockerBarrier(reportError);
  1219. #if !defined(CMAKE_BOOTSTRAP)
  1220. this->GetGlobalGenerator()->GetFileLockPool().PopFunctionScope();
  1221. #endif
  1222. this->PopLoopBlockBarrier();
  1223. }
  1224. void cmMakefile::PushMacroScope(std::string const& fileName,
  1225. cmPolicies::PolicyMap const& pm)
  1226. {
  1227. this->StateSnapshot =
  1228. this->GetState()->CreateMacroCallSnapshot(this->StateSnapshot, fileName);
  1229. assert(this->StateSnapshot.IsValid());
  1230. this->PushFunctionBlockerBarrier();
  1231. this->PushPolicy(true, pm);
  1232. }
  1233. void cmMakefile::PopMacroScope(bool reportError)
  1234. {
  1235. this->PopPolicy();
  1236. this->PopSnapshot(reportError);
  1237. this->PopFunctionBlockerBarrier(reportError);
  1238. }
  1239. bool cmMakefile::IsRootMakefile() const
  1240. {
  1241. return !this->StateSnapshot.GetBuildsystemDirectoryParent().IsValid();
  1242. }
  1243. class cmMakefile::BuildsystemFileScope
  1244. {
  1245. public:
  1246. BuildsystemFileScope(cmMakefile* mf)
  1247. : Makefile(mf)
  1248. {
  1249. std::string currentStart =
  1250. this->Makefile->GetCMakeInstance()->GetCMakeListFile(
  1251. this->Makefile->StateSnapshot.GetDirectory().GetCurrentSource());
  1252. this->Makefile->StateSnapshot.SetListFile(currentStart);
  1253. this->Makefile->StateSnapshot =
  1254. this->Makefile->StateSnapshot.GetState()->CreatePolicyScopeSnapshot(
  1255. this->Makefile->StateSnapshot);
  1256. this->Makefile->PushFunctionBlockerBarrier();
  1257. this->GG = mf->GetGlobalGenerator();
  1258. this->CurrentMakefile = this->GG->GetCurrentMakefile();
  1259. this->Snapshot = this->GG->GetCMakeInstance()->GetCurrentSnapshot();
  1260. this->GG->GetCMakeInstance()->SetCurrentSnapshot(this->Snapshot);
  1261. this->GG->SetCurrentMakefile(mf);
  1262. #if !defined(CMAKE_BOOTSTRAP)
  1263. this->GG->GetFileLockPool().PushFileScope();
  1264. #endif
  1265. }
  1266. ~BuildsystemFileScope()
  1267. {
  1268. this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
  1269. this->Makefile->PopSnapshot(this->ReportError);
  1270. #if !defined(CMAKE_BOOTSTRAP)
  1271. this->GG->GetFileLockPool().PopFileScope();
  1272. #endif
  1273. this->GG->SetCurrentMakefile(this->CurrentMakefile);
  1274. this->GG->GetCMakeInstance()->SetCurrentSnapshot(this->Snapshot);
  1275. }
  1276. void Quiet() { this->ReportError = false; }
  1277. BuildsystemFileScope(BuildsystemFileScope const&) = delete;
  1278. BuildsystemFileScope& operator=(BuildsystemFileScope const&) = delete;
  1279. private:
  1280. cmMakefile* Makefile;
  1281. cmGlobalGenerator* GG;
  1282. cmMakefile* CurrentMakefile;
  1283. cmStateSnapshot Snapshot;
  1284. bool ReportError = true;
  1285. };
  1286. void cmMakefile::Configure()
  1287. {
  1288. std::string currentStart = this->GetCMakeInstance()->GetCMakeListFile(
  1289. this->StateSnapshot.GetDirectory().GetCurrentSource());
  1290. // Add the bottom of all backtraces within this directory.
  1291. // We will never pop this scope because it should be available
  1292. // for messages during the generate step too.
  1293. this->Backtrace =
  1294. this->Backtrace.Push(cmListFileContext::FromListFilePath(currentStart));
  1295. BuildsystemFileScope scope(this);
  1296. // make sure the CMakeFiles dir is there
  1297. std::string filesDir = cmStrCat(
  1298. this->StateSnapshot.GetDirectory().GetCurrentBinary(), "/CMakeFiles");
  1299. cmSystemTools::MakeDirectory(filesDir);
  1300. assert(cmSystemTools::FileExists(currentStart, true));
  1301. this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentStart);
  1302. #ifdef CMake_ENABLE_DEBUGGER
  1303. if (this->GetCMakeInstance()->GetDebugAdapter()) {
  1304. this->GetCMakeInstance()->GetDebugAdapter()->OnBeginFileParse(
  1305. this, currentStart);
  1306. }
  1307. #endif
  1308. cmListFile listFile;
  1309. if (!listFile.ParseFile(currentStart.c_str(), this->GetMessenger(),
  1310. this->Backtrace)) {
  1311. #ifdef CMake_ENABLE_DEBUGGER
  1312. if (this->GetCMakeInstance()->GetDebugAdapter()) {
  1313. this->GetCMakeInstance()->GetDebugAdapter()->OnEndFileParse();
  1314. }
  1315. #endif
  1316. return;
  1317. }
  1318. #ifdef CMake_ENABLE_DEBUGGER
  1319. if (this->GetCMakeInstance()->GetDebugAdapter()) {
  1320. this->GetCMakeInstance()->GetDebugAdapter()->OnEndFileParse();
  1321. this->GetCMakeInstance()->GetDebugAdapter()->OnFileParsedSuccessfully(
  1322. currentStart, listFile.Functions);
  1323. }
  1324. #endif
  1325. if (this->IsRootMakefile()) {
  1326. bool hasVersion = false;
  1327. // search for the right policy command
  1328. for (cmListFileFunction const& func : listFile.Functions) {
  1329. if (func.LowerCaseName() == "cmake_minimum_required"_s) {
  1330. hasVersion = true;
  1331. break;
  1332. }
  1333. }
  1334. // if no policy command is found this is an error if they use any
  1335. // non advanced functions or a lot of functions
  1336. if (!hasVersion) {
  1337. bool isProblem = true;
  1338. if (listFile.Functions.size() < 30) {
  1339. // the list of simple commands DO NOT ADD TO THIS LIST!!!!!
  1340. // these commands must have backwards compatibility forever and
  1341. // and that is a lot longer than your tiny mind can comprehend mortal
  1342. std::set<std::string> allowedCommands;
  1343. allowedCommands.insert("project");
  1344. allowedCommands.insert("set");
  1345. allowedCommands.insert("if");
  1346. allowedCommands.insert("endif");
  1347. allowedCommands.insert("else");
  1348. allowedCommands.insert("elseif");
  1349. allowedCommands.insert("add_executable");
  1350. allowedCommands.insert("add_library");
  1351. allowedCommands.insert("target_link_libraries");
  1352. allowedCommands.insert("option");
  1353. allowedCommands.insert("message");
  1354. isProblem = false;
  1355. for (cmListFileFunction const& func : listFile.Functions) {
  1356. if (!cm::contains(allowedCommands, func.LowerCaseName())) {
  1357. isProblem = true;
  1358. break;
  1359. }
  1360. }
  1361. }
  1362. if (isProblem) {
  1363. // Tell the top level cmMakefile to diagnose
  1364. // this violation of CMP0000.
  1365. this->SetCheckCMP0000(true);
  1366. // Implicitly set the version for the user.
  1367. cmPolicies::ApplyPolicyVersion(this, 3, 5, 0,
  1368. cmPolicies::WarnCompat::Off);
  1369. }
  1370. }
  1371. bool hasProject = false;
  1372. // search for a project command
  1373. for (cmListFileFunction const& func : listFile.Functions) {
  1374. if (func.LowerCaseName() == "project"_s) {
  1375. hasProject = true;
  1376. break;
  1377. }
  1378. }
  1379. // if no project command is found, add one
  1380. if (!hasProject) {
  1381. this->GetCMakeInstance()->IssueMessage(
  1382. MessageType::AUTHOR_WARNING,
  1383. "No project() command is present. The top-level CMakeLists.txt "
  1384. "file must contain a literal, direct call to the project() command. "
  1385. "Add a line of code such as\n"
  1386. " project(ProjectName)\n"
  1387. "near the top of the file, but after cmake_minimum_required().\n"
  1388. "CMake is pretending there is a \"project(Project)\" command on "
  1389. "the first line.",
  1390. this->Backtrace);
  1391. cmListFileFunction project{
  1392. "project", 0, 0, { { "Project", cmListFileArgument::Unquoted, 0 } }
  1393. };
  1394. listFile.Functions.insert(listFile.Functions.begin(), project);
  1395. }
  1396. }
  1397. this->Defer = cm::make_unique<DeferCommands>();
  1398. this->RunListFile(listFile, currentStart, this->Defer.get());
  1399. this->Defer.reset();
  1400. if (cmSystemTools::GetFatalErrorOccurred()) {
  1401. scope.Quiet();
  1402. }
  1403. // at the end handle any old style subdirs
  1404. std::vector<cmMakefile*> subdirs = this->UnConfiguredDirectories;
  1405. // for each subdir recurse
  1406. auto sdi = subdirs.begin();
  1407. for (; sdi != subdirs.end(); ++sdi) {
  1408. (*sdi)->StateSnapshot.InitializeFromParent_ForSubdirsCommand();
  1409. this->ConfigureSubDirectory(*sdi);
  1410. }
  1411. this->AddCMakeDependFilesFromUser();
  1412. }
  1413. void cmMakefile::ConfigureSubDirectory(cmMakefile* mf)
  1414. {
  1415. mf->InitializeFromParent(this);
  1416. std::string currentStart = mf->GetCurrentSourceDirectory();
  1417. if (this->GetCMakeInstance()->GetDebugOutput()) {
  1418. std::string msg = cmStrCat(" Entering ", currentStart);
  1419. cmSystemTools::Message(msg);
  1420. }
  1421. std::string currentStartFile =
  1422. this->GetCMakeInstance()->GetCMakeListFile(currentStart);
  1423. if (!cmSystemTools::FileExists(currentStartFile, true)) {
  1424. this->IssueMessage(MessageType::FATAL_ERROR,
  1425. cmStrCat("The source directory\n ", currentStart,
  1426. "\n"
  1427. "does not contain a CMakeLists.txt file."));
  1428. return;
  1429. }
  1430. // finally configure the subdir
  1431. mf->Configure();
  1432. if (this->GetCMakeInstance()->GetDebugOutput()) {
  1433. auto msg =
  1434. cmStrCat(" Returning to ", this->GetCurrentSourceDirectory());
  1435. cmSystemTools::Message(msg);
  1436. }
  1437. }
  1438. void cmMakefile::AddSubDirectory(std::string const& srcPath,
  1439. std::string const& binPath,
  1440. bool excludeFromAll, bool immediate,
  1441. bool system)
  1442. {
  1443. if (this->DeferRunning) {
  1444. this->IssueMessage(
  1445. MessageType::FATAL_ERROR,
  1446. "Subdirectories may not be created during deferred execution.");
  1447. return;
  1448. }
  1449. // Make sure the binary directory is unique.
  1450. if (!this->EnforceUniqueDir(srcPath, binPath)) {
  1451. return;
  1452. }
  1453. cmStateSnapshot newSnapshot =
  1454. this->GetState()->CreateBuildsystemDirectorySnapshot(this->StateSnapshot);
  1455. newSnapshot.GetDirectory().SetCurrentSource(srcPath);
  1456. newSnapshot.GetDirectory().SetCurrentBinary(binPath);
  1457. cmSystemTools::MakeDirectory(binPath);
  1458. auto subMfu =
  1459. cm::make_unique<cmMakefile>(this->GlobalGenerator, newSnapshot);
  1460. auto* subMf = subMfu.get();
  1461. this->GetGlobalGenerator()->AddMakefile(std::move(subMfu));
  1462. if (excludeFromAll) {
  1463. subMf->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
  1464. }
  1465. if (system) {
  1466. subMf->SetProperty("SYSTEM", "TRUE");
  1467. }
  1468. if (immediate) {
  1469. this->ConfigureSubDirectory(subMf);
  1470. } else {
  1471. this->UnConfiguredDirectories.push_back(subMf);
  1472. }
  1473. this->AddInstallGenerator(cm::make_unique<cmInstallSubdirectoryGenerator>(
  1474. subMf, binPath, this->GetBacktrace()));
  1475. }
  1476. std::string const& cmMakefile::GetCurrentSourceDirectory() const
  1477. {
  1478. return this->StateSnapshot.GetDirectory().GetCurrentSource();
  1479. }
  1480. std::string const& cmMakefile::GetCurrentBinaryDirectory() const
  1481. {
  1482. return this->StateSnapshot.GetDirectory().GetCurrentBinary();
  1483. }
  1484. std::vector<cmTarget*> cmMakefile::GetImportedTargets() const
  1485. {
  1486. std::vector<cmTarget*> tgts;
  1487. tgts.reserve(this->ImportedTargets.size());
  1488. for (auto const& impTarget : this->ImportedTargets) {
  1489. tgts.push_back(impTarget.second);
  1490. }
  1491. return tgts;
  1492. }
  1493. void cmMakefile::AddIncludeDirectories(std::vector<std::string> const& incs,
  1494. bool before)
  1495. {
  1496. if (incs.empty()) {
  1497. return;
  1498. }
  1499. std::string entryString = cmList::to_string(incs);
  1500. if (before) {
  1501. this->StateSnapshot.GetDirectory().PrependIncludeDirectoriesEntry(
  1502. BT<std::string>(entryString, this->Backtrace));
  1503. } else {
  1504. this->StateSnapshot.GetDirectory().AppendIncludeDirectoriesEntry(
  1505. BT<std::string>(entryString, this->Backtrace));
  1506. }
  1507. // Property on each target:
  1508. for (auto& target : this->Targets) {
  1509. cmTarget& t = target.second;
  1510. t.InsertInclude(BT<std::string>(entryString, this->Backtrace), before);
  1511. }
  1512. }
  1513. void cmMakefile::AddSystemIncludeDirectories(std::set<std::string> const& incs)
  1514. {
  1515. if (incs.empty()) {
  1516. return;
  1517. }
  1518. this->SystemIncludeDirectories.insert(incs.begin(), incs.end());
  1519. for (auto& target : this->Targets) {
  1520. cmTarget& t = target.second;
  1521. t.AddSystemIncludeDirectories(incs);
  1522. }
  1523. }
  1524. void cmMakefile::AddDefinition(std::string const& name, cm::string_view value)
  1525. {
  1526. this->StateSnapshot.SetDefinition(name, value);
  1527. #ifndef CMAKE_BOOTSTRAP
  1528. cmVariableWatch* vv = this->GetVariableWatch();
  1529. if (vv) {
  1530. vv->VariableAccessed(name, cmVariableWatch::VARIABLE_MODIFIED_ACCESS,
  1531. value.data(), this);
  1532. }
  1533. #endif
  1534. }
  1535. void cmMakefile::AddDefinitionBool(std::string const& name, bool value)
  1536. {
  1537. this->AddDefinition(name, value ? "ON" : "OFF");
  1538. }
  1539. void cmMakefile::AddCacheDefinition(std::string const& name, cmValue value,
  1540. cmValue doc,
  1541. cmStateEnums::CacheEntryType type,
  1542. bool force)
  1543. {
  1544. cmValue existingValue = this->GetState()->GetInitializedCacheValue(name);
  1545. // must be outside the following if() to keep it alive long enough
  1546. std::string nvalue;
  1547. if (existingValue &&
  1548. (this->GetState()->GetCacheEntryType(name) ==
  1549. cmStateEnums::UNINITIALIZED)) {
  1550. // if this is not a force, then use the value from the cache
  1551. // if it is a force, then use the value being passed in
  1552. if (!force) {
  1553. value = existingValue;
  1554. }
  1555. if (type == cmStateEnums::PATH || type == cmStateEnums::FILEPATH) {
  1556. cmList files(value);
  1557. for (auto& file : files) {
  1558. if (!cmIsOff(file)) {
  1559. file = cmSystemTools::ToNormalizedPathOnDisk(file);
  1560. }
  1561. }
  1562. nvalue = files.to_string();
  1563. value = cmValue{ nvalue };
  1564. this->GetCMakeInstance()->AddCacheEntry(name, value, doc, type);
  1565. value = this->GetState()->GetInitializedCacheValue(name);
  1566. }
  1567. }
  1568. this->GetCMakeInstance()->AddCacheEntry(name, value, doc, type);
  1569. switch (this->GetPolicyStatus(cmPolicies::CMP0126)) {
  1570. case cmPolicies::WARN:
  1571. if (this->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0126") &&
  1572. this->IsNormalDefinitionSet(name)) {
  1573. this->IssueMessage(
  1574. MessageType::AUTHOR_WARNING,
  1575. cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0126),
  1576. "\nFor compatibility with older versions of CMake, normal "
  1577. "variable \"",
  1578. name, "\" will be removed from the current scope."));
  1579. }
  1580. CM_FALLTHROUGH;
  1581. case cmPolicies::OLD:
  1582. // if there was a definition then remove it
  1583. this->StateSnapshot.RemoveDefinition(name);
  1584. break;
  1585. case cmPolicies::NEW:
  1586. break;
  1587. }
  1588. }
  1589. void cmMakefile::MarkVariableAsUsed(std::string const& var)
  1590. {
  1591. this->StateSnapshot.GetDefinition(var);
  1592. }
  1593. bool cmMakefile::VariableInitialized(std::string const& var) const
  1594. {
  1595. return this->StateSnapshot.IsInitialized(var);
  1596. }
  1597. void cmMakefile::MaybeWarnUninitialized(std::string const& variable,
  1598. char const* sourceFilename) const
  1599. {
  1600. // check to see if we need to print a warning
  1601. // if strict mode is on and the variable has
  1602. // not been "cleared"/initialized with a set(foo ) call
  1603. if (this->GetCMakeInstance()->GetWarnUninitialized() &&
  1604. !this->VariableInitialized(variable)) {
  1605. if (this->CheckSystemVars ||
  1606. (sourceFilename && this->IsProjectFile(sourceFilename))) {
  1607. this->IssueMessage(MessageType::AUTHOR_WARNING,
  1608. cmStrCat("uninitialized variable '", variable, '\''));
  1609. }
  1610. }
  1611. }
  1612. void cmMakefile::RemoveDefinition(std::string const& name)
  1613. {
  1614. this->StateSnapshot.RemoveDefinition(name);
  1615. #ifndef CMAKE_BOOTSTRAP
  1616. cmVariableWatch* vv = this->GetVariableWatch();
  1617. if (vv) {
  1618. vv->VariableAccessed(name, cmVariableWatch::VARIABLE_REMOVED_ACCESS,
  1619. nullptr, this);
  1620. }
  1621. #endif
  1622. }
  1623. void cmMakefile::RemoveCacheDefinition(std::string const& name) const
  1624. {
  1625. this->GetState()->RemoveCacheEntry(name);
  1626. }
  1627. void cmMakefile::SetProjectName(std::string const& p)
  1628. {
  1629. this->StateSnapshot.SetProjectName(p);
  1630. }
  1631. void cmMakefile::AddGlobalLinkInformation(cmTarget& target)
  1632. {
  1633. // for these targets do not add anything
  1634. switch (target.GetType()) {
  1635. case cmStateEnums::UTILITY:
  1636. case cmStateEnums::GLOBAL_TARGET:
  1637. case cmStateEnums::INTERFACE_LIBRARY:
  1638. return;
  1639. default:;
  1640. }
  1641. if (cmValue linkLibsProp = this->GetProperty("LINK_LIBRARIES")) {
  1642. cmList linkLibs{ *linkLibsProp };
  1643. for (auto j = linkLibs.begin(); j != linkLibs.end(); ++j) {
  1644. std::string libraryName = *j;
  1645. cmTargetLinkLibraryType libType = GENERAL_LibraryType;
  1646. if (libraryName == "optimized"_s) {
  1647. libType = OPTIMIZED_LibraryType;
  1648. ++j;
  1649. libraryName = *j;
  1650. } else if (libraryName == "debug"_s) {
  1651. libType = DEBUG_LibraryType;
  1652. ++j;
  1653. libraryName = *j;
  1654. }
  1655. // This is equivalent to the target_link_libraries plain signature.
  1656. target.AddLinkLibrary(*this, libraryName, libType);
  1657. target.AppendProperty(
  1658. "INTERFACE_LINK_LIBRARIES",
  1659. target.GetDebugGeneratorExpressions(libraryName, libType));
  1660. }
  1661. }
  1662. }
  1663. void cmMakefile::AddAlias(std::string const& lname, std::string const& tgtName,
  1664. bool globallyVisible)
  1665. {
  1666. this->AliasTargets[lname] = tgtName;
  1667. if (globallyVisible) {
  1668. this->GetGlobalGenerator()->AddAlias(lname, tgtName);
  1669. }
  1670. }
  1671. cmTarget* cmMakefile::AddLibrary(std::string const& lname,
  1672. cmStateEnums::TargetType type,
  1673. std::vector<std::string> const& srcs,
  1674. bool excludeFromAll)
  1675. {
  1676. assert(type == cmStateEnums::STATIC_LIBRARY ||
  1677. type == cmStateEnums::SHARED_LIBRARY ||
  1678. type == cmStateEnums::MODULE_LIBRARY ||
  1679. type == cmStateEnums::OBJECT_LIBRARY ||
  1680. type == cmStateEnums::INTERFACE_LIBRARY);
  1681. cmTarget* target = this->AddNewTarget(type, lname);
  1682. // Clear its dependencies. Otherwise, dependencies might persist
  1683. // over changes in CMakeLists.txt, making the information stale and
  1684. // hence useless.
  1685. target->ClearDependencyInformation(*this);
  1686. if (excludeFromAll) {
  1687. target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
  1688. }
  1689. target->AddSources(srcs);
  1690. this->AddGlobalLinkInformation(*target);
  1691. return target;
  1692. }
  1693. cmTarget* cmMakefile::AddExecutable(std::string const& exeName,
  1694. std::vector<std::string> const& srcs,
  1695. bool excludeFromAll)
  1696. {
  1697. cmTarget* target = this->AddNewTarget(cmStateEnums::EXECUTABLE, exeName);
  1698. if (excludeFromAll) {
  1699. target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
  1700. }
  1701. target->AddSources(srcs);
  1702. this->AddGlobalLinkInformation(*target);
  1703. return target;
  1704. }
  1705. cmTarget* cmMakefile::AddNewTarget(cmStateEnums::TargetType type,
  1706. std::string const& name)
  1707. {
  1708. return &this->CreateNewTarget(name, type).first;
  1709. }
  1710. cmTarget* cmMakefile::AddSynthesizedTarget(cmStateEnums::TargetType type,
  1711. std::string const& name)
  1712. {
  1713. return &this
  1714. ->CreateNewTarget(name, type, cmTarget::PerConfig::Yes,
  1715. cmTarget::Visibility::Generated)
  1716. .first;
  1717. }
  1718. std::pair<cmTarget&, bool> cmMakefile::CreateNewTarget(
  1719. std::string const& name, cmStateEnums::TargetType type,
  1720. cmTarget::PerConfig perConfig, cmTarget::Visibility vis)
  1721. {
  1722. auto ib =
  1723. this->Targets.emplace(name, cmTarget(name, type, vis, this, perConfig));
  1724. auto it = ib.first;
  1725. if (!ib.second) {
  1726. return std::make_pair(std::ref(it->second), false);
  1727. }
  1728. this->OrderedTargets.push_back(&it->second);
  1729. this->GetGlobalGenerator()->IndexTarget(&it->second);
  1730. this->GetStateSnapshot().GetDirectory().AddNormalTargetName(name);
  1731. return std::make_pair(std::ref(it->second), true);
  1732. }
  1733. cmTarget* cmMakefile::AddNewUtilityTarget(std::string const& utilityName,
  1734. bool excludeFromAll)
  1735. {
  1736. cmTarget* target = this->AddNewTarget(cmStateEnums::UTILITY, utilityName);
  1737. if (excludeFromAll) {
  1738. target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
  1739. }
  1740. return target;
  1741. }
  1742. namespace {
  1743. }
  1744. #if !defined(CMAKE_BOOTSTRAP)
  1745. cmSourceGroup* cmMakefile::GetSourceGroup(
  1746. std::vector<std::string> const& name) const
  1747. {
  1748. cmSourceGroup* sg = nullptr;
  1749. // first look for source group starting with the same as the one we want
  1750. for (cmSourceGroup const& srcGroup : this->SourceGroups) {
  1751. std::string const& sgName = srcGroup.GetName();
  1752. if (sgName == name[0]) {
  1753. sg = const_cast<cmSourceGroup*>(&srcGroup);
  1754. break;
  1755. }
  1756. }
  1757. if (sg) {
  1758. // iterate through its children to find match source group
  1759. for (unsigned int i = 1; i < name.size(); ++i) {
  1760. sg = sg->LookupChild(name[i]);
  1761. if (!sg) {
  1762. break;
  1763. }
  1764. }
  1765. }
  1766. return sg;
  1767. }
  1768. void cmMakefile::AddSourceGroup(std::string const& name, char const* regex)
  1769. {
  1770. std::vector<std::string> nameVector;
  1771. nameVector.push_back(name);
  1772. this->AddSourceGroup(nameVector, regex);
  1773. }
  1774. void cmMakefile::AddSourceGroup(std::vector<std::string> const& name,
  1775. char const* regex)
  1776. {
  1777. cmSourceGroup* sg = nullptr;
  1778. std::vector<std::string> currentName;
  1779. int i = 0;
  1780. int const lastElement = static_cast<int>(name.size() - 1);
  1781. for (i = lastElement; i >= 0; --i) {
  1782. currentName.assign(name.begin(), name.begin() + i + 1);
  1783. sg = this->GetSourceGroup(currentName);
  1784. if (sg) {
  1785. break;
  1786. }
  1787. }
  1788. // i now contains the index of the last found component
  1789. if (i == lastElement) {
  1790. // group already exists, replace its regular expression
  1791. if (regex && sg) {
  1792. // We only want to set the regular expression. If there are already
  1793. // source files in the group, we don't want to remove them.
  1794. sg->SetGroupRegex(regex);
  1795. }
  1796. return;
  1797. }
  1798. if (i == -1) {
  1799. // group does not exist nor belong to any existing group
  1800. // add its first component
  1801. this->SourceGroups.emplace_back(name[0], regex);
  1802. sg = this->GetSourceGroup(currentName);
  1803. i = 0; // last component found
  1804. }
  1805. if (!sg) {
  1806. cmSystemTools::Error("Could not create source group ");
  1807. return;
  1808. }
  1809. // build the whole source group path
  1810. for (++i; i <= lastElement; ++i) {
  1811. sg->AddChild(cmSourceGroup(name[i], nullptr, sg->GetFullName().c_str()));
  1812. sg = sg->LookupChild(name[i]);
  1813. }
  1814. sg->SetGroupRegex(regex);
  1815. }
  1816. cmSourceGroup* cmMakefile::GetOrCreateSourceGroup(
  1817. std::vector<std::string> const& folders)
  1818. {
  1819. cmSourceGroup* sg = this->GetSourceGroup(folders);
  1820. if (!sg) {
  1821. this->AddSourceGroup(folders);
  1822. sg = this->GetSourceGroup(folders);
  1823. }
  1824. return sg;
  1825. }
  1826. cmSourceGroup* cmMakefile::GetOrCreateSourceGroup(std::string const& name)
  1827. {
  1828. auto p = this->GetDefinition("SOURCE_GROUP_DELIMITER");
  1829. return this->GetOrCreateSourceGroup(
  1830. cmTokenize(name, p ? cm::string_view(*p) : R"(\/)"_s));
  1831. }
  1832. /**
  1833. * Find a source group whose regular expression matches the filename
  1834. * part of the given source name. Search backward through the list of
  1835. * source groups, and take the first matching group found. This way
  1836. * non-inherited SOURCE_GROUP commands will have precedence over
  1837. * inherited ones.
  1838. */
  1839. cmSourceGroup* cmMakefile::FindSourceGroup(
  1840. std::string const& source, std::vector<cmSourceGroup>& groups) const
  1841. {
  1842. // First search for a group that lists the file explicitly.
  1843. for (auto sg = groups.rbegin(); sg != groups.rend(); ++sg) {
  1844. cmSourceGroup* result = sg->MatchChildrenFiles(source);
  1845. if (result) {
  1846. return result;
  1847. }
  1848. }
  1849. // Now search for a group whose regex matches the file.
  1850. for (auto sg = groups.rbegin(); sg != groups.rend(); ++sg) {
  1851. cmSourceGroup* result = sg->MatchChildrenRegex(source);
  1852. if (result) {
  1853. return result;
  1854. }
  1855. }
  1856. // Shouldn't get here, but just in case, return the default group.
  1857. return groups.data();
  1858. }
  1859. #endif
  1860. bool cmMakefile::IsOn(std::string const& name) const
  1861. {
  1862. return this->GetDefinition(name).IsOn();
  1863. }
  1864. bool cmMakefile::IsSet(std::string const& name) const
  1865. {
  1866. cmValue value = this->GetDefinition(name);
  1867. if (!value) {
  1868. return false;
  1869. }
  1870. if (value->empty()) {
  1871. return false;
  1872. }
  1873. if (cmIsNOTFOUND(*value)) {
  1874. return false;
  1875. }
  1876. return true;
  1877. }
  1878. bool cmMakefile::PlatformIs32Bit() const
  1879. {
  1880. if (cmValue plat_abi = this->GetDefinition("CMAKE_INTERNAL_PLATFORM_ABI")) {
  1881. if (*plat_abi == "ELF X32"_s) {
  1882. return false;
  1883. }
  1884. }
  1885. if (cmValue sizeof_dptr = this->GetDefinition("CMAKE_SIZEOF_VOID_P")) {
  1886. return atoi(sizeof_dptr->c_str()) == 4;
  1887. }
  1888. return false;
  1889. }
  1890. bool cmMakefile::PlatformIs64Bit() const
  1891. {
  1892. if (cmValue sizeof_dptr = this->GetDefinition("CMAKE_SIZEOF_VOID_P")) {
  1893. return atoi(sizeof_dptr->c_str()) == 8;
  1894. }
  1895. return false;
  1896. }
  1897. bool cmMakefile::PlatformIsx32() const
  1898. {
  1899. if (cmValue plat_abi = this->GetDefinition("CMAKE_INTERNAL_PLATFORM_ABI")) {
  1900. if (*plat_abi == "ELF X32"_s) {
  1901. return true;
  1902. }
  1903. }
  1904. return false;
  1905. }
  1906. cmMakefile::AppleSDK cmMakefile::GetAppleSDKType() const
  1907. {
  1908. std::string sdkRoot;
  1909. sdkRoot = this->GetSafeDefinition("CMAKE_OSX_SYSROOT");
  1910. sdkRoot = cmSystemTools::LowerCase(sdkRoot);
  1911. struct
  1912. {
  1913. std::string name;
  1914. AppleSDK sdk;
  1915. } const sdkDatabase[]{
  1916. { "appletvos", AppleSDK::AppleTVOS },
  1917. { "appletvsimulator", AppleSDK::AppleTVSimulator },
  1918. { "iphoneos", AppleSDK::IPhoneOS },
  1919. { "iphonesimulator", AppleSDK::IPhoneSimulator },
  1920. { "watchos", AppleSDK::WatchOS },
  1921. { "watchsimulator", AppleSDK::WatchSimulator },
  1922. { "xros", AppleSDK::XROS },
  1923. { "xrsimulator", AppleSDK::XRSimulator },
  1924. };
  1925. for (auto const& entry : sdkDatabase) {
  1926. if (cmHasPrefix(sdkRoot, entry.name) ||
  1927. sdkRoot.find(cmStrCat('/', entry.name)) != std::string::npos) {
  1928. return entry.sdk;
  1929. }
  1930. }
  1931. return AppleSDK::MacOS;
  1932. }
  1933. bool cmMakefile::PlatformIsAppleEmbedded() const
  1934. {
  1935. return this->GetAppleSDKType() != AppleSDK::MacOS;
  1936. }
  1937. bool cmMakefile::PlatformIsAppleSimulator() const
  1938. {
  1939. return std::set<AppleSDK>{
  1940. AppleSDK::AppleTVSimulator,
  1941. AppleSDK::IPhoneSimulator,
  1942. AppleSDK::WatchSimulator,
  1943. AppleSDK::XRSimulator,
  1944. }
  1945. .count(this->GetAppleSDKType());
  1946. }
  1947. bool cmMakefile::PlatformIsAppleCatalyst() const
  1948. {
  1949. std::string systemName;
  1950. systemName = this->GetSafeDefinition("CMAKE_SYSTEM_NAME");
  1951. systemName = cmSystemTools::LowerCase(systemName);
  1952. return systemName == "ios" && this->GetAppleSDKType() == AppleSDK::MacOS;
  1953. }
  1954. bool cmMakefile::PlatformSupportsAppleTextStubs() const
  1955. {
  1956. return this->IsOn("APPLE") && this->IsSet("CMAKE_TAPI");
  1957. }
  1958. char const* cmMakefile::GetSONameFlag(std::string const& language) const
  1959. {
  1960. std::string name = "CMAKE_SHARED_LIBRARY_SONAME";
  1961. if (!language.empty()) {
  1962. name += "_";
  1963. name += language;
  1964. }
  1965. name += "_FLAG";
  1966. return this->GetDefinition(name).GetCStr();
  1967. }
  1968. bool cmMakefile::CanIWriteThisFile(std::string const& fileName) const
  1969. {
  1970. if (!this->IsOn("CMAKE_DISABLE_SOURCE_CHANGES")) {
  1971. return true;
  1972. }
  1973. // If we are doing an in-source build, then the test will always fail
  1974. if (cmSystemTools::SameFile(this->GetHomeDirectory(),
  1975. this->GetHomeOutputDirectory())) {
  1976. return !this->IsOn("CMAKE_DISABLE_IN_SOURCE_BUILD");
  1977. }
  1978. return !cmSystemTools::IsSubDirectory(fileName, this->GetHomeDirectory()) ||
  1979. cmSystemTools::IsSubDirectory(fileName, this->GetHomeOutputDirectory()) ||
  1980. cmSystemTools::SameFile(fileName, this->GetHomeOutputDirectory());
  1981. }
  1982. std::string const& cmMakefile::GetRequiredDefinition(
  1983. std::string const& name) const
  1984. {
  1985. static std::string const empty;
  1986. cmValue def = this->GetDefinition(name);
  1987. if (!def) {
  1988. cmSystemTools::Error("Error required internal CMake variable not "
  1989. "set, cmake may not be built correctly.\n"
  1990. "Missing variable is:\n" +
  1991. name);
  1992. return empty;
  1993. }
  1994. return *def;
  1995. }
  1996. bool cmMakefile::IsDefinitionSet(std::string const& name) const
  1997. {
  1998. cmValue def = this->StateSnapshot.GetDefinition(name);
  1999. if (!def) {
  2000. def = this->GetState()->GetInitializedCacheValue(name);
  2001. }
  2002. #ifndef CMAKE_BOOTSTRAP
  2003. if (cmVariableWatch* vv = this->GetVariableWatch()) {
  2004. if (!def) {
  2005. vv->VariableAccessed(
  2006. name, cmVariableWatch::UNKNOWN_VARIABLE_DEFINED_ACCESS, nullptr, this);
  2007. }
  2008. }
  2009. #endif
  2010. return def != nullptr;
  2011. }
  2012. bool cmMakefile::IsNormalDefinitionSet(std::string const& name) const
  2013. {
  2014. cmValue def = this->StateSnapshot.GetDefinition(name);
  2015. #ifndef CMAKE_BOOTSTRAP
  2016. if (cmVariableWatch* vv = this->GetVariableWatch()) {
  2017. if (!def) {
  2018. vv->VariableAccessed(
  2019. name, cmVariableWatch::UNKNOWN_VARIABLE_DEFINED_ACCESS, nullptr, this);
  2020. }
  2021. }
  2022. #endif
  2023. return def != nullptr;
  2024. }
  2025. cmValue cmMakefile::GetDefinition(std::string const& name) const
  2026. {
  2027. cmValue def = this->StateSnapshot.GetDefinition(name);
  2028. if (!def) {
  2029. def = this->GetState()->GetInitializedCacheValue(name);
  2030. }
  2031. #ifndef CMAKE_BOOTSTRAP
  2032. cmVariableWatch* vv = this->GetVariableWatch();
  2033. if (vv) {
  2034. bool const watch_function_executed =
  2035. vv->VariableAccessed(name,
  2036. def ? cmVariableWatch::VARIABLE_READ_ACCESS
  2037. : cmVariableWatch::UNKNOWN_VARIABLE_READ_ACCESS,
  2038. def.GetCStr(), this);
  2039. if (watch_function_executed) {
  2040. // A callback was executed and may have caused re-allocation of the
  2041. // variable storage. Look it up again for now.
  2042. // FIXME: Refactor variable storage to avoid this problem.
  2043. def = this->StateSnapshot.GetDefinition(name);
  2044. if (!def) {
  2045. def = this->GetState()->GetInitializedCacheValue(name);
  2046. }
  2047. }
  2048. }
  2049. #endif
  2050. return def;
  2051. }
  2052. std::string const& cmMakefile::GetSafeDefinition(std::string const& name) const
  2053. {
  2054. return this->GetDefinition(name);
  2055. }
  2056. std::vector<std::string> cmMakefile::GetDefinitions() const
  2057. {
  2058. std::vector<std::string> res = this->StateSnapshot.ClosureKeys();
  2059. cm::append(res, this->GetState()->GetCacheEntryKeys());
  2060. std::sort(res.begin(), res.end());
  2061. return res;
  2062. }
  2063. std::string const& cmMakefile::ExpandVariablesInString(
  2064. std::string& source) const
  2065. {
  2066. return this->ExpandVariablesInString(source, false, false);
  2067. }
  2068. std::string const& cmMakefile::ExpandVariablesInString(
  2069. std::string& source, bool escapeQuotes, bool noEscapes, bool atOnly,
  2070. char const* filename, long line, bool removeEmpty, bool replaceAt) const
  2071. {
  2072. // Sanity check the @ONLY mode.
  2073. if (atOnly && (!noEscapes || !removeEmpty)) {
  2074. // This case should never be called. At-only is for
  2075. // configure-file/string which always does no escapes.
  2076. this->IssueMessage(MessageType::INTERNAL_ERROR,
  2077. "ExpandVariablesInString @ONLY called "
  2078. "on something with escapes.");
  2079. return source;
  2080. }
  2081. std::string errorstr;
  2082. MessageType mtype = this->ExpandVariablesInStringImpl(
  2083. errorstr, source, escapeQuotes, noEscapes, atOnly, filename, line,
  2084. replaceAt);
  2085. if (mtype != MessageType::LOG) {
  2086. if (mtype == MessageType::FATAL_ERROR) {
  2087. cmSystemTools::SetFatalErrorOccurred();
  2088. }
  2089. this->IssueMessage(mtype, errorstr);
  2090. }
  2091. return source;
  2092. }
  2093. enum t_domain
  2094. {
  2095. NORMAL,
  2096. ENVIRONMENT,
  2097. CACHE
  2098. };
  2099. struct t_lookup
  2100. {
  2101. t_domain domain = NORMAL;
  2102. size_t loc = 0;
  2103. };
  2104. bool cmMakefile::IsProjectFile(char const* filename) const
  2105. {
  2106. return cmSystemTools::IsSubDirectory(filename, this->GetHomeDirectory()) ||
  2107. (cmSystemTools::IsSubDirectory(filename, this->GetHomeOutputDirectory()) &&
  2108. !cmSystemTools::IsSubDirectory(filename, "/CMakeFiles"));
  2109. }
  2110. size_t cmMakefile::GetRecursionDepthLimit() const
  2111. {
  2112. size_t depth = CMake_DEFAULT_RECURSION_LIMIT;
  2113. if (cmValue depthStr =
  2114. this->GetDefinition("CMAKE_MAXIMUM_RECURSION_DEPTH")) {
  2115. unsigned long depthUL;
  2116. if (cmStrToULong(depthStr.GetCStr(), &depthUL)) {
  2117. depth = depthUL;
  2118. }
  2119. } else if (cm::optional<std::string> depthEnv =
  2120. cmSystemTools::GetEnvVar("CMAKE_MAXIMUM_RECURSION_DEPTH")) {
  2121. unsigned long depthUL;
  2122. if (cmStrToULong(*depthEnv, &depthUL)) {
  2123. depth = depthUL;
  2124. }
  2125. }
  2126. return depth;
  2127. }
  2128. size_t cmMakefile::GetRecursionDepth() const
  2129. {
  2130. return this->RecursionDepth;
  2131. }
  2132. void cmMakefile::SetRecursionDepth(size_t recursionDepth)
  2133. {
  2134. this->RecursionDepth = recursionDepth;
  2135. }
  2136. std::string cmMakefile::NewDeferId() const
  2137. {
  2138. return this->GetGlobalGenerator()->NewDeferId();
  2139. }
  2140. bool cmMakefile::DeferCall(std::string id, std::string file,
  2141. cmListFileFunction lff)
  2142. {
  2143. if (!this->Defer) {
  2144. return false;
  2145. }
  2146. this->Defer->Commands.emplace_back(
  2147. DeferCommand{ std::move(id), std::move(file), std::move(lff) });
  2148. return true;
  2149. }
  2150. bool cmMakefile::DeferCancelCall(std::string const& id)
  2151. {
  2152. if (!this->Defer) {
  2153. return false;
  2154. }
  2155. for (DeferCommand& dc : this->Defer->Commands) {
  2156. if (dc.Id == id) {
  2157. dc.Id.clear();
  2158. }
  2159. }
  2160. return true;
  2161. }
  2162. cm::optional<std::string> cmMakefile::DeferGetCallIds() const
  2163. {
  2164. cm::optional<std::string> ids;
  2165. if (this->Defer) {
  2166. ids = cmList::to_string(
  2167. cmMakeRange(this->Defer->Commands)
  2168. .filter([](DeferCommand const& dc) -> bool { return !dc.Id.empty(); })
  2169. .transform(
  2170. [](DeferCommand const& dc) -> std::string const& { return dc.Id; }));
  2171. }
  2172. return ids;
  2173. }
  2174. cm::optional<std::string> cmMakefile::DeferGetCall(std::string const& id) const
  2175. {
  2176. cm::optional<std::string> call;
  2177. if (this->Defer) {
  2178. std::string tmp;
  2179. for (DeferCommand const& dc : this->Defer->Commands) {
  2180. if (dc.Id == id) {
  2181. tmp = dc.Command.OriginalName();
  2182. for (cmListFileArgument const& arg : dc.Command.Arguments()) {
  2183. tmp = cmStrCat(tmp, ';', arg.Value);
  2184. }
  2185. break;
  2186. }
  2187. }
  2188. call = std::move(tmp);
  2189. }
  2190. return call;
  2191. }
  2192. MessageType cmMakefile::ExpandVariablesInStringImpl(
  2193. std::string& errorstr, std::string& source, bool escapeQuotes,
  2194. bool noEscapes, bool atOnly, char const* filename, long line,
  2195. bool replaceAt) const
  2196. {
  2197. // This method replaces ${VAR} and @VAR@ where VAR is looked up
  2198. // with GetDefinition(), if not found in the map, nothing is expanded.
  2199. // It also supports the $ENV{VAR} syntax where VAR is looked up in
  2200. // the current environment variables.
  2201. char const* in = source.c_str();
  2202. char const* last = in;
  2203. std::string result;
  2204. result.reserve(source.size());
  2205. std::vector<t_lookup> openstack;
  2206. bool error = false;
  2207. bool done = false;
  2208. MessageType mtype = MessageType::LOG;
  2209. cmState* state = this->GetCMakeInstance()->GetState();
  2210. static std::string const lineVar = "CMAKE_CURRENT_LIST_LINE";
  2211. do {
  2212. char inc = *in;
  2213. switch (inc) {
  2214. case '}':
  2215. if (!openstack.empty()) {
  2216. t_lookup var = openstack.back();
  2217. openstack.pop_back();
  2218. result.append(last, in - last);
  2219. std::string const& lookup = result.substr(var.loc);
  2220. cmValue value = nullptr;
  2221. std::string varresult;
  2222. std::string svalue;
  2223. switch (var.domain) {
  2224. case NORMAL:
  2225. if (filename && lookup == lineVar) {
  2226. cmListFileContext const& top = this->Backtrace.Top();
  2227. if (top.DeferId) {
  2228. varresult = cmStrCat("DEFERRED:"_s, *top.DeferId);
  2229. } else {
  2230. varresult = std::to_string(line);
  2231. }
  2232. } else {
  2233. value = this->GetDefinition(lookup);
  2234. }
  2235. break;
  2236. case ENVIRONMENT:
  2237. if (cmSystemTools::GetEnv(lookup, svalue)) {
  2238. value = cmValue(svalue);
  2239. }
  2240. break;
  2241. case CACHE:
  2242. value = state->GetCacheEntryValue(lookup);
  2243. break;
  2244. }
  2245. // Get the string we're meant to append to.
  2246. if (value) {
  2247. if (escapeQuotes) {
  2248. varresult = cmEscapeQuotes(*value);
  2249. } else {
  2250. varresult = *value;
  2251. }
  2252. } else {
  2253. this->MaybeWarnUninitialized(lookup, filename);
  2254. }
  2255. result.replace(var.loc, result.size() - var.loc, varresult);
  2256. // Start looking from here on out.
  2257. last = in + 1;
  2258. }
  2259. break;
  2260. case '$':
  2261. if (!atOnly) {
  2262. t_lookup lookup;
  2263. char const* next = in + 1;
  2264. char const* start = nullptr;
  2265. char nextc = *next;
  2266. if (nextc == '{') {
  2267. // Looking for a variable.
  2268. start = in + 2;
  2269. lookup.domain = NORMAL;
  2270. } else if (nextc == '<') {
  2271. } else if (!nextc) {
  2272. result.append(last, next - last);
  2273. last = next;
  2274. } else if (cmHasLiteralPrefix(next, "ENV{")) {
  2275. // Looking for an environment variable.
  2276. start = in + 5;
  2277. lookup.domain = ENVIRONMENT;
  2278. } else if (cmHasLiteralPrefix(next, "CACHE{")) {
  2279. // Looking for a cache variable.
  2280. start = in + 7;
  2281. lookup.domain = CACHE;
  2282. } else {
  2283. if (this->cmNamedCurly.find(next)) {
  2284. errorstr = "Syntax $" +
  2285. std::string(next, this->cmNamedCurly.end()) +
  2286. "{} is not supported. Only ${}, $ENV{}, "
  2287. "and $CACHE{} are allowed.";
  2288. mtype = MessageType::FATAL_ERROR;
  2289. error = true;
  2290. }
  2291. }
  2292. if (start) {
  2293. result.append(last, in - last);
  2294. last = start;
  2295. in = start - 1;
  2296. lookup.loc = result.size();
  2297. openstack.push_back(lookup);
  2298. }
  2299. break;
  2300. }
  2301. CM_FALLTHROUGH;
  2302. case '\\':
  2303. if (!noEscapes) {
  2304. char const* next = in + 1;
  2305. char nextc = *next;
  2306. if (nextc == 't') {
  2307. result.append(last, in - last);
  2308. result.push_back('\t');
  2309. last = next + 1;
  2310. } else if (nextc == 'n') {
  2311. result.append(last, in - last);
  2312. result.push_back('\n');
  2313. last = next + 1;
  2314. } else if (nextc == 'r') {
  2315. result.append(last, in - last);
  2316. result.push_back('\r');
  2317. last = next + 1;
  2318. } else if (nextc == ';' && openstack.empty()) {
  2319. // Handled in ExpandListArgument; pass the backslash literally.
  2320. } else if (isalnum(nextc) || nextc == '\0') {
  2321. errorstr += "Invalid character escape '\\";
  2322. if (nextc) {
  2323. errorstr += nextc;
  2324. errorstr += "'.";
  2325. } else {
  2326. errorstr += "' (at end of input).";
  2327. }
  2328. error = true;
  2329. } else {
  2330. // Take what we've found so far, skipping the escape character.
  2331. result.append(last, in - last);
  2332. // Start tracking from the next character.
  2333. last = in + 1;
  2334. }
  2335. // Skip the next character since it was escaped, but don't read past
  2336. // the end of the string.
  2337. if (*last) {
  2338. ++in;
  2339. }
  2340. }
  2341. break;
  2342. case '\n':
  2343. // Onto the next line.
  2344. ++line;
  2345. break;
  2346. case '\0':
  2347. done = true;
  2348. break;
  2349. case '@':
  2350. if (replaceAt) {
  2351. char const* nextAt = strchr(in + 1, '@');
  2352. if (nextAt && nextAt != in + 1 &&
  2353. nextAt ==
  2354. in + 1 +
  2355. std::strspn(in + 1,
  2356. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  2357. "abcdefghijklmnopqrstuvwxyz"
  2358. "0123456789/_.+-")) {
  2359. std::string variable(in + 1, nextAt - in - 1);
  2360. std::string varresult;
  2361. if (filename && variable == lineVar) {
  2362. varresult = std::to_string(line);
  2363. } else {
  2364. cmValue def = this->GetDefinition(variable);
  2365. if (def) {
  2366. varresult = *def;
  2367. } else {
  2368. this->MaybeWarnUninitialized(variable, filename);
  2369. }
  2370. }
  2371. if (escapeQuotes) {
  2372. varresult = cmEscapeQuotes(varresult);
  2373. }
  2374. // Skip over the variable.
  2375. result.append(last, in - last);
  2376. result.append(varresult);
  2377. in = nextAt;
  2378. last = in + 1;
  2379. break;
  2380. }
  2381. }
  2382. // Failed to find a valid @ expansion; treat it as literal.
  2383. CM_FALLTHROUGH;
  2384. default: {
  2385. if (!openstack.empty() &&
  2386. !(isalnum(inc) || inc == '_' || inc == '/' || inc == '.' ||
  2387. inc == '+' || inc == '-')) {
  2388. errorstr += cmStrCat("Invalid character ('", inc);
  2389. result.append(last, in - last);
  2390. errorstr += cmStrCat("') in a variable name: '",
  2391. result.substr(openstack.back().loc), '\'');
  2392. mtype = MessageType::FATAL_ERROR;
  2393. error = true;
  2394. }
  2395. break;
  2396. }
  2397. }
  2398. // Look at the next character.
  2399. } while (!error && !done && *++in);
  2400. // Check for open variable references yet.
  2401. if (!error && !openstack.empty()) {
  2402. errorstr += "There is an unterminated variable reference.";
  2403. error = true;
  2404. }
  2405. if (error) {
  2406. std::string e = "Syntax error in cmake code ";
  2407. if (filename) {
  2408. // This filename and line number may be more specific than the
  2409. // command context because one command invocation can have
  2410. // arguments on multiple lines.
  2411. e += cmStrCat("at\n ", filename, ':', line, '\n');
  2412. }
  2413. errorstr = cmStrCat(e, "when parsing string\n ", source, '\n', errorstr);
  2414. mtype = MessageType::FATAL_ERROR;
  2415. } else {
  2416. // Append the rest of the unchanged part of the string.
  2417. result.append(last);
  2418. source = result;
  2419. }
  2420. return mtype;
  2421. }
  2422. void cmMakefile::RemoveVariablesInString(std::string& source,
  2423. bool atOnly) const
  2424. {
  2425. if (!atOnly) {
  2426. cmsys::RegularExpression var("(\\${[A-Za-z_0-9]*})");
  2427. while (var.find(source)) {
  2428. source.erase(var.start(), var.end() - var.start());
  2429. }
  2430. }
  2431. if (!atOnly) {
  2432. cmsys::RegularExpression varb("(\\$ENV{[A-Za-z_0-9]*})");
  2433. while (varb.find(source)) {
  2434. source.erase(varb.start(), varb.end() - varb.start());
  2435. }
  2436. }
  2437. cmsys::RegularExpression var2("(@[A-Za-z_0-9]*@)");
  2438. while (var2.find(source)) {
  2439. source.erase(var2.start(), var2.end() - var2.start());
  2440. }
  2441. }
  2442. void cmMakefile::InitCMAKE_CONFIGURATION_TYPES(std::string const& genDefault)
  2443. {
  2444. if (this->GetDefinition("CMAKE_CONFIGURATION_TYPES")) {
  2445. return;
  2446. }
  2447. std::string initConfigs;
  2448. if (this->GetCMakeInstance()->GetIsInTryCompile() ||
  2449. !cmSystemTools::GetEnv("CMAKE_CONFIGURATION_TYPES", initConfigs)) {
  2450. initConfigs = genDefault;
  2451. }
  2452. this->AddCacheDefinition(
  2453. "CMAKE_CONFIGURATION_TYPES", initConfigs,
  2454. "Semicolon separated list of supported configuration types, "
  2455. "only supports Debug, Release, MinSizeRel, and RelWithDebInfo, "
  2456. "anything else will be ignored.",
  2457. cmStateEnums::STRING);
  2458. }
  2459. std::string cmMakefile::GetDefaultConfiguration() const
  2460. {
  2461. if (this->GetGlobalGenerator()->IsMultiConfig()) {
  2462. return std::string{};
  2463. }
  2464. return this->GetSafeDefinition("CMAKE_BUILD_TYPE");
  2465. }
  2466. std::vector<std::string> cmMakefile::GetGeneratorConfigs(
  2467. GeneratorConfigQuery mode) const
  2468. {
  2469. cmList configs;
  2470. if (this->GetGlobalGenerator()->IsMultiConfig()) {
  2471. configs.assign(this->GetDefinition("CMAKE_CONFIGURATION_TYPES"));
  2472. } else if (mode != cmMakefile::OnlyMultiConfig) {
  2473. std::string const& buildType = this->GetSafeDefinition("CMAKE_BUILD_TYPE");
  2474. if (!buildType.empty()) {
  2475. configs.emplace_back(buildType);
  2476. }
  2477. }
  2478. if (mode == cmMakefile::IncludeEmptyConfig && configs.empty()) {
  2479. configs.emplace_back();
  2480. }
  2481. return std::move(configs.data());
  2482. }
  2483. bool cmMakefile::IsFunctionBlocked(cmListFileFunction const& lff,
  2484. cmExecutionStatus& status)
  2485. {
  2486. // if there are no blockers get out of here
  2487. if (this->FunctionBlockers.empty()) {
  2488. return false;
  2489. }
  2490. return this->FunctionBlockers.top()->IsFunctionBlocked(lff, status);
  2491. }
  2492. void cmMakefile::PushFunctionBlockerBarrier()
  2493. {
  2494. this->FunctionBlockerBarriers.push_back(this->FunctionBlockers.size());
  2495. }
  2496. void cmMakefile::PopFunctionBlockerBarrier(bool reportError)
  2497. {
  2498. // Remove any extra entries pushed on the barrier.
  2499. FunctionBlockersType::size_type barrier =
  2500. this->FunctionBlockerBarriers.back();
  2501. while (this->FunctionBlockers.size() > barrier) {
  2502. std::unique_ptr<cmFunctionBlocker> fb(
  2503. std::move(this->FunctionBlockers.top()));
  2504. this->FunctionBlockers.pop();
  2505. if (reportError) {
  2506. // Report the context in which the unclosed block was opened.
  2507. cmListFileContext const& lfc = fb->GetStartingContext();
  2508. std::ostringstream e;
  2509. /* clang-format off */
  2510. e << "A logical block opening on the line\n"
  2511. " " << lfc << "\n"
  2512. "is not closed.";
  2513. /* clang-format on */
  2514. this->IssueMessage(MessageType::FATAL_ERROR, e.str());
  2515. reportError = false;
  2516. }
  2517. }
  2518. // Remove the barrier.
  2519. this->FunctionBlockerBarriers.pop_back();
  2520. }
  2521. void cmMakefile::PushLoopBlock()
  2522. {
  2523. assert(!this->LoopBlockCounter.empty());
  2524. this->LoopBlockCounter.top()++;
  2525. }
  2526. void cmMakefile::PopLoopBlock()
  2527. {
  2528. assert(!this->LoopBlockCounter.empty());
  2529. assert(this->LoopBlockCounter.top() > 0);
  2530. this->LoopBlockCounter.top()--;
  2531. }
  2532. void cmMakefile::PushLoopBlockBarrier()
  2533. {
  2534. this->LoopBlockCounter.push(0);
  2535. }
  2536. void cmMakefile::PopLoopBlockBarrier()
  2537. {
  2538. assert(!this->LoopBlockCounter.empty());
  2539. assert(this->LoopBlockCounter.top() == 0);
  2540. this->LoopBlockCounter.pop();
  2541. }
  2542. bool cmMakefile::IsLoopBlock() const
  2543. {
  2544. assert(!this->LoopBlockCounter.empty());
  2545. return !this->LoopBlockCounter.empty() && this->LoopBlockCounter.top() > 0;
  2546. }
  2547. bool cmMakefile::ExpandArguments(std::vector<cmListFileArgument> const& inArgs,
  2548. std::vector<std::string>& outArgs) const
  2549. {
  2550. std::string const& filename = this->GetBacktrace().Top().FilePath;
  2551. std::string value;
  2552. outArgs.reserve(inArgs.size());
  2553. for (cmListFileArgument const& i : inArgs) {
  2554. // No expansion in a bracket argument.
  2555. if (i.Delim == cmListFileArgument::Bracket) {
  2556. outArgs.push_back(i.Value);
  2557. continue;
  2558. }
  2559. // Expand the variables in the argument.
  2560. value = i.Value;
  2561. this->ExpandVariablesInString(value, false, false, false, filename.c_str(),
  2562. i.Line, false, false);
  2563. // If the argument is quoted, it should be one argument.
  2564. // Otherwise, it may be a list of arguments.
  2565. if (i.Delim == cmListFileArgument::Quoted) {
  2566. outArgs.push_back(value);
  2567. } else {
  2568. cmExpandList(value, outArgs);
  2569. }
  2570. }
  2571. return !cmSystemTools::GetFatalErrorOccurred();
  2572. }
  2573. bool cmMakefile::ExpandArguments(
  2574. std::vector<cmListFileArgument> const& inArgs,
  2575. std::vector<cmExpandedCommandArgument>& outArgs) const
  2576. {
  2577. std::string const& filename = this->GetBacktrace().Top().FilePath;
  2578. std::string value;
  2579. outArgs.reserve(inArgs.size());
  2580. for (cmListFileArgument const& i : inArgs) {
  2581. // No expansion in a bracket argument.
  2582. if (i.Delim == cmListFileArgument::Bracket) {
  2583. outArgs.emplace_back(i.Value, true);
  2584. continue;
  2585. }
  2586. // Expand the variables in the argument.
  2587. value = i.Value;
  2588. this->ExpandVariablesInString(value, false, false, false, filename.c_str(),
  2589. i.Line, false, false);
  2590. // If the argument is quoted, it should be one argument.
  2591. // Otherwise, it may be a list of arguments.
  2592. if (i.Delim == cmListFileArgument::Quoted) {
  2593. outArgs.emplace_back(value, true);
  2594. } else {
  2595. cmList stringArgs{ value };
  2596. for (std::string const& stringArg : stringArgs) {
  2597. outArgs.emplace_back(stringArg, false);
  2598. }
  2599. }
  2600. }
  2601. return !cmSystemTools::GetFatalErrorOccurred();
  2602. }
  2603. void cmMakefile::AddFunctionBlocker(std::unique_ptr<cmFunctionBlocker> fb)
  2604. {
  2605. if (!this->ExecutionStatusStack.empty()) {
  2606. // Record the context in which the blocker is created.
  2607. fb->SetStartingContext(this->Backtrace.Top());
  2608. }
  2609. this->FunctionBlockers.push(std::move(fb));
  2610. }
  2611. std::unique_ptr<cmFunctionBlocker> cmMakefile::RemoveFunctionBlocker()
  2612. {
  2613. assert(!this->FunctionBlockers.empty());
  2614. assert(this->FunctionBlockerBarriers.empty() ||
  2615. this->FunctionBlockers.size() > this->FunctionBlockerBarriers.back());
  2616. auto b = std::move(this->FunctionBlockers.top());
  2617. this->FunctionBlockers.pop();
  2618. return b;
  2619. }
  2620. std::string const& cmMakefile::GetHomeDirectory() const
  2621. {
  2622. return this->GetCMakeInstance()->GetHomeDirectory();
  2623. }
  2624. std::string const& cmMakefile::GetHomeOutputDirectory() const
  2625. {
  2626. return this->GetCMakeInstance()->GetHomeOutputDirectory();
  2627. }
  2628. void cmMakefile::SetScriptModeFile(std::string const& scriptfile)
  2629. {
  2630. this->AddDefinition("CMAKE_SCRIPT_MODE_FILE", scriptfile);
  2631. }
  2632. void cmMakefile::SetArgcArgv(std::vector<std::string> const& args)
  2633. {
  2634. this->AddDefinition("CMAKE_ARGC", std::to_string(args.size()));
  2635. for (auto i = 0u; i < args.size(); ++i) {
  2636. this->AddDefinition(cmStrCat("CMAKE_ARGV", i), args[i]);
  2637. }
  2638. }
  2639. cmSourceFile* cmMakefile::GetSource(std::string const& sourceName,
  2640. cmSourceFileLocationKind kind) const
  2641. {
  2642. // First check "Known" paths (avoids the creation of cmSourceFileLocation)
  2643. if (kind == cmSourceFileLocationKind::Known) {
  2644. auto sfsi = this->KnownFileSearchIndex.find(sourceName);
  2645. if (sfsi != this->KnownFileSearchIndex.end()) {
  2646. return sfsi->second;
  2647. }
  2648. }
  2649. cmSourceFileLocation sfl(this, sourceName, kind);
  2650. auto name = this->GetCMakeInstance()->StripExtension(sfl.GetName());
  2651. #if defined(_WIN32) || defined(__APPLE__)
  2652. name = cmSystemTools::LowerCase(name);
  2653. #endif
  2654. auto sfsi = this->SourceFileSearchIndex.find(name);
  2655. if (sfsi != this->SourceFileSearchIndex.end()) {
  2656. for (auto* sf : sfsi->second) {
  2657. if (sf->Matches(sfl)) {
  2658. return sf;
  2659. }
  2660. }
  2661. }
  2662. return nullptr;
  2663. }
  2664. cmSourceFile* cmMakefile::CreateSource(std::string const& sourceName,
  2665. bool generated,
  2666. cmSourceFileLocationKind kind)
  2667. {
  2668. auto sf = cm::make_unique<cmSourceFile>(this, sourceName, generated, kind);
  2669. auto name =
  2670. this->GetCMakeInstance()->StripExtension(sf->GetLocation().GetName());
  2671. #if defined(_WIN32) || defined(__APPLE__)
  2672. name = cmSystemTools::LowerCase(name);
  2673. #endif
  2674. this->SourceFileSearchIndex[name].push_back(sf.get());
  2675. // for "Known" paths add direct lookup (used for faster lookup in GetSource)
  2676. if (kind == cmSourceFileLocationKind::Known) {
  2677. this->KnownFileSearchIndex[sourceName] = sf.get();
  2678. }
  2679. this->SourceFiles.push_back(std::move(sf));
  2680. return this->SourceFiles.back().get();
  2681. }
  2682. cmSourceFile* cmMakefile::GetOrCreateSource(std::string const& sourceName,
  2683. bool generated,
  2684. cmSourceFileLocationKind kind)
  2685. {
  2686. if (cmSourceFile* esf = this->GetSource(sourceName, kind)) {
  2687. return esf;
  2688. }
  2689. return this->CreateSource(sourceName, generated, kind);
  2690. }
  2691. cmSourceFile* cmMakefile::GetOrCreateGeneratedSource(
  2692. std::string const& sourceName)
  2693. {
  2694. cmSourceFile* sf =
  2695. this->GetOrCreateSource(sourceName, true, cmSourceFileLocationKind::Known);
  2696. sf->MarkAsGenerated(); // In case we did not create the source file.
  2697. return sf;
  2698. }
  2699. void cmMakefile::CreateGeneratedOutputs(
  2700. std::vector<std::string> const& outputs)
  2701. {
  2702. for (std::string const& o : outputs) {
  2703. if (cmGeneratorExpression::Find(o) == std::string::npos) {
  2704. this->GetOrCreateGeneratedSource(o);
  2705. }
  2706. }
  2707. }
  2708. void cmMakefile::AddTargetObject(std::string const& tgtName,
  2709. std::string const& objFile)
  2710. {
  2711. cmSourceFile* sf =
  2712. this->GetOrCreateSource(objFile, true, cmSourceFileLocationKind::Known);
  2713. sf->SetObjectLibrary(tgtName);
  2714. sf->SetProperty("EXTERNAL_OBJECT", "1");
  2715. // TODO: Compute a language for this object based on the associated source
  2716. // file that compiles to it. Needs a policy as it likely affects link
  2717. // language selection if done unconditionally.
  2718. #if !defined(CMAKE_BOOTSTRAP)
  2719. this->SourceGroups[this->ObjectLibrariesSourceGroupIndex].AddGroupFile(
  2720. sf->ResolveFullPath());
  2721. #endif
  2722. }
  2723. void cmMakefile::EnableLanguage(std::vector<std::string> const& languages,
  2724. bool optional)
  2725. {
  2726. if (this->DeferRunning) {
  2727. this->IssueMessage(
  2728. MessageType::FATAL_ERROR,
  2729. "Languages may not be enabled during deferred execution.");
  2730. return;
  2731. }
  2732. if (char const* def = this->GetGlobalGenerator()->GetCMakeCFGIntDir()) {
  2733. this->AddDefinition("CMAKE_CFG_INTDIR", def);
  2734. }
  2735. std::vector<std::string> unique_languages;
  2736. {
  2737. std::vector<std::string> duplicate_languages;
  2738. for (std::string const& language : languages) {
  2739. if (!cm::contains(unique_languages, language)) {
  2740. unique_languages.push_back(language);
  2741. } else if (!cm::contains(duplicate_languages, language)) {
  2742. duplicate_languages.push_back(language);
  2743. }
  2744. }
  2745. if (!duplicate_languages.empty()) {
  2746. auto quantity = duplicate_languages.size() == 1 ? " has"_s : "s have"_s;
  2747. this->IssueMessage(
  2748. MessageType::AUTHOR_WARNING,
  2749. cmStrCat("Languages to be enabled may not be specified more "
  2750. "than once at the same time. The following language",
  2751. quantity, " been specified multiple times: ",
  2752. cmJoin(duplicate_languages, ", ")));
  2753. }
  2754. }
  2755. // If RC is explicitly listed we need to do it after other languages.
  2756. // On some platforms we enable RC implicitly while enabling others.
  2757. // Do not let that look like recursive enable_language(RC).
  2758. std::vector<std::string> languages_without_RC;
  2759. std::vector<std::string> languages_for_RC;
  2760. languages_without_RC.reserve(unique_languages.size());
  2761. for (std::string const& language : unique_languages) {
  2762. if (language == "RC"_s) {
  2763. languages_for_RC.push_back(language);
  2764. } else {
  2765. languages_without_RC.push_back(language);
  2766. }
  2767. }
  2768. if (!languages_without_RC.empty()) {
  2769. this->GetGlobalGenerator()->EnableLanguage(languages_without_RC, this,
  2770. optional);
  2771. }
  2772. if (!languages_for_RC.empty()) {
  2773. this->GetGlobalGenerator()->EnableLanguage(languages_for_RC, this,
  2774. optional);
  2775. }
  2776. }
  2777. int cmMakefile::TryCompile(std::string const& srcdir,
  2778. std::string const& bindir,
  2779. std::string const& projectName,
  2780. std::string const& targetName, bool fast, int jobs,
  2781. std::vector<std::string> const* cmakeArgs,
  2782. std::string& output)
  2783. {
  2784. this->IsSourceFileTryCompile = fast;
  2785. // does the binary directory exist ? If not create it...
  2786. if (!cmSystemTools::FileIsDirectory(bindir)) {
  2787. cmSystemTools::MakeDirectory(bindir);
  2788. }
  2789. // change to the tests directory and run cmake
  2790. // use the cmake object instead of calling cmake
  2791. cmWorkingDirectory workdir(bindir);
  2792. if (workdir.Failed()) {
  2793. this->IssueMessage(MessageType::FATAL_ERROR, workdir.GetError());
  2794. cmSystemTools::SetFatalErrorOccurred();
  2795. this->IsSourceFileTryCompile = false;
  2796. return 1;
  2797. }
  2798. // make sure the same generator is used
  2799. // use this program as the cmake to be run, it should not
  2800. // be run that way but the cmake object requires a valid path
  2801. cmake cm(cmake::RoleProject, cmState::Project,
  2802. cmState::ProjectKind::TryCompile);
  2803. auto gg = cm.CreateGlobalGenerator(this->GetGlobalGenerator()->GetName());
  2804. if (!gg) {
  2805. this->IssueMessage(MessageType::INTERNAL_ERROR,
  2806. "Global generator '" +
  2807. this->GetGlobalGenerator()->GetName() +
  2808. "' could not be created.");
  2809. cmSystemTools::SetFatalErrorOccurred();
  2810. this->IsSourceFileTryCompile = false;
  2811. return 1;
  2812. }
  2813. gg->RecursionDepth = this->RecursionDepth;
  2814. cm.SetGlobalGenerator(std::move(gg));
  2815. // copy trace state
  2816. cm.SetTraceRedirect(this->GetCMakeInstance());
  2817. // do a configure
  2818. cm.SetHomeDirectory(srcdir);
  2819. cm.SetHomeOutputDirectory(bindir);
  2820. cm.SetGeneratorInstance(this->GetSafeDefinition("CMAKE_GENERATOR_INSTANCE"));
  2821. cm.SetGeneratorPlatform(this->GetSafeDefinition("CMAKE_GENERATOR_PLATFORM"));
  2822. cm.SetGeneratorToolset(this->GetSafeDefinition("CMAKE_GENERATOR_TOOLSET"));
  2823. cm.LoadCache();
  2824. if (!cm.GetGlobalGenerator()->IsMultiConfig()) {
  2825. if (cmValue config =
  2826. this->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION")) {
  2827. // Tell the single-configuration generator which one to use.
  2828. // Add this before the user-provided CMake arguments in case
  2829. // one of the arguments is -DCMAKE_BUILD_TYPE=...
  2830. cm.AddCacheEntry("CMAKE_BUILD_TYPE", config, "Build configuration",
  2831. cmStateEnums::STRING);
  2832. }
  2833. }
  2834. cmValue recursionDepth =
  2835. this->GetDefinition("CMAKE_MAXIMUM_RECURSION_DEPTH");
  2836. if (recursionDepth) {
  2837. cm.AddCacheEntry("CMAKE_MAXIMUM_RECURSION_DEPTH", recursionDepth,
  2838. "Maximum recursion depth", cmStateEnums::STRING);
  2839. }
  2840. // if cmake args were provided then pass them in
  2841. if (cmakeArgs) {
  2842. // FIXME: Workaround to ignore unused CLI variables in try-compile.
  2843. //
  2844. // Ideally we should use SetArgs for options like --no-warn-unused-cli.
  2845. // However, there is a subtle problem when certain arguments are passed to
  2846. // a macro wrapping around try_compile or try_run that does not escape
  2847. // semicolons in its parameters but just passes ${ARGV} or ${ARGN}. In
  2848. // this case a list argument like "-DVAR=a;b" gets split into multiple
  2849. // cmake arguments "-DVAR=a" and "b". Currently SetCacheArgs ignores
  2850. // argument "b" and uses just "-DVAR=a", leading to a subtle bug in that
  2851. // the try_compile or try_run does not get the proper value of VAR. If we
  2852. // call SetArgs here then it would treat "b" as the source directory and
  2853. // cause an error such as "The source directory .../CMakeFiles/CMakeTmp/b
  2854. // does not exist", thus breaking the try_compile or try_run completely.
  2855. //
  2856. // Strictly speaking the bug is in the wrapper macro because the CMake
  2857. // language has always flattened nested lists and the macro should escape
  2858. // the semicolons in its arguments before forwarding them. However, this
  2859. // bug is so subtle that projects typically work anyway, usually because
  2860. // the value VAR=a is sufficient for the try_compile or try_run to get the
  2861. // correct result. Calling SetArgs here would break such projects that
  2862. // previously built. Instead we work around the issue by never reporting
  2863. // unused arguments and ignoring options such as --no-warn-unused-cli.
  2864. cm.SetWarnUnusedCli(false);
  2865. // cm.SetArgs(*cmakeArgs, true);
  2866. cm.SetCacheArgs(*cmakeArgs);
  2867. }
  2868. // to save time we pass the EnableLanguage info directly
  2869. cm.GetGlobalGenerator()->EnableLanguagesFromGenerator(
  2870. this->GetGlobalGenerator(), this);
  2871. if (this->IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) {
  2872. cm.AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_WARNINGS", "TRUE", "",
  2873. cmStateEnums::INTERNAL);
  2874. } else {
  2875. cm.AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_WARNINGS", "FALSE", "",
  2876. cmStateEnums::INTERNAL);
  2877. }
  2878. if (cm.Configure() != 0) {
  2879. this->IssueMessage(MessageType::FATAL_ERROR,
  2880. "Failed to configure test project build system.");
  2881. cmSystemTools::SetFatalErrorOccurred();
  2882. this->IsSourceFileTryCompile = false;
  2883. return 1;
  2884. }
  2885. if (cm.Generate() != 0) {
  2886. this->IssueMessage(MessageType::FATAL_ERROR,
  2887. "Failed to generate test project build system.");
  2888. cmSystemTools::SetFatalErrorOccurred();
  2889. this->IsSourceFileTryCompile = false;
  2890. return 1;
  2891. }
  2892. // finally call the generator to actually build the resulting project
  2893. int ret = this->GetGlobalGenerator()->TryCompile(
  2894. jobs, srcdir, bindir, projectName, targetName, fast, output, this);
  2895. this->IsSourceFileTryCompile = false;
  2896. return ret;
  2897. }
  2898. bool cmMakefile::GetIsSourceFileTryCompile() const
  2899. {
  2900. return this->IsSourceFileTryCompile;
  2901. }
  2902. cmake* cmMakefile::GetCMakeInstance() const
  2903. {
  2904. return this->GlobalGenerator->GetCMakeInstance();
  2905. }
  2906. cmMessenger* cmMakefile::GetMessenger() const
  2907. {
  2908. return this->GetCMakeInstance()->GetMessenger();
  2909. }
  2910. cmGlobalGenerator* cmMakefile::GetGlobalGenerator() const
  2911. {
  2912. return this->GlobalGenerator;
  2913. }
  2914. #ifndef CMAKE_BOOTSTRAP
  2915. cmVariableWatch* cmMakefile::GetVariableWatch() const
  2916. {
  2917. if (this->GetCMakeInstance() &&
  2918. this->GetCMakeInstance()->GetVariableWatch()) {
  2919. return this->GetCMakeInstance()->GetVariableWatch();
  2920. }
  2921. return nullptr;
  2922. }
  2923. #endif
  2924. cmState* cmMakefile::GetState() const
  2925. {
  2926. return this->GetCMakeInstance()->GetState();
  2927. }
  2928. void cmMakefile::DisplayStatus(std::string const& message, float s) const
  2929. {
  2930. cmake* cm = this->GetCMakeInstance();
  2931. if (cm->GetWorkingMode() == cmake::FIND_PACKAGE_MODE) {
  2932. // don't output any STATUS message in FIND_PACKAGE_MODE, since they will
  2933. // directly be fed to the compiler, which will be confused.
  2934. return;
  2935. }
  2936. cm->UpdateProgress(message, s);
  2937. #ifdef CMake_ENABLE_DEBUGGER
  2938. if (cm->GetDebugAdapter()) {
  2939. cm->GetDebugAdapter()->OnMessageOutput(MessageType::MESSAGE, message);
  2940. }
  2941. #endif
  2942. }
  2943. std::string cmMakefile::GetModulesFile(cm::string_view filename, bool& system,
  2944. bool debug,
  2945. std::string& debugBuffer) const
  2946. {
  2947. std::string result;
  2948. std::string moduleInCMakeRoot;
  2949. std::string moduleInCMakeModulePath;
  2950. // Always search in CMAKE_MODULE_PATH:
  2951. cmValue cmakeModulePath = this->GetDefinition("CMAKE_MODULE_PATH");
  2952. if (cmakeModulePath) {
  2953. cmList modulePath{ *cmakeModulePath };
  2954. // Look through the possible module directories.
  2955. for (std::string itempl : modulePath) {
  2956. cmSystemTools::ConvertToUnixSlashes(itempl);
  2957. itempl += "/";
  2958. itempl += filename;
  2959. if (cmSystemTools::FileExists(itempl)) {
  2960. moduleInCMakeModulePath = itempl;
  2961. break;
  2962. }
  2963. if (debug) {
  2964. debugBuffer = cmStrCat(debugBuffer, " ", itempl, '\n');
  2965. }
  2966. }
  2967. }
  2968. // Always search in the standard modules location.
  2969. moduleInCMakeRoot =
  2970. cmStrCat(cmSystemTools::GetCMakeRoot(), "/Modules/", filename);
  2971. cmSystemTools::ConvertToUnixSlashes(moduleInCMakeRoot);
  2972. if (!cmSystemTools::FileExists(moduleInCMakeRoot)) {
  2973. if (debug) {
  2974. debugBuffer = cmStrCat(debugBuffer, " ", moduleInCMakeRoot, '\n');
  2975. }
  2976. moduleInCMakeRoot.clear();
  2977. }
  2978. // Normally, prefer the files found in CMAKE_MODULE_PATH. Only when the file
  2979. // from which we are being called is located itself in CMAKE_ROOT, then
  2980. // prefer results from CMAKE_ROOT depending on the policy setting.
  2981. if (!moduleInCMakeModulePath.empty() && !moduleInCMakeRoot.empty()) {
  2982. cmValue currentFile = this->GetDefinition("CMAKE_CURRENT_LIST_FILE");
  2983. std::string mods = cmStrCat(cmSystemTools::GetCMakeRoot(), "/Modules/");
  2984. if (currentFile && cmSystemTools::IsSubDirectory(*currentFile, mods)) {
  2985. system = true;
  2986. result = moduleInCMakeRoot;
  2987. } else {
  2988. system = false;
  2989. result = moduleInCMakeModulePath;
  2990. }
  2991. } else if (!moduleInCMakeModulePath.empty()) {
  2992. system = false;
  2993. result = moduleInCMakeModulePath;
  2994. } else {
  2995. system = true;
  2996. result = moduleInCMakeRoot;
  2997. }
  2998. return result;
  2999. }
  3000. void cmMakefile::ConfigureString(std::string const& input, std::string& output,
  3001. bool atOnly, bool escapeQuotes) const
  3002. {
  3003. // Split input to handle one line at a time.
  3004. std::string::const_iterator lineStart = input.begin();
  3005. while (lineStart != input.end()) {
  3006. // Find the end of this line.
  3007. std::string::const_iterator lineEnd = lineStart;
  3008. while (lineEnd != input.end() && *lineEnd != '\n') {
  3009. ++lineEnd;
  3010. }
  3011. // Copy the line.
  3012. std::string line(lineStart, lineEnd);
  3013. // Skip the newline character.
  3014. bool haveNewline = (lineEnd != input.end());
  3015. if (haveNewline) {
  3016. ++lineEnd;
  3017. }
  3018. // Replace #cmakedefine instances.
  3019. if (this->cmDefineRegex.find(line)) {
  3020. cmValue def = this->GetDefinition(this->cmDefineRegex.match(2));
  3021. if (!def.IsOff()) {
  3022. std::string const indentation = this->cmDefineRegex.match(1);
  3023. cmSystemTools::ReplaceString(line,
  3024. cmStrCat('#', indentation, "cmakedefine"),
  3025. cmStrCat('#', indentation, "define"));
  3026. output += line;
  3027. } else {
  3028. output += "/* #undef ";
  3029. output += this->cmDefineRegex.match(2);
  3030. output += " */";
  3031. }
  3032. } else if (this->cmDefine01Regex.find(line)) {
  3033. std::string const indentation = this->cmDefine01Regex.match(1);
  3034. cmValue def = this->GetDefinition(this->cmDefine01Regex.match(2));
  3035. cmSystemTools::ReplaceString(line,
  3036. cmStrCat('#', indentation, "cmakedefine01"),
  3037. cmStrCat('#', indentation, "define"));
  3038. output += line;
  3039. if (!def.IsOff()) {
  3040. output += " 1";
  3041. } else {
  3042. output += " 0";
  3043. }
  3044. } else {
  3045. output += line;
  3046. }
  3047. if (haveNewline) {
  3048. output += '\n';
  3049. }
  3050. // Move to the next line.
  3051. lineStart = lineEnd;
  3052. }
  3053. // Perform variable replacements.
  3054. char const* filename = nullptr;
  3055. long lineNumber = -1;
  3056. if (!this->Backtrace.Empty()) {
  3057. auto const& currentTrace = this->Backtrace.Top();
  3058. filename = currentTrace.FilePath.c_str();
  3059. lineNumber = currentTrace.Line;
  3060. }
  3061. this->ExpandVariablesInString(output, escapeQuotes, true, atOnly, filename,
  3062. lineNumber, true, true);
  3063. }
  3064. int cmMakefile::ConfigureFile(std::string const& infile,
  3065. std::string const& outfile, bool copyonly,
  3066. bool atOnly, bool escapeQuotes,
  3067. mode_t permissions, cmNewLineStyle newLine)
  3068. {
  3069. int res = 1;
  3070. if (!this->CanIWriteThisFile(outfile)) {
  3071. cmSystemTools::Error(cmStrCat("Attempt to write file: ", outfile,
  3072. " into a source directory."));
  3073. return 0;
  3074. }
  3075. if (!cmSystemTools::FileExists(infile)) {
  3076. cmSystemTools::Error(cmStrCat("File ", infile, " does not exist."));
  3077. return 0;
  3078. }
  3079. std::string soutfile = outfile;
  3080. std::string const& sinfile = infile;
  3081. this->AddCMakeDependFile(sinfile);
  3082. cmSystemTools::ConvertToUnixSlashes(soutfile);
  3083. // Re-generate if non-temporary outputs are missing.
  3084. // when we finalize the configuration we will remove all
  3085. // output files that now don't exist.
  3086. this->AddCMakeOutputFile(soutfile);
  3087. if (permissions == 0) {
  3088. cmSystemTools::GetPermissions(sinfile, permissions);
  3089. }
  3090. std::string::size_type pos = soutfile.rfind('/');
  3091. if (pos != std::string::npos) {
  3092. std::string path = soutfile.substr(0, pos);
  3093. cmSystemTools::MakeDirectory(path);
  3094. }
  3095. if (copyonly) {
  3096. auto const copy_status =
  3097. cmSystemTools::CopyFileIfDifferent(sinfile, soutfile);
  3098. if (!copy_status) {
  3099. this->IssueMessage(
  3100. MessageType::FATAL_ERROR,
  3101. cmStrCat("Fail to copy ",
  3102. copy_status.Path == cmsys::SystemTools::CopyStatus::SourcePath
  3103. ? "source"
  3104. : "destination",
  3105. "file: ", copy_status.GetString()));
  3106. res = 0;
  3107. } else {
  3108. auto const status = cmSystemTools::SetPermissions(soutfile, permissions);
  3109. if (!status) {
  3110. this->IssueMessage(MessageType::FATAL_ERROR, status.GetString());
  3111. res = 0;
  3112. }
  3113. }
  3114. return res;
  3115. }
  3116. std::string newLineCharacters;
  3117. std::ios::openmode omode = std::ios::out | std::ios::trunc;
  3118. if (newLine.IsValid()) {
  3119. newLineCharacters = newLine.GetCharacters();
  3120. omode |= std::ios::binary;
  3121. } else {
  3122. newLineCharacters = "\n";
  3123. }
  3124. std::string tempOutputFile = cmStrCat(soutfile, ".tmp");
  3125. cmsys::ofstream fout(tempOutputFile.c_str(), omode);
  3126. if (!fout) {
  3127. cmSystemTools::Error("Could not open file for write in copy operation " +
  3128. tempOutputFile);
  3129. cmSystemTools::ReportLastSystemError("");
  3130. return 0;
  3131. }
  3132. cmsys::ifstream fin(sinfile.c_str());
  3133. if (!fin) {
  3134. cmSystemTools::Error("Could not open file for read in copy operation " +
  3135. sinfile);
  3136. return 0;
  3137. }
  3138. cmsys::FStream::BOM bom = cmsys::FStream::ReadBOM(fin);
  3139. if (bom != cmsys::FStream::BOM_None && bom != cmsys::FStream::BOM_UTF8) {
  3140. this->IssueMessage(
  3141. MessageType::FATAL_ERROR,
  3142. cmStrCat("File starts with a Byte-Order-Mark that is not UTF-8:\n ",
  3143. sinfile));
  3144. return 0;
  3145. }
  3146. // rewind to copy BOM to output file
  3147. fin.seekg(0);
  3148. // now copy input to output and expand variables in the
  3149. // input file at the same time
  3150. std::string inLine;
  3151. std::string outLine;
  3152. while (cmSystemTools::GetLineFromStream(fin, inLine)) {
  3153. outLine.clear();
  3154. this->ConfigureString(inLine, outLine, atOnly, escapeQuotes);
  3155. fout << outLine << newLineCharacters;
  3156. }
  3157. // close the files before attempting to copy
  3158. fin.close();
  3159. fout.close();
  3160. auto status = cmSystemTools::MoveFileIfDifferent(tempOutputFile, soutfile);
  3161. if (!status) {
  3162. this->IssueMessage(MessageType::FATAL_ERROR, status.GetString());
  3163. res = 0;
  3164. } else {
  3165. status = cmSystemTools::SetPermissions(soutfile, permissions);
  3166. if (!status) {
  3167. this->IssueMessage(MessageType::FATAL_ERROR, status.GetString());
  3168. res = 0;
  3169. }
  3170. }
  3171. return res;
  3172. }
  3173. void cmMakefile::SetProperty(std::string const& prop, cmValue value)
  3174. {
  3175. this->StateSnapshot.GetDirectory().SetProperty(prop, value, this->Backtrace);
  3176. }
  3177. void cmMakefile::AppendProperty(std::string const& prop,
  3178. std::string const& value, bool asString)
  3179. {
  3180. this->StateSnapshot.GetDirectory().AppendProperty(prop, value, asString,
  3181. this->Backtrace);
  3182. }
  3183. cmValue cmMakefile::GetProperty(std::string const& prop) const
  3184. {
  3185. // Check for computed properties.
  3186. static std::string output;
  3187. if (prop == "TESTS"_s) {
  3188. std::vector<std::string> keys;
  3189. // get list of keys
  3190. auto const* t = this;
  3191. std::transform(
  3192. t->Tests.begin(), t->Tests.end(), std::back_inserter(keys),
  3193. [](decltype(t->Tests)::value_type const& pair) { return pair.first; });
  3194. output = cmList::to_string(keys);
  3195. return cmValue(output);
  3196. }
  3197. return this->StateSnapshot.GetDirectory().GetProperty(prop);
  3198. }
  3199. cmValue cmMakefile::GetProperty(std::string const& prop, bool chain) const
  3200. {
  3201. return this->StateSnapshot.GetDirectory().GetProperty(prop, chain);
  3202. }
  3203. bool cmMakefile::GetPropertyAsBool(std::string const& prop) const
  3204. {
  3205. return this->GetProperty(prop).IsOn();
  3206. }
  3207. std::vector<std::string> cmMakefile::GetPropertyKeys() const
  3208. {
  3209. return this->StateSnapshot.GetDirectory().GetPropertyKeys();
  3210. }
  3211. cmTarget* cmMakefile::FindLocalNonAliasTarget(std::string const& name) const
  3212. {
  3213. auto i = this->Targets.find(name);
  3214. if (i != this->Targets.end()) {
  3215. return &i->second;
  3216. }
  3217. return nullptr;
  3218. }
  3219. cmTest* cmMakefile::CreateTest(std::string const& testName)
  3220. {
  3221. cmTest* test = this->GetTest(testName);
  3222. if (test) {
  3223. return test;
  3224. }
  3225. auto newTest = cm::make_unique<cmTest>(this);
  3226. test = newTest.get();
  3227. newTest->SetName(testName);
  3228. this->Tests[testName] = std::move(newTest);
  3229. return test;
  3230. }
  3231. cmTest* cmMakefile::GetTest(std::string const& testName) const
  3232. {
  3233. auto mi = this->Tests.find(testName);
  3234. if (mi != this->Tests.end()) {
  3235. return mi->second.get();
  3236. }
  3237. return nullptr;
  3238. }
  3239. void cmMakefile::GetTests(std::string const& config,
  3240. std::vector<cmTest*>& tests) const
  3241. {
  3242. for (auto const& generator : this->GetTestGenerators()) {
  3243. if (generator->TestsForConfig(config)) {
  3244. tests.push_back(generator->GetTest());
  3245. }
  3246. }
  3247. }
  3248. void cmMakefile::AddCMakeDependFilesFromUser()
  3249. {
  3250. cmList deps;
  3251. if (cmValue deps_str = this->GetProperty("CMAKE_CONFIGURE_DEPENDS")) {
  3252. deps.assign(*deps_str);
  3253. }
  3254. for (auto const& dep : deps) {
  3255. if (cmSystemTools::FileIsFullPath(dep)) {
  3256. this->AddCMakeDependFile(dep);
  3257. } else {
  3258. std::string f = cmStrCat(this->GetCurrentSourceDirectory(), '/', dep);
  3259. this->AddCMakeDependFile(f);
  3260. }
  3261. }
  3262. }
  3263. std::string cmMakefile::FormatListFileStack() const
  3264. {
  3265. std::vector<std::string> listFiles;
  3266. for (auto snp = this->StateSnapshot; snp.IsValid();
  3267. snp = snp.GetCallStackParent()) {
  3268. listFiles.emplace_back(snp.GetExecutionListFile());
  3269. }
  3270. if (listFiles.empty()) {
  3271. return {};
  3272. }
  3273. auto depth = 1;
  3274. std::transform(listFiles.begin(), listFiles.end(), listFiles.begin(),
  3275. [&depth](std::string const& file) {
  3276. return cmStrCat('[', depth++, "]\t", file);
  3277. });
  3278. return cmJoinStrings(cmMakeRange(listFiles.rbegin(), listFiles.rend()),
  3279. "\n "_s, {});
  3280. }
  3281. void cmMakefile::PushScope()
  3282. {
  3283. this->StateSnapshot =
  3284. this->GetState()->CreateVariableScopeSnapshot(this->StateSnapshot);
  3285. this->PushLoopBlockBarrier();
  3286. #if !defined(CMAKE_BOOTSTRAP)
  3287. this->GetGlobalGenerator()->GetFileLockPool().PushFunctionScope();
  3288. #endif
  3289. }
  3290. void cmMakefile::PopScope()
  3291. {
  3292. #if !defined(CMAKE_BOOTSTRAP)
  3293. this->GetGlobalGenerator()->GetFileLockPool().PopFunctionScope();
  3294. #endif
  3295. this->PopLoopBlockBarrier();
  3296. this->PopSnapshot();
  3297. }
  3298. void cmMakefile::RaiseScope(std::string const& var, char const* varDef)
  3299. {
  3300. if (var.empty()) {
  3301. return;
  3302. }
  3303. if (!this->StateSnapshot.RaiseScope(var, varDef)) {
  3304. this->IssueMessage(
  3305. MessageType::AUTHOR_WARNING,
  3306. cmStrCat("Cannot set \"", var, "\": current scope has no parent."));
  3307. return;
  3308. }
  3309. #ifndef CMAKE_BOOTSTRAP
  3310. cmVariableWatch* vv = this->GetVariableWatch();
  3311. if (vv) {
  3312. vv->VariableAccessed(var, cmVariableWatch::VARIABLE_MODIFIED_ACCESS,
  3313. varDef, this);
  3314. }
  3315. #endif
  3316. }
  3317. void cmMakefile::RaiseScope(std::vector<std::string> const& variables)
  3318. {
  3319. for (auto const& varName : variables) {
  3320. if (this->IsNormalDefinitionSet(varName)) {
  3321. this->RaiseScope(varName, this->GetDefinition(varName));
  3322. } else {
  3323. // unset variable in parent scope
  3324. this->RaiseScope(varName, nullptr);
  3325. }
  3326. }
  3327. }
  3328. cmTarget* cmMakefile::AddImportedTarget(std::string const& name,
  3329. cmStateEnums::TargetType type,
  3330. bool global)
  3331. {
  3332. // Create the target.
  3333. std::unique_ptr<cmTarget> target(
  3334. new cmTarget(name, type,
  3335. global ? cmTarget::Visibility::ImportedGlobally
  3336. : cmTarget::Visibility::Imported,
  3337. this, cmTarget::PerConfig::Yes));
  3338. // Add to the set of available imported targets.
  3339. this->ImportedTargets[name] = target.get();
  3340. this->GetGlobalGenerator()->IndexTarget(target.get());
  3341. this->GetStateSnapshot().GetDirectory().AddImportedTargetName(name);
  3342. // Transfer ownership to this cmMakefile object.
  3343. this->ImportedTargetsOwned.push_back(std::move(target));
  3344. return this->ImportedTargetsOwned.back().get();
  3345. }
  3346. cmTarget* cmMakefile::AddForeignTarget(std::string const& origin,
  3347. std::string const& name)
  3348. {
  3349. auto foreign_name = cmStrCat("@foreign_", origin, "::", name);
  3350. std::unique_ptr<cmTarget> target(new cmTarget(
  3351. foreign_name, cmStateEnums::TargetType::INTERFACE_LIBRARY,
  3352. cmTarget::Visibility::Foreign, this, cmTarget::PerConfig::Yes));
  3353. this->ImportedTargets[foreign_name] = target.get();
  3354. this->GetGlobalGenerator()->IndexTarget(target.get());
  3355. this->GetStateSnapshot().GetDirectory().AddImportedTargetName(foreign_name);
  3356. this->ImportedTargetsOwned.push_back(std::move(target));
  3357. return this->ImportedTargetsOwned.back().get();
  3358. }
  3359. cmTarget* cmMakefile::FindTargetToUse(
  3360. std::string const& name, cmStateEnums::TargetDomainSet domains) const
  3361. {
  3362. // Look for an imported target. These take priority because they
  3363. // are more local in scope and do not have to be globally unique.
  3364. auto targetName = name;
  3365. if (domains.contains(cmStateEnums::TargetDomain::ALIAS)) {
  3366. // Look for local alias targets.
  3367. auto alias = this->AliasTargets.find(name);
  3368. if (alias != this->AliasTargets.end()) {
  3369. targetName = alias->second;
  3370. }
  3371. }
  3372. auto const imported = this->ImportedTargets.find(targetName);
  3373. bool const useForeign =
  3374. domains.contains(cmStateEnums::TargetDomain::FOREIGN);
  3375. bool const useNative = domains.contains(cmStateEnums::TargetDomain::NATIVE);
  3376. if (imported != this->ImportedTargets.end()) {
  3377. if (imported->second->IsForeign() ? useForeign : useNative) {
  3378. return imported->second;
  3379. }
  3380. }
  3381. // Look for a target built in this directory.
  3382. if (cmTarget* t = this->FindLocalNonAliasTarget(name)) {
  3383. if (t->IsForeign() ? useForeign : useNative) {
  3384. return t;
  3385. }
  3386. }
  3387. // Look for a target built in this project.
  3388. return this->GetGlobalGenerator()->FindTarget(name, domains);
  3389. }
  3390. bool cmMakefile::IsAlias(std::string const& name) const
  3391. {
  3392. if (cm::contains(this->AliasTargets, name)) {
  3393. return true;
  3394. }
  3395. return this->GetGlobalGenerator()->IsAlias(name);
  3396. }
  3397. bool cmMakefile::EnforceUniqueName(std::string const& name, std::string& msg,
  3398. bool isCustom) const
  3399. {
  3400. if (this->IsAlias(name)) {
  3401. msg = cmStrCat("cannot create target \"", name,
  3402. "\" because an alias with the same name already exists.");
  3403. return false;
  3404. }
  3405. if (cmTarget* existing = this->FindTargetToUse(name)) {
  3406. // The name given conflicts with an existing target. Produce an
  3407. // error in a compatible way.
  3408. if (existing->IsImported()) {
  3409. // Imported targets were not supported in previous versions.
  3410. // This is new code, so we can make it an error.
  3411. msg = cmStrCat(
  3412. "cannot create target \"", name,
  3413. "\" because an imported target with the same name already exists.");
  3414. return false;
  3415. }
  3416. // The conflict is with a non-imported target.
  3417. // Allow this if the user has requested support.
  3418. cmake* cm = this->GetCMakeInstance();
  3419. if (isCustom && existing->GetType() == cmStateEnums::UTILITY &&
  3420. this != existing->GetMakefile() &&
  3421. cm->GetState()->GetGlobalPropertyAsBool(
  3422. "ALLOW_DUPLICATE_CUSTOM_TARGETS")) {
  3423. return true;
  3424. }
  3425. // Produce an error that tells the user how to work around the
  3426. // problem.
  3427. std::ostringstream e;
  3428. e << "cannot create target \"" << name
  3429. << "\" because another target with the same name already exists. "
  3430. "The existing target is ";
  3431. switch (existing->GetType()) {
  3432. case cmStateEnums::EXECUTABLE:
  3433. e << "an executable ";
  3434. break;
  3435. case cmStateEnums::STATIC_LIBRARY:
  3436. e << "a static library ";
  3437. break;
  3438. case cmStateEnums::SHARED_LIBRARY:
  3439. e << "a shared library ";
  3440. break;
  3441. case cmStateEnums::MODULE_LIBRARY:
  3442. e << "a module library ";
  3443. break;
  3444. case cmStateEnums::UTILITY:
  3445. e << "a custom target ";
  3446. break;
  3447. case cmStateEnums::INTERFACE_LIBRARY:
  3448. e << "an interface library ";
  3449. break;
  3450. default:
  3451. break;
  3452. }
  3453. e << "created in source directory \""
  3454. << existing->GetMakefile()->GetCurrentSourceDirectory()
  3455. << "\". "
  3456. "See documentation for policy CMP0002 for more details.";
  3457. msg = e.str();
  3458. return false;
  3459. }
  3460. return true;
  3461. }
  3462. bool cmMakefile::EnforceUniqueDir(std::string const& srcPath,
  3463. std::string const& binPath) const
  3464. {
  3465. // Make sure the binary directory is unique.
  3466. cmGlobalGenerator* gg = this->GetGlobalGenerator();
  3467. if (gg->BinaryDirectoryIsNew(binPath)) {
  3468. return true;
  3469. }
  3470. this->IssueMessage(MessageType::FATAL_ERROR,
  3471. cmStrCat("The binary directory\n"
  3472. " ",
  3473. binPath,
  3474. "\n"
  3475. "is already used to build a source directory. "
  3476. "It cannot be used to build source directory\n"
  3477. " ",
  3478. srcPath,
  3479. "\n"
  3480. "Specify a unique binary directory name."));
  3481. return false;
  3482. }
  3483. static std::string const matchVariables[] = {
  3484. "CMAKE_MATCH_0", "CMAKE_MATCH_1", "CMAKE_MATCH_2", "CMAKE_MATCH_3",
  3485. "CMAKE_MATCH_4", "CMAKE_MATCH_5", "CMAKE_MATCH_6", "CMAKE_MATCH_7",
  3486. "CMAKE_MATCH_8", "CMAKE_MATCH_9"
  3487. };
  3488. static std::string const nMatchesVariable = "CMAKE_MATCH_COUNT";
  3489. void cmMakefile::ClearMatches()
  3490. {
  3491. cmValue nMatchesStr = this->GetDefinition(nMatchesVariable);
  3492. if (!nMatchesStr) {
  3493. return;
  3494. }
  3495. int nMatches = atoi(nMatchesStr->c_str());
  3496. for (int i = 0; i <= nMatches; i++) {
  3497. std::string const& var = matchVariables[i];
  3498. std::string const& s = this->GetSafeDefinition(var);
  3499. if (!s.empty()) {
  3500. this->AddDefinition(var, "");
  3501. this->MarkVariableAsUsed(var);
  3502. }
  3503. }
  3504. this->AddDefinition(nMatchesVariable, "0");
  3505. this->MarkVariableAsUsed(nMatchesVariable);
  3506. }
  3507. void cmMakefile::StoreMatches(cmsys::RegularExpression& re)
  3508. {
  3509. char highest = 0;
  3510. for (int i = 0; i < 10; i++) {
  3511. std::string const& m = re.match(i);
  3512. if (!m.empty()) {
  3513. std::string const& var = matchVariables[i];
  3514. this->AddDefinition(var, m);
  3515. this->MarkVariableAsUsed(var);
  3516. highest = static_cast<char>('0' + i);
  3517. }
  3518. }
  3519. char nMatches[] = { highest, '\0' };
  3520. this->AddDefinition(nMatchesVariable, nMatches);
  3521. this->MarkVariableAsUsed(nMatchesVariable);
  3522. }
  3523. cmStateSnapshot cmMakefile::GetStateSnapshot() const
  3524. {
  3525. return this->StateSnapshot;
  3526. }
  3527. cmPolicies::PolicyStatus cmMakefile::GetPolicyStatus(cmPolicies::PolicyID id,
  3528. bool parent_scope) const
  3529. {
  3530. return this->StateSnapshot.GetPolicy(id, parent_scope);
  3531. }
  3532. bool cmMakefile::PolicyOptionalWarningEnabled(std::string const& var) const
  3533. {
  3534. // Check for an explicit CMAKE_POLICY_WARNING_CMP<NNNN> setting.
  3535. if (cmValue val = this->GetDefinition(var)) {
  3536. return val.IsOn();
  3537. }
  3538. // Enable optional policy warnings with --debug-output, --trace,
  3539. // or --trace-expand.
  3540. cmake* cm = this->GetCMakeInstance();
  3541. return cm->GetDebugOutput() || cm->GetTrace();
  3542. }
  3543. bool cmMakefile::SetPolicy(char const* id, cmPolicies::PolicyStatus status)
  3544. {
  3545. cmPolicies::PolicyID pid;
  3546. if (!cmPolicies::GetPolicyID(id, /* out */ pid)) {
  3547. this->IssueMessage(
  3548. MessageType::FATAL_ERROR,
  3549. cmStrCat("Policy \"", id, "\" is not known to this version of CMake."));
  3550. return false;
  3551. }
  3552. return this->SetPolicy(pid, status);
  3553. }
  3554. bool cmMakefile::SetPolicy(cmPolicies::PolicyID id,
  3555. cmPolicies::PolicyStatus status)
  3556. {
  3557. // A removed policy may be set only to NEW.
  3558. if (cmPolicies::IsRemoved(id) && status != cmPolicies::NEW) {
  3559. std::string msg = cmPolicies::GetRemovedPolicyError(id);
  3560. this->IssueMessage(MessageType::FATAL_ERROR, msg);
  3561. return false;
  3562. }
  3563. // Deprecate old policies.
  3564. if (status == cmPolicies::OLD && id <= cmPolicies::CMP0142 &&
  3565. !(this->GetCMakeInstance()->GetIsInTryCompile() &&
  3566. (
  3567. // Policies set by cmCoreTryCompile::TryCompileCode.
  3568. id == cmPolicies::CMP0083 || id == cmPolicies::CMP0091 ||
  3569. id == cmPolicies::CMP0104 || id == cmPolicies::CMP0123 ||
  3570. id == cmPolicies::CMP0126 || id == cmPolicies::CMP0128 ||
  3571. id == cmPolicies::CMP0136 || id == cmPolicies::CMP0141)) &&
  3572. (!this->IsSet("CMAKE_WARN_DEPRECATED") ||
  3573. this->IsOn("CMAKE_WARN_DEPRECATED"))) {
  3574. this->IssueMessage(MessageType::DEPRECATION_WARNING,
  3575. cmPolicies::GetPolicyDeprecatedWarning(id));
  3576. }
  3577. this->StateSnapshot.SetPolicy(id, status);
  3578. return true;
  3579. }
  3580. cmMakefile::PolicyPushPop::PolicyPushPop(cmMakefile* m)
  3581. : Makefile(m)
  3582. {
  3583. this->Makefile->PushPolicy();
  3584. }
  3585. cmMakefile::PolicyPushPop::~PolicyPushPop()
  3586. {
  3587. this->Makefile->PopPolicy();
  3588. }
  3589. void cmMakefile::PushPolicy(bool weak, cmPolicies::PolicyMap const& pm)
  3590. {
  3591. this->StateSnapshot.PushPolicy(pm, weak);
  3592. }
  3593. void cmMakefile::PopPolicy()
  3594. {
  3595. if (!this->StateSnapshot.PopPolicy()) {
  3596. this->IssueMessage(MessageType::FATAL_ERROR,
  3597. "cmake_policy POP without matching PUSH");
  3598. }
  3599. }
  3600. void cmMakefile::PopSnapshot(bool reportError)
  3601. {
  3602. // cmStateSnapshot manages nested policy scopes within it.
  3603. // Since the scope corresponding to the snapshot is closing,
  3604. // reject any still-open nested policy scopes with an error.
  3605. while (this->StateSnapshot.CanPopPolicyScope()) {
  3606. if (reportError) {
  3607. this->IssueMessage(MessageType::FATAL_ERROR,
  3608. "cmake_policy PUSH without matching POP");
  3609. reportError = false;
  3610. }
  3611. this->PopPolicy();
  3612. }
  3613. this->StateSnapshot = this->GetState()->Pop(this->StateSnapshot);
  3614. assert(this->StateSnapshot.IsValid());
  3615. }
  3616. bool cmMakefile::SetPolicyVersion(std::string const& version_min,
  3617. std::string const& version_max)
  3618. {
  3619. return cmPolicies::ApplyPolicyVersion(this, version_min, version_max,
  3620. cmPolicies::WarnCompat::On);
  3621. }
  3622. cmMakefile::VariablePushPop::VariablePushPop(cmMakefile* m)
  3623. : Makefile(m)
  3624. {
  3625. this->Makefile->StateSnapshot =
  3626. this->Makefile->GetState()->CreateVariableScopeSnapshot(
  3627. this->Makefile->StateSnapshot);
  3628. }
  3629. cmMakefile::VariablePushPop::~VariablePushPop()
  3630. {
  3631. this->Makefile->PopSnapshot();
  3632. }
  3633. void cmMakefile::RecordPolicies(cmPolicies::PolicyMap& pm) const
  3634. {
  3635. /* Record the setting of every policy. */
  3636. using PolicyID = cmPolicies::PolicyID;
  3637. for (PolicyID pid = cmPolicies::CMP0000; pid != cmPolicies::CMPCOUNT;
  3638. pid = static_cast<PolicyID>(pid + 1)) {
  3639. pm.Set(pid, this->GetPolicyStatus(pid));
  3640. }
  3641. }
  3642. cmMakefile::FunctionPushPop::FunctionPushPop(cmMakefile* mf,
  3643. std::string const& fileName,
  3644. cmPolicies::PolicyMap const& pm)
  3645. : Makefile(mf)
  3646. {
  3647. this->Makefile->PushFunctionScope(fileName, pm);
  3648. }
  3649. cmMakefile::FunctionPushPop::~FunctionPushPop()
  3650. {
  3651. this->Makefile->PopFunctionScope(this->ReportError);
  3652. }
  3653. cmMakefile::MacroPushPop::MacroPushPop(cmMakefile* mf,
  3654. std::string const& fileName,
  3655. cmPolicies::PolicyMap const& pm)
  3656. : Makefile(mf)
  3657. {
  3658. this->Makefile->PushMacroScope(fileName, pm);
  3659. }
  3660. cmMakefile::MacroPushPop::~MacroPushPop()
  3661. {
  3662. this->Makefile->PopMacroScope(this->ReportError);
  3663. }
  3664. cmMakefile::FindPackageStackRAII::FindPackageStackRAII(cmMakefile* mf,
  3665. std::string const& name)
  3666. : Makefile(mf)
  3667. {
  3668. this->Makefile->FindPackageStack =
  3669. this->Makefile->FindPackageStack.Push(cmFindPackageCall{
  3670. name,
  3671. this->Makefile->FindPackageStackNextIndex,
  3672. });
  3673. this->Makefile->FindPackageStackNextIndex++;
  3674. }
  3675. cmMakefile::FindPackageStackRAII::~FindPackageStackRAII()
  3676. {
  3677. this->Makefile->FindPackageStackNextIndex =
  3678. this->Makefile->FindPackageStack.Top().Index + 1;
  3679. this->Makefile->FindPackageStack = this->Makefile->FindPackageStack.Pop();
  3680. if (!this->Makefile->FindPackageStack.Empty()) {
  3681. auto top = this->Makefile->FindPackageStack.Top();
  3682. this->Makefile->FindPackageStack = this->Makefile->FindPackageStack.Pop();
  3683. top.Index = this->Makefile->FindPackageStackNextIndex;
  3684. this->Makefile->FindPackageStackNextIndex++;
  3685. this->Makefile->FindPackageStack =
  3686. this->Makefile->FindPackageStack.Push(top);
  3687. }
  3688. }
  3689. cmMakefile::DebugFindPkgRAII::DebugFindPkgRAII(cmMakefile* mf,
  3690. std::string const& pkg)
  3691. : Makefile(mf)
  3692. , OldValue(this->Makefile->DebugFindPkg)
  3693. {
  3694. this->Makefile->DebugFindPkg =
  3695. this->Makefile->GetCMakeInstance()->GetDebugFindPkgOutput(pkg);
  3696. }
  3697. cmMakefile::DebugFindPkgRAII::~DebugFindPkgRAII()
  3698. {
  3699. this->Makefile->DebugFindPkg = this->OldValue;
  3700. }
  3701. bool cmMakefile::GetDebugFindPkgMode() const
  3702. {
  3703. return this->DebugFindPkg;
  3704. }