/* 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$ */
#ifndef __MHMAKEFILE_PARSER__
#define __MHMAKEFILE_PARSER__
#include "fileinfo.h"
#include "util.h"
class rule;
class mhmakelexer;
struct TOKENVALUE
{
string theString;
int ival;
};
class mhmakefileparser;
typedef string (mhmakefileparser::*function_f)(const string &) const;
struct funcdef
{
const char *szFuncName;
function_f pFunc;
};
class fileinfoarray : public refbase,public vector >
{
};
typedef set< refptr > deps_t;
typedef pair< bool, deps_t > autodeps_entry_t;
typedef map< refptr, autodeps_entry_t > autodeps_t;
class mhmakefileparser : public refbase
{
private:
mhmakelexer *m_ptheLexer;
int m_yyloc;
refptr m_RuleThatIsBuild;
vector m_ToBeIncludeAfterBuild;
vector m_MakefilesToLoad;
refptr m_AutoDepFileLoaded;
int m_InExpandExpression;
mh_time_t m_Date;
uint32 m_EnvMd5_32; /* Cached Md5_32 value of the userd environment variables */
#ifdef _DEBUG
int m_ImplicitSearch;
#endif
map m_CommandCache;
protected:
map m_Variables;
map m_CommandLineVars;
TOKENVALUE m_theTokenValue;
refptr m_MakeDir;
refptr m_pCurrentRule;
refptr m_pCurrentItems;
refptr m_pCurrentDeps;
refptr m_FirstTarget;
fileinfoarray m_IncludedMakefiles;
refptr< fileinfoarray > m_pIncludeDirs;
string m_IncludeDirs;
autodeps_t m_AutoDeps;
set< const fileinfo* , less_fileinfo > m_Targets; // List of targets that are build by this makefile
bool m_DoubleColonRule;
bool m_AutoDepsDirty;
bool m_ForceAutoDepRescan;
set m_SkipHeaders; // Headers to skip
vector m_PercentHeaders; // Percent specification of headers to skip
bool m_SkipHeadersInitialized; // true when previous 2 variables are initialized
bool m_RebuildAll; /* true when to rebuild all targets of this makefile */
vector m_Exports; // Array of variables to export.
map m_SavedExports; // Original values of the environment are saved here.
set m_UsedEnvVars; // Array containing a list of variables that are taken from the environment (This is used for rebuild checking)
static const mhmakefileparser *m_spCurEnv; // Identifies which makefiles exports are currently set
static mh_time_t m_sBuildTime;
public:
#ifdef _DEBUG
deque< refptr > m_TargetStack; /* Used to detect circular dependencies */
#endif
mhmakefileparser(const map &CommandLineVars)
: m_CommandLineVars(CommandLineVars)
,m_InExpandExpression(0)
,m_AutoDepsDirty(false)
,m_ForceAutoDepRescan(false)
,m_SkipHeadersInitialized(false)
,m_RebuildAll(false)
,m_EnvMd5_32(0)
#ifdef _DEBUG
,m_ImplicitSearch(false)
#endif
{
if (!m_FunctionsInitialised) InitFuncs();
SetVariable("MAKE_VERSION",MHMAKEVER);
SetVariable(OBJEXTVAR,OBJEXT);
SetVariable(EXEEXTVAR,EXEEXT);
}
bool CompareEnv() const;
uint32 CreateEnvMd5_32() const;
string GetFromEnv(const string &Var,bool Cache=true) const;
void CreateUSED_ENVVARS();
void SaveEnv();
void RestoreEnv() const;
void CheckEnv(void);
void SetRebuildAll()
{
m_RebuildAll=true;
m_AutoDepsDirty=true; /* This is to be sure that all new calculated md5 strings are saved. */
}
void SetVariable(string Var,string Val)
{
m_Variables[Var]=Val;
}
void EnableAutoDepRescan(void)
{
m_ForceAutoDepRescan=true;
m_AutoDepsDirty=true;
}
bool ForceAutoDepRescan(void)
{
return m_ForceAutoDepRescan;
}
void SetRuleThatIsBuild(const refptr &Target)
{
m_RuleThatIsBuild=Target;
}
void ClearRuleThatIsBuild()
{
m_RuleThatIsBuild=NULL;
}
void GetAutoDepsIfNeeded(const refptr &Target, const refptr&FirstDep);
void UpdateAutomaticDependencies(const refptr &Target);
const refptr GetIncludeDirs() const;
void GetAutoDeps(const refptr &FirstDep, deps_t &Autodeps);
void SaveAutoDepsFile();
void LoadAutoDepsFile(refptr &DepFile);
bool SkipHeaderFile(const string &FileName);
void InitEnv() const;
virtual ~mhmakefileparser()
{
SaveAutoDepsFile();
}
virtual int yylex(void);
virtual void yyerror(const char *m);
virtual int yyparse()=0;
int ParseFile(const refptr &FileInfo,bool SetMakeDir=false);
/* Functions to handle variables */
bool IsDefined(const string &Var) const;
bool IsEqual(const string &EqualExpr) const;
string ExpandExpression(const string &Expr) const;
string ExpandMacro(const string &Expr) const;
string ExpandVar(const string &Var) const;
void PrintVariables(bool Expand=false) const;
/* Functions for macro functions */
static funcdef m_FunctionsDef[];
static map m_Functions;
static bool m_FunctionsInitialised;
static void InitFuncs(void);
string f_filter(const string &) const;
string f_call(const string &) const;
string f_if(const string &) const;
string f_findstring(const string &) const;
string f_firstword(const string &) const;
string f_wildcard(const string &) const;
string f_subst(const string &) const;
string f_patsubst(const string &) const;
string f_concat(const string &) const;
string f_basename(const string & Arg) const;
string f_notdir(const string & Arg) const;
string f_dir(const string & Arg) const;
string f_shell(const string & Arg) const;
string f_relpath(const string & Arg) const;
string f_toupper(const string & Arg) const;
string f_tolower(const string & Arg) const;
string f_exist(const string & Arg) const;
string f_filesindirs(const string & Arg) const;
string f_fullname(const string & Arg) const;
string f_addprefix(const string & Arg) const;
string f_addsuffix(const string & Arg) const;
string f_filterout(const string & Arg) const;
string f_word(const string & Arg) const;
string f_words(const string & Arg) const;
string f_strip(const string & Arg) const;
const refptr GetFirstTarget() const
{
return m_FirstTarget;
}
const refptr GetMakeDir() const
{
return m_MakeDir;
}
mh_time_t GetDate(void) const
{
return m_Date;
}
void UpdateDate(mh_time_t Date)
{
if (Date.IsNewer(m_Date))
m_Date=Date;
}
void AddTarget(const fileinfo* pTarget)
{
m_Targets.insert(pTarget);
}
mh_time_t BuildTarget(const refptr &Target, bool bCheckTargetDir=true); /* returns the date of the target after build, especially important for phony rules, since this will be the youngest date of all dependencies */
void BuildDependencies(const refptr &pRule, const refptr &Target, mh_time_t TargetDate, mh_time_t &YoungestDate, bool &MakeTarget);
void BuildIncludedMakefiles();
void AddIncludedMakefile(refptr &MakeInfo)
{
UpdateDate(MakeInfo->GetDate());
m_IncludedMakefiles.push_back(MakeInfo);
}
fileinfoarray &GetIncludedMakefiles()
{
return m_IncludedMakefiles;
}
void IncludeAfterBuild(const string &IncludeFile)
{
m_ToBeIncludeAfterBuild.push_back(IncludeFile);
}
void ParseBuildedIncludeFiles();
void AddMakefileToMakefilesToLoad(const string &Makefile)
{
m_MakefilesToLoad.push_back(Makefile);
}
vector& GetMakefilesToLoad()
{
return m_MakefilesToLoad;
}
void AddRule();
bool ExecuteCommand(string Command,string *pOutput=NULL);
string GetFullCommand(string Command);
void CreatePythonExe(const string &FullCommand);
static void InitBuildTime();
};
void SplitToItems(const string &String,vector< refptr > &Items,refptr Dir=curdir::GetCurDir());
#endif