From 437bca524595d1007f37988e862db8bfeff329b0 Mon Sep 17 00:00:00 2001 From: marha Date: Wed, 29 Jul 2009 09:17:47 +0000 Subject: Added mhmake GNU make compatible (with extensions) make utility. --- tools/mhmake/src/mhmakefileparser.cpp | 1086 +++++++++++++++++++++++++++++++++ 1 file changed, 1086 insertions(+) create mode 100644 tools/mhmake/src/mhmakefileparser.cpp (limited to 'tools/mhmake/src/mhmakefileparser.cpp') diff --git a/tools/mhmake/src/mhmakefileparser.cpp b/tools/mhmake/src/mhmakefileparser.cpp new file mode 100644 index 000000000..28ad0a682 --- /dev/null +++ b/tools/mhmake/src/mhmakefileparser.cpp @@ -0,0 +1,1086 @@ +/* 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" + +/////////////////////////////////////////////////////////////////////////////// +int mhmakefileparser::yylex(void) +{ + m_yyloc=m_ptheLexer->m_Line; + return m_ptheLexer->yylex(m_theTokenValue); +} + +/////////////////////////////////////////////////////////////////////////////// +void mhmakefileparser::yyerror(char *m) +{ + cerr << this->m_ptheLexer->m_InputFileName<< " ("< &FileInfo,bool SetMakeDir) +{ + mhmakelexer theLexer; + m_ptheLexer=&theLexer; + if (SetMakeDir) + { + m_MakeDir=curdir::GetCurDir(); + m_Variables[CURDIR]=m_MakeDir->GetFullFileName(); + } + 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: "<GetFullFileName()< SplitExpr(const string &Expr,char Item) +{ + int 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++; + int Pos=pTmp-pStr; + int 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++; + int i=0; + int Length=Expr.size(); + string Ret; + bool DollarEscaped=false; + while (ii) + { + Ret+=ExpandMacro(Expr.substr(i,inew-i-1)); + i=inew; + } + else + { + // This is a single character expression + Ret+=ExpandMacro(string(1,Expr[i-1])); + } + } + } + else + { + Ret+=Char; + } + + } + // Here we do a special case in case we still have a $ without a % + if (m_InExpandExpression==1) + { + if (Ret.find('$')!=string::npos) + Ret=ExpandExpression(Ret); + if (DollarEscaped) + { + int 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==':') + { + 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); + 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 + { + cerr << "Unknown function specified in macro: "<*pFunc)(Arg); + #endif + } + else + { + #ifdef _DEBUG + cerr << "Fatal error in ExpandMacro (bug in mhmake ? ? ?)"; + throw 1; + #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]->GetFullFileName(); + case '@': // return full target file name + return m_RuleThatIsBuild->GetFullFileName(); + 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 SplitToItems(const string &String,vector< refptr > &Items,refptr Dir) +{ + const char *pTmp=String.c_str(); + while (*pTmp) + { + string Item; + pTmp=NextItem(pTmp,Item); + if (!Item.empty()) + { + if (Item[0]=='"') + { + Item=Item.substr(1,Item.size()-2); + } + Items.push_back(GetFileInfo(Item,Dir)); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +void mhmakefileparser::ParseBuildedIncludeFiles() +{ + vector::iterator It=m_ToBeIncludeAfterBuild.begin(); + while (It!=m_ToBeIncludeAfterBuild.end()) + { + int result=ParseFile(GetFileInfo(*It)); + if (result) + { + fprintf(stderr,"Error parsing %s\n",It->c_str()); + throw(1); + } + 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<::const_iterator It2=m_Exports.begin(); + while (It2!=m_Exports.end()) + { + cout<<*It2< >::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; + + refptr CurDir=curdir::GetCurDir(); /* Since we are calling BuildTarget, the current directory might change, which is not what we should expecting */ + 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=='#') + 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 */ + if (BuildTarget(pInclude).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); + if (BuildTarget(pInclude).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); + curdir::ChangeCurDir(CurDir); +} + +/////////////////////////////////////////////////////////////////////////////// +void mhmakefileparser::UpdateAutomaticDependencies(const refptr &Target) +{ + m_AutoDepsDirty=true; /* Always assume dirty since in the autodeps file, the md5 strings are also saved. */ + 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++; + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +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 "<GetFullFileName()<GetFullFileName()<<": "< Target=GetFileInfo(FileName); + 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); + Autodeps.insert(Dep); + Target->AddDep(Dep); + } + ReadStr(pIn,FileName); + } + ReadStr(pIn,FileName); + } + + uint32 Md5_32; + 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) + { + #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)->GetFullFileName()<<" Old: "<GetCommandsMd5_32()<<" New: "<GetFullFileName()<<" to "<SetCommandsMd5_32(Md5_32); // If it was already there, just update the md5 value + } + AddTarget(*pPair.first); + } + + 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 (!m_AutoDepsDirty) + 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; + } + +#ifdef _DEBUG + if (g_PrintAdditionalInfo) + cout<<"Saving automatic dependency 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; +} + +/////////////////////////////////////////////////////////////////////////////// +// Makes sure that the makefile exports are set in the environment + +const mhmakefileparser *mhmakefileparser::m_spCurEnv; // Identifies which makefiles exports are currently set + +void mhmakefileparser::InitEnv() const +{ + if (this!=m_spCurEnv) + { + /* First restore the previous set environment variables */ + if (m_spCurEnv) + m_spCurEnv->RestoreEnv(); + + ((mhmakefileparser*)this)->SaveEnv(); + vector::const_iterator It=m_Exports.begin(); + vector::const_iterator ItEnd=m_Exports.end(); + while (It!=ItEnd) + { + putenv((char *)It->c_str()); + It++; + } + m_spCurEnv=this; + } +} + +/////////////////////////////////////////////////////////////////////////////// +void mhmakefileparser::SaveEnv() +{ + vector::const_iterator It=m_Exports.begin(); + vector::const_iterator ItEnd=m_Exports.end(); + while (It!=ItEnd) + { + string Export=*It++; + const char *pTmp=Export.c_str(); + string Var; + NextItem(pTmp,Var,"="); + const char *pEnv=getenv(Var.c_str()); + string Env; + if (pEnv) + Env=pEnv; + m_SavedExports[Var]=Env; + } +} + +/////////////////////////////////////////////////////////////////////////////// +void mhmakefileparser::RestoreEnv() const +{ + if (m_spCurEnv && this!=m_spCurEnv) + { + m_spCurEnv->RestoreEnv(); // Make sure that environment variable that were set in the other makefile (m_spCurEnv) are cleared, otherwise the environment is not completely restored. + } + + map::const_iterator It=m_SavedExports.begin(); + map::const_iterator ItEnd=m_SavedExports.end(); + while (It!=ItEnd) + { +#ifdef WIN32 + char Env[1024]; + sprintf(Env,"%s=%s",It->first.c_str(),It->second.c_str()); + putenv(Env); +#else + /* on linux, only use putenv if you know the supplied string will stay in memory */ + setenv(It->first.c_str(),It->second.c_str(),1); +#endif + It++; + } + ((mhmakefileparser*)this)->m_SavedExports.clear(); + m_spCurEnv=NULL; +} + +/////////////////////////////////////////////////////////////////////////////// +// +//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(); + map Variables; + + RestoreEnv(); // Restore the environment before creating the md5, so that we have the original environment when the makefile was parsed. + + /* First create a list of variables to put in the md5 string. This is needed because a variable could be in the + * environment and passed on the command-line. This is especially important when switching environments were a certain + * variable sometimes is passed with the environment and sometimes on the command line */ + + while (*pTmp) + { + string Var; + pTmp=NextItem(pTmp,Var,";"); + if (!SkipVar(Var)) + { + string Val=GetFromEnv(Var,false); + transform(Var.begin(),Var.end(),Var.begin(),(int(__CDECL *)(int))toupper); + transform(Val.begin(),Val.end(),Val.begin(),(int(__CDECL *)(int))toupper); + DBGOUT(cout << GetMakeDir()->GetFullFileName() << " -> Setting GetFromEnv var " << Var << " to " << Val << endl); + Variables[Var]=Val; + } + } + map::const_iterator ItEnd=loadedmakefile::sm_Statics.m_GlobalCommandLineVars.end(); + map::const_iterator It=loadedmakefile::sm_Statics.m_GlobalCommandLineVars.begin(); + while (It!=ItEnd) + { + if (!SkipVar(It->first)) + { + string Var=It->first; + transform(Var.begin(),Var.end(),Var.begin(),(int(__CDECL *)(int))toupper); + string Val=It->second; + transform(Val.begin(),Val.end(),Val.begin(),(int(__CDECL *)(int))toupper); + DBGOUT(cout << GetMakeDir()->GetFullFileName() << " -> Setting Commandline var " << Var << " to " << Val << endl); + Variables[Var]=Val; + } + It++; + } + + // Now create the md5 string + md5_starts( &ctx ); + + DBGOUT(cout << "MD5 of " << m_MakeDir->GetFullFileName() << endl); + + map::const_iterator VarIt=Variables.begin(); + map::const_iterator VarItEnd=Variables.end(); + while (VarIt!=VarItEnd) + { + md5_update( &ctx, (uint8 *) VarIt->first.c_str(), (unsigned long)VarIt->first.size()); + + if (!VarIt->second.empty()) + { + md5_update( &ctx, (uint8 *) "=", 1); + md5_update( &ctx, (uint8 *) VarIt->second.c_str(), (unsigned long)VarIt->second.size()); + DBGOUT(cout << VarIt->first << "=" << VarIt->second << endl); + } + DBGOUT(else cout << VarIt->first << endl;) + VarIt++; + } + + 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::const_iterator It=m_UsedEnvVars.begin(); + set::const_iterator ItEnd=m_UsedEnvVars.end(); + string Val; + while (It!=ItEnd) + { + Val+=*It; + Val+=";"; + It++; + } + m_Variables[USED_ENVVARS]=Val; +} + -- cgit v1.2.3