Introduce "generator expressions" to add_test()
[cmake.git] / Source / cmExecuteProcessCommand.cxx
blob5551c334eebb4f1a4e4a0b4adb4180743f30519f
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmExecuteProcessCommand.cxx,v $
5 Language: C++
6 Date: $Date: 2008-01-23 15:27:59 $
7 Version: $Revision: 1.10 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmExecuteProcessCommand.h"
18 #include "cmSystemTools.h"
20 #include <cmsys/Process.h>
22 #include <ctype.h> /* isspace */
24 static bool cmExecuteProcessCommandIsWhitespace(char c)
26 return (isspace((int)c) || c == '\n' || c == '\r');
29 void cmExecuteProcessCommandFixText(std::vector<char>& output,
30 bool strip_trailing_whitespace);
31 void cmExecuteProcessCommandAppend(std::vector<char>& output,
32 const char* data, int length);
34 // cmExecuteProcessCommand
35 bool cmExecuteProcessCommand
36 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
38 if(args.size() < 1 )
40 this->SetError("called with incorrect number of arguments");
41 return false;
43 std::vector< std::vector<const char*> > cmds;
44 std::string arguments;
45 bool doing_command = false;
46 size_t command_index = 0;
47 bool output_quiet = false;
48 bool error_quiet = false;
49 bool output_strip_trailing_whitespace = false;
50 bool error_strip_trailing_whitespace = false;
51 std::string timeout_string;
52 std::string input_file;
53 std::string output_file;
54 std::string error_file;
55 std::string output_variable;
56 std::string error_variable;
57 std::string result_variable;
58 std::string working_directory;
59 for(size_t i=0; i < args.size(); ++i)
61 if(args[i] == "COMMAND")
63 doing_command = true;
64 command_index = cmds.size();
65 cmds.push_back(std::vector<const char*>());
67 else if(args[i] == "OUTPUT_VARIABLE")
69 doing_command = false;
70 if(++i < args.size())
72 output_variable = args[i];
74 else
76 this->SetError(" called with no value for OUTPUT_VARIABLE.");
77 return false;
80 else if(args[i] == "ERROR_VARIABLE")
82 doing_command = false;
83 if(++i < args.size())
85 error_variable = args[i];
87 else
89 this->SetError(" called with no value for ERROR_VARIABLE.");
90 return false;
93 else if(args[i] == "RESULT_VARIABLE")
95 doing_command = false;
96 if(++i < args.size())
98 result_variable = args[i];
100 else
102 this->SetError(" called with no value for RESULT_VARIABLE.");
103 return false;
106 else if(args[i] == "WORKING_DIRECTORY")
108 doing_command = false;
109 if(++i < args.size())
111 working_directory = args[i];
113 else
115 this->SetError(" called with no value for WORKING_DIRECTORY.");
116 return false;
119 else if(args[i] == "INPUT_FILE")
121 doing_command = false;
122 if(++i < args.size())
124 input_file = args[i];
126 else
128 this->SetError(" called with no value for INPUT_FILE.");
129 return false;
132 else if(args[i] == "OUTPUT_FILE")
134 doing_command = false;
135 if(++i < args.size())
137 output_file = args[i];
139 else
141 this->SetError(" called with no value for OUTPUT_FILE.");
142 return false;
145 else if(args[i] == "ERROR_FILE")
147 doing_command = false;
148 if(++i < args.size())
150 error_file = args[i];
152 else
154 this->SetError(" called with no value for ERROR_FILE.");
155 return false;
158 else if(args[i] == "TIMEOUT")
160 doing_command = false;
161 if(++i < args.size())
163 timeout_string = args[i];
165 else
167 this->SetError(" called with no value for TIMEOUT.");
168 return false;
171 else if(args[i] == "OUTPUT_QUIET")
173 doing_command = false;
174 output_quiet = true;
176 else if(args[i] == "ERROR_QUIET")
178 doing_command = false;
179 error_quiet = true;
181 else if(args[i] == "OUTPUT_STRIP_TRAILING_WHITESPACE")
183 doing_command = false;
184 output_strip_trailing_whitespace = true;
186 else if(args[i] == "ERROR_STRIP_TRAILING_WHITESPACE")
188 doing_command = false;
189 error_strip_trailing_whitespace = true;
191 else if(doing_command)
193 cmds[command_index].push_back(args[i].c_str());
195 else
197 cmOStringStream e;
198 e << " given unknown argument \"" << args[i] << "\".";
199 this->SetError(e.str().c_str());
200 return false;
204 if ( !this->Makefile->CanIWriteThisFile(output_file.c_str()) )
206 std::string e = "attempted to output into a file: " + output_file
207 + " into a source directory.";
208 this->SetError(e.c_str());
209 cmSystemTools::SetFatalErrorOccured();
210 return false;
213 // Check for commands given.
214 if(cmds.empty())
216 this->SetError(" called with no COMMAND argument.");
217 return false;
219 for(unsigned int i=0; i < cmds.size(); ++i)
221 if(cmds[i].empty())
223 this->SetError(" given COMMAND argument with no value.");
224 return false;
226 else
228 // Add the null terminating pointer to the command argument list.
229 cmds[i].push_back(0);
233 // Parse the timeout string.
234 double timeout = -1;
235 if(!timeout_string.empty())
237 if(sscanf(timeout_string.c_str(), "%lg", &timeout) != 1)
239 this->SetError(" called with TIMEOUT value that could not be parsed.");
240 return false;
244 // Create a process instance.
245 cmsysProcess* cp = cmsysProcess_New();
247 // Set the command sequence.
248 for(unsigned int i=0; i < cmds.size(); ++i)
250 cmsysProcess_AddCommand(cp, &*cmds[i].begin());
253 // Set the process working directory.
254 if(!working_directory.empty())
256 cmsysProcess_SetWorkingDirectory(cp, working_directory.c_str());
259 // Always hide the process window.
260 cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
262 // Check the output variables.
263 bool merge_output = (output_variable == error_variable);
264 if(error_variable.empty() && !error_quiet)
266 cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
268 if(!input_file.empty())
270 cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDIN, input_file.c_str());
272 if(!output_file.empty())
274 cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDOUT,
275 output_file.c_str());
277 if(!error_file.empty())
279 cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDERR,
280 error_file.c_str());
283 // Set the timeout if any.
284 if(timeout >= 0)
286 cmsysProcess_SetTimeout(cp, timeout);
289 // Start the process.
290 cmsysProcess_Execute(cp);
292 // Read the process output.
293 std::vector<char> tempOutput;
294 std::vector<char> tempError;
295 int length;
296 char* data;
297 int p;
298 while((p = cmsysProcess_WaitForData(cp, &data, &length, 0), p))
300 // Put the output in the right place.
301 if(p == cmsysProcess_Pipe_STDOUT && !output_quiet ||
302 p == cmsysProcess_Pipe_STDERR && !error_quiet && merge_output)
304 if(output_variable.empty())
306 cmSystemTools::Stdout(data, length);
308 else
310 cmExecuteProcessCommandAppend(tempOutput, data, length);
313 else if(p == cmsysProcess_Pipe_STDERR && !error_quiet)
315 if(!error_variable.empty())
317 cmExecuteProcessCommandAppend(tempError, data, length);
322 // All output has been read. Wait for the process to exit.
323 cmsysProcess_WaitForExit(cp, 0);
325 // Fix the text in the output strings.
326 cmExecuteProcessCommandFixText(tempOutput,
327 output_strip_trailing_whitespace);
328 cmExecuteProcessCommandFixText(tempError,
329 error_strip_trailing_whitespace);
331 // Store the output obtained.
332 if(!output_variable.empty() && tempOutput.size())
334 this->Makefile->AddDefinition(output_variable.c_str(),
335 &*tempOutput.begin());
337 if(!merge_output && !error_variable.empty() && tempError.size())
339 this->Makefile->AddDefinition(error_variable.c_str(),
340 &*tempError.begin());
343 // Store the result of running the process.
344 if(!result_variable.empty())
346 switch(cmsysProcess_GetState(cp))
348 case cmsysProcess_State_Exited:
350 int v = cmsysProcess_GetExitValue(cp);
351 char buf[100];
352 sprintf(buf, "%d", v);
353 this->Makefile->AddDefinition(result_variable.c_str(), buf);
355 break;
356 case cmsysProcess_State_Exception:
357 this->Makefile->AddDefinition(result_variable.c_str(),
358 cmsysProcess_GetExceptionString(cp));
359 break;
360 case cmsysProcess_State_Error:
361 this->Makefile->AddDefinition(result_variable.c_str(),
362 cmsysProcess_GetErrorString(cp));
363 break;
364 case cmsysProcess_State_Expired:
365 this->Makefile->AddDefinition(result_variable.c_str(),
366 "Process terminated due to timeout");
367 break;
371 // Delete the process instance.
372 cmsysProcess_Delete(cp);
374 return true;
377 //----------------------------------------------------------------------------
378 void cmExecuteProcessCommandFixText(std::vector<char>& output,
379 bool strip_trailing_whitespace)
381 // Remove \0 characters and the \r part of \r\n pairs.
382 unsigned int in_index = 0;
383 unsigned int out_index = 0;
384 while(in_index < output.size())
386 char c = output[in_index++];
387 if((c != '\r' || !(in_index < output.size() && output[in_index] == '\n'))
388 && c != '\0')
390 output[out_index++] = c;
394 // Remove trailing whitespace if requested.
395 if(strip_trailing_whitespace)
397 while(out_index > 0 &&
398 cmExecuteProcessCommandIsWhitespace(output[out_index-1]))
400 --out_index;
404 // Shrink the vector to the size needed.
405 output.resize(out_index);
407 // Put a terminator on the text string.
408 output.push_back('\0');
411 //----------------------------------------------------------------------------
412 void cmExecuteProcessCommandAppend(std::vector<char>& output,
413 const char* data, int length)
415 #if defined(__APPLE__)
416 // HACK on Apple to work around bug with inserting at the
417 // end of an empty vector. This resulted in random failures
418 // that were hard to reproduce.
419 if(output.empty() && length > 0)
421 output.push_back(data[0]);
422 ++data;
423 --length;
425 #endif
426 output.insert(output.end(), data, data+length);