|
|
@@ -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)
|