/* This file is part of mhmake. * * Copyright (C) 2001-2009 Marc Haesen * * Mhmake is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Mhmake is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Mhmake. If not, see . */ /* $Rev$ */ #include "stdafx.h" #include "util.h" #include "md5.h" #include "mhmakefileparser.h" #include "rule.h" #include "mhmakelexer.h" commandqueue mhmakefileparser::sm_CommandQueue; /////////////////////////////////////////////////////////////////////////////// int mhmakefileparser::yylex(void) { m_yyloc=m_ptheLexer->m_Line; return m_ptheLexer->yylex(m_theTokenValue); } /////////////////////////////////////////////////////////////////////////////// void mhmakefileparser::yyerror(const char *m) { cerr << this->m_ptheLexer->m_InputFileName<< " ("< &FileInfo, refptr &pMakeDir) { mhmakelexer theLexer; m_ptheLexer=&theLexer; if (pMakeDir) { m_MakeDir=pMakeDir; m_Variables[CURDIR]=m_MakeDir->GetQuotedFullFileName(); } theLexer.m_InputFileName=FileInfo->GetFullFileName(); theLexer.m_pParser=(mhmakeparser*)this; theLexer.yyin=::fopen(FileInfo->GetFullFileName().c_str(),"r"); if (!theLexer.yyin) { cerr << "Error opening makefile: "<GetQuotedFullFileName()< SplitExpr(const string &Expr,char Item) { size_t i=0; char Char=Expr[i++]; while (Char!=Item) { if (Char=='"' || Char=='\'') { i=SkipUntilQuote(Expr,i,Char); } else if (Char=='$') { i=SkipMakeExpr(Expr,i); } Char=Expr[i++]; } return pair(Expr.substr(0,i-1),Expr.substr(i)); } /////////////////////////////////////////////////////////////////////////////// bool mhmakefileparser::IsEqual(const string &EqualExpr) const { string Expr=ExpandExpression(EqualExpr); const char *pStr=Expr.c_str(); const char *pTmp=pStr; while (*pTmp && *pTmp!=',') pTmp++; ptrdiff_t Pos=pTmp-pStr; size_t Size=Expr.size(); pTmp=pStr+Size-1; while (pTmp>pStr && strchr(" \t",*pTmp)) { pTmp--; } if (2*Pos != pTmp-pStr) { return false; } pTmp=pStr; const char *pTmp2=pTmp+Pos+1; if (*pTmp=='(') { pTmp++; Pos--; } for (int i=0; im_InExpandExpression++; size_t i=0; size_t Length=Expr.size(); string Ret; string ToAdd; while (ii) { ToAdd=ExpandMacro(Expr.substr(i,inew-i-1)); i=inew; } else { // This is a single character expression ToAdd=ExpandMacro(string(1,Expr[i-1])); } } Ret+=ToAdd; } else { Ret+=Char; } } if (m_InExpandExpression==1) { // Here we do a special case in case we still have a $ within a % if (Ret.find('$')!=string::npos) Ret=ExpandExpression(Ret); size_t Pos; while ((Pos=Ret.find("$$"))!=string::npos) { Ret=Ret.replace(Pos,2,"$"); } } ((mhmakefileparser*)this)->m_InExpandExpression--; return Ret; } /////////////////////////////////////////////////////////////////////////////// string mhmakefileparser::ExpandMacro(const string &Expr) const { if (Expr.find('%')!=string::npos && Expr.find('$')==string::npos && Expr.find(':')==string::npos) return string("$(")+Expr+")"; string ExpandedExpr=ExpandExpression(Expr); const char *pTmp=ExpandedExpr.c_str(); /* First remove leading spaces */ while (*pTmp==' ' || *pTmp=='\t') pTmp++; const char *pVar=pTmp; while (*pTmp && *pTmp!=' ' && *pTmp!='\t' && *pTmp!=':') pTmp++; const char *pVarEnd=pTmp; char Type=*pTmp++; while (*pTmp && (*pTmp==' ' || *pTmp=='\t')) pTmp++; if (Type&&*pTmp) { // We have a match for the regular expression ^([^ \\t:]+)([: \\t])[ \\t]*(.+) if (Type==':') { #ifdef WIN32 bool IsFileName=false; if (pVarEnd-pVar == 1 && (*pVar=='<' || *pVar =='@')) IsFileName=true; #endif string ToSubst=ExpandExpression(ExpandVar(string(pVar,pVarEnd))); const char *pSrc=pTmp; const char *pStop=pSrc; while (*pStop!='=') pStop++; const char *pTo=pStop+1; string SrcStr(pSrc,pStop); string ToStr(pTo); #ifdef WIN32 if (IsFileName) { matchres Res; string FileName(UnquoteFileName(ToSubst)); if (PercentMatch(FileName,UnquoteFileName(SrcStr),&Res)) { FileName=ReplaceWithStem(UnquoteFileName(ToStr),Res.m_Stem); } return QuoteFileName(FileName); } #endif return Substitute(ToSubst,SrcStr,ToStr); } else if (Type==' ' || Type == '\t') { string Func(pVar,pVarEnd); string Arg(pTmp); if (Arg.find('%')!=string::npos && Arg.find('$')!=string::npos) return string("$(")+ExpandedExpr+")"; function_f pFunc=m_Functions[Func]; #ifdef _DEBUG if (pFunc) { return (this->*pFunc)(Arg); } else { throw string("Unknown function specified in macro: ")+Func; } #else return (this->*pFunc)(Arg); #endif } else { #ifdef _DEBUG throw string("Fatal error in ExpandMacro (bug in mhmake ? ? ?)"); #else return g_EmptyString; #endif } } else { return ExpandExpression(ExpandVar(ExpandedExpr)); } } /////////////////////////////////////////////////////////////////////////////// string mhmakefileparser::ExpandVar(const string &Var) const { map::const_iterator pIt=m_Variables.find(Var); if (pIt==m_Variables.end()) { if (Var.size()==1) { char Char=Var[0]; if (m_RuleThatIsBuild) { switch (Char) { case '<': // return first prerequisit #ifdef _DEBUG if (!m_RuleThatIsBuild->GetDeps().size()) { return ""; } #endif return m_RuleThatIsBuild->GetDeps()[0]->GetQuotedFullFileName(); case '@': // return full target file name return m_RuleThatIsBuild->GetQuotedFullFileName(); case '*': // return stem return m_RuleThatIsBuild->GetRule()->GetStem(); case '^': // return all prerequisits return m_RuleThatIsBuild->GetPrerequisits(); case '/': return OSPATHSEPSTR; default: break; } } else { switch (Char) { case '<': // return first prerequisit case '@': // return full target file name case '*': // return stem case '^': // return all prerequisits return Var; // To make comparing of rules more accurate case '/': return OSPATHSEPSTR; default: break; } } } string Env=GetFromEnv(Var); if (Env.empty()) { #ifdef _DEBUG if (g_PrintAdditionalInfo) { cout<<"Warning: Variable "<second; } /////////////////////////////////////////////////////////////////////////////// void mhmakefileparser::SplitToItems(const string &String,vector< refptr > &Items) const { const char *pTmp=String.c_str(); while (*pTmp) { string Item; pTmp=NextItem(pTmp,Item); if (!Item.empty()) { Items.push_back(GetFileInfo(Item,m_MakeDir)); } } } /////////////////////////////////////////////////////////////////////////////// void mhmakefileparser::ParseBuildedIncludeFiles() { vector::iterator It=m_ToBeIncludeAfterBuild.begin(); while (It!=m_ToBeIncludeAfterBuild.end()) { int result=ParseFile(GetFileInfo(*It,m_MakeDir)); if (result) { throw string("Error parsing ")+*It; } It++; } } #ifdef _DEBUG /////////////////////////////////////////////////////////////////////////////// void mhmakefileparser::PrintVariables(bool Expand) const { map::const_iterator It=m_Variables.begin(); while (It!=m_Variables.end()) { if (Expand) { try { cout<first<<" : "<second)<first<<" : "<second< >::iterator pIt=m_pCurrentItems->begin(); while (pIt!=m_pCurrentItems->end()) { if ((*pIt)->GetFullFileName().find('%')!=string::npos) { IMPLICITRULE::AddImplicitRule(*pIt,*m_pCurrentDeps,m_pCurrentRule); } else { // If we had a double colon we must make sure that the target is always build if (m_DoubleColonRule) { (*pIt)->SetNotExist(); } (*pIt)->SetRuleIfNotExist(m_pCurrentRule); if (!m_pCurrentRule) (*pIt)->AddDeps(*m_pCurrentDeps); else (*pIt)->InsertDeps(*m_pCurrentDeps); if (!m_FirstTarget) { // Only check this if the rule is not an implicit rule m_FirstTarget=(*m_pCurrentItems)[0]; } } pIt++; } m_pCurrentItems=NULL; m_pCurrentRule=NullRule; } /////////////////////////////////////////////////////////////////////////////// void mhmakefileparser::GetAutoDeps(const refptr &FirstDep,set< refptr > &Autodeps) { /* Here we have to scan only c/c++ headers so skip certain extensions */ const char *pFullName=FirstDep->GetFullFileName().c_str(); const char *pExt=strrchr(pFullName,'.'); bool bPython=false; if (pExt) { if (!_stricmp(pExt+1,"py")) bPython=true; } FILE *pIn=fopen(pFullName,"r"); if (!pIn) return; char IncludeList[255]; int PrevRet=0; int Ret=fgetc(pIn); while(Ret!=EOF) { char Type[2]; bool bFound=false; if (bPython) { Type[0]='"'; if (Ret=='i') { Ret=fscanf(pIn,"mport %254[^\"\n]",IncludeList); if (Ret==1) { if (IncludeList[0]!='*') bFound=true; } } } else { if (PrevRet=='/') { if (Ret=='/') { /* This is a C++ command so read until the next line-feed */ do { Ret=fgetc(pIn); } while (Ret!='\n' && Ret!=EOF); } else if (Ret=='*') { /* This is a standard C comment, so read until then end of the command */ do { PrevRet=Ret; Ret=fgetc(pIn); } while ((PrevRet!='*' || Ret!='/') && Ret!=EOF); } } else if (Ret=='#' || Ret=='.') { if (Ret=='#') { fscanf(pIn,"%*[ \t]"); Ret=fscanf(pIn,"include %1[\"<]%254[^>\"]%*[\">]",&Type,IncludeList); } else Ret=fscanf(pIn,"import %1[\"<]%254[^>\"]%*[\">]",&Type,IncludeList); if (Ret==2) { bFound=true; } } } if (bFound) { const char *pTmp=IncludeList; while (*pTmp) { string IncludeFile; pTmp=NextItem(pTmp,IncludeFile," \t,"); if (bPython) IncludeFile+=".py"; if (SkipHeaderFile(IncludeFile)) continue; #ifdef _DEBUG m_ImplicitSearch++; // This is to avoid warnings of targets that does not exist #endif if (Type[0]=='"') { refptr pInclude=GetFileInfo(IncludeFile,FirstDep->GetDir()); /* Add the dependency when the file alrady exist or there is a rule available to be build */ mh_time_t Date=BuildTarget(pInclude); if (Date.DoesExist()) // Try to build the target, and add it if it exists after building { set< refptr >::iterator pFind=Autodeps.find(pInclude); if (pFind==Autodeps.end()) { Autodeps.insert(pInclude); GetAutoDeps(pInclude,Autodeps); } } } const refptr IncludeDirs=GetIncludeDirs(); vector< refptr >::const_iterator It=IncludeDirs->begin(); while (Itend()) { refptr pInclude=GetFileInfo(IncludeFile,*It); mh_time_t Date=BuildTarget(pInclude); if (Date.DoesExist()) // Try to build the target, and add it if it exists after building { set< refptr >::iterator pFind=Autodeps.find(pInclude); if (pFind==Autodeps.end()) { Autodeps.insert(pInclude); GetAutoDeps(pInclude,Autodeps); } break; } It++; } #ifdef _DEBUG m_ImplicitSearch--; #endif } } PrevRet=Ret; Ret=fgetc(pIn); } fclose(pIn); } /////////////////////////////////////////////////////////////////////////////// void mhmakefileparser::UpdateAutomaticDependencies(const refptr &Target) { const char *pName=Target->GetFullFileName().c_str(); const char *pExt=strrchr(pName,'.'); if (!pExt) return; if (Target->IsAutoDepExtention()) { // we have to search for the include files in the first dependency of Target vector< refptr > &Deps=Target->GetDeps(); if (!Deps.size()) return; // There is no first dep refptr FirstDep=Deps[0]; set< refptr > &Autodeps=m_AutoDeps[Target]; Autodeps.clear(); // We are going to scan again, so clear the list GetAutoDeps(FirstDep,Autodeps); // Now add these dependencies also to the rules set< refptr >::iterator It=Autodeps.begin(); while (It!=Autodeps.end()) { Target->AddDep(*It); It++; } SetAutoDepsDirty(); } } /////////////////////////////////////////////////////////////////////////////// const refptr mhmakefileparser::GetIncludeDirs() const { string Includes=ExpandExpression("$(INCLUDES)"); if (!m_pIncludeDirs || Includes != m_IncludeDirs) { ((mhmakefileparser*)this)->m_IncludeDirs=Includes; ((mhmakefileparser*)this)->m_pIncludeDirs=refptr(new fileinfoarray); if (Includes.empty()) // If not defined try a default path Includes="include inc .."OSPATHSEPSTR"include .."OSPATHSEPSTR"inc"; const char *pTmp=Includes.c_str(); while (*pTmp) { string Item; pTmp=NextItem(pTmp,Item); refptr pIncDir=GetFileInfo(Item,m_MakeDir); if (pIncDir->Exists() || pIncDir->GetRule()) ((mhmakefileparser*)this)->m_pIncludeDirs->push_back(pIncDir); } } return m_pIncludeDirs; } static void ReadStr(FILE *pFile,char *Str) { int i=0; while (1) { Str[i]=fgetc(pFile); #ifdef _DEBUG if (Str[i]==EOF) { cout<<"Premature end of depency file.\n"; Str[i]=0; return; } #endif if (Str[i]=='\n') break; i++; } Str[i]='\0'; } void mhmakefileparser::LoadAutoDepsFile(refptr &DepFile) { if (m_AutoDepFileLoaded && m_AutoDepFileLoaded==DepFile) return; /* This autodep file is already loaded. */ m_AutoDepFileLoaded=DepFile; FILE *pIn=fopen(DepFile->GetFullFileName().c_str(),"rb"); #ifdef _DEBUG if (!pIn) { cerr << "Error opening autodep file "<GetQuotedFullFileName()<GetQuotedFullFileName()<<": "< Target=GetFileInfo(FileName,m_MakeDir); set< refptr > &Autodeps=m_AutoDeps[Target]; ReadStr(pIn,FileName); while (FileName[0]) { if (!g_ForceAutoDepRescan) /* If we are forcing the autodepscan we do not have to load the dependencies. */ { refptr Dep=GetFileInfo(FileName,m_MakeDir); Autodeps.insert(Dep); Target->AddDep(Dep); } ReadStr(pIn,FileName); } ReadStr(pIn,FileName); } uint32 Md5_32; bool MakeNotDirty=true; while (fread(&Md5_32,sizeof(Md5_32),1,pIn)) { ReadStr(pIn,FileName); pair ,less_refptrfileinfo >::iterator, bool> pPair=g_FileInfos.insert(new fileinfo(FileName,Md5_32)); if (!pPair.second) { if (!(*pPair.first)->CompareMd5_32(Md5_32) && !(*pPair.first)->CompareMd5_32(0)) MakeNotDirty=false; /* BuildTarget had set the dirty flag, but since the md5 did not change it was a false dirty. This is for BuildTargets called before this routine */ #ifdef _DEBUG if (!(*pPair.first)->CompareMd5_32(Md5_32) && !(*pPair.first)->CompareMd5_32(0)) cout << "Warning: trying to set to different md5's for Target "<<(*pPair.first)->GetQuotedFullFileName()<<" Old: "<GetCommandsMd5_32()<<" New: "<GetQuotedFullFileName()<<" to "<SetCommandsMd5_32(Md5_32); // If it was already there, just update the md5 value } AddTarget(*pPair.first); } if (MakeNotDirty) ClearAutoDepsDirty(); fclose(pIn); } static void MakeDirs(const refptr & Dir) { refptr ParentDir=Dir->GetDir(); if (!ParentDir->GetDate().DoesExist()) { /* First make parent dirs */ MakeDirs(ParentDir); } if (!Dir->GetDate().DoesExist()) { /* Create directory */ mkdir(Dir->GetFullFileName().c_str(),S_IRWXU); } } void mhmakefileparser::SaveAutoDepsFile() { if (!IsAutoDepsDirty()) return; if (g_Clean #ifdef _DEBUG || g_DoNotExecute || g_GenProjectTree #endif ) return; // do not save on clean or if no commands are executed string DepFile=ExpandVar(AUTODEPFILE); if (!DepFile.size()) { return; } refptr pDepFile=GetFileInfo(DepFile,m_MakeDir); #ifdef _DEBUG if (g_PrintAdditionalInfo) cout<<"Saving automatic dependency file "<GetFullFileName().c_str(),"wb"); if (!pOut) { /* Maybe it is because the directory does not exist, so try to create this first */ MakeDirs(pDepFile->GetDir()); pOut=fopen(pDepFile->GetFullFileName().c_str(),"wb"); if (!pOut) { #ifdef _DEBUG if (!g_DoNotExecute) #endif cerr << "Error creating file "<, set< refptr > >::const_iterator It=m_AutoDeps.begin(); while (It!=m_AutoDeps.end()) { fprintf(pOut,"%s\n",It->first->GetFullFileName().c_str()); set< refptr >::const_iterator DepIt=It->second.begin(); while (DepIt!=It->second.end()) { fprintf(pOut,"%s\n",(*DepIt)->GetFullFileName().c_str()); DepIt++; } fprintf(pOut,"\n"); It++; } /* Now save the Md5 strings */ fprintf(pOut,"\n"); set< const fileinfo * , less_fileinfo>::iterator pIt=m_Targets.begin(); while (pIt!=m_Targets.end()) { if (!(*pIt)->CompareMd5_32(0)) { (*pIt)->WriteMd5_32(pOut); string FileName=(*pIt)->GetFullFileName(); fwrite(FileName.c_str(),FileName.size(),1,pOut); fputc('\n',pOut); } pIt++; } fclose(pOut); } /////////////////////////////////////////////////////////////////////////////// // Uses the SKIPHEADERS variable to check if we have to skip the header in // the automatic dependency scanning bool mhmakefileparser::SkipHeaderFile(const string &FileName) { if (!m_SkipHeadersInitialized) { m_SkipHeadersInitialized=true; string HeadersToSkip=ExpandVar(SKIPHEADERS); const char *pTmp=HeadersToSkip.c_str(); while (*pTmp) { string Item; pTmp=NextItem(pTmp,Item); if (Item.find('%')==string::npos) { m_SkipHeaders.insert(Item); } else { m_PercentHeaders.push_back(Item); } } } if (m_SkipHeaders.find(FileName)!=m_SkipHeaders.end()) return true; vector::const_iterator It=m_PercentHeaders.begin(); vector::const_iterator ItEnd=m_PercentHeaders.end(); while (It!=ItEnd) { if (PercentMatch(FileName,*It++)) return true; } return false; } /////////////////////////////////////////////////////////////////////////////// void mhmakefileparser::SetExport(const string &Var, const string &Val) { #ifdef WIN32 if (!m_pEnv) { /* Environment not created yet, so create one */ char *pEnv=GetEnvironmentStrings(); char *pEnd=pEnv; while (*pEnd) { while (*pEnd++); } int Len=pEnd-pEnv+1; m_pEnv=(char*)malloc(Len); memcpy(m_pEnv,pEnv,Len); m_EnvLen=Len; FreeEnvironmentStrings(pEnv); } /* First check if the variable is in the environment, if so remove it first */ char *pEnv=m_pEnv; while (*pEnv) { const char *pVar=Var.c_str(); char *pStart=pEnv; while (*pEnv!='=' && *pEnv==*pVar) { pEnv++; pVar++; } if (*pEnv=='=' && !*pVar) { /* Variable found, remove it */ while (*pEnv++); m_EnvLen-=pEnv-pStart; while (*pEnv) { while (*pEnv) { *pStart=*pEnv++; pStart++; } *pStart=*pEnv++; pStart++; } *pStart=*pEnv; break; } while (*pEnv++); } int VarLen=Var.length(); int ValLen=Val.length(); int Extra=VarLen+ValLen+2; /* Add the variable at the end */ m_pEnv=(char*)realloc(m_pEnv,m_EnvLen+Extra); pEnv=m_pEnv+m_EnvLen-1; memcpy(pEnv,Var.c_str(),VarLen); pEnv+=VarLen; *pEnv++='='; memcpy(pEnv,Val.c_str(),ValLen); pEnv+=ValLen; *pEnv++='\0'; *pEnv++='\0'; m_EnvLen+=Extra; #else if (!m_pEnv) { /* Environment not created yet, so create one */ char **pEnv=environ; char **pEnd=pEnv; int Len=1; while (*pEnd) { Len++; pEnd++; } m_EnvLen=Len; m_pEnv=(char**)malloc(Len*sizeof(pEnv)); int i=0; while (*pEnv) { m_pEnv[i]=strdup(*pEnv); i++; pEnv++; } m_pEnv[i]=NULL; } /* First check if the variable is in the environment, if so replace it */ char **pEnv=m_pEnv; while (*pEnv) { const char *pVar=Var.c_str(); char *pStart=*pEnv; char *pTmp=pStart; while (*pTmp!='=' && *pTmp==*pVar) { pTmp++; pVar++; } if (*pTmp=='=' && !*pVar) { free(*pEnv); *pEnv=strdup((Var+"="+Val).c_str()); break; } pEnv++; } if (!*pEnv) { // Add it at the end of the list m_pEnv=(char**)realloc(m_pEnv,(m_EnvLen+1)*sizeof(*pEnv)); m_pEnv[m_EnvLen-1]=strdup((Var+"="+Val).c_str()); m_pEnv[m_EnvLen++]=NULL; } #endif } /////////////////////////////////////////////////////////////////////////////// // //Checks if the variables retreived from the environment or command-line have been //changed. Do this at late as possible because they can also be changed in theLexer //makefiles. // void mhmakefileparser::CheckEnv(void) { if (CompareEnv()) { #ifdef _DEBUG if (!g_GenProjectTree) cout << "Rebuilding everything of "<< m_MakeDir->GetQuotedFullFileName() <<" because environment and/or command-line variables have been changed.\n"; #endif SetRebuildAll(); } } /////////////////////////////////////////////////////////////////////////////// // //Create a Md5 string from m_GlobalCommandLineVars and USED_ENVVARS // static bool SkipVar(const string &Var) { if (Var==WC_REVISION) return true; if (Var==WC_URL) return true; if (Var==MAKE) return true; return false; } #define DBGOUT(stuff) uint32 mhmakefileparser::CreateEnvMd5_32() const { md5_context ctx; string Md5; string EnvVars=ExpandVar(USED_ENVVARS); const char *pTmp=EnvVars.c_str(); // Now create the md5 string md5_starts( &ctx ); DBGOUT(cout << "MD5 of " << m_MakeDir->GetQuotedFullFileName() << endl); while (*pTmp) { string Var; pTmp=NextItem(pTmp,Var,";"); if (!SkipVar(Var)) { string Val=ExpandVar(Var); transform(Val.begin(),Val.end(),Val.begin(),(int(__CDECL *)(int))toupper); DBGOUT(cout << GetMakeDir()->GetQuotedFullFileName() << " -> Setting GetFromEnv var " << Var << " to " << Val << endl); md5_update( &ctx, (uint8 *) Var.c_str(), (unsigned long)Var.size()); md5_update( &ctx, (uint8 *) "=", 1); md5_update( &ctx, (uint8 *) Val.c_str(), (unsigned long)Val.size()); } } return md5_finish32( &ctx); } /////////////////////////////////////////////////////////////////////////////// // Makes sure that the makefile exports are set in the environment bool mhmakefileparser::CompareEnv() const { uint32 Md5_32=CreateEnvMd5_32(); #ifdef _DEBUG if (!g_GenProjectTree && Md5_32!=m_EnvMd5_32) cout << "Environment has been changed: "<::const_iterator pLineFind=m_CommandLineVars.find(Var); if (pLineFind!=m_CommandLineVars.end()) { ((mhmakefileparser*)this)->m_UsedEnvVars.insert(Var); if (Cache) ((mhmakefileparser*)this)->m_Variables[Var]=pLineFind->second; return pLineFind->second; } const char *pEnv=getenv(Var.c_str()); if (!pEnv) { return g_EmptyString; } ((mhmakefileparser*)this)->m_UsedEnvVars.insert(Var); if (Cache) ((mhmakefileparser*)this)->m_Variables[Var]=pEnv; return pEnv; } /////////////////////////////////////////////////////////////////////////////// // Creates the variable USER_ENVVARS to be saved in the autodeps file // void mhmakefileparser::CreateUSED_ENVVARS() { set Variables; set::const_iterator It=m_UsedEnvVars.begin(); set::const_iterator ItEnd=m_UsedEnvVars.end(); while (It!=ItEnd) { string Var=*It; if (!SkipVar(Var)) { transform(Var.begin(),Var.end(),Var.begin(),(int(__CDECL *)(int))toupper); Variables.insert(Var); } It++; } map::const_iterator CLItEnd=loadedmakefile::sm_Statics.m_GlobalCommandLineVars.end(); map::const_iterator CLIt=loadedmakefile::sm_Statics.m_GlobalCommandLineVars.begin(); while (CLIt!=CLItEnd) { string Var=CLIt->first; if (!SkipVar(Var)) { transform(Var.begin(),Var.end(),Var.begin(),(int(__CDECL *)(int))toupper); Variables.insert(Var); } CLIt++; } It=Variables.begin(); ItEnd=Variables.end(); string Val; while (It!=ItEnd) { Val+=*It; Val+=";"; It++; } m_Variables[USED_ENVVARS]=Val; }