/* 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;
mhmakeparser *m_pAutoDepsMakefile;
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_pAutoDepsMakefile=NULL;
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 SetAutoDepsScan(mhmakeparser *pMakefile)
{
#ifdef _DEBUG
if (m_pAutoDepsMakefile)
throw(string(".AUTODEPS can only defined ones for rule ")+GetFullFileName());
#endif
m_pAutoDepsMakefile=pMakefile;
}
mhmakeparser *GetAutoDepsMakefile(void) const
{
return m_pAutoDepsMakefile;
}
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