/* This file is part of mhmake.
*
* Copyright (C) 2001-2009 Marc Haesen
*
* Mhmake is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mhmake is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mhmake. If not, see .
*/
/* $Rev$ */
#include "stdafx.h"
#include "fileinfo.h"
#include "rule.h"
#include "util.h"
#include "mhmakeparser.h"
refptr NullRule;
map< string, vector > > > IMPLICITRULE::m_ImplicitRules;
makecommand g_MakeCommand; // Order is important since sm_Statics is using g_MakeCommand
const string g_QuoteString("\""); // Order is important since sm_Statics is using g_QuoteString
loadedmakefile::loadedmakefile_statics loadedmakefile::sm_Statics;
///////////////////////////////////////////////////////////////////////////////
static bool FindDep(const string &DepName,vector > >&ImplicitRule,refptr &Rule)
{
vector > >::iterator SecIt=ImplicitRule.begin();
while (SecIt!=ImplicitRule.end())
{
if (SecIt->first==DepName)
{
#ifdef _DEBUG
// Check if the rule has the same commands
vector &OldCommands=SecIt->second->GetCommands();
vector &NewCommands=Rule->GetCommands();
bool bCommandsDifferent=OldCommands.size()!=NewCommands.size();
if (g_PrintMultipleDefinedRules || bCommandsDifferent)
{
string ErrorMessage;
if (bCommandsDifferent)
ErrorMessage += "Implicit Rule '"+ DepName + "' defined twice with different commands\n";
else
ErrorMessage += "Implicit Rule '"+ DepName + "' defined twice with same commands\n";
ErrorMessage += "Command 1: makedir = " + SecIt->second->GetMakefile()->GetMakeDir()->GetQuotedFullFileName()+ "\n";
vector::const_iterator It;
if (bCommandsDifferent)
{
It=OldCommands.begin();
while (It!=OldCommands.end())
{
ErrorMessage += " " + *It + "\n";
}
}
cerr << "Command 2: makedir = "+ Rule->GetMakefile()->GetMakeDir()->GetQuotedFullFileName()+ "\n";
if (bCommandsDifferent)
{
It=NewCommands.begin();
while (It!=NewCommands.end())
{
ErrorMessage += " " + *It + "\n";
}
throw ErrorMessage;
}
else
cerr << ErrorMessage << endl;
}
mhmakeparser *pOldMakefile=SecIt->second->GetMakefile();
mhmakeparser *pNewMakefile=Rule->GetMakefile();
vector::iterator OldIt=OldCommands.begin();
vector::iterator NewIt=NewCommands.begin();
while (OldIt!=OldCommands.end())
{
if (pOldMakefile->ExpandExpression(*OldIt)!=pNewMakefile->ExpandExpression(*NewIt))
{
string ErrorMessage = string("Implicit Rule '") + DepName + "' defined twice with different commands\n";
ErrorMessage += "Command 1: makedir = " + pOldMakefile->GetMakeDir()->GetQuotedFullFileName()+ "\n";
ErrorMessage += " " + pOldMakefile->ExpandExpression(*OldIt) + "\n";
ErrorMessage += "Command 2: makedir = " + pNewMakefile->GetMakeDir()->GetQuotedFullFileName()+ "\n";
ErrorMessage += " " + pNewMakefile->ExpandExpression(*NewIt);
throw ErrorMessage;
}
OldIt++;
NewIt++;
}
#endif
return true;
}
SecIt++;
}
return false;
}
///////////////////////////////////////////////////////////////////////////////
void IMPLICITRULE::AddImplicitRule(const refptr &Target,const vector< refptr > &Deps,refptr Rule)
{
vector > >& ImplicitRule=m_ImplicitRules[Target->GetFullFileName()];
if (Deps.size())
{
vector< refptr >::const_iterator DepIt=Deps.begin();
while (DepIt!=Deps.end())
{
const string &DepName=(*DepIt)->GetFullFileName();
if (!FindDep(DepName,ImplicitRule,Rule))
ImplicitRule.push_back(pair >(DepName,Rule));
DepIt++;
}
}
else
{
if (!FindDep(g_EmptyString,ImplicitRule,Rule))
ImplicitRule.push_back(pair >(g_EmptyString,Rule));
}
}
///////////////////////////////////////////////////////////////////////////////
void IMPLICITRULE::SearchImplicitRule(const refptr &Target,vector< pair,refptr > >&Result)
{
string TargetFileName=Target->GetFullFileName();
map< string, vector > > >::iterator ImpRegExIt=m_ImplicitRules.begin();
while (ImpRegExIt!=m_ImplicitRules.end())
{
matchres Res;
if (PercentMatch(TargetFileName,ImpRegExIt->first,&Res))
{
vector > >::iterator ResIt=ImpRegExIt->second.begin();
while (ResIt!=ImpRegExIt->second.end())
{
#ifdef _DEBUG
if (!ResIt->second)
{
throw string("No rhs for implicit rule : ") + ImpRegExIt->first;
}
#endif
ResIt->second->SetStem(Res.m_Stem);
if (!ResIt->first.empty())
{
string Dependent=ReplaceWithStem(ResIt->first,Res.m_Stem);
Result.push_back(pair,refptr >(GetFileInfo(Dependent,ResIt->second->GetMakefile()->GetMakeDir()),ResIt->second));
}
else
Result.push_back(pair,refptr >(NullFileInfo,ResIt->second));
ResIt++;
}
}
ImpRegExIt++;
}
return;
}
///////////////////////////////////////////////////////////////////////////////
bool rule::operator != (const rule &Other)
{
if (m_Commands.size()!=Other.m_Commands.size())
return true;
vector::const_iterator It=m_Commands.begin();
vector::const_iterator OtherIt=Other.m_Commands.begin();
while (It!=m_Commands.end())
{
if (m_pMakefile->ExpandExpression(*It)!=Other.m_pMakefile->ExpandExpression(*OtherIt))
return true;
It++;
OtherIt++;
}
return false;
}
///////////////////////////////////////////////////////////////////////////////
void rule::SetTargetsIsBuild(uint32 Md5_32)
{
vector< fileinfo* >::iterator It=m_Targets.begin();
while (It!=m_Targets.end())
{
(*It)->SetCommandsMd5_32(Md5_32);
(*It)->SetBuild();
m_pMakefile->AddTarget(*It);
It++;
}
}
#ifdef _DEBUG
///////////////////////////////////////////////////////////////////////////////
void IMPLICITRULE::PrintImplicitRules()
{
map< string, vector > > >::iterator ImpRegExIt=m_ImplicitRules.begin();
while (ImpRegExIt!=m_ImplicitRules.end())
{
vector > >::iterator SecIt=ImpRegExIt->second.begin();
cout << ImpRegExIt->first << " :\n";
while (SecIt!=ImpRegExIt->second.end())
{
cout << " : " << SecIt->first <second)
{
SecIt->second->PrintCommands();
}
else
{
cout << " No rhs\n";
}
SecIt++;
}
ImpRegExIt++;
}
return;
}
///////////////////////////////////////////////////////////////////////////////
void rule::PrintCommands(refptr Target) const
{
if (Target)
m_pMakefile->SetRuleThatIsBuild(Target);
vector::const_iterator pCommandIt=m_Commands.begin();
while (pCommandIt!=m_Commands.end())
{
cout<ExpandExpression(*pCommandIt)<<")\n";
}
pCommandIt++;
}
}
#endif