aboutsummaryrefslogtreecommitdiff
path: root/tools/mhmake/src
diff options
context:
space:
mode:
Diffstat (limited to 'tools/mhmake/src')
-rw-r--r--tools/mhmake/src/build.cpp235
-rw-r--r--tools/mhmake/src/commandqueue.cpp288
-rw-r--r--tools/mhmake/src/commandqueue.h40
-rw-r--r--tools/mhmake/src/curdir.cpp21
-rw-r--r--tools/mhmake/src/curdir.h1
-rw-r--r--tools/mhmake/src/fileinfo.cpp40
-rw-r--r--tools/mhmake/src/fileinfo.h76
-rw-r--r--tools/mhmake/src/functions.cpp154
-rw-r--r--tools/mhmake/src/mhmake.cpp7
-rw-r--r--tools/mhmake/src/mhmakefileparser.cpp170
-rw-r--r--tools/mhmake/src/mhmakefileparser.h155
-rw-r--r--tools/mhmake/src/mhmakeparser.y8
-rw-r--r--tools/mhmake/src/rule.cpp2
-rw-r--r--tools/mhmake/src/stdafx.h1
-rw-r--r--tools/mhmake/src/util.cpp111
-rw-r--r--tools/mhmake/src/util.h6
16 files changed, 830 insertions, 485 deletions
diff --git a/tools/mhmake/src/build.cpp b/tools/mhmake/src/build.cpp
index 8e4732c32..d14f00ff3 100644
--- a/tools/mhmake/src/build.cpp
+++ b/tools/mhmake/src/build.cpp
@@ -27,7 +27,6 @@
/* Calling py2exe is only implemented on windows for now. */
#ifdef WIN32
-static const string &GetPythonExe();
/* Python exe create script in parts:
import zipfile,tempfile,shutil,os
@@ -214,12 +213,12 @@ void mhmakefileparser::CreatePythonExe(const string &FullCommand)
PythonScript+=GetPythonExe();
PythonScript+=PythonScriptPart3;
- char Filename[10];
+ char Filename[MAX_PATH];
int Nr=0;
FILE *pFile=(FILE*)1;
while (1)
{
- sprintf(Filename,"tmp%d.py",Nr);
+ sprintf(Filename,"%s\\tmp%d.py",m_MakeDir->GetFullFileName().c_str(),Nr);
pFile=fopen(Filename,"r");
if (!pFile)
break;
@@ -231,7 +230,7 @@ void mhmakefileparser::CreatePythonExe(const string &FullCommand)
fclose(pFile);
string GenExeCommand=GetPythonExe();
- GenExeCommand+=Filename;
+ GenExeCommand+=QuoteFileName(Filename);
string Output;
ExecuteCommand(GenExeCommand,&Output);
@@ -241,21 +240,22 @@ void mhmakefileparser::CreatePythonExe(const string &FullCommand)
#endif
/*****************************************************************************/
-#ifndef WIN32
-static int SearchPath(void *NotUsed, const char *szCommand, const char *pExt, int Len, char *szFullCommand,char **pFilePart)
+int mhmakefileparser::SearchPath(void *NotUsed, const char *szCommand, const char *pExt, int Len, char *szFullCommand,char **pFilePart) const
{
+ static vector< refptr<fileinfo> > vSearchPath;
+
string Command(szCommand);
if (pExt)
Command+=pExt;
vector< refptr<fileinfo> >::iterator It;
vector< refptr<fileinfo> >::iterator ItEnd;
- refptr<fileinfo> CommandFile=GetFileInfo(Command);
+ refptr<fileinfo> CommandFile=GetFileInfo(Command,m_MakeDir);
if (CommandFile->Exists())
{
goto found;
}
- static vector< refptr<fileinfo> > vSearchPath;
+ CommandFile->InvalidateDate(); // It could be created in the makefile later
if (!vSearchPath.size())
{
char Path[1024];
@@ -266,7 +266,7 @@ static int SearchPath(void *NotUsed, const char *szCommand, const char *pExt, in
char *pTok=strtok(Path,OSPATHENVSEPSTR);
while (pTok)
{
- vSearchPath.push_back(GetFileInfo(pTok));
+ vSearchPath.push_back(GetFileInfo(pTok,m_MakeDir));
pTok=strtok(NULL,OSPATHENVSEPSTR);
}
}
@@ -292,10 +292,9 @@ found:
strcpy(szFullCommand,FullCommand.c_str());
return 1;
}
-#endif
/*****************************************************************************/
-string SearchCommand(const string &Command, const string &Extension)
+string mhmakefileparser::SearchCommand(const string &Command, const string &Extension) const
{
char FullCommand[MAX_PATH]="";
unsigned long Size=sizeof(FullCommand);
@@ -390,7 +389,7 @@ static bool DeleteDir(const string &Dir,const string WildSearch="*",bool bRemove
}
/*****************************************************************************/
-static bool DeleteFiles(const string &Params)
+HANDLE mhmakefileparser::DeleteFiles(const string &Params) const
{
bool IgnoreError=false;
vector< refptr<fileinfo> > Files;
@@ -406,7 +405,7 @@ static bool DeleteFiles(const string &Params)
else
{
cerr << "Invalid option "<<Params[1]<<" in del statement\n";
- return false;
+ return (HANDLE)-1;
}
}
else
@@ -449,11 +448,11 @@ static bool DeleteFiles(const string &Params)
if (-1==remove(FileName.c_str()) && !IgnoreError)
{
cerr << "Error deleting "<<FileName<<endl;
- return false;
+ return (HANDLE)-1;
}
}
}
- return true;
+ return (HANDLE)0;
}
/*****************************************************************************/
@@ -599,7 +598,7 @@ exit:
}
/*****************************************************************************/
-static bool EchoCommand(const string &Params)
+HANDLE mhmakefileparser::EchoCommand(const string &Params) const
{
// Find the first > character
size_t Pos=Params.find_first_of('>');
@@ -616,20 +615,20 @@ static bool EchoCommand(const string &Params)
if (Params[Pos+1]=='>')
{
NextItem(Params.substr(Pos+2).c_str(),Filename);
- refptr<fileinfo> pFile=GetFileInfo(Filename);
+ refptr<fileinfo> pFile=GetFileInfo(Filename,m_MakeDir);
// Open file in append
pfFile=fopen(pFile->GetFullFileName().c_str(),"a");
}
else
{
NextItem(Params.substr(Pos+1).c_str(),Filename);
- refptr<fileinfo> pFile=GetFileInfo(Filename);
+ refptr<fileinfo> pFile=GetFileInfo(Filename,m_MakeDir);
pfFile=fopen(pFile->GetFullFileName().c_str(),"w");
}
if (!pfFile)
{
cerr << "Error opening file "<<Filename<<endl;
- return false;
+ return (HANDLE)-1;
}
int Begin=0;
while (Params[Begin]==' ' || Params[Begin] == '\t') Begin++; // Strip leading white space
@@ -637,15 +636,15 @@ static bool EchoCommand(const string &Params)
if (EchoStr.length()!=fwrite(EchoStr.c_str(),1,EchoStr.length(),pfFile))
{
cerr << "Error writing file "<<Filename<<endl;
- return false;
+ return (HANDLE)-1;
}
fclose(pfFile);
}
- return true;
+ return (HANDLE)0;
}
/*****************************************************************************/
-static bool CopyFiles(const string &Params)
+HANDLE mhmakefileparser::CopyFiles(const string &Params) const
{
vector< refptr<fileinfo> > Files;
@@ -663,7 +662,7 @@ static bool CopyFiles(const string &Params)
if (NrSrcs>1 && !pDest->IsDir())
{
cerr << "copy: Destination must be a directory when more then one source : "<<Params<<endl;
- return false;
+ return (HANDLE)-1;
}
for (size_t i=0; i<NrSrcs; i++)
@@ -675,7 +674,7 @@ static bool CopyFiles(const string &Params)
if (pSrc->IsDir())
{
SrcFileName+=OSPATHSEPSTR"*";
- pSrc=GetFileInfo(SrcFileName);
+ pSrc=GetFileInfo(SrcFileName,m_MakeDir);
}
//cerr << "copy "<<pSrc->GetFullFileName()<<" "<<pDest->GetFullFileName()<<endl;
@@ -685,7 +684,7 @@ static bool CopyFiles(const string &Params)
if (!CopyDir(pSrc->GetDir(), pDest, pSrc->GetName()))
{
cerr << "copy: Error copying directory: " << Params << endl;
- return false;
+ return (HANDLE)-1;
}
}
else
@@ -693,17 +692,17 @@ static bool CopyFiles(const string &Params)
if (!CopyFile(pSrc,pDest))
{
cerr << "copy: Error copying file: " << Params << endl;
- return false;
+ return (HANDLE)-1;
}
}
}
- return true;
+ return (HANDLE)0;
}
/*****************************************************************************/
-static bool TouchFiles(const string &Params)
+HANDLE mhmakefileparser::TouchFiles(const string &Params) const
{
vector< refptr<fileinfo> > Files;
@@ -723,7 +722,7 @@ static bool TouchFiles(const string &Params)
if (pFile->IsDir())
{
cerr << "touch: Cannot touch a directory: " << FileName << endl;
- return false;
+ return (HANDLE)-1;
}
if (pFile->Exists())
{
@@ -744,7 +743,7 @@ static bool TouchFiles(const string &Params)
if (fstat (fd, &st) < 0)
{
cerr << "touch: Cannot stat file " << FileName << endl;
- return false;
+ return (HANDLE)-1;
}
}
@@ -754,14 +753,14 @@ static bool TouchFiles(const string &Params)
if (fd>=0 && close(fd) < 0)
{
cerr << "touch: Error closing file " << FileName << endl;
- return false;
+ return (HANDLE)-1;
}
/*Re-Create an empty file */
pFile=fopen(FileName.c_str(),"wb");
if (!pFile)
{
cerr << "touch: Cannot create file: " << FileName << endl;
- return false;
+ return (HANDLE)-1;
}
fclose(pFile);
}
@@ -771,22 +770,22 @@ static bool TouchFiles(const string &Params)
if (Ret!=sizeof(c) && Ret!=EOF)
{
cerr << "touch: Cannot read file " << FileName << ": "<<Ret<<endl;
- return false;
+ return (HANDLE)-1;
}
if (lseek (fd, (off_t) 0, SEEK_SET) < 0)
{
cerr << "touch: Error changing file pointer " << FileName << endl;
- return false;
+ return (HANDLE)-1;
}
if (write (fd, &c, sizeof c) != sizeof(c))
{
cerr << "touch: Error writing file " << FileName << endl;
- return false;
+ return (HANDLE)-1;
}
if (close (fd) < 0)
{
cerr << "touch: Error closing file " << FileName << endl;
- return false;
+ return (HANDLE)-1;
}
}
}
@@ -797,17 +796,17 @@ static bool TouchFiles(const string &Params)
if (!pFile)
{
cerr << "touch: Cannot create file: " << FileName << endl;
- return false;
+ return (HANDLE)-1;
}
fclose(pFile);
}
pFile->InvalidateDate();
}
- return true;
+ return (HANDLE)0;
}
/*****************************************************************************/
-static const string &GetPythonExe()
+const string &mhmakefileparser::GetPythonExe() const
{
static string PythonExe;
if (PythonExe.empty())
@@ -905,8 +904,8 @@ string mhmakefileparser::GetFullCommand(string Command)
Command=FullCommand;
if (!PythonFullCommand.empty()&&s_Py2ExeInstalled)
{
- refptr<fileinfo> pExeFile=GetFileInfo(FullCommand);
- refptr<fileinfo> pPyFile=GetFileInfo(PythonFullCommand);
+ refptr<fileinfo> pExeFile=GetFileInfo(FullCommand,m_MakeDir);
+ refptr<fileinfo> pPyFile=GetFileInfo(PythonFullCommand,m_MakeDir);
bool bBuild=false;
if (pExeFile->GetDate().IsOlder(pPyFile->GetDate()))
{
@@ -956,7 +955,7 @@ string mhmakefileparser::GetFullCommand(string Command)
string ExeFullCommand=SearchCommand(Command,EXEEXT);
if (!ExeFullCommand.empty())
{
- pExeFile=GetFileInfo(ExeFullCommand);
+ pExeFile=GetFileInfo(ExeFullCommand,m_MakeDir);
pExeFile->InvalidateDate(); // The file was just generated, make sure the correct date is taken.
}
if (ExeFullCommand.empty() || !pExeFile->Exists())
@@ -984,7 +983,7 @@ string mhmakefileparser::GetFullCommand(string Command)
return pFound->second;
}
-bool OsExeCommand(const string &Command,const string &Params,bool IgnoreError,string *pOutput)
+HANDLE mhmakefileparser::OsExeCommand(const string &Command, const string &Params, bool IgnoreError, string *pOutput) const
{
string FullCommandLine;
string ComSpec=GetComspec();
@@ -1059,7 +1058,7 @@ bool OsExeCommand(const string &Command,const string &Params,bool IgnoreError,st
StartupInfo.hStdOutput = hChildStdoutWr;
StartupInfo.hStdError = hChildStdoutWr;
- if (!CreateProcess(NULL,pFullCommand,NULL,NULL,TRUE,CREATE_NO_WINDOW,NULL,curdir::GetCurDir()->GetFullFileName().c_str(),&StartupInfo,&ProcessInfo))
+ if (!CreateProcess(NULL,pFullCommand,NULL,NULL,TRUE,CREATE_NO_WINDOW,m_pEnv,m_MakeDir->GetFullFileName().c_str(),&StartupInfo,&ProcessInfo))
{
delete[] pFullCommand;
string ErrorMessage=string("Error starting command: ") + FullCommandLine + " : " + stringify(GetLastError());
@@ -1086,10 +1085,24 @@ bool OsExeCommand(const string &Command,const string &Params,bool IgnoreError,st
WaitForSingleObject(ProcessInfo.hProcess,INFINITE);
fclose(pStdIn);
fclose(pStdOut);
+
+ DWORD ExitCode=0;
+ if (!GetExitCodeProcess(ProcessInfo.hProcess,&ExitCode) || ExitCode)
+ {
+ if (IgnoreError)
+ {
+ cerr << "Error running command: "<<Command<<", but ignoring error\n";
+ return (HANDLE)0; // Ignore error
+ }
+ else
+ return (HANDLE)-1;
+ }
+ CloseHandle(ProcessInfo.hProcess);
+ return (HANDLE)0;
}
else
{
- if (!CreateProcess(NULL,pFullCommand,NULL,NULL,TRUE,0,NULL,curdir::GetCurDir()->GetFullFileName().c_str(),&StartupInfo,&ProcessInfo))
+ if (!CreateProcess(NULL,pFullCommand,NULL,NULL,TRUE,0,m_pEnv,m_MakeDir->GetFullFileName().c_str(),&StartupInfo,&ProcessInfo))
{
delete[] pFullCommand;
string ErrorMessage=string("Error starting command: ") + Command + " : " + stringify(GetLastError());
@@ -1100,21 +1113,8 @@ bool OsExeCommand(const string &Command,const string &Params,bool IgnoreError,st
}
delete[] pFullCommand;
CloseHandle(ProcessInfo.hThread);
- WaitForSingleObject(ProcessInfo.hProcess,INFINITE);
+ return ProcessInfo.hProcess;
}
- DWORD ExitCode=0;
- if (!GetExitCodeProcess(ProcessInfo.hProcess,&ExitCode) || ExitCode)
- {
- if (IgnoreError)
- {
- cerr << "Error running command: "<<Command<<", but ignoring error\n";
- return true; // Ignore error
- }
- else
- return false;
- }
- CloseHandle(ProcessInfo.hProcess);
- return true;
#else
int pipeto[2]; /* pipe to feed the exec'ed program input */
int pipefrom[2]; /* pipe to get the exec'ed program output */
@@ -1278,10 +1278,10 @@ string EscapeQuotes(const string &Params)
#endif
///////////////////////////////////////////////////////////////////////////////
-bool mhmakefileparser::ExecuteCommand(string Command,string *pOutput)
+HANDLE mhmakefileparser::ExecuteCommand(string Command, bool &IgnoreError, string *pOutput)
{
bool Echo=true;
- bool IgnoreError=false;
+ IgnoreError=false;
while (1)
{
if (Command[0]=='@')
@@ -1398,7 +1398,7 @@ bool mhmakefileparser::ExecuteCommand(string Command,string *pOutput)
#ifdef _DEBUG
}
#endif
- return true; /* No Error */
+ return (HANDLE)0; /* No Error */
}
///////////////////////////////////////////////////////////////////////////////
@@ -1409,7 +1409,13 @@ void mhmakefileparser::BuildDependencies(const refptr<rule> &pRule, const refptr
vector< refptr<fileinfo> >::iterator pDepIt=Deps.begin();
while (pDepIt!=Deps.end())
{
- mh_time_t DepDate=BuildTarget(*pDepIt);
+ StartBuildTarget(*pDepIt);
+ pDepIt++;
+ }
+ pDepIt=Deps.begin();
+ while (pDepIt!=Deps.end())
+ {
+ mh_time_t DepDate=WaitBuildTarget(*pDepIt);
if (DepDate.IsNewer(YoungestDate))
YoungestDate=DepDate;
if (DepDate.IsNewer(TargetDate))
@@ -1425,7 +1431,7 @@ void mhmakefileparser::BuildDependencies(const refptr<rule> &pRule, const refptr
}
///////////////////////////////////////////////////////////////////////////////
-mh_time_t mhmakefileparser::BuildTarget(const refptr<fileinfo> &Target,bool bCheckTargetDir)
+mh_time_t mhmakefileparser::StartBuildTarget(const refptr<fileinfo> &Target,bool bCheckTargetDir)
{
#ifdef _DEBUG
if (g_CheckCircularDeps)
@@ -1442,7 +1448,7 @@ mh_time_t mhmakefileparser::BuildTarget(const refptr<fileinfo> &Target,bool bChe
pIt++;
}
}
- if (!Target->IsBuild()) m_TargetStack.push_back(Target);
+ if (!Target->IsBuildStarted()) m_TargetStack.push_back(Target);
}
#endif
@@ -1467,6 +1473,8 @@ mh_time_t mhmakefileparser::BuildTarget(const refptr<fileinfo> &Target,bool bChe
#endif
return Target->GetDate();
}
+ if (Target->IsBuilding())
+ return mh_time_t(); // Target is still building, so we have to wait
#ifdef _DEBUG
if (g_GenProjectTree)
@@ -1567,6 +1575,16 @@ mh_time_t mhmakefileparser::BuildTarget(const refptr<fileinfo> &Target,bool bChe
}
ResultIt++;
}
+ if (pRule)
+ {
+ #ifdef _DEBUG
+ Target->SetBuilding();
+ Target->SetRule(pRule);
+ Target->ClearBuilding();
+ #else
+ Target->SetRule(pRule);
+ #endif
+ }
}
mhmakeparser *pMakefile=NULL;
@@ -1614,24 +1632,9 @@ mh_time_t mhmakefileparser::BuildTarget(const refptr<fileinfo> &Target,bool bChe
// Now execute the commands
vector<string> &Commands=pRule->GetCommands();
- while (1)
+ if (!MakeTarget)
{
vector<string>::iterator CommandIt=Commands.begin();
- if (MakeTarget)
- {
- pMakefile->UpdateAutomaticDependencies(Target);
- BuildDependencies(pRule,Target,TargetDate,YoungestDate,MakeTarget); /* Since it could be that there are dependencies added, make sure that they are all build before building this target */
-
- pMakefile->InitEnv(); // Make sure that the exports are set in the evironment
-#ifdef _DEBUG
- if (!g_GenProjectTree && !g_Quiet)
-#else
- if (!g_Quiet)
-#endif
- cout << "Building " << Target->GetQuotedFullFileName()<<endl;
- }
-
- curdir::ChangeCurDir(pMakefile->GetMakeDir());
md5_context ctx;
md5_starts( &ctx );
@@ -1641,57 +1644,18 @@ mh_time_t mhmakefileparser::BuildTarget(const refptr<fileinfo> &Target,bool bChe
string Command=pMakefile->ExpandExpression(*CommandIt);
pMakefile->ClearRuleThatIsBuild(); /* Make sure that further expansion is not taking this rule into account.*/
md5_update( &ctx, (uint8 *)Command.c_str(), (unsigned long)Command.size());
- if (MakeTarget)
- {
- #ifdef _DEBUG
- if (g_pPrintDependencyCheck)
- {
- for (int i=0; i<Indent; i++)
- cout<<" ";
- cout<<"-> "<<Command<<endl;
- }
- if (!g_GenProjectTree)
- #endif
- if (!pMakefile->ExecuteCommand(Command))
- {
- string ErrorMessage = string("Error running command: ")+ Command +"\n";
- ErrorMessage += "Command defined in makefile: " + pMakefile->GetMakeDir()->GetQuotedFullFileName();
- Target->SetCommandsMd5_32(0); /* Clear the md5 to make sure that the target is rebuild the next time mhmake is ran */
- m_AutoDepsDirty=true; /* We need to update the autodeps file if the md5 has been changed */
- throw ErrorMessage;
- }
- }
CommandIt++;
}
uint32 Md5_32=md5_finish32( &ctx);
- if (MakeTarget)
- {
- #ifdef _DEBUG
- if (g_DoNotExecute||g_GenProjectTree)
- Target->SetDateToNow();
- else
- #endif
- Target->InvalidateDate();
- mh_time_t NewDate=Target->GetDate();
- if (NewDate.IsNewer(YoungestDate))
- YoungestDate=NewDate;
-
- Target->SetCommandsMd5_32(Md5_32); /* If the rule of the target was added with an implicit rule the targets in the rule is empty */
- pMakefile->AddTarget(Target);
- pMakefile->m_AutoDepsDirty=true;
- pRule->SetTargetsIsBuild(Md5_32);
- break;
- }
- else if (!Target->CompareMd5_32(Md5_32))
+ if (!Target->CompareMd5_32(Md5_32))
{
if (TargetDate.IsNewerOrSame(m_sBuildTime) || TargetDate.IsDir())
{
// Only rebuild if it is not yet rebuild in this current run. This may happen for implicit rules that have multiple targets (implicit rules that build more then one target at the same time
Target->SetCommandsMd5_32(Md5_32);
pMakefile->AddTarget(Target);
- pMakefile->m_AutoDepsDirty=true; /* We need to update the autodeps file if the md5 has been changed */
- break;
+ pMakefile->SetAutoDepsDirty(); /* We need to update the autodeps file if the md5 has been changed */
}
else
{
@@ -1699,11 +1663,28 @@ mh_time_t mhmakefileparser::BuildTarget(const refptr<fileinfo> &Target,bool bChe
if (!g_GenProjectTree)
cout << "Md5 is different for " << Target->GetQuotedFullFileName() << " Old:"<<hex<<Target->GetCommandsMd5_32()<<", New: "<<Md5_32<<". Commandline must have been changed so recompiling\n";
#endif
+
+ #ifdef _DEBUG
+ Indent--;
+ if (g_CheckCircularDeps)
+ {
+ m_TargetStack.pop_back();
+ }
+ #endif
+
MakeTarget=true;
}
}
- else
- break;
+ }
+ if (MakeTarget)
+ {
+ // Queue for execution
+// Target->SetDate(YoungestDate);
+ if (sm_CommandQueue.QueueTarget(Target))
+ return mh_time_t();
+ mh_time_t NewDate=Target->GetDate();
+ if (NewDate.IsNewer(YoungestDate))
+ YoungestDate=NewDate;
}
}
@@ -1731,6 +1712,12 @@ mh_time_t mhmakefileparser::BuildTarget(const refptr<fileinfo> &Target,bool bChe
}
///////////////////////////////////////////////////////////////////////////////
+mh_time_t mhmakefileparser::WaitBuildTarget(const refptr<fileinfo> &Target)
+{
+ return sm_CommandQueue.WaitForTarget(Target);
+}
+
+///////////////////////////////////////////////////////////////////////////////
void mhmakefileparser::BuildIncludedMakefiles()
{
vector< refptr<fileinfo> >::iterator MakefileIt=m_IncludedMakefiles.begin();
diff --git a/tools/mhmake/src/commandqueue.cpp b/tools/mhmake/src/commandqueue.cpp
new file mode 100644
index 000000000..db14ac38d
--- /dev/null
+++ b/tools/mhmake/src/commandqueue.cpp
@@ -0,0 +1,288 @@
+#include "stdafx.h"
+
+#include "commandqueue.h"
+#include "mhmakeparser.h"
+
+commandqueue::commandqueue() :
+ m_NrActiveEntries(0)
+{
+ SYSTEM_INFO SysInfo;
+ GetSystemInfo(&SysInfo);
+ m_MaxNrCommandsInParallel=SysInfo.dwNumberOfProcessors;
+
+ m_pActiveProcesses=new HANDLE[m_MaxNrCommandsInParallel];
+ m_pActiveEntries= new activeentry[m_MaxNrCommandsInParallel];
+}
+
+commandqueue::~commandqueue()
+{
+ delete [] m_pActiveProcesses;
+ delete [] m_pActiveEntries;
+}
+
+void commandqueue::SetNrParallelBuilds(unsigned NrParallelBuilds)
+{
+ if (m_NrActiveEntries)
+ throw("Changing of number of parallel builds is only allowed when no commands are executing");
+ NrParallelBuilds=max(1,NrParallelBuilds);
+ m_MaxNrCommandsInParallel=NrParallelBuilds;
+ delete [] m_pActiveProcesses;
+ delete [] m_pActiveEntries;
+ m_pActiveProcesses=new HANDLE[NrParallelBuilds];
+ m_pActiveEntries= new activeentry[NrParallelBuilds];
+}
+
+void commandqueue::ThrowCommandExecutionError(activeentry *pActiveEntry)
+{
+ refptr<fileinfo> pTarget=pActiveEntry->pTarget;
+ const string &Command=pActiveEntry->Command;
+ mhmakeparser *pMakefile=pTarget->GetRule()->GetMakefile();
+
+ string ErrorMessage = string("Error running command: ")+ Command +"\n";
+ ErrorMessage += "Command defined in makefile: " + pMakefile->GetMakeDir()->GetQuotedFullFileName();
+ pTarget->SetCommandsMd5_32(0); /* Clear the md5 to make sure that the target is rebuild the next time mhmake is ran */
+ pMakefile->SetAutoDepsDirty(); /* We need to update the autodeps file if the md5 has been changed */
+ throw ErrorMessage;
+}
+
+void commandqueue::RemoveActiveEntry(unsigned Entry)
+{
+//cout << "Remove entry "<<Entry<<" of "<<m_NrActiveEntries<<" from queue:"<<m_pActiveEntries[Entry].pTarget->GetQuotedFullFileName()<<endl;
+ unsigned NrToMove=m_NrActiveEntries-Entry-1;
+ if (NrToMove)
+ {
+ for (unsigned i=0; i<NrToMove; i++)
+ {
+ unsigned EntryP1=Entry+1;
+ m_pActiveEntries[Entry]=m_pActiveEntries[EntryP1];
+ m_pActiveProcesses[Entry]=m_pActiveProcesses[EntryP1];
+ Entry=EntryP1;
+ }
+ }
+ m_pActiveEntries[Entry]=activeentry();
+ m_pActiveProcesses[Entry]=NULL;
+ m_NrActiveEntries--;
+}
+
+/* Start to execute next command, return true when command is completely executed
+ upon return */
+bool commandqueue::StartExecuteNextCommand(activeentry *pActiveEntry, HANDLE *pActiveProcess)
+{
+ refptr<fileinfo> pTarget=pActiveEntry->pTarget;
+ mhmakeparser *pMakefile=pTarget->GetRule()->GetMakefile();
+
+ pMakefile->SetRuleThatIsBuild(pTarget); // Make sure that the command expension is correct
+ string Command=pMakefile->ExpandExpression(*pActiveEntry->CurrentCommandIt);
+ pMakefile->ClearRuleThatIsBuild(); /* Make sure that further expansion is not taking this rule into account.*/
+ md5_update( &pActiveEntry->md5ctx, (uint8 *)Command.c_str(), (unsigned long)Command.size());
+
+ pActiveEntry->Command=Command;
+
+ #ifdef _DEBUG
+ if (g_pPrintDependencyCheck)
+ {
+ cout<<"-> "<<Command<<endl;
+ }
+ if (!g_GenProjectTree)
+ {
+ #endif
+ HANDLE hProcess=pMakefile->ExecuteCommand(Command,pActiveEntry->IgnoreError);
+ if (hProcess==(HANDLE)-1)
+ {
+ ThrowCommandExecutionError(pActiveEntry);
+ }
+ else if (!hProcess)
+ {
+ // Command already finished, so execute next command
+ return true;
+ }
+ else
+ {
+ // Command still executing, so add it to the list of handles to wait for
+ *pActiveProcess=hProcess;
+ return false;
+ }
+ #ifdef _DEBUG
+ }
+ #endif
+ return true;
+}
+
+void commandqueue::TargetBuildFinished(activeentry *pActiveEntry)
+{
+ refptr<fileinfo> pTarget=pActiveEntry->pTarget;
+
+ // Building of this target finished
+ uint32 Md5_32=md5_finish32( &pActiveEntry->md5ctx);
+ #ifdef _DEBUG
+ if (g_DoNotExecute||g_GenProjectTree)
+ pTarget->SetDateToNow();
+ else
+ #endif
+ pTarget->InvalidateDate();
+
+ pTarget->SetCommandsMd5_32(Md5_32); /* If the rule of the target was added with an implicit rule the targets in the rule is empty */
+
+ refptr<rule> pRule=pTarget->GetRule();
+ mhmakeparser *pMakefile=pRule->GetMakefile();
+
+ pMakefile->AddTarget(pTarget);
+ pMakefile->SetAutoDepsDirty();
+ pRule->SetTargetsIsBuild(Md5_32);
+
+ #ifdef _DEBUG
+ if (g_pPrintDependencyCheck)
+ {
+ cout<<"Building "<<pTarget->GetQuotedFullFileName()<<" finished : "<< pTarget->GetDate() << endl;
+ }
+
+ if (!pMakefile->ImplicitSearch() && !pTarget->Exists() && !pTarget->IsPhony() && !g_DoNotExecute && !g_GenProjectTree)
+ {
+ // This is only a warning for phony messages
+ cout<<"Warning: don't know how to make "<<pTarget->GetQuotedFullFileName()<<"\nMake the rule a phony rule to avoid this warning (but only do it when it is really phony).\n";;
+ }
+ #endif
+
+ pTarget->ClearBuilding();
+}
+
+/* Start executing the commands of a target
+*/
+bool commandqueue::StartExecuteCommands(const refptr<fileinfo> &pTarget)
+{
+ cout << "Building " << pTarget->GetQuotedFullFileName()<<endl;
+ // We do not have to put it in the queue, we can start executing directly
+ refptr<rule> pRule=pTarget->GetRule();
+ mhmakeparser *pMakefile=pRule->GetMakefile();
+ vector<string>::iterator CommandIt=pRule->GetCommands().begin();
+ activeentry *pActiveEntry=&m_pActiveEntries[m_NrActiveEntries];
+ md5_starts( &pActiveEntry->md5ctx );
+
+ pActiveEntry->pTarget=pTarget;
+ pActiveEntry->CurrentCommandIt=CommandIt;
+ pActiveEntry->pTarget=pTarget;
+
+ while (1)
+ {
+ if (StartExecuteNextCommand(pActiveEntry, &m_pActiveProcesses[m_NrActiveEntries]))
+ {
+ pActiveEntry->CurrentCommandIt++;
+ if (pActiveEntry->CurrentCommandIt==pRule->GetCommands().end())
+ {
+ // All commands executed
+ break;
+ }
+ }
+ else
+ {
+//cout << "Adding entry "<<m_NrActiveEntries<<" to queue:"<<pActiveEntry->pTarget->GetQuotedFullFileName()<<endl;
+ m_NrActiveEntries++;
+ return false;
+ }
+ }
+ TargetBuildFinished(pActiveEntry);
+ *pActiveEntry=activeentry();
+ return true;
+}
+
+
+/* put the target in the execution queue or start executing immediately
+*/
+bool commandqueue::QueueTarget(const refptr<fileinfo> &pTarget)
+{
+ pTarget->SetBuilding();
+ // First check if there is place in the active entries
+ if (m_NrActiveEntries==m_MaxNrCommandsInParallel)
+ {
+ // commands cannot be started yet
+ m_Queue.push(pTarget);
+ return true;
+ }
+ else
+ {
+ return !StartExecuteCommands(pTarget);
+ }
+}
+
+/* Wait for all the commands being executed of a target. In the mean time also continue
+ executing all other commands in the queue
+*/
+mh_time_t commandqueue::WaitForTarget(const refptr<fileinfo> &pTarget)
+{
+ if (!pTarget->IsBuilding())
+ return pTarget->GetDate();
+
+ while (1)
+ {
+ // First wait until one of the processes that are running is finished
+ DWORD Ret=WaitForMultipleObjects(m_NrActiveEntries,m_pActiveProcesses,FALSE,INFINITE);
+ if (Ret>=m_NrActiveEntries)
+ throw("fatal error: unexpected return value of WaitForMultipleObjects " + stringify(Ret));
+ activeentry *pActiveEntry=&m_pActiveEntries[Ret];
+ refptr<fileinfo> pCurrentTarget=pActiveEntry->pTarget;
+ refptr<rule> pRule=pCurrentTarget->GetRule();
+
+ // First check the error code of the command
+ DWORD ExitCode=0;
+ HANDLE hProcess=m_pActiveProcesses[Ret];
+ if (!GetExitCodeProcess(hProcess,&ExitCode) || ExitCode)
+ {
+ if (pActiveEntry->IgnoreError)
+ {
+ cerr << "Error running command: "<<pActiveEntry->Command<<", but ignoring error\n";
+ }
+ else
+ ThrowCommandExecutionError(pActiveEntry);
+ }
+ CloseHandle(hProcess);
+
+ // Now check if we have to execute more commands for this target
+ pActiveEntry->CurrentCommandIt++;
+ while (pActiveEntry->CurrentCommandIt!=pRule->GetCommands().end())
+ {
+ if (!StartExecuteNextCommand(pActiveEntry, &m_pActiveProcesses[Ret]))
+ break; // We have to wait for end of command execution
+ pActiveEntry->CurrentCommandIt++;
+ }
+
+ if (pActiveEntry->CurrentCommandIt==pRule->GetCommands().end())
+ {
+ TargetBuildFinished(pActiveEntry);
+ // Target building finished, so remove it from the list of active entries
+ RemoveActiveEntry(Ret);
+
+ bool Return=false;
+ if (pTarget==pCurrentTarget)
+ {
+ Return = true;
+ }
+ // Check if we have other entries in the queue to start
+ while (1)
+ {
+ if (m_Queue.empty())
+ {
+ // There should still be active entries, otherwise this is a serious bug
+ if (!m_NrActiveEntries && !Return)
+ throw("Fatal error: WaitForTarget "+pTarget->GetQuotedFullFileName()+": no active targets anymore.");
+ else
+ break;
+ }
+ else
+ {
+ refptr<fileinfo> pNewTarget=m_Queue.front();
+ m_Queue.pop();
+ if (StartExecuteCommands(pNewTarget))
+ {
+ if (pNewTarget==pTarget)
+ Return=true;
+ }
+ else
+ break;
+ }
+ }
+ if (Return)
+ return pTarget->GetDate();
+ }
+ }
+
+}
diff --git a/tools/mhmake/src/commandqueue.h b/tools/mhmake/src/commandqueue.h
new file mode 100644
index 000000000..54a22e98e
--- /dev/null
+++ b/tools/mhmake/src/commandqueue.h
@@ -0,0 +1,40 @@
+#ifndef __COMMANDQUEUE_H__
+#define __COMMANDQUEUE_H__
+
+#include "fileinfo.h"
+
+class commandqueue
+{
+ struct activeentry
+ {
+ refptr<fileinfo> pTarget;
+ vector<string>::iterator CurrentCommandIt;
+ string Command;
+ md5_context md5ctx;
+ bool IgnoreError;
+ };
+private:
+ queue< refptr<fileinfo> > m_Queue;
+ unsigned m_MaxNrCommandsInParallel;
+ HANDLE *m_pActiveProcesses;
+ activeentry *m_pActiveEntries;
+ unsigned m_NrActiveEntries;
+
+private:
+ void ThrowCommandExecutionError(activeentry *pActiveEntry);
+ void RemoveActiveEntry(unsigned Entry);
+ bool StartExecuteCommands(const refptr<fileinfo> &pTarget);
+ bool StartExecuteNextCommand(activeentry *pActiveEntry, HANDLE *pActiveProcess);
+ void TargetBuildFinished(activeentry *pActiveEntry);
+
+public:
+ commandqueue();
+ ~commandqueue();
+
+ bool QueueTarget(const refptr<fileinfo> &pTarget); // Returns true if target has been queued, false when commands are executed upon return
+ mh_time_t WaitForTarget(const refptr<fileinfo> &pTarget);
+ void SetNrParallelBuilds(unsigned NrParallelBuilds);
+};
+
+
+#endif
diff --git a/tools/mhmake/src/curdir.cpp b/tools/mhmake/src/curdir.cpp
index 64389c993..094093a9b 100644
--- a/tools/mhmake/src/curdir.cpp
+++ b/tools/mhmake/src/curdir.cpp
@@ -38,23 +38,6 @@ curdir::initcurdir::initcurdir()
{
char CurDir[MAX_PATH];
getcwd(CurDir,MAX_PATH);
- *this=GetFileInfo(CurDir,refptr<fileinfo>());
+ string strCurDir=CurDir;
+ *this=GetAbsFileInfo(NormalizePathName(strCurDir));
}
-
-///////////////////////////////////////////////////////////////////////////////
-void curdir::ChangeCurDir(const refptr<fileinfo>&NewDir)
-{
- if (NewDir!=m_pCurrentDir)
- {
- #ifdef _DEBUG
- if (g_PrintAdditionalInfo)
- cout << "Changing to dir "<<NewDir->GetFullFileName()<<endl;
- #endif
- if (-1==chdir(NewDir->GetFullFileName().c_str()))
- {
- throw string("Error changing to directory ") + NewDir->GetQuotedFullFileName();
- }
- m_pCurrentDir=NewDir;
- }
-}
-
diff --git a/tools/mhmake/src/curdir.h b/tools/mhmake/src/curdir.h
index 1dad43457..169dca8a7 100644
--- a/tools/mhmake/src/curdir.h
+++ b/tools/mhmake/src/curdir.h
@@ -42,7 +42,6 @@ public:
{
return m_pCurrentDir;
}
- static void ChangeCurDir(const refptr<fileinfo>&NewDir);
};
#endif
diff --git a/tools/mhmake/src/fileinfo.cpp b/tools/mhmake/src/fileinfo.cpp
index 387b2816d..e0feb0a79 100644
--- a/tools/mhmake/src/fileinfo.cpp
+++ b/tools/mhmake/src/fileinfo.cpp
@@ -25,13 +25,13 @@
#include "util.h"
#include "mhmakeparser.h"
+#ifndef S_ISDIR
+#define S_ISDIR(val) ((val)&_S_IFDIR)
+#endif
+
const string NullString;
refptr<fileinfo> NullFileInfo;
-#ifdef WIN32
-ZEROTIME g_ZeroTime;
-#endif
-
///////////////////////////////////////////////////////////////////////////////
string QuoteFileName(const string &Filename)
{
@@ -92,27 +92,6 @@ string fileinfo::GetName() const
///////////////////////////////////////////////////////////////////////////////
mh_time_t fileinfo::realGetDate()
{
-#ifdef WIN32
- WIN32_FIND_DATA FindData;
- HANDLE hFind=FindFirstFile(m_AbsFileName.c_str(),&FindData);
- if (hFind==INVALID_HANDLE_VALUE)
- {
- m_Date.SetNotExist();
- }
- else
- {
- FindClose(hFind);
- if (FindData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
- { // For directories we just take an old time since the lastwritetime is changed each time something
- // is added to the directory
- m_Date.SetDir();
- }
- else
- {
- m_Date=g_ZeroTime.ConvertTime(&FindData.ftLastWriteTime);
- }
- }
-#else
struct stat Buf;
if (-1==stat(m_AbsFileName.c_str(),&Buf))
m_Date.SetNotExist();
@@ -120,7 +99,6 @@ mh_time_t fileinfo::realGetDate()
m_Date.SetDir();
else
m_Date=Buf.st_mtime;
-#endif
return m_Date;
}
@@ -157,16 +135,12 @@ bool fileinfo::IsDir() const
}
///////////////////////////////////////////////////////////////////////////////
+#ifdef _DEBUG
void fileinfo::SetDateToNow()
{
-#ifdef WIN32
- FILETIME FileTime;
- GetSystemTimeAsFileTime(&FileTime);
- m_Date=g_ZeroTime.ConvertTime(&FileTime);
-#else
m_Date=time(NULL);
-#endif
}
+#endif
///////////////////////////////////////////////////////////////////////////////
string fileinfo::GetPrerequisits() const
@@ -252,7 +226,7 @@ string fileinfo::GetErrorMessageDuplicateRule(const refptr<rule>&pRule)
#endif
///////////////////////////////////////////////////////////////////////////////
-static inline string &NormalizePathName(string &Name)
+string &NormalizePathName(string &Name)
{
const char *pPtr=Name.c_str();
const char *pBeg=pPtr;
diff --git a/tools/mhmake/src/fileinfo.h b/tools/mhmake/src/fileinfo.h
index 9a521d4a6..146ade02b 100644
--- a/tools/mhmake/src/fileinfo.h
+++ b/tools/mhmake/src/fileinfo.h
@@ -137,7 +137,7 @@ class fileinfo : public refbase
{
string m_AbsFileName;
bool m_IsPhony;
- bool m_IsBuild;
+ int m_BuildStatus; /* Bit 0 means the target built is started, Bit 1 means the target is still building */
refptr<rule> m_pRule;
vector< refptr<fileinfo> > m_Deps;
mh_time_t m_Date;
@@ -150,7 +150,7 @@ public:
fileinfo(const string &AbsFileName,uint32 Md5_32)
{
m_IsPhony=false;
- m_IsBuild=false;
+ m_BuildStatus=0;
m_AbsFileName=UnquoteFileName(AbsFileName);
InvalidateDate();
m_CommandsMd5_32=Md5_32;
@@ -210,7 +210,7 @@ public:
void SetRule(refptr<rule> &pRule)
{
#if defined(_DEBUG) && defined(_MSC_VER)
- if (m_pRule && m_pRule->GetCommands().size()) {
+ if (m_pRule && m_pRule->GetCommands().size() && !IsBuilding()) {
DebugBreak();
}
#endif
@@ -305,7 +305,9 @@ public:
return m_IsPhony;
}
mh_time_t realGetDate(void);
+#ifdef _DEBUG
void SetDateToNow(void);
+#endif
void SetDate(mh_time_t Date)
{
@@ -336,17 +338,29 @@ public:
{
return GetDate().DoesExist();
}
+ bool IsBuildStarted(void) const
+ {
+ return (m_BuildStatus&1)==1;
+ }
bool IsBuild(void) const
{
- return m_IsBuild;
+ return m_BuildStatus==1;
}
void SetBuild(void)
{
- m_IsBuild=true;
+ m_BuildStatus=1;
+ }
+ bool IsBuilding(void) const
+ {
+ return (m_BuildStatus&2)==2;
+ }
+ void SetBuilding(void)
+ {
+ m_BuildStatus|=2;
}
- void ClearBuild(void)
+ void ClearBuilding(void)
{
- m_IsBuild=false;
+ m_BuildStatus&=~2;
}
bool IsAutoDepExtention(void) const;
@@ -393,7 +407,7 @@ struct less_fileinfo : public binary_function <const fileinfo*, const fileinfo*,
extern const string NullString;
extern refptr<fileinfo> NullFileInfo;
-const refptr<fileinfo> &GetFileInfo(const string &szName,const refptr<fileinfo> &pRelDir=curdir::GetCurDir());
+const refptr<fileinfo> &GetFileInfo(const string &szName,const refptr<fileinfo> &pRelDir);
extern set<refptr<fileinfo>,less_refptrfileinfo > g_FileInfos;
@@ -412,55 +426,13 @@ inline const refptr<fileinfo> &GetAbsFileInfo(const string &strAbsName)
return *pFind;
}
-
-inline const refptr<fileinfo> &GetFileInfo(const string &szName,const string &RelDir)
-{
- return GetFileInfo(szName,GetFileInfo(RelDir));
-}
-
-inline const refptr<fileinfo> &GetFileInfo(const char *szName,const char *RelDir)
-{
- return GetFileInfo(string(szName),string(RelDir));
-}
-
-inline const refptr<fileinfo> &GetFileInfo(const char *szName,const refptr<fileinfo> &RelDir=curdir::GetCurDir())
+inline const refptr<fileinfo> &GetFileInfo(const char *szName,const refptr<fileinfo> &RelDir)
{
return GetFileInfo(string(szName),RelDir);
}
+string &NormalizePathName(string &Name);
void PrintFileInfos();
-#ifdef WIN32
-class ZEROTIME
-{
- __int64 m_ZeroTime;
-public:
- ZEROTIME()
- {
- SYSTEMTIME SystemTime;
-
- memset(&SystemTime,0,sizeof(SystemTime));
- SystemTime.wYear=1970;
- SystemTime.wMonth=1;
- SystemTime.wDay=1;
- SystemTime.wDayOfWeek=4;
-
- SystemTimeToFileTime(&SystemTime,(FILETIME*)&m_ZeroTime);
- }
-
- __int64 GetZeroTime()
- {
- return m_ZeroTime;
- }
-
- mh_time_t ConvertTime(FILETIME *pFileTime)
- {
- return (mh_time_t)((*(__int64*)pFileTime-m_ZeroTime)/10000000); /* filetime is in nano seconds*/
- }
-};
-
-extern ZEROTIME g_ZeroTime;
-#endif
-
#endif
diff --git a/tools/mhmake/src/functions.cpp b/tools/mhmake/src/functions.cpp
index c93292d88..b4ea64783 100644
--- a/tools/mhmake/src/functions.cpp
+++ b/tools/mhmake/src/functions.cpp
@@ -60,6 +60,35 @@ map<string,function_f> mhmakefileparser::m_Functions;
bool mhmakefileparser::m_FunctionsInitialised;
///////////////////////////////////////////////////////////////////////////////
+// Loop over a list of filenames
+static string IterList(const string &List,string (*iterFunc)(const string &FileName,void *pArg), void *pArg=NULL)
+{
+ const char *pTmp=List.c_str();
+ string Ret=g_EmptyString;
+ bool first=true;
+ while (*pTmp)
+ {
+ if (!first)
+ {
+ Ret+=g_SpaceString;
+ }
+ else
+ {
+ first=false;
+ }
+ string Item;
+ pTmp=NextItem(pTmp,Item);
+ Item=iterFunc(Item,pArg);
+ if (Item.empty())
+ first=true; // Do not add space the next iteration
+ else
+ Ret+=Item;
+ }
+
+ return Ret;
+}
+
+///////////////////////////////////////////////////////////////////////////////
void mhmakefileparser::InitFuncs(void)
{
for (int i=0; i<sizeof(m_FunctionsDef)/sizeof(funcdef); i++)
@@ -79,6 +108,16 @@ static string TrimString(const string &Input)
}
///////////////////////////////////////////////////////////////////////////////
+
+static string filter(const string &FileName, void *pvFilter)
+{
+ string *pFilter=(string*)pvFilter;
+ if (PercentMatchList(UnquoteFileName(FileName),*pFilter))
+ return FileName;
+ else
+ return g_EmptyString;
+}
+///////////////////////////////////////////////////////////////////////////////
string mhmakefileparser::f_filter(const string & Arg) const
{
size_t ipos=Arg.find(',');
@@ -93,28 +132,7 @@ string mhmakefileparser::f_filter(const string & Arg) const
if (Str.empty())
return Str;
- bool First=true;
- string Ret;
- char *pTok=strtok((char*)List.c_str()," \t"); // doing this is changing string, so this is very dangerous
- while (pTok)
- {
- string Item(pTok);
- if (PercentMatchList(Item,Str))
- {
- if (First)
- {
- Ret=Item;
- First=false;
- }
- else
- {
- Ret+=g_SpaceString;
- Ret+=Item;
- }
- }
- pTok=strtok(NULL," \t");
- }
- return Ret;
+ return IterList(List,filter,(void*)&Str);
}
///////////////////////////////////////////////////////////////////////////////
@@ -333,30 +351,28 @@ string mhmakefileparser::f_firstword(const string & Arg) const
///////////////////////////////////////////////////////////////////////////////
string mhmakefileparser::f_wildcard(const string & Arg) const
{
- string FileSpec=TrimString(Arg);
- size_t LastSep=FileSpec.find_last_of(OSPATHSEP)+1;
- string Dir=FileSpec.substr(0,LastSep);
+ refptr<fileinfo> FileSpec=GetFileInfo(TrimString(Arg),m_MakeDir); /* Use GetFileInfo to make the relative path absolute */
+ refptr<fileinfo> Dir=FileSpec->GetDir();
#ifdef WIN32
struct _finddata_t FileInfo;
- intptr_t hFile=_findfirst(FileSpec.c_str(),&FileInfo);
+ intptr_t hFile=_findfirst(FileSpec->GetFullFileName().c_str(),&FileInfo);
if (hFile==-1)
return g_EmptyString;
string Ret=g_EmptyString;
- /* We have to verify with percentmatch since the find functions *.ext also matches the functions *.xmlbrol */
- string CheckSpec=FileSpec.substr(LastSep);
+ /* We have to verify with percentmatch since the find functions *.ext also matches the functions *.extbrol */
+ string CheckSpec=FileSpec->GetName();
if (PercentMatch(FileInfo.name,CheckSpec,NULL,'*'))
{
- Ret=Dir+FileInfo.name;
+ Ret=GetFileInfo(FileInfo.name,Dir)->GetQuotedFullFileName();
}
while (-1!=_findnext(hFile,&FileInfo))
{
if (PercentMatch(FileInfo.name,CheckSpec,NULL,'*'))
{
Ret+=g_SpaceString;
- Ret+=Dir;
- Ret+=FileInfo.name;
+ Ret+=GetFileInfo(FileInfo.name,Dir)->GetQuotedFullFileName();
}
}
_findclose(hFile);
@@ -386,7 +402,7 @@ string mhmakefileparser::f_wildcard(const string & Arg) const
string mhmakefileparser::f_exist(const string & Arg) const
{
string File=TrimString(Arg);
- refptr<fileinfo> pFile=GetFileInfo(File);
+ refptr<fileinfo> pFile=GetFileInfo(File,m_MakeDir);
if (pFile->Exists())
{
return string("1");
@@ -454,41 +470,16 @@ string mhmakefileparser::f_filesindirs(const string & Arg) const
string mhmakefileparser::f_fullname(const string & Arg) const
{
string File=TrimString(Arg);
- refptr<fileinfo> pFile=GetFileInfo(File);
+ refptr<fileinfo> pFile=GetFileInfo(File,m_MakeDir);
return pFile->GetQuotedFullFileName();
}
///////////////////////////////////////////////////////////////////////////////
-static string IterList(const string &List,string (*iterFunc)(const string &FileName,const string &Arg),const string &Arg=NullString)
+static string basename(const string &FileName,void*)
{
- const char *pTmp=List.c_str();
- string Ret=g_EmptyString;
- bool first=true;
- while (*pTmp)
- {
- if (!first)
- {
- Ret+=g_SpaceString;
- }
- else
- {
- first=false;
- }
- string Item;
- pTmp=NextItem(pTmp,Item);
- Ret+=iterFunc(Item,Arg);
- }
-
- return Ret;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-static string basename(const string &FileName,const string &)
-{
- string Ret=FileName.substr(0,FileName.find_last_of('.'));
- if (FileName[0]=='"' && FileName.end()[-1]=='"')
- Ret+=s_QuoteString;
- return Ret;
+ string Ret=UnquoteFileName(FileName);
+ Ret=Ret.substr(0,Ret.find_last_of('.'));
+ return QuoteFileName(Ret);
}
///////////////////////////////////////////////////////////////////////////////
@@ -498,20 +489,18 @@ string mhmakefileparser::f_basename(const string & FileNames) const
}
///////////////////////////////////////////////////////////////////////////////
-static string notdir(const string &FileName,const string &)
+static string notdir(const string &FileName,void*)
{
- size_t Pos=FileName.find_last_of(OSPATHSEP);
+ string Ret=UnquoteFileName(FileName);
+ size_t Pos=Ret.find_last_of(OSPATHSEP);
if (Pos==string::npos)
{
return FileName;
}
else
{
- string Ret=g_EmptyString;
- if (FileName[0]=='"' && FileName.end()[-1]=='"')
- Ret+=s_QuoteString;
- Ret+=FileName.substr(Pos+1);
- return Ret;
+ Ret=Ret.substr(Pos+1);
+ return QuoteFileName(Ret);
}
}
@@ -523,9 +512,9 @@ string mhmakefileparser::f_notdir(const string & FileNames) const
}
///////////////////////////////////////////////////////////////////////////////
-static string addprefix(const string &FileName,const string &Prefix)
+static string addprefix(const string &FileName,void *pPrefix)
{
- return Prefix+FileName;
+ return *(const string *)pPrefix+FileName;
}
///////////////////////////////////////////////////////////////////////////////
@@ -541,13 +530,13 @@ string mhmakefileparser::f_addprefix(const string & Arg) const
#endif
string FileNames;
pTmp=NextCharItem(pTmp,FileNames,',');
- return IterList(FileNames,addprefix,PreFix);
+ return IterList(FileNames,addprefix,&PreFix);
}
///////////////////////////////////////////////////////////////////////////////
-static string addsuffix(const string &FileName,const string &Suffix)
+static string addsuffix(const string &FileName,void *pSuffix)
{
- return FileName+Suffix;
+ return FileName+*(const string *)pSuffix;
}
///////////////////////////////////////////////////////////////////////////////
@@ -563,7 +552,7 @@ string mhmakefileparser::f_addsuffix(const string & Arg) const
#endif
string FileNames;
pTmp=NextCharItem(pTmp,FileNames,',');
- return IterList(FileNames,addsuffix,SufFix);
+ return IterList(FileNames,addsuffix,&SufFix);
}
///////////////////////////////////////////////////////////////////////////////
@@ -639,7 +628,7 @@ string mhmakefileparser::f_strip(const string & Arg) const
}
///////////////////////////////////////////////////////////////////////////////
-static string dir(const string &FileName,const string &)
+static string dir(const string &FileName, void *)
{
size_t Pos=FileName.find_last_of(OSPATHSEP);
if (Pos==string::npos)
@@ -682,10 +671,11 @@ string mhmakefileparser::f_shell(const string & Command) const
}
///////////////////////////////////////////////////////////////////////////////
-static string relpath(const string &FileName,const string &)
+static string relpath(const string &FileName,void *pvDir)
{
- refptr<fileinfo> Path=GetFileInfo(FileName);
- const char *pCur=curdir::GetCurDir()->GetFullFileName().c_str();
+ const refptr<fileinfo> pDir=*(const refptr<fileinfo> *)pvDir;
+ refptr<fileinfo> Path=GetFileInfo(FileName,pDir);
+ const char *pCur=pDir->GetFullFileName().c_str();
const char *pPath=Path->GetFullFileName().c_str();
const char *pLast=pPath;
@@ -736,11 +726,11 @@ static string relpath(const string &FileName,const string &)
// Make a path name relative to the current directory
string mhmakefileparser::f_relpath(const string & FileNames) const
{
- return IterList(FileNames,relpath);
+ return IterList(FileNames,relpath,(void*)&m_MakeDir);
}
///////////////////////////////////////////////////////////////////////////////
-static string makeupper(const string &FileName,const string &)
+static string makeupper(const string &FileName,void *)
{
string Ret=FileName;
string::const_iterator pSrc=FileName.begin();
@@ -759,7 +749,7 @@ string mhmakefileparser::f_toupper(const string & FileNames) const
}
///////////////////////////////////////////////////////////////////////////////
-static string makelower(const string &FileName,const string &)
+static string makelower(const string &FileName, void *)
{
string Ret=FileName;
string::const_iterator pSrc=FileName.begin();
diff --git a/tools/mhmake/src/mhmake.cpp b/tools/mhmake/src/mhmake.cpp
index 77f7a8db6..db9a13682 100644
--- a/tools/mhmake/src/mhmake.cpp
+++ b/tools/mhmake/src/mhmake.cpp
@@ -84,7 +84,7 @@ int __CDECL main(int argc, char* argv[])
CmdLineArgs.push_back(argv[i]);
}
- refptr<loadedmakefile> pFirstMakefile(new loadedmakefile(CmdLineArgs,"makefile"));
+ refptr<loadedmakefile> pFirstMakefile(new loadedmakefile(curdir::GetCurDir(),CmdLineArgs,"makefile"));
// For the first makefile we add the defines passed on the command line to the
// environment so that the other load_makefile see the same variables
pFirstMakefile->AddCommandLineVarsToEnvironment();
@@ -120,7 +120,8 @@ int __CDECL main(int argc, char* argv[])
{
g_Clean=true;
}
- pFirstMakefile->m_pParser->BuildTarget(GetFileInfo(*It,pFirstMakefile->m_MakeDir));
+ refptr<fileinfo> pTarget=GetFileInfo(*It,pFirstMakefile->m_MakeDir);
+ pFirstMakefile->m_pParser->BuildTarget(pTarget);
It++;
}
}
@@ -128,7 +129,9 @@ int __CDECL main(int argc, char* argv[])
{
refptr<fileinfo> FirstTarget=pFirstMakefile->m_pParser->GetFirstTarget();
if (FirstTarget)
+ {
pFirstMakefile->m_pParser->BuildTarget(FirstTarget);
+ }
else
cout << "Warning: no targets in makefile. Nothing to be build.\nMHMAKECONF defined?\n";
}
diff --git a/tools/mhmake/src/mhmakefileparser.cpp b/tools/mhmake/src/mhmakefileparser.cpp
index d5d2980f8..76e43f475 100644
--- a/tools/mhmake/src/mhmakefileparser.cpp
+++ b/tools/mhmake/src/mhmakefileparser.cpp
@@ -26,6 +26,8 @@
#include "rule.h"
#include "mhmakelexer.h"
+commandqueue mhmakefileparser::sm_CommandQueue;
+
///////////////////////////////////////////////////////////////////////////////
int mhmakefileparser::yylex(void)
{
@@ -40,13 +42,13 @@ void mhmakefileparser::yyerror(const char *m)
}
///////////////////////////////////////////////////////////////////////////////
-int mhmakefileparser::ParseFile(const refptr<fileinfo> &FileInfo,bool SetMakeDir)
+int mhmakefileparser::ParseFile(const refptr<fileinfo> &FileInfo, refptr<fileinfo> &pMakeDir)
{
mhmakelexer theLexer;
m_ptheLexer=&theLexer;
- if (SetMakeDir)
+ if (pMakeDir)
{
- m_MakeDir=curdir::GetCurDir();
+ m_MakeDir=pMakeDir;
m_Variables[CURDIR]=m_MakeDir->GetQuotedFullFileName();
}
theLexer.m_InputFileName=FileInfo->GetFullFileName();
@@ -357,7 +359,7 @@ string mhmakefileparser::ExpandVar(const string &Var) const
}
///////////////////////////////////////////////////////////////////////////////
-void SplitToItems(const string &String,vector< refptr<fileinfo> > &Items,refptr<fileinfo> Dir)
+void mhmakefileparser::SplitToItems(const string &String,vector< refptr<fileinfo> > &Items) const
{
const char *pTmp=String.c_str();
while (*pTmp)
@@ -366,7 +368,7 @@ void SplitToItems(const string &String,vector< refptr<fileinfo> > &Items,refptr<
pTmp=NextItem(pTmp,Item);
if (!Item.empty())
{
- Items.push_back(GetFileInfo(Item,Dir));
+ Items.push_back(GetFileInfo(Item,m_MakeDir));
}
}
}
@@ -377,7 +379,7 @@ void mhmakefileparser::ParseBuildedIncludeFiles()
vector<string>::iterator It=m_ToBeIncludeAfterBuild.begin();
while (It!=m_ToBeIncludeAfterBuild.end())
{
- int result=ParseFile(GetFileInfo(*It));
+ int result=ParseFile(GetFileInfo(*It,m_MakeDir));
if (result)
{
throw string("Error parsing ")+*It;
@@ -410,12 +412,15 @@ void mhmakefileparser::PrintVariables(bool Expand) const
}
It++;
}
- cout << "Exported Variables:\n";
- vector<string>::const_iterator It2=m_Exports.begin();
- while (It2!=m_Exports.end())
+ if (m_pEnv)
{
- cout<<*It2<<endl;
- It2++;
+ cout << "Environment overruled:\n";
+ char *pEnv=m_pEnv;
+ while (*pEnv)
+ {
+ cout<<pEnv<<endl;
+ pEnv+=strlen(pEnv)+1;
+ }
}
}
#endif
@@ -474,7 +479,6 @@ void mhmakefileparser::GetAutoDeps(const refptr<fileinfo> &FirstDep,set< refptr<
if (!pIn)
return;
- refptr<fileinfo> 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);
@@ -551,7 +555,8 @@ void mhmakefileparser::GetAutoDeps(const refptr<fileinfo> &FirstDep,set< refptr<
{
refptr<fileinfo> 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
+ mh_time_t Date=BuildTarget(pInclude);
+ if (Date.DoesExist()) // Try to build the target, and add it if it exists after building
{
set< refptr<fileinfo> >::iterator pFind=Autodeps.find(pInclude);
if (pFind==Autodeps.end())
@@ -566,7 +571,8 @@ void mhmakefileparser::GetAutoDeps(const refptr<fileinfo> &FirstDep,set< refptr<
while (It<IncludeDirs->end())
{
refptr<fileinfo> pInclude=GetFileInfo(IncludeFile,*It);
- if (BuildTarget(pInclude).DoesExist()) // Try to build the target, and add it if it exists after building
+ mh_time_t Date=BuildTarget(pInclude);
+ if (Date.DoesExist()) // Try to build the target, and add it if it exists after building
{
set< refptr<fileinfo> >::iterator pFind=Autodeps.find(pInclude);
if (pFind==Autodeps.end())
@@ -587,7 +593,6 @@ void mhmakefileparser::GetAutoDeps(const refptr<fileinfo> &FirstDep,set< refptr<
Ret=fgetc(pIn);
}
fclose(pIn);
- curdir::ChangeCurDir(CurDir);
}
///////////////////////////////////////////////////////////////////////////////
@@ -615,7 +620,7 @@ void mhmakefileparser::UpdateAutomaticDependencies(const refptr<fileinfo> &Targe
Target->AddDep(*It);
It++;
}
- m_AutoDepsDirty=true;
+ SetAutoDepsDirty();
}
}
@@ -691,14 +696,14 @@ void mhmakefileparser::LoadAutoDepsFile(refptr<fileinfo> &DepFile)
ReadStr(pIn,FileName);
while (FileName[0])
{
- refptr<fileinfo> Target=GetFileInfo(FileName);
+ refptr<fileinfo> Target=GetFileInfo(FileName,m_MakeDir);
set< refptr<fileinfo> > &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<fileinfo> Dep=GetFileInfo(FileName);
+ refptr<fileinfo> Dep=GetFileInfo(FileName,m_MakeDir);
Autodeps.insert(Dep);
Target->AddDep(Dep);
}
@@ -728,7 +733,7 @@ void mhmakefileparser::LoadAutoDepsFile(refptr<fileinfo> &DepFile)
AddTarget(*pPair.first);
}
if (MakeNotDirty)
- m_AutoDepsDirty=false;
+ ClearAutoDepsDirty();
fclose(pIn);
}
@@ -748,7 +753,7 @@ static void MakeDirs(const refptr<fileinfo> & Dir)
void mhmakefileparser::SaveAutoDepsFile()
{
- if (!m_AutoDepsDirty)
+ if (!IsAutoDepsDirty())
return;
if (g_Clean
@@ -763,7 +768,7 @@ void mhmakefileparser::SaveAutoDepsFile()
{
return;
}
- refptr<fileinfo> pDepFile=GetFileInfo(DepFile);
+ refptr<fileinfo> pDepFile=GetFileInfo(DepFile,m_MakeDir);
#ifdef _DEBUG
if (g_PrintAdditionalInfo)
@@ -864,76 +869,69 @@ bool mhmakefileparser::SkipHeaderFile(const string &FileName)
}
///////////////////////////////////////////////////////////////////////////////
-// 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
+void mhmakefileparser::SetExport(const string &Var, const string &Val)
{
- if (this!=m_spCurEnv)
+ if (!m_pEnv)
{
- /* First restore the previous set environment variables */
- if (m_spCurEnv)
- m_spCurEnv->RestoreEnv();
-
- ((mhmakefileparser*)this)->SaveEnv();
- vector<string>::const_iterator It=m_Exports.begin();
- vector<string>::const_iterator ItEnd=m_Exports.end();
- while (It!=ItEnd)
+ /* Environment not created yet, so create one */
+ char *pEnv=GetEnvironmentStrings();
+ char *pEnd=pEnv;
+ while (*pEnd)
{
- putenv((char *)It->c_str());
- It++;
+ while (*pEnd++);
}
- m_spCurEnv=this;
+ int Len=pEnd-pEnv+1;
+ m_pEnv=(char*)malloc(Len);
+ memcpy(m_pEnv,pEnv,Len);
+ m_EnvLen=Len;
+ FreeEnvironmentStrings(pEnv);
}
-}
-
-///////////////////////////////////////////////////////////////////////////////
-void mhmakefileparser::SaveEnv()
-{
- vector<string>::const_iterator It=m_Exports.begin();
- vector<string>::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)
+ /* First check if the variable is in the environment, if so remove it first */
+ char *pEnv=m_pEnv;
+ while (*pEnv)
{
- 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<string,string>::const_iterator It=m_SavedExports.begin();
- map<string,string>::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++;
+ 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++);
}
- ((mhmakefileparser*)this)->m_SavedExports.clear();
- m_spCurEnv=NULL;
+ 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;
}
-
///////////////////////////////////////////////////////////////////////////////
//
//Checks if the variables retreived from the environment or command-line have been
@@ -979,8 +977,6 @@ uint32 mhmakefileparser::CreateEnvMd5_32() const
string EnvVars=ExpandVar(USED_ENVVARS);
const char *pTmp=EnvVars.c_str();
- RestoreEnv(); // Restore the environment before creating the md5, so that we have the original environment when the makefile was parsed.
-
// Now create the md5 string
md5_starts( &ctx );
@@ -1023,13 +1019,7 @@ mh_time_t mhmakefileparser::m_sBuildTime;
void mhmakefileparser::InitBuildTime()
{
-#ifdef WIN32
- FILETIME FileTime;
- GetSystemTimeAsFileTime(&FileTime);
- m_sBuildTime=g_ZeroTime.ConvertTime(&FileTime);
-#else
m_sBuildTime=time(NULL);
-#endif
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/tools/mhmake/src/mhmakefileparser.h b/tools/mhmake/src/mhmakefileparser.h
index 3afe84995..acf27987b 100644
--- a/tools/mhmake/src/mhmakefileparser.h
+++ b/tools/mhmake/src/mhmakefileparser.h
@@ -23,6 +23,7 @@
#include "fileinfo.h"
#include "util.h"
+#include "commandqueue.h"
class rule;
@@ -52,47 +53,50 @@ class mhmakefileparser : public refbase
{
private:
- mhmakelexer *m_ptheLexer;
- int m_yyloc;
- refptr<fileinfo> m_RuleThatIsBuild;
- vector<string> m_ToBeIncludeAfterBuild;
- vector<string> m_MakefilesToLoad;
- refptr<fileinfo> m_AutoDepFileLoaded;
- int m_InExpandExpression;
- mh_time_t m_Date;
- uint32 m_EnvMd5_32; /* Cached Md5_32 value of the userd environment variables */
+ static commandqueue sm_CommandQueue;
+
+ mhmakelexer *m_ptheLexer;
+ int m_yyloc;
+ refptr<fileinfo> m_RuleThatIsBuild;
+ vector<string> m_ToBeIncludeAfterBuild;
+ vector<string> m_MakefilesToLoad;
+ refptr<fileinfo> 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;
+ int m_ImplicitSearch;
#endif
- map<string,string> m_CommandCache;
+ map<string,string> m_CommandCache;
protected:
- map<string,string> m_Variables;
- map<string,string> m_CommandLineVars;
- TOKENVALUE m_theTokenValue;
- refptr<fileinfo> m_MakeDir;
- refptr<rule> m_pCurrentRule;
+ map<string,string> m_Variables;
+ map<string,string> m_CommandLineVars;
+ TOKENVALUE m_theTokenValue;
+ refptr<fileinfo> m_MakeDir;
+ refptr<rule> m_pCurrentRule;
refptr<fileinfoarray> m_pCurrentItems;
refptr<fileinfoarray> m_pCurrentDeps;
- refptr<fileinfo> m_FirstTarget;
- fileinfoarray m_IncludedMakefiles;
- refptr< fileinfoarray > m_pIncludeDirs;
- string m_IncludeDirs;
+ refptr<fileinfo> m_FirstTarget;
+ fileinfoarray m_IncludedMakefiles;
+ refptr<fileinfoarray> m_pIncludeDirs;
+ string m_IncludeDirs;
+
+ bool m_DoubleColonRule;
+ bool m_AutoDepsDirty;
+ bool m_ForceAutoDepRescan;
+ set<string> m_SkipHeaders; // Headers to skip
+ vector<string> 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 */
+
+ set<string> m_UsedEnvVars; // Array containing a list of variables that are taken from the environment (This is used for rebuild checking)
+ char *m_pEnv; // New environment in case the makefile exports variables
+ int m_EnvLen; // Current length of m_pEnv
+
map< refptr<fileinfo>, set< refptr<fileinfo> > > 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<string> m_SkipHeaders; // Headers to skip
- vector<string> 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<string> m_Exports; // Array of variables to export.
- map<string,string> m_SavedExports; // Original values of the environment are saved here.
- set<string> 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;
@@ -109,8 +113,9 @@ public:
,m_SkipHeadersInitialized(false)
,m_RebuildAll(false)
,m_EnvMd5_32(0)
+ ,m_pEnv(NULL)
#ifdef _DEBUG
- ,m_ImplicitSearch(false)
+ ,m_ImplicitSearch(0)
#endif
{
if (!m_FunctionsInitialised) InitFuncs();
@@ -119,19 +124,49 @@ public:
SetVariable(EXEEXTVAR,EXEEXT);
}
+ /* Needed if you only want to use the searchcommand and execommand functions */
+ mhmakefileparser(const refptr<fileinfo> &pMakeDir) : m_MakeDir(pMakeDir), m_pEnv(NULL)
+ {}
+
+ static void SetNrParallelBuilds(int NrParallelBuilds)
+ {
+ sm_CommandQueue.SetNrParallelBuilds(NrParallelBuilds);
+ }
+
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 SetExport(const string & Var, const string & Val);
+
void CheckEnv(void);
+ #ifdef _DEBUG
+ int ImplicitSearch() const
+ {
+ return m_ImplicitSearch;
+ }
+ #endif
+
+ void SetAutoDepsDirty()
+ {
+ m_AutoDepsDirty=true;
+ }
+
+ void ClearAutoDepsDirty()
+ {
+ m_AutoDepsDirty=false;
+ }
+ bool IsAutoDepsDirty() const
+ {
+ return m_AutoDepsDirty;
+ }
+
void SetRebuildAll()
{
m_RebuildAll=true;
- m_AutoDepsDirty=true; /* This is to be sure that all new calculated md5 strings are saved. */
+ SetAutoDepsDirty(); /* This is to be sure that all new calculated md5 strings are saved. */
}
void SetVariable(string Var,string Val)
@@ -141,7 +176,7 @@ public:
void EnableAutoDepRescan(void)
{
m_ForceAutoDepRescan=true;
- m_AutoDepsDirty=true;
+ SetAutoDepsDirty();
}
bool ForceAutoDepRescan(void)
{
@@ -166,12 +201,16 @@ public:
virtual ~mhmakefileparser()
{
SaveAutoDepsFile();
+ free(m_pEnv);
}
virtual int yylex(void);
virtual void yyerror(const char *m);
- virtual int yyparse()=0;
+ virtual int yyparse()
+ {
+ throw("Please derive if you want to execute yyparse.");
+ }
- int ParseFile(const refptr<fileinfo> &FileInfo,bool SetMakeDir=false);
+ int ParseFile(const refptr<fileinfo> &FileInfo,refptr<fileinfo> &pMakeDir=NullFileInfo);
/* Functions to handle variables */
bool IsDefined(const string &Var) const;
@@ -239,7 +278,23 @@ public:
{
m_Targets.insert(pTarget);
}
- mh_time_t BuildTarget(const refptr<fileinfo> &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 */
+ /* Starts building the target,
+ returns 0 when target build is not finished,
+ returns the date of the target when target is build, especially important for phony rules, since this will be the youngest date of all dependencies */
+ mh_time_t StartBuildTarget(const refptr<fileinfo> &Target, bool bCheckTargetDir=true);
+ /* Waits for the target being build, returns the date of the target. Not needed to be cald when StartBuildTarget returned a value different from zero */
+ mh_time_t WaitBuildTarget(const refptr<fileinfo> &Target);
+
+ /* Use the following command when you want to wait for the target is built */
+ mh_time_t BuildTarget(const refptr<fileinfo> &Target, bool bCheckTargetDir=true)
+ {
+ mh_time_t TargetDate=StartBuildTarget(Target,bCheckTargetDir);
+ if (!TargetDate.IsDateValid())
+ return WaitBuildTarget(Target);
+ else
+ return TargetDate;
+ }
+
void BuildDependencies(const refptr<rule> &pRule, const refptr<fileinfo> &Target, mh_time_t TargetDate, mh_time_t &YoungestDate, bool &MakeTarget);
void BuildIncludedMakefiles();
@@ -270,14 +325,28 @@ public:
}
void AddRule();
- bool ExecuteCommand(string Command,string *pOutput=NULL);
+ HANDLE ExecuteCommand(string Command, bool &IgnoreError, string *pOutput=NULL);
+ HANDLE ExecuteCommand(string Command, string *pOutput=NULL)
+ {
+ bool IgnoreError;
+ return ExecuteCommand(Command, IgnoreError, pOutput);
+ }
string GetFullCommand(string Command);
void CreatePythonExe(const string &FullCommand);
static void InitBuildTime();
+
+ void SplitToItems(const string &String, vector< refptr<fileinfo> > &Items) const;
+ HANDLE DeleteFiles(const string &Params) const;
+ HANDLE CopyFiles(const string &Params) const;
+ HANDLE TouchFiles(const string &Params) const;
+ HANDLE EchoCommand(const string &Params) const;
+ string SearchCommand(const string &Command, const string &Extension="") const;
+ const string &GetPythonExe() const;
+ int SearchPath(void *NotUsed, const char *szCommand, const char *pExt, int Len, char *szFullCommand,char **pFilePart) const;
+ HANDLE OsExeCommand(const string &Command, const string &Params, bool IgnoreError, string *pOutput) const;
};
-void SplitToItems(const string &String,vector< refptr<fileinfo> > &Items,refptr<fileinfo> Dir=curdir::GetCurDir());
#endif
diff --git a/tools/mhmake/src/mhmakeparser.y b/tools/mhmake/src/mhmakeparser.y
index 68b0a489e..336ddb6dc 100644
--- a/tools/mhmake/src/mhmakeparser.y
+++ b/tools/mhmake/src/mhmakeparser.y
@@ -114,8 +114,8 @@ ruledef: expression_nocolorequal rulecolon maybeemptyexpression
throw string("Empty left hand side in rule: ") + $1 + " : " + $3;
}
#endif
- SplitToItems(ExpandExpression($1),*m_pCurrentItems,m_MakeDir);
- SplitToItems(ExpandExpression($3),*m_pCurrentDeps,m_MakeDir);
+ SplitToItems(ExpandExpression($1),*m_pCurrentItems);
+ SplitToItems(ExpandExpression($3),*m_pCurrentDeps);
m_DoubleColonRule= ($2==1) ;
PRINTF(("Defining rule %s : %s\n",$1.c_str(),$3.c_str()));
PRINTF((" Expanded to %s : %s\n",ExpandExpression($1).c_str(),ExpandExpression($3).c_str()));
@@ -129,7 +129,7 @@ rulecolon: COLON {$$=0;} |
phonyrule: PHONY COLON expression
{
vector< refptr<fileinfo> > Items;
- SplitToItems(ExpandExpression($3),Items,m_MakeDir);
+ SplitToItems(ExpandExpression($3),Items);
vector< refptr<fileinfo> >::iterator pIt=Items.begin();
while (pIt!=Items.end())
{
@@ -151,7 +151,7 @@ exportstrings : exportstring |
exportstring : STRING
{
- m_Exports.push_back($1+"="+ExpandExpression(ExpandVar($1)));
+ SetExport($1,ExpandExpression(ExpandVar($1)));
PRINTF(("Exporting %s : %s\n",$1.c_str(),ExpandExpression(ExpandVar($1)).c_str()));
}
;
diff --git a/tools/mhmake/src/rule.cpp b/tools/mhmake/src/rule.cpp
index 90fee8a91..f9485b560 100644
--- a/tools/mhmake/src/rule.cpp
+++ b/tools/mhmake/src/rule.cpp
@@ -151,7 +151,7 @@ void IMPLICITRULE::SearchImplicitRule(const refptr<fileinfo> &Target,vector< pai
if (!ResIt->first.empty())
{
string Dependent=ReplaceWithStem(ResIt->first,Res.m_Stem);
- Result.push_back(pair<refptr<fileinfo>,refptr<rule> >(GetFileInfo(Dependent),ResIt->second));
+ Result.push_back(pair<refptr<fileinfo>,refptr<rule> >(GetFileInfo(Dependent,ResIt->second->GetMakefile()->GetMakeDir()),ResIt->second));
}
else
Result.push_back(pair<refptr<fileinfo>,refptr<rule> >(NullFileInfo,ResIt->second));
diff --git a/tools/mhmake/src/stdafx.h b/tools/mhmake/src/stdafx.h
index bc686e03e..b8eca6204 100644
--- a/tools/mhmake/src/stdafx.h
+++ b/tools/mhmake/src/stdafx.h
@@ -38,6 +38,7 @@
#include <iostream>
#include <string>
#include <vector>
+#include <queue>
#include <map>
#include <set>
#include <stack>
diff --git a/tools/mhmake/src/util.cpp b/tools/mhmake/src/util.cpp
index a6ce9e8bf..9d8b9510e 100644
--- a/tools/mhmake/src/util.cpp
+++ b/tools/mhmake/src/util.cpp
@@ -19,15 +19,30 @@
/* $Rev$ */
#include "stdafx.h"
+#include <WinIoCtl.h>
#include "rule.h"
#include "util.h"
#include "mhmakeparser.h"
+#ifdef WIN32
+#define REPARSE_MOUNTPOINT_HEADER_SIZE 8
+
+typedef struct {
+ DWORD ReparseTag;
+ DWORD ReparseDataLength;
+ WORD Reserved;
+ WORD ReparseTargetLength;
+ WORD ReparseTargetMaximumLength;
+ WORD Reserved1;
+ WCHAR ReparseTarget[1];
+} REPARSE_MOUNTPOINT_DATA_BUFFER, *PREPARSE_MOUNTPOINT_DATA_BUFFER;
+#endif
+
static char s_UsageString[]=
"\
Usage: mhmake [-f <Makefile>] [-[c|C] <RunDir>] [<Var>=<Value>]\n\
- [-a] [-q] [-s] [-v] [targets]+\n"
+ [-a] [-q] [-s] [-v] [-P <Nr Parallel Builds>] [targets]+\n"
#ifdef _DEBUG
"\
[-p] [-n] [-e] [-l] [-w] [-d] [-CD] [-m] [-b]\n"
@@ -41,7 +56,11 @@ Usage: mhmake [-f <Makefile>] [-[c|C] <RunDir>] [<Var>=<Value>]\n\
-a : Rebuild all targets\n\
-s : Rescan automatic dependencies\n\
-v : Print version information\n\
- -q : Quiet. Disable all output \n"
+ -q : Quiet. Disable all output \n\
+ -P <Nr Parallel Builds> :\n\
+ Number of parallel build commands executed at the \n\
+ same time. Default is this the number of processor \n\
+ cores. 1 disables parallel builds.\n"
#ifdef _DEBUG
"\n\
The following options are additional options in mhmake_dbg which are not\n\
@@ -255,8 +274,6 @@ refptr<loadedmakefile> LOADEDMAKEFILES::find(const loadedmakefile &ToSearch)
LOADEDMAKEFILES g_LoadedMakefiles;
-bool OsExeCommand(const string &Command,const string &Params,bool IgnoreError,string *pOutput);
-
///////////////////////////////////////////////////////////////////////////////
loadedmakefile::loadedmakefile_statics::loadedmakefile_statics()
{
@@ -266,18 +283,50 @@ loadedmakefile::loadedmakefile_statics::loadedmakefile_statics()
{
string Env(QuoteFileName(pEnv));
m_GlobalCommandLineVars[MHMAKECONF]=Env;
- m_MhMakeConf=GetFileInfo(Env);
+ m_MhMakeConf=GetAbsFileInfo(Env);
// Get the revision of the working copy
// We do it with the svn info command
string Output;
- bool Ret;
try
{
- string SvnCommand=SearchCommand("svn",EXEEXT);
+ mhmakefileparser Dummy(curdir::GetCurDir());
+ string SvnCommand=Dummy.SearchCommand("svn",EXEEXT);
#ifdef WIN32
- Ret=OsExeCommand(SvnCommand,string(" info ")+m_MhMakeConf->GetQuotedFullFileName(),false,&Output);
+ if (GetFileAttributes(m_MhMakeConf->GetFullFileName().c_str())&FILE_ATTRIBUTE_REPARSE_POINT)
+ {
+ WIN32_FIND_DATA FindData;
+ HANDLE hFind=FindFirstFile(m_MhMakeConf->GetFullFileName().c_str(),&FindData);
+ if (hFind!=INVALID_HANDLE_VALUE)
+ {
+ if (FindData.dwReserved0==IO_REPARSE_TAG_MOUNT_POINT)
+ {
+ HANDLE hDir = ::CreateFile(m_MhMakeConf->GetFullFileName().c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ BYTE buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; // We need a large buffer
+ REPARSE_MOUNTPOINT_DATA_BUFFER& ReparseBuffer = (REPARSE_MOUNTPOINT_DATA_BUFFER&)buf;
+ DWORD dwRet;
+
+ if (::DeviceIoControl(hDir, FSCTL_GET_REPARSE_POINT, NULL, 0, &ReparseBuffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dwRet, NULL))
+ {
+ // Success
+ ::CloseHandle(hDir);
+
+ LPCWSTR pPath = ReparseBuffer.ReparseTarget;
+ if (wcsncmp(pPath, L"\\??\\", 4) == 0) pPath += 4; // Skip 'non-parsed' prefix
+ char szPath[MAX_PATH];
+ ::WideCharToMultiByte(CP_ACP, 0, pPath, -1, szPath, MAX_PATH, NULL, NULL);
+ Dummy.OsExeCommand(SvnCommand,string(" info ")+GetFileInfo(szPath,m_MhMakeConf->GetDir())->GetQuotedFullFileName(),false,&Output);
+ }
+ else
+ { // Error
+ ::CloseHandle(hDir);
+ }
+ }
+ FindClose(hFind);
+ }
+ }
#else
struct stat Stat;
lstat(m_MhMakeConf->GetFullFileName().c_str(),&Stat);
@@ -286,15 +335,14 @@ loadedmakefile::loadedmakefile_statics::loadedmakefile_statics()
char FileName[1024];
int len=readlink(m_MhMakeConf->GetFullFileName().c_str(),FileName,sizeof(FileName));
FileName[len]=0;
- Ret=OsExeCommand(SvnCommand,string(" info ")+GetFileInfo(FileName,m_MhMakeConf->GetDir())->GetQuotedFullFileName(),false,&Output);
+ Dummy.OsExeCommand(SvnCommand,string(" info ")+GetFileInfo(FileName,m_MhMakeConf->GetDir())->GetQuotedFullFileName(),false,&Output);
}
- else
- Ret=OsExeCommand(SvnCommand,string(" info ")+m_MhMakeConf->GetQuotedFullFileName(),false,&Output);
#endif
+ else
+ Dummy.OsExeCommand(SvnCommand,string(" info ")+m_MhMakeConf->GetQuotedFullFileName(),false,&Output);
}
catch (string Message)
{
- Ret=false;
}
char *pTok=strtok((char*)Output.c_str(),"\n"); // doing this is changing string, so this is very dangerous !!!
@@ -315,7 +363,7 @@ loadedmakefile::loadedmakefile_statics::loadedmakefile_statics()
}
///////////////////////////////////////////////////////////////////////////////
-loadedmakefile::loadedmakefile(vector<string> &Args,const string&Makefile)
+loadedmakefile::loadedmakefile(const refptr<fileinfo> &pDir, vector<string> &Args,const string&Makefile)
{
m_CommandLineVars=sm_Statics.m_GlobalCommandLineVars;
@@ -339,7 +387,7 @@ loadedmakefile::loadedmakefile(vector<string> &Args,const string&Makefile)
{
if (!m_MakeDir)
{
- m_Makefile=GetFileInfo(ArgIt->substr(2));
+ m_Makefile=GetFileInfo(ArgIt->substr(2),pDir);
}
else
{
@@ -351,7 +399,7 @@ loadedmakefile::loadedmakefile(vector<string> &Args,const string&Makefile)
ArgIt++;
if (!m_MakeDir)
{
- m_Makefile=GetFileInfo(*ArgIt);
+ m_Makefile=GetFileInfo(*ArgIt,pDir);
}
else
{
@@ -370,11 +418,11 @@ loadedmakefile::loadedmakefile(vector<string> &Args,const string&Makefile)
/* Fall through */
case 'c':
if (ArgIt->size()>2)
- m_MakeDir=GetFileInfo(ArgIt->substr(2));
+ m_MakeDir=GetFileInfo(ArgIt->substr(2),pDir);
else
{
ArgIt++;
- m_MakeDir=GetFileInfo(*ArgIt);
+ m_MakeDir=GetFileInfo(*ArgIt,pDir);
}
break;
case 'a':
@@ -389,6 +437,15 @@ loadedmakefile::loadedmakefile(vector<string> &Args,const string&Makefile)
case 'v':
PrintVersionInfo();
break;
+ case 'P':
+ if (ArgIt->size()>2)
+ mhmakefileparser::SetNrParallelBuilds(atoi(ArgIt->substr(2).c_str()));
+ else
+ {
+ ArgIt++;
+ mhmakefileparser::SetNrParallelBuilds(atoi((*ArgIt).c_str()));
+ }
+ break;
#ifdef _DEBUG
case 'p':
g_PrintVarsAndRules=true;
@@ -433,7 +490,7 @@ loadedmakefile::loadedmakefile(vector<string> &Args,const string&Makefile)
if (!Makefile.empty())
{
if (!m_MakeDir)
- m_Makefile=GetFileInfo(Makefile);
+ m_Makefile=GetFileInfo(Makefile,pDir);
else
m_Makefile=GetFileInfo(Makefile,m_MakeDir);
}
@@ -441,7 +498,7 @@ loadedmakefile::loadedmakefile(vector<string> &Args,const string&Makefile)
if (!m_Makefile)
{
if (!m_MakeDir)
- m_Makefile=GetFileInfo(m_CommandLineTargets[0]);
+ m_Makefile=GetFileInfo(m_CommandLineTargets[0],pDir);
else
m_Makefile=GetFileInfo(m_CommandLineTargets[0],m_MakeDir);
@@ -470,10 +527,6 @@ loadedmakefile::loadedmakefile(vector<string> &Args,const string&Makefile)
///////////////////////////////////////////////////////////////////////////////
void loadedmakefile::LoadMakefile()
{
- refptr<fileinfo> CurDir=curdir::GetCurDir();
-
- curdir::ChangeCurDir(m_MakeDir);
-
#ifdef _DEBUG
if (g_PrintAdditionalInfo)
cout << "Loading makefile "<<m_Makefile->GetQuotedFullFileName()<<endl;
@@ -510,7 +563,7 @@ void loadedmakefile::LoadMakefile()
}
refptr<fileinfo> BeforeMakefile=GetFileInfo(BaseAutoMak+".before",sm_Statics.m_MhMakeConf);
- int result=m_pParser->ParseFile(BeforeMakefile,true);
+ int result=m_pParser->ParseFile(BeforeMakefile,m_MakeDir);
if (result)
{
throw string("Error parsing ")+BeforeMakefile->GetQuotedFullFileName();
@@ -523,7 +576,7 @@ void loadedmakefile::LoadMakefile()
{
throw string("When making use of MHMAKECONF, you have to define OBJDIR in makefile.before");
}
- DepFile=GetFileInfo(ObjDirName+OSPATHSEPSTR "." + m_Makefile->GetName()+ ".dep");
+ DepFile=GetFileInfo(ObjDirName+OSPATHSEPSTR "." + m_Makefile->GetName()+ ".dep",m_MakeDir);
m_pParser->SetVariable(AUTODEPFILE,DepFile->GetQuotedFullFileName());
}
else
@@ -545,7 +598,7 @@ void loadedmakefile::LoadMakefile()
char ID[10];
sprintf(ID,"_%x",md5_finish32( &ctx));
- DepFile=GetFileInfo(string(".") + m_Makefile->GetName()+ ".dep"+ID);
+ DepFile=GetFileInfo(string(".") + m_Makefile->GetName()+ ".dep"+ID,m_MakeDir);
m_pParser->SetVariable(AUTODEPFILE,DepFile->GetQuotedFullFileName());
}
@@ -553,7 +606,7 @@ void loadedmakefile::LoadMakefile()
m_pParser->LoadAutoDepsFile(DepFile); /* Already load this autodep file before parsing of the makefile to avoid needless rebuilds. */
//m_pParser->yydebug=1;
- int result=m_pParser->ParseFile(m_Makefile,true);
+ int result=m_pParser->ParseFile(m_Makefile,m_MakeDir);
if (result)
{
throw string("Error parsing ")+m_Makefile->GetQuotedFullFileName();
@@ -608,7 +661,7 @@ void loadedmakefile::LoadMakefile()
Args.push_back(Item);
}
- refptr<loadedmakefile> pLoadedMakefile(new loadedmakefile(Args));
+ refptr<loadedmakefile> pLoadedMakefile(new loadedmakefile(m_MakeDir,Args));
refptr<loadedmakefile> Found=g_LoadedMakefiles.find(*pLoadedMakefile);
if (Found)
{
@@ -627,8 +680,6 @@ void loadedmakefile::LoadMakefile()
}
It++;
}
- curdir::ChangeCurDir(CurDir);
-
}
#ifdef _DEBUG
diff --git a/tools/mhmake/src/util.h b/tools/mhmake/src/util.h
index 4c5528452..457823abb 100644
--- a/tools/mhmake/src/util.h
+++ b/tools/mhmake/src/util.h
@@ -50,9 +50,7 @@
#define PLATFORM "linux"
#endif
-#define MHMAKEVER "1.4.13"
-
-string SearchCommand(const string &Command, const string &Extension="");
+#define MHMAKEVER "2.0.0_rc"
class makecommand
{
@@ -173,7 +171,7 @@ struct loadedmakefile : public refbase
vector<string> m_CommandLineTargets;
refptr<mhmakeparser> m_pParser;
- loadedmakefile(vector<string> &Args,const string &Makefile=g_EmptyString);
+ loadedmakefile(const refptr<fileinfo> &pDir, vector<string> &Args,const string &Makefile=g_EmptyString);
void LoadMakefile();
void AddCommandLineVarsToEnvironment()