/* 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 __FILEINFO_H #define __FILEINFO_H #include "curdir.h" #include "rule.h" #include "md5.h" #ifdef WIN32 #define OSPATHSEP '\\' #define OSPATHSEPSTR "\\" #define OSPATHENVSEP ';' #define OSPATHENVSEPSTR ";" #else #define OSPATHSEP '/' #define OSPATHSEPSTR "/" #define OSPATHENVSEP ':' #define OSPATHENVSEPSTR ":" #endif extern bool g_DumpOnError; extern bool g_PrintVarsAndRules; extern bool g_DoNotExecute; extern bool g_GenProjectTree; extern bool g_Quiet; extern bool g_RebuildAll; extern bool g_PrintAdditionalInfo; extern bool g_pPrintDependencyCheck; extern bool g_CheckCircularDeps; extern bool g_ForceAutoDepRescan; extern bool g_PrintLexYacc; extern bool g_Clean; extern bool g_StopCompiling; extern bool g_PrintMultipleDefinedRules; extern const string g_EmptyString; extern const string g_SpaceString; extern const string g_QuoteString; string QuoteFileName(const string &Filename); string UnquoteFileName(const string &Filename); template inline string stringify(const T& x) { ostringstream o; o << x; return o.str(); } #define TIMESAFETY 3 class mh_time { enum { DATENOTVALID=0, NOTEXISTTIME=1, DIRTIME =2+TIMESAFETY }; unsigned long m_Time; bool operator < (const mh_time &Src); public: mh_time(){m_Time=DATENOTVALID;} mh_time(time_t Time) : m_Time((unsigned long)Time) {} mh_time(unsigned long Time) : m_Time(Time) {} mh_time(const mh_time &Time) : m_Time(Time.m_Time) {} void SetDir(void) { m_Time=DIRTIME; } bool IsDir(void) const { return m_Time==DIRTIME; } void SetNotExist(void) { m_Time=NOTEXISTTIME; } bool IsExistingFile(void) const { return m_Time>DIRTIME; } bool DoesExist(void) const { return m_Time!=NOTEXISTTIME; } void Invalidate(void) { m_Time=DATENOTVALID; } bool IsDateValid(void) const { return m_Time!=DATENOTVALID; } friend ostream& operator<<(ostream& out,const mh_time &Src); mh_time &operator = (const mh_time &Src) { m_Time=Src.m_Time; return *this;} bool IsOlder(const mh_time &Src) const { return m_TimeSrc.m_Time+TIMESAFETY; } bool IsNewerOrSame(const mh_time &Src) const { return m_Time>=Src.m_Time-TIMESAFETY; } }; typedef mh_time mh_time_t; inline ostream& operator<<(ostream& out,const mh_time &Src) { out << hex << (unsigned long)Src.m_Time; return out; } class fileinfo : public refbase { string m_AbsFileName; bool m_IsPhony; int m_BuildStatus; /* Bit 0 means the target built is started, Bit 1 means the target is still building */ refptr m_pRule; vector< refptr > m_Deps; mh_time_t m_Date; uint32 m_CommandsMd5_32; // 32-bit Md5 checksum of commands to build this target fileinfo(const fileinfo &Src); fileinfo(void); public: fileinfo(const string &AbsFileName,uint32 Md5_32) { m_IsPhony=false; m_BuildStatus=0; m_AbsFileName=UnquoteFileName(AbsFileName); InvalidateDate(); m_CommandsMd5_32=Md5_32; #ifdef _DEBUG if (g_PrintAdditionalInfo) cout << "Initialising Md5 of "< GetDir(void) const; string GetName() const; bool IsDir() const; string GetErrorMessageDuplicateRule(const refptr &pRule); void SetRule(refptr &pRule) { #if defined(_DEBUG) && defined(_MSC_VER) if (m_pRule && m_pRule->GetCommands().size() && !IsBuilding()) { DebugBreak(); } #endif m_pRule=pRule; } void SetRuleIfNotExist(refptr &pRule) { if (pRule) { if (!m_pRule) { SetRule(pRule); pRule->AddTarget(this); } #ifdef _DEBUG else { if (*m_pRule!=*pRule) { throw(GetErrorMessageDuplicateRule(pRule)); } else if (g_PrintMultipleDefinedRules) { cerr< GetRule(void) { return m_pRule; } void AddDep(const refptr &Dep) { if (&*Dep==this) { #ifdef _DEBUG cout << GetQuotedFullFileName()<<" is directly dependent on itself\n"; #endif return; } m_Deps.push_back(Dep); } void AddDeps(vector< refptr > &Deps); void InsertDeps(vector< refptr > &Deps) { vector< refptr > NewDeps; vector< refptr >::const_iterator It=Deps.begin(); vector< refptr >::const_iterator ItEnd=Deps.end(); while (It!=ItEnd) { if (&**It==this) { #ifdef _DEBUG cout << GetQuotedFullFileName()<<" is directly dependent on itself\n"; #endif } else NewDeps.push_back(*It); It++; } if (NewDeps.size()) m_Deps.insert(m_Deps.begin(),NewDeps.begin(),NewDeps.end()); } void AddMainDep(refptr &MainDep) { if (&*MainDep==this) { #ifdef _DEBUG cout << GetQuotedFullFileName()<<" is directly dependent on itself\n"; #endif return; } m_Deps.insert(m_Deps.begin(),MainDep); } vector< refptr > &GetDeps(void) { return m_Deps; } string GetPrerequisits(void) const; void SetPhony(void) { m_IsPhony=true; m_Date.SetNotExist(); // This will sure that this target will always be build (even if a corresponding file exists) } bool IsPhony(void) { return m_IsPhony; } mh_time_t realGetDate(void); #ifdef _DEBUG void SetDateToNow(void); #endif void SetDate(mh_time_t Date) { m_Date=Date; } bool IsDateValid() const { return m_Date.IsDateValid(); } void InvalidateDate(void) { m_Date.Invalidate(); } mh_time_t GetDate(void) { if (m_Date.IsDateValid()) return m_Date; else return realGetDate(); } void SetNotExist(void) { // this is used to make sure that this item is rebuild, even if it really exists m_Date.SetNotExist(); } bool Exists(void) { return GetDate().DoesExist(); } bool IsBuildStarted(void) const { return (m_BuildStatus&1)==1; } bool IsBuild(void) const { return m_BuildStatus==1; } void SetBuild(void) { m_BuildStatus=1; } bool IsBuilding(void) const { return (m_BuildStatus&2)==2; } void SetBuilding(bool Others=true) { m_BuildStatus|=2; /* Check if there are targets build by the rule attached to this target, if so set them also to building */ if (Others && m_pRule) { m_pRule->SetTargetsIsBuilding(this); } } void ClearBuilding(void) { m_BuildStatus&=~2; } bool IsAutoDepExtention(void) const; void SetCommandsMd5_32(uint32 Md5_32) { #ifdef _DEBUG if (g_PrintAdditionalInfo) cout << "Setting Md5 of "<, refptr, bool> { bool operator()(const refptr& _Left, const refptr& _Right) const { return less().operator ()(_Left->GetFullFileName(),_Right->GetFullFileName()); } }; struct less_fileinfo : public binary_function { bool operator()(const fileinfo *_Left, const fileinfo *_Right) const { return less().operator ()(_Left->GetFullFileName(),_Right->GetFullFileName()); } }; extern const string NullString; extern refptr NullFileInfo; const refptr &GetFileInfo(const string &szName,const refptr &pRelDir); extern set,less_refptrfileinfo > g_FileInfos; inline const refptr &GetAbsFileInfo(const string &strAbsName) { static refptr SearchFileInfo(new fileinfo("")); SearchFileInfo->SetFullFileName(strAbsName); /* Using find is just an optimalisation, you could use insert immediately */ set,less_refptrfileinfo >::const_iterator pFind=g_FileInfos.find(SearchFileInfo); if (pFind==g_FileInfos.end()) { pair ,less_refptrfileinfo >::iterator, bool> pPair=g_FileInfos.insert(new fileinfo(SearchFileInfo->GetFullFileName())); return *(pPair.first); } else return *pFind; } inline const refptr &GetFileInfo(const char *szName,const refptr &RelDir) { return GetFileInfo(string(szName),RelDir); } string &NormalizePathName(string &Name); void PrintFileInfos(); #endif