summaryrefslogtreecommitdiffstats
path: root/Source/cmMacroCommand.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmMacroCommand.cxx')
-rw-r--r--Source/cmMacroCommand.cxx403
1 files changed, 238 insertions, 165 deletions
diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx
index 9db5f16..daf3989 100644
--- a/Source/cmMacroCommand.cxx
+++ b/Source/cmMacroCommand.cxx
@@ -16,214 +16,287 @@
=========================================================================*/
#include "cmMacroCommand.h"
-bool cmMacroFunctionBlocker::
-IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf)
+// define the class for macro commands
+class cmMacroHelperCommand : public cmCommand
{
- // record commands until we hit the ENDMACRO
- if (!m_Executing)
+public:
+ cmMacroHelperCommand() {}
+
+ ///! clean up any memory allocated by the macro
+ ~cmMacroHelperCommand() {};
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ virtual cmCommand* Clone()
+ {
+ cmMacroHelperCommand *newC = new cmMacroHelperCommand;
+ // we must copy when we clone
+ newC->m_Args = this->m_Args;
+ newC->m_Functions = this->m_Functions;
+ return newC;
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ virtual bool InvokeInitialPass(const std::vector<cmListFileArgument>& args);
+
+ virtual bool InitialPass(std::vector<std::string> const& args)
+ { return false; };
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ virtual const char* GetName() { return this->m_Args[0].c_str(); }
+
+ /**
+ * Succinct documentation.
+ */
+ virtual const char* GetTerseDocumentation()
+ {
+ std::string docs = "Macro named: ";
+ docs += this->GetName();
+ return docs.c_str();
+ }
+
+ /**
+ * More documentation.
+ */
+ virtual const char* GetFullDocumentation()
+ {
+ return this->GetTerseDocumentation();
+ }
+
+ cmTypeMacro(cmMacroHelperCommand, cmCommand);
+
+ std::vector<std::string> m_Args;
+ std::vector<cmListFileFunction> m_Functions;
+};
+
+
+bool cmMacroHelperCommand::InvokeInitialPass
+(const std::vector<cmListFileArgument>& args)
+{
+ // Expand the argument list to the macro.
+ std::vector<std::string> expandedArgs;
+ m_Makefile->ExpandArguments(args, expandedArgs);
+
+ std::string tmps;
+ cmListFileArgument arg;
+ std::string variable;
+
+ // make sure the number of arguments passed is at least the number
+ // required by the signature
+ if (expandedArgs.size() < m_Args.size() - 1)
{
- // at the ENDMACRO call we shift gears and start looking for invocations
- if(lff.m_Name == "ENDMACRO")
- {
- std::vector<std::string> expandedArguments;
- mf.ExpandArguments(lff.m_Arguments, expandedArguments);
- if(!expandedArguments.empty() && (expandedArguments[0] == m_Args[0]))
- {
- m_Executing = true;
- std::string name = m_Args[0];
- std::vector<std::string>::size_type cc;
- name += "(";
- for ( cc = 0; cc < m_Args.size(); cc ++ )
- {
- name += " " + m_Args[cc];
- }
- name += " )";
- mf.AddMacro(m_Args[0].c_str(), name.c_str());
- return true;
- }
- }
- // if it wasn't an endmacro and we are not executing then we must be
- // recording
- m_Functions.push_back(lff);
- return true;
+ std::string errorMsg =
+ "Macro invoked with incorrect arguments for macro named: ";
+ errorMsg += m_Args[0];
+ this->SetError(errorMsg.c_str());
+ return false;
}
- // otherwise the macro has been recorded and we are executing
- // so we look for macro invocations
- if(lff.m_Name == m_Args[0])
+ // set the value of argc
+ cmOStringStream argcDefStream;
+ argcDefStream << expandedArgs.size();
+ std::string argcDef = argcDefStream.str();
+
+ // declare varuiables for ARGV ARGN but do not compute until needed
+ std::string argvDef;
+ std::string argnDef;
+ bool argnDefInitialized = false;
+ bool argvDefInitialized = false;
+
+ // Invoke all the functions that were collected in the block.
+ cmListFileFunction newLFF;
+ // for each function
+ for(unsigned int c = 0; c < m_Functions.size(); ++c)
{
- std::string tmps;
- cmListFileArgument arg;
- std::string variable;
- // Expand the argument list to the macro.
- std::vector<std::string> expandedArguments;
- mf.ExpandArguments(lff.m_Arguments, expandedArguments);
-
- // make sure the number of arguments passed is at least the number
- // required by the signature
- if (expandedArguments.size() < m_Args.size() - 1)
+ // Replace the formal arguments and then invoke the command.
+ newLFF.m_Arguments.clear();
+ newLFF.m_Arguments.reserve(m_Functions[c].m_Arguments.size());
+ newLFF.m_Name = m_Functions[c].m_Name;
+ newLFF.m_FilePath = m_Functions[c].m_FilePath;
+ newLFF.m_Line = m_Functions[c].m_Line;
+ // for each argument of the current function
+ for (std::vector<cmListFileArgument>::const_iterator k =
+ m_Functions[c].m_Arguments.begin();
+ k != m_Functions[c].m_Arguments.end(); ++k)
{
- cmOStringStream error;
- error << "Error in cmake code at\n"
- << lff.m_FilePath << ":" << lff.m_Line << ":\n"
- << "Invocation of macro \""
- << lff.m_Name.c_str() << "\" with incorrect number of arguments.";
- cmSystemTools::Error(error.str().c_str());
- return true;
- }
-
- // set the value of argc
- cmOStringStream argcDefStream;
- argcDefStream << expandedArguments.size();
- std::string argcDef = argcDefStream.str();
-
- // declare varuiables for ARGV ARGN but do not compute until needed
- std::string argvDef;
- std::string argnDef;
- bool argnDefInitialized = false;
- bool argvDefInitialized = false;
-
- // Invoke all the functions that were collected in the block.
- cmListFileFunction newLFF;
- // for each function
- for(unsigned int c = 0; c < m_Functions.size(); ++c)
- {
- // Replace the formal arguments and then invoke the command.
- newLFF.m_Arguments.clear();
- newLFF.m_Arguments.reserve(m_Functions[c].m_Arguments.size());
- newLFF.m_Name = m_Functions[c].m_Name;
- newLFF.m_FilePath = m_Functions[c].m_FilePath;
- newLFF.m_Line = m_Functions[c].m_Line;
- // for each argument of the current function
- for (std::vector<cmListFileArgument>::const_iterator k =
- m_Functions[c].m_Arguments.begin();
- k != m_Functions[c].m_Arguments.end(); ++k)
+ tmps = k->Value;
+ // replace formal arguments
+ for (unsigned int j = 1; j < m_Args.size(); ++j)
{
- tmps = k->Value;
- // replace formal arguments
- for (unsigned int j = 1; j < m_Args.size(); ++j)
- {
- variable = "${";
- variable += m_Args[j];
- variable += "}";
- cmSystemTools::ReplaceString(tmps, variable.c_str(),
- expandedArguments[j-1].c_str());
- }
- // replace argc
- cmSystemTools::ReplaceString(tmps, "${ARGC}",argcDef.c_str());
-
- // repleace ARGN
- if (tmps.find("${ARGN}") != std::string::npos)
+ variable = "${";
+ variable += m_Args[j];
+ variable += "}";
+ cmSystemTools::ReplaceString(tmps, variable.c_str(),
+ expandedArgs[j-1].c_str());
+ }
+ // replace argc
+ cmSystemTools::ReplaceString(tmps, "${ARGC}",argcDef.c_str());
+
+ // repleace ARGN
+ if (tmps.find("${ARGN}") != std::string::npos)
+ {
+ if (!argnDefInitialized)
{
- if (!argnDefInitialized)
+ std::vector<std::string>::const_iterator eit;
+ std::vector<std::string>::size_type cnt = 0;
+ for ( eit = expandedArgs.begin(); eit != expandedArgs.end(); ++eit )
{
- std::vector<std::string>::iterator eit;
- std::vector<std::string>::size_type cnt = 0;
- for ( eit = expandedArguments.begin();
- eit != expandedArguments.end();
- ++ eit )
+ if ( cnt >= m_Args.size()-1 )
{
- if ( cnt >= m_Args.size()-1 )
+ if ( argnDef.size() > 0 )
{
- if ( argnDef.size() > 0 )
- {
- argnDef += ";";
- }
- argnDef += *eit;
+ argnDef += ";";
}
- cnt ++;
+ argnDef += *eit;
}
- argnDefInitialized = true;
+ cnt ++;
}
- cmSystemTools::ReplaceString(tmps, "${ARGN}", argnDef.c_str());
+ argnDefInitialized = true;
}
+ cmSystemTools::ReplaceString(tmps, "${ARGN}", argnDef.c_str());
+ }
+
+ // if the current argument of the current function has ${ARGV in it
+ // then try replacing ARGV values
+ if (tmps.find("${ARGV") != std::string::npos)
+ {
+ char argvName[60];
- // if the current argument of the current function has ${ARGV in it
- // then try replacing ARGV values
- if (tmps.find("${ARGV") != std::string::npos)
+ // repleace ARGV, compute it only once
+ if (!argvDefInitialized)
{
- char argvName[60];
-
- // repleace ARGV, compute it only once
- if (!argvDefInitialized)
+ std::vector<std::string>::const_iterator eit;
+ for ( eit = expandedArgs.begin(); eit != expandedArgs.end(); ++eit )
{
- std::vector<std::string>::iterator eit;
- for ( eit = expandedArguments.begin();
- eit != expandedArguments.end();
- ++ eit )
+ if ( argvDef.size() > 0 )
{
- if ( argvDef.size() > 0 )
- {
- argvDef += ";";
- }
- argvDef += *eit;
+ argvDef += ";";
}
- argvDefInitialized = true;
- }
- cmSystemTools::ReplaceString(tmps, "${ARGV}", argvDef.c_str());
-
- // also replace the ARGV1 ARGV2 ... etc
- for (unsigned int t = 0; t < expandedArguments.size(); ++t)
- {
- sprintf(argvName,"${ARGV%i}",t);
- cmSystemTools::ReplaceString(tmps, argvName,
- expandedArguments[t].c_str());
+ argvDef += *eit;
}
+ argvDefInitialized = true;
}
+ cmSystemTools::ReplaceString(tmps, "${ARGV}", argvDef.c_str());
- arg.Value = tmps;
- arg.Quoted = k->Quoted;
- const char* def =
- mf.GetDefinition("CMAKE_MACRO_REPORT_DEFINITION_LOCATION");
- if(def && !cmSystemTools::IsOff(def))
+ // also replace the ARGV1 ARGV2 ... etc
+ for (unsigned int t = 0; t < expandedArgs.size(); ++t)
{
- // Report the location of the argument where the macro was
- // defined.
- arg.FilePath = k->FilePath;
- arg.Line = k->Line;
+ sprintf(argvName,"${ARGV%i}",t);
+ cmSystemTools::ReplaceString(tmps, argvName,
+ expandedArgs[t].c_str());
+ }
+ }
+
+ arg.Value = tmps;
+ arg.Quoted = k->Quoted;
+ const char* def =
+ m_Makefile->GetDefinition("CMAKE_MACRO_REPORT_DEFINITION_LOCATION");
+ if(def && !cmSystemTools::IsOff(def))
+ {
+ // Report the location of the argument where the macro was
+ // defined.
+ arg.FilePath = k->FilePath;
+ arg.Line = k->Line;
+ }
+ else
+ {
+ // Report the location of the argument where the macro was
+ // invoked.
+ if (args.size())
+ {
+ arg.FilePath = args[0].FilePath;
+ arg.Line = args[0].Line;
}
else
{
- // Report the location of the argument where the macro was
- // invoked.
- arg.FilePath = lff.m_FilePath;
- arg.Line = lff.m_Line;
+ arg.FilePath = "Unknown";
+ arg.Line = 0;
}
- newLFF.m_Arguments.push_back(arg);
}
- if(!mf.ExecuteCommand(newLFF))
+ newLFF.m_Arguments.push_back(arg);
+ }
+ if(!m_Makefile->ExecuteCommand(newLFF))
+ {
+ cmOStringStream error;
+ error << "Error in cmake code at\n"
+ << args[0].FilePath << ":" << args[0].Line << ":\n"
+ << "A command failed during the invocation of macro \""
+ << this->m_Args[0].c_str() << "\".";
+ cmSystemTools::Error(error.str().c_str());
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmMacroFunctionBlocker::
+IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf)
+{
+ // record commands until we hit the ENDMACRO
+ // at the ENDMACRO call we shift gears and start looking for invocations
+ if(lff.m_Name == "ENDMACRO")
+ {
+ std::vector<std::string> expandedArguments;
+ mf.ExpandArguments(lff.m_Arguments, expandedArguments);
+ if(!expandedArguments.empty() && (expandedArguments[0] == m_Args[0]))
+ {
+ std::string name = m_Args[0];
+ std::vector<std::string>::size_type cc;
+ name += "(";
+ for ( cc = 0; cc < m_Args.size(); cc ++ )
{
- cmOStringStream error;
- error << "Error in cmake code at\n"
- << lff.m_FilePath << ":" << lff.m_Line << ":\n"
- << "A command failed during the invocation of macro \""
- << lff.m_Name.c_str() << "\".";
- cmSystemTools::Error(error.str().c_str());
+ name += " " + m_Args[cc];
}
+ name += " )";
+ mf.AddMacro(m_Args[0].c_str(), name.c_str());
+
+ // create a new command and add it to cmake
+ cmMacroHelperCommand *f = new cmMacroHelperCommand();
+ f->m_Args = this->m_Args;
+ f->m_Functions = this->m_Functions;
+ mf.AddCommand(f);
+
+ // remove the function blocker now that the macro is defined
+ mf.RemoveFunctionBlocker(lff);
+ return true;
}
- return true;
}
-
- // if not an invocation then it is just an ordinary line
- return false;
+
+ // if it wasn't an endmacro and we are not executing then we must be
+ // recording
+ m_Functions.push_back(lff);
+ return true;
}
+
bool cmMacroFunctionBlocker::
-ShouldRemove(const cmListFileFunction&, cmMakefile &)
+ShouldRemove(const cmListFileFunction& lff, cmMakefile &mf)
{
+ if(lff.m_Name == "ENDMACRO")
+ {
+ std::vector<std::string> expandedArguments;
+ mf.ExpandArguments(lff.m_Arguments, expandedArguments);
+ if(!expandedArguments.empty() && (expandedArguments[0] == m_Args[0]))
+ {
+ return true;
+ }
+ }
return false;
}
void cmMacroFunctionBlocker::
ScopeEnded(cmMakefile &mf)
{
- // macros never leave scope but we should have seen the ENDMACRO call by now
- if (m_Executing != true)
- {
- cmSystemTools::Error("The end of a CMakeLists file was reached with a MACRO statement that was not closed properly. Within the directory: ",
- mf.GetCurrentDirectory(), " with macro ",
- m_Args[0].c_str());
- }
+ // macros should end with an EndMacro
+ cmSystemTools::Error("The end of a CMakeLists file was reached with a MACRO statement that was not closed properly. Within the directory: ",
+ mf.GetCurrentDirectory(), " with macro ",
+ m_Args[0].c_str());
}
bool cmMacroCommand::InitialPass(std::vector<std::string> const& args)