packaging: Initial packaging
[platform/upstream/cmake.git] / Source / cmAddCustomTargetCommand.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
8   This software is distributed WITHOUT ANY WARRANTY; without even the
9   implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10   See the License for more information.
11 ============================================================================*/
12 #include "cmAddCustomTargetCommand.h"
13
14 // cmAddCustomTargetCommand
15 bool cmAddCustomTargetCommand
16 ::InitialPass(std::vector<std::string> const& args,
17               cmExecutionStatus&)
18 {
19   if(args.size() < 1 )
20     {
21     this->SetError("called with incorrect number of arguments");
22     return false;
23     }
24
25   // Check the target name.
26   if(args[0].find_first_of("/\\") != args[0].npos)
27     {
28     if(!this->Makefile->NeedBackwardsCompatibility(2,2))
29       {
30       cmOStringStream e;
31       e << "called with invalid target name \"" << args[0]
32         << "\".  Target names may not contain a slash.  "
33         << "Use ADD_CUSTOM_COMMAND to generate files.  "
34         << "Set CMAKE_BACKWARDS_COMPATIBILITY to 2.2 "
35         << "or lower to skip this check.";
36       this->SetError(e.str().c_str());
37       return false;
38       }
39     }
40
41   // Accumulate one command line at a time.
42   cmCustomCommandLine currentLine;
43
44   // Save all command lines.
45   cmCustomCommandLines commandLines;
46
47   // Accumulate dependencies.
48   std::vector<std::string> depends;
49   std::string working_directory;
50   bool verbatim = false;
51   std::string comment_buffer;
52   const char* comment = 0;
53   std::vector<std::string> sources;
54
55   // Keep track of parser state.
56   enum tdoing {
57     doing_command,
58     doing_depends,
59     doing_working_directory,
60     doing_comment,
61     doing_source,
62     doing_verbatim
63   };
64   tdoing doing = doing_command;
65
66   // Look for the ALL option.
67   bool excludeFromAll = true;
68   unsigned int start = 1;
69   if(args.size() > 1)
70     {
71     if(args[1] == "ALL")
72       {
73       excludeFromAll = false;
74       start = 2;
75       }
76     }
77
78   // Parse the rest of the arguments.
79   for(unsigned int j = start; j < args.size(); ++j)
80     {
81     std::string const& copy = args[j];
82
83     if(copy == "DEPENDS")
84       {
85       doing = doing_depends;
86       }
87     else if(copy == "WORKING_DIRECTORY")
88       {
89       doing = doing_working_directory;
90       }
91     else if(copy == "VERBATIM")
92       {
93       doing = doing_verbatim;
94       verbatim = true;
95       }
96     else if (copy == "COMMENT")
97       {
98       doing = doing_comment;
99       }
100     else if(copy == "COMMAND")
101       {
102       doing = doing_command;
103
104       // Save the current command before starting the next command.
105       if(!currentLine.empty())
106         {
107         commandLines.push_back(currentLine);
108         currentLine.clear();
109         }
110       }
111     else if(copy == "SOURCES")
112       {
113       doing = doing_source;
114       }
115     else
116       {
117       switch (doing)
118         {
119         case doing_working_directory:
120           working_directory = copy;
121           break;
122         case doing_command:
123           currentLine.push_back(copy);
124           break;
125         case doing_depends:
126           {
127           std::string dep = copy;
128           cmSystemTools::ConvertToUnixSlashes(dep);
129           depends.push_back(dep);
130           }
131           break;
132          case doing_comment:
133            comment_buffer = copy;
134            comment = comment_buffer.c_str();
135            break;
136         case doing_source:
137           sources.push_back(copy);
138           break;
139         default:
140           this->SetError("Wrong syntax. Unknown type of argument.");
141           return false;
142         }
143       }
144     }
145
146   std::string::size_type pos = args[0].find_first_of("#<>");
147   if(pos != args[0].npos)
148     {
149     cmOStringStream msg;
150     msg << "called with target name containing a \"" << args[0][pos]
151         << "\".  This character is not allowed.";
152     this->SetError(msg.str().c_str());
153     return false;
154     }
155
156   // Store the last command line finished.
157   if(!currentLine.empty())
158     {
159     commandLines.push_back(currentLine);
160     currentLine.clear();
161     }
162
163   // Enforce name uniqueness.
164   {
165   std::string msg;
166   if(!this->Makefile->EnforceUniqueName(args[0], msg, true))
167     {
168     this->SetError(msg.c_str());
169     return false;
170     }
171   }
172
173   // Convert working directory to a full path.
174   if(!working_directory.empty())
175     {
176     const char* build_dir = this->Makefile->GetCurrentOutputDirectory();
177     working_directory =
178       cmSystemTools::CollapseFullPath(working_directory.c_str(), build_dir);
179     }
180
181   // Add the utility target to the makefile.
182   bool escapeOldStyle = !verbatim;
183   cmTarget* target =
184     this->Makefile->AddUtilityCommand(args[0].c_str(), excludeFromAll,
185                                       working_directory.c_str(), depends,
186                                       commandLines, escapeOldStyle, comment);
187
188   // Add additional user-specified source files to the target.
189   target->AddSources(sources);
190
191   return true;
192 }