cmCTestBuildAndTestHandler.cxx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "cmCTestBuildAndTestHandler.h"
  14. #include "cmSystemTools.h"
  15. #include "cmCTest.h"
  16. #include "cmake.h"
  17. #include "cmGlobalGenerator.h"
  18. #include <cmsys/Process.h>
  19. //----------------------------------------------------------------------
  20. cmCTestBuildAndTestHandler::cmCTestBuildAndTestHandler()
  21. {
  22. m_BuildTwoConfig = false;
  23. m_BuildNoClean = false;
  24. m_BuildNoCMake = false;
  25. }
  26. //----------------------------------------------------------------------
  27. void cmCTestBuildAndTestHandler::Initialize()
  28. {
  29. this->Superclass::Initialize();
  30. }
  31. //----------------------------------------------------------------------
  32. const char* cmCTestBuildAndTestHandler::GetOutput()
  33. {
  34. return m_Output.c_str();
  35. }
  36. //----------------------------------------------------------------------
  37. int cmCTestBuildAndTestHandler::ProcessHandler()
  38. {
  39. m_Output = "";
  40. std::string output;
  41. cmSystemTools::ResetErrorOccuredFlag();
  42. cmListFileCache::ClearCache();
  43. int retv = this->RunCMakeAndTest(&m_Output);
  44. cmSystemTools::ResetErrorOccuredFlag();
  45. cmListFileCache::ClearCache();
  46. return retv;
  47. }
  48. //----------------------------------------------------------------------
  49. int cmCTestBuildAndTestHandler::RunCMake(std::string* outstring, cmOStringStream &out,
  50. std::string &cmakeOutString, std::string &cwd,
  51. cmake *cm)
  52. {
  53. unsigned int k;
  54. std::vector<std::string> args;
  55. args.push_back(m_CTest->GetCMakeExecutable());
  56. args.push_back(m_SourceDir);
  57. if(m_BuildGenerator.size())
  58. {
  59. std::string generator = "-G";
  60. generator += m_BuildGenerator;
  61. args.push_back(generator);
  62. }
  63. if ( m_CTest->GetConfigType().size() > 0 )
  64. {
  65. std::string btype = "-DBUILD_TYPE:STRING=" + m_CTest->GetConfigType();
  66. args.push_back(btype);
  67. }
  68. for(k=0; k < m_BuildOptions.size(); ++k)
  69. {
  70. args.push_back(m_BuildOptions[k]);
  71. }
  72. if (cm->Run(args) != 0)
  73. {
  74. out << "Error: cmake execution failed\n";
  75. out << cmakeOutString << "\n";
  76. // return to the original directory
  77. cmSystemTools::ChangeDirectory(cwd.c_str());
  78. if(outstring)
  79. {
  80. *outstring = out.str();
  81. }
  82. else
  83. {
  84. cmCTestLog(m_CTest, ERROR_MESSAGE, out.str() << std::endl);
  85. }
  86. return 1;
  87. }
  88. // do another config?
  89. if(m_BuildTwoConfig)
  90. {
  91. if (cm->Run(args) != 0)
  92. {
  93. out << "Error: cmake execution failed\n";
  94. out << cmakeOutString << "\n";
  95. // return to the original directory
  96. cmSystemTools::ChangeDirectory(cwd.c_str());
  97. if(outstring)
  98. {
  99. *outstring = out.str();
  100. }
  101. else
  102. {
  103. cmCTestLog(m_CTest, ERROR_MESSAGE, out.str() << std::endl);
  104. }
  105. return 1;
  106. }
  107. }
  108. return 0;
  109. }
  110. //----------------------------------------------------------------------
  111. void CMakeMessageCallback(const char* m, const char*, bool&, void* s)
  112. {
  113. std::string* out = (std::string*)s;
  114. *out += m;
  115. *out += "\n";
  116. }
  117. //----------------------------------------------------------------------
  118. void CMakeStdoutCallback(const char* m, int len, void* s)
  119. {
  120. std::string* out = (std::string*)s;
  121. out->append(m, len);
  122. }
  123. //----------------------------------------------------------------------
  124. int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
  125. {
  126. unsigned int k;
  127. std::string cmakeOutString;
  128. cmSystemTools::SetErrorCallback(CMakeMessageCallback, &cmakeOutString);
  129. cmSystemTools::SetStdoutCallback(CMakeStdoutCallback, &cmakeOutString);
  130. cmOStringStream out;
  131. // What is this? double timeout = m_CTest->GetTimeOut();
  132. int retVal = 0;
  133. // if the generator and make program are not specified then it is an error
  134. if (!m_BuildGenerator.size() || !m_BuildMakeProgram.size())
  135. {
  136. if(outstring)
  137. {
  138. *outstring =
  139. "--build-and-test requires that both the generator and makeprogram "
  140. "be provided using the --build-generator and --build-makeprogram "
  141. "command line options. ";
  142. }
  143. return 1;
  144. }
  145. // make sure the binary dir is there
  146. std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
  147. out << "Internal cmake changing into directory: " << m_BinaryDir << "\n";
  148. if (!cmSystemTools::FileIsDirectory(m_BinaryDir.c_str()))
  149. {
  150. cmSystemTools::MakeDirectory(m_BinaryDir.c_str());
  151. }
  152. cmSystemTools::ChangeDirectory(m_BinaryDir.c_str());
  153. // should we cmake?
  154. cmake cm;
  155. cm.SetGlobalGenerator(cm.CreateGlobalGenerator(m_BuildGenerator.c_str()));
  156. if(!m_BuildNoCMake)
  157. {
  158. // do the cmake step
  159. if (this->RunCMake(outstring,out,cmakeOutString,cwd,&cm))
  160. {
  161. return 1;
  162. }
  163. }
  164. // do the build
  165. std::string output;
  166. retVal = cm.GetGlobalGenerator()->Build(
  167. m_SourceDir.c_str(), m_BinaryDir.c_str(),
  168. m_BuildProject.c_str(), m_BuildTarget.c_str(),
  169. &output, m_BuildMakeProgram.c_str(),
  170. m_CTest->GetConfigType().c_str(),!m_BuildNoClean);
  171. out << output;
  172. if(outstring)
  173. {
  174. *outstring = out.str();
  175. }
  176. // if the build failed then return
  177. if (retVal)
  178. {
  179. return 1;
  180. }
  181. // if not test was specified then we are done
  182. if (!m_TestCommand.size())
  183. {
  184. return 0;
  185. }
  186. // now run the compiled test if we can find it
  187. std::vector<std::string> attempted;
  188. std::vector<std::string> failed;
  189. std::string tempPath;
  190. std::string filepath =
  191. cmSystemTools::GetFilenamePath(m_TestCommand);
  192. std::string filename =
  193. cmSystemTools::GetFilenameName(m_TestCommand);
  194. // if full path specified then search that first
  195. if (filepath.size())
  196. {
  197. tempPath = filepath;
  198. tempPath += "/";
  199. tempPath += filename;
  200. attempted.push_back(tempPath);
  201. if(m_CTest->GetConfigType().size())
  202. {
  203. tempPath = filepath;
  204. tempPath += "/";
  205. tempPath += m_CTest->GetConfigType();
  206. tempPath += "/";
  207. tempPath += filename;
  208. attempted.push_back(tempPath);
  209. }
  210. }
  211. // otherwise search local dirs
  212. else
  213. {
  214. attempted.push_back(filename);
  215. if(m_CTest->GetConfigType().size())
  216. {
  217. tempPath = m_CTest->GetConfigType();
  218. tempPath += "/";
  219. tempPath += filename;
  220. attempted.push_back(tempPath);
  221. }
  222. }
  223. // if m_ExecutableDirectory is set try that as well
  224. if (m_ExecutableDirectory.size())
  225. {
  226. tempPath = m_ExecutableDirectory;
  227. tempPath += "/";
  228. tempPath += m_TestCommand;
  229. attempted.push_back(tempPath);
  230. if(m_CTest->GetConfigType().size())
  231. {
  232. tempPath = m_ExecutableDirectory;
  233. tempPath += "/";
  234. tempPath += m_CTest->GetConfigType();
  235. tempPath += "/";
  236. tempPath += filename;
  237. attempted.push_back(tempPath);
  238. }
  239. }
  240. // store the final location in fullPath
  241. std::string fullPath;
  242. // now look in the paths we specified above
  243. for(unsigned int ai=0;
  244. ai < attempted.size() && fullPath.size() == 0; ++ai)
  245. {
  246. // first check without exe extension
  247. if(cmSystemTools::FileExists(attempted[ai].c_str())
  248. && !cmSystemTools::FileIsDirectory(attempted[ai].c_str()))
  249. {
  250. fullPath = cmSystemTools::CollapseFullPath(attempted[ai].c_str());
  251. }
  252. // then try with the exe extension
  253. else
  254. {
  255. failed.push_back(attempted[ai].c_str());
  256. tempPath = attempted[ai];
  257. tempPath += cmSystemTools::GetExecutableExtension();
  258. if(cmSystemTools::FileExists(tempPath.c_str())
  259. && !cmSystemTools::FileIsDirectory(tempPath.c_str()))
  260. {
  261. fullPath = cmSystemTools::CollapseFullPath(tempPath.c_str());
  262. }
  263. else
  264. {
  265. failed.push_back(tempPath.c_str());
  266. }
  267. }
  268. }
  269. if(!cmSystemTools::FileExists(fullPath.c_str()))
  270. {
  271. out << "Could not find path to executable, perhaps it was not built: " <<
  272. m_TestCommand << "\n";
  273. out << "tried to find it in these places:\n";
  274. out << fullPath.c_str() << "\n";
  275. for(unsigned int i=0; i < failed.size(); ++i)
  276. {
  277. out << failed[i] << "\n";
  278. }
  279. if(outstring)
  280. {
  281. *outstring = out.str();
  282. }
  283. else
  284. {
  285. cmCTestLog(m_CTest, ERROR_MESSAGE, out.str());
  286. }
  287. // return to the original directory
  288. cmSystemTools::ChangeDirectory(cwd.c_str());
  289. return 1;
  290. }
  291. std::vector<const char*> testCommand;
  292. testCommand.push_back(fullPath.c_str());
  293. for(k=0; k < m_TestCommandArgs.size(); ++k)
  294. {
  295. testCommand.push_back(m_TestCommandArgs[k].c_str());
  296. }
  297. testCommand.push_back(0);
  298. std::string outs;
  299. int retval = 0;
  300. // run the test from the m_BuildRunDir if set
  301. if(m_BuildRunDir.size())
  302. {
  303. out << "Run test in directory: " << m_BuildRunDir << "\n";
  304. cmSystemTools::ChangeDirectory(m_BuildRunDir.c_str());
  305. }
  306. out << "Running test executable: " << fullPath << " ";
  307. for(k=0; k < m_TestCommandArgs.size(); ++k)
  308. {
  309. out << m_TestCommandArgs[k] << " ";
  310. }
  311. out << "\n";
  312. // What is this? m_TimeOut = timeout;
  313. int runTestRes = m_CTest->RunTest(testCommand, &outs, &retval, 0);
  314. if(runTestRes != cmsysProcess_State_Exited || retval != 0)
  315. {
  316. out << "Failed to run test command: " << testCommand[0] << "\n";
  317. retval = 1;
  318. }
  319. out << outs << "\n";
  320. if(outstring)
  321. {
  322. *outstring = out.str();
  323. }
  324. else
  325. {
  326. cmCTestLog(m_CTest, OUTPUT, out.str() << std::endl);
  327. }
  328. return retval;
  329. }
  330. //----------------------------------------------------------------------
  331. int cmCTestBuildAndTestHandler::ProcessCommandLineArguments(
  332. const std::string& currentArg, size_t& idx,
  333. const std::vector<std::string>& allArgs)
  334. {
  335. // --build-and-test options
  336. if(currentArg.find("--build-and-test",0) == 0 && idx < allArgs.size() - 1)
  337. {
  338. if(idx+2 < allArgs.size())
  339. {
  340. idx++;
  341. m_SourceDir = allArgs[idx];
  342. idx++;
  343. m_BinaryDir = allArgs[idx];
  344. // dir must exist before CollapseFullPath is called
  345. cmSystemTools::MakeDirectory(m_BinaryDir.c_str());
  346. m_BinaryDir = cmSystemTools::CollapseFullPath(m_BinaryDir.c_str());
  347. m_SourceDir = cmSystemTools::CollapseFullPath(m_SourceDir.c_str());
  348. }
  349. else
  350. {
  351. cmCTestLog(m_CTest, ERROR_MESSAGE, "--build-and-test must have source and binary dir" << std::endl);
  352. return 0;
  353. }
  354. }
  355. if(currentArg.find("--build-target",0) == 0 && idx < allArgs.size() - 1)
  356. {
  357. idx++;
  358. m_BuildTarget = allArgs[idx];
  359. }
  360. if(currentArg.find("--build-nocmake",0) == 0)
  361. {
  362. m_BuildNoCMake = true;
  363. }
  364. if(currentArg.find("--build-run-dir",0) == 0 && idx < allArgs.size() - 1)
  365. {
  366. idx++;
  367. m_BuildRunDir = allArgs[idx];
  368. }
  369. if(currentArg.find("--build-two-config",0) == 0)
  370. {
  371. m_BuildTwoConfig = true;
  372. }
  373. if(currentArg.find("--build-exe-dir",0) == 0 && idx < allArgs.size() - 1)
  374. {
  375. idx++;
  376. m_ExecutableDirectory = allArgs[idx];
  377. }
  378. if(currentArg.find("--build-generator",0) == 0 && idx < allArgs.size() - 1)
  379. {
  380. idx++;
  381. m_BuildGenerator = allArgs[idx];
  382. }
  383. if(currentArg.find("--build-project",0) == 0 && idx < allArgs.size() - 1)
  384. {
  385. idx++;
  386. m_BuildProject = allArgs[idx];
  387. }
  388. if(currentArg.find("--build-makeprogram",0) == 0 && idx < allArgs.size() - 1)
  389. {
  390. idx++;
  391. m_BuildMakeProgram = allArgs[idx];
  392. }
  393. if(currentArg.find("--build-noclean",0) == 0)
  394. {
  395. m_BuildNoClean = true;
  396. }
  397. if(currentArg.find("--build-options",0) == 0 && idx < allArgs.size() - 1)
  398. {
  399. ++idx;
  400. bool done = false;
  401. while(idx < allArgs.size() && !done)
  402. {
  403. m_BuildOptions.push_back(allArgs[idx]);
  404. if(idx+1 < allArgs.size()
  405. && (allArgs[idx+1] == "--build-target" || allArgs[idx+1] == "--test-command"))
  406. {
  407. done = true;
  408. }
  409. else
  410. {
  411. ++idx;
  412. }
  413. }
  414. }
  415. if(currentArg.find("--test-command",0) == 0 && idx < allArgs.size() - 1)
  416. {
  417. ++idx;
  418. m_TestCommand = allArgs[idx];
  419. while(idx+1 < allArgs.size())
  420. {
  421. ++idx;
  422. m_TestCommandArgs.push_back(allArgs[idx]);
  423. }
  424. }
  425. return 1;
  426. }