| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374 | /*============================================================================  CMake - Cross Platform Makefile Generator  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium  Distributed under the OSI-approved BSD License (the "License");  see accompanying file Copyright.txt for details.  This software is distributed WITHOUT ANY WARRANTY; without even the  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the License for more information.============================================================================*/#include "cmAddCustomCommandCommand.h"#include "cmTarget.h"#include "cmSourceFile.h"// cmAddCustomCommandCommandbool cmAddCustomCommandCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &){  /* Let's complain at the end of this function about the lack of a particular     arg. For the moment, let's say that COMMAND, and either TARGET or SOURCE     are required.  */  if (args.size() < 4)    {      this->SetError("called with wrong number of arguments.");      return false;    }  std::string source, target, main_dependency, working;  std::string comment_buffer;  const char* comment = 0;  std::vector<std::string> depends, outputs, output;  bool verbatim = false;  bool append = false;  std::string implicit_depends_lang;  cmCustomCommand::ImplicitDependsList implicit_depends;  // Accumulate one command line at a time.  cmCustomCommandLine currentLine;  // Save all command lines.  cmCustomCommandLines commandLines;  cmTarget::CustomCommandType cctype = cmTarget::POST_BUILD;  enum tdoing {    doing_source,    doing_command,    doing_target,    doing_depends,    doing_implicit_depends_lang,    doing_implicit_depends_file,    doing_main_dependency,    doing_output,    doing_outputs,    doing_comment,    doing_working_directory,    doing_nothing  };  tdoing doing = doing_nothing;  for (unsigned int j = 0; j < args.size(); ++j)    {    std::string const& copy = args[j];    if(copy == "SOURCE")      {      doing = doing_source;      }    else if(copy == "COMMAND")      {      doing = doing_command;      // Save the current command before starting the next command.      if(!currentLine.empty())        {        commandLines.push_back(currentLine);        currentLine.clear();        }      }    else if(copy == "PRE_BUILD")      {      cctype = cmTarget::PRE_BUILD;      }    else if(copy == "PRE_LINK")      {      cctype = cmTarget::PRE_LINK;      }    else if(copy == "POST_BUILD")      {      cctype = cmTarget::POST_BUILD;      }    else if(copy == "VERBATIM")      {      verbatim = true;      }    else if(copy == "APPEND")      {      append = true;      }    else if(copy == "TARGET")      {      doing = doing_target;      }    else if(copy == "ARGS")      {      // Ignore this old keyword.      }    else if (copy == "DEPENDS")      {      doing = doing_depends;      }    else if (copy == "OUTPUTS")      {      doing = doing_outputs;      }    else if (copy == "OUTPUT")      {      doing = doing_output;      }    else if (copy == "WORKING_DIRECTORY")      {      doing = doing_working_directory;      }    else if (copy == "MAIN_DEPENDENCY")      {      doing = doing_main_dependency;      }    else if (copy == "IMPLICIT_DEPENDS")      {      doing = doing_implicit_depends_lang;      }    else if (copy == "COMMENT")      {      doing = doing_comment;      }    else      {      std::string filename;      switch (doing)        {        case doing_output:        case doing_outputs:          if (!cmSystemTools::FileIsFullPath(copy.c_str()))            {            // This is an output to be generated, so it should be            // under the build tree.  CMake 2.4 placed this under the            // source tree.  However the only case that this change            // will break is when someone writes            //            //   add_custom_command(OUTPUT out.txt ...)            //            // and later references "${CMAKE_CURRENT_SOURCE_DIR}/out.txt".            // This is fairly obscure so we can wait for someone to            // complain.            filename = this->Makefile->GetCurrentOutputDirectory();            filename += "/";            }          filename += copy;          cmSystemTools::ConvertToUnixSlashes(filename);          break;        case doing_source:          // We do not want to convert the argument to SOURCE because          // that option is only available for backward compatibility.          // Old-style use of this command may use the SOURCE==TARGET          // trick which we must preserve.  If we convert the source          // to a full path then it will no longer equal the target.        default:          break;        }       switch (doing)         {         case doing_working_directory:           working = copy;           break;         case doing_source:           source = copy;           break;         case doing_output:           output.push_back(filename);           break;         case doing_main_dependency:           main_dependency = copy;           break;         case doing_implicit_depends_lang:           implicit_depends_lang = copy;           doing = doing_implicit_depends_file;           break;         case doing_implicit_depends_file:           {           // An implicit dependency starting point is also an           // explicit dependency.           depends.push_back(copy);           // Add the implicit dependency language and file.           cmCustomCommand::ImplicitDependsPair             entry(implicit_depends_lang, copy);           implicit_depends.push_back(entry);           // Switch back to looking for a language.           doing = doing_implicit_depends_lang;           }           break;         case doing_command:           currentLine.push_back(copy);           break;         case doing_target:           target = copy;           break;         case doing_depends:           depends.push_back(copy);           break;         case doing_outputs:           outputs.push_back(filename);           break;         case doing_comment:           comment_buffer = copy;           comment = comment_buffer.c_str();           break;         default:           this->SetError("Wrong syntax. Unknown type of argument.");           return false;         }      }    }  // Store the last command line finished.  if(!currentLine.empty())    {    commandLines.push_back(currentLine);    currentLine.clear();    }  // At this point we could complain about the lack of arguments.  For  // the moment, let's say that COMMAND, TARGET are always required.  if(output.empty() && target.empty())    {    this->SetError("Wrong syntax. A TARGET or OUTPUT must be specified.");    return false;    }  if(source.empty() && !target.empty() && !output.empty())    {    this->SetError(      "Wrong syntax. A TARGET and OUTPUT can not both be specified.");    return false;    }  if(append && output.empty())    {    this->SetError("given APPEND option with no OUTPUT.");    return false;    }  // Make sure the output names and locations are safe.  if(!this->CheckOutputs(output) || !this->CheckOutputs(outputs))    {    return false;    }  // Check for an append request.  if(append)    {    // Lookup an existing command.    if(cmSourceFile* sf =       this->Makefile->GetSourceFileWithOutput(output[0].c_str()))      {      if(cmCustomCommand* cc = sf->GetCustomCommand())        {        cc->AppendCommands(commandLines);        cc->AppendDepends(depends);        cc->AppendImplicitDepends(implicit_depends);        return true;        }      }    // No command for this output exists.    cmOStringStream e;    e << "given APPEND option with output \"" << output[0].c_str()      << "\" which is not already a custom command output.";    this->SetError(e.str().c_str());    return false;    }  // Choose which mode of the command to use.  bool escapeOldStyle = !verbatim;  if(source.empty() && output.empty())    {    // Source is empty, use the target.    std::vector<std::string> no_depends;    this->Makefile->AddCustomCommandToTarget(target.c_str(), no_depends,                                             commandLines, cctype,                                             comment, working.c_str(),                                             escapeOldStyle);    }  else if(target.empty())    {    // Target is empty, use the output.    this->Makefile->AddCustomCommandToOutput(output, depends,                                             main_dependency.c_str(),                                             commandLines, comment,                                             working.c_str(), false,                                             escapeOldStyle);    // Add implicit dependency scanning requests if any were given.    if(!implicit_depends.empty())      {      bool okay = false;      if(cmSourceFile* sf =         this->Makefile->GetSourceFileWithOutput(output[0].c_str()))        {        if(cmCustomCommand* cc = sf->GetCustomCommand())          {          okay = true;          cc->SetImplicitDepends(implicit_depends);          }        }      if(!okay)        {        cmOStringStream e;        e << "could not locate source file with a custom command producing \""          << output[0] << "\" even though this command tried to create it!";        this->SetError(e.str().c_str());        return false;        }      }    }  else    {    // Use the old-style mode for backward compatibility.    this->Makefile->AddCustomCommandOldStyle(target.c_str(), outputs, depends,                                             source.c_str(), commandLines,                                             comment);    }  return true;}//----------------------------------------------------------------------------boolcmAddCustomCommandCommand::CheckOutputs(const std::vector<std::string>& outputs){  for(std::vector<std::string>::const_iterator o = outputs.begin();      o != outputs.end(); ++o)    {    // Make sure the file will not be generated into the source    // directory during an out of source build.    if(!this->Makefile->CanIWriteThisFile(o->c_str()))      {      std::string e = "attempted to have a file \"" + *o +        "\" in a source directory as an output of custom command.";      this->SetError(e.c_str());      cmSystemTools::SetFatalErrorOccured();      return false;      }    // Make sure the output file name has no invalid characters.    std::string::size_type pos = o->find_first_of("#<>");    if(pos != o->npos)      {      cmOStringStream msg;      msg << "called with OUTPUT containing a \"" << (*o)[pos]          << "\".  This character is not allowed.";      this->SetError(msg.str().c_str());      return false;      }    }  return true;}
 |