cmCreateTestSourceList.cxx 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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 "cmCreateTestSourceList.h"
  14. #include "cmSourceFile.h"
  15. // cmCreateTestSourceList
  16. bool cmCreateTestSourceList::InitialPass(std::vector<std::string> const& argsIn)
  17. {
  18. if (argsIn.size() < 3)
  19. {
  20. this->SetError("called with wrong number of arguments.");
  21. return false;
  22. }
  23. std::vector<std::string> args;
  24. cmSystemTools::ExpandListArguments(argsIn, args);
  25. std::vector<std::string>::iterator i = args.begin();
  26. std::string extraInclude;
  27. std::string function;
  28. std::vector<std::string> tests;
  29. // extract extra include and function ot
  30. for(; i != args.end(); i++)
  31. {
  32. if(*i == "EXTRA_INCLUDE")
  33. {
  34. ++i;
  35. if(i == args.end())
  36. {
  37. this->SetError("incorrect arguments to EXTRA_INCLUDE");
  38. return false;
  39. }
  40. extraInclude = *i;
  41. }
  42. else if(*i == "FUNCTION")
  43. {
  44. ++i;
  45. if(i == args.end())
  46. {
  47. this->SetError("incorrect arguments to FUNCTION");
  48. return false;
  49. }
  50. function = *i;
  51. }
  52. else
  53. {
  54. tests.push_back(*i);
  55. }
  56. }
  57. i = tests.begin();
  58. // Name of the source list
  59. const char* sourceList = i->c_str();
  60. ++i;
  61. // Name of the test driver
  62. // make sure they specified an extension
  63. if (cmSystemTools::GetFilenameExtension(*i).size() < 2)
  64. {
  65. this->SetError("You must specify a file extenion for the test driver file.");
  66. return false;
  67. }
  68. std::string driver = m_Makefile->GetCurrentOutputDirectory();
  69. driver += "/";
  70. driver += *i;
  71. ++i;
  72. std::ofstream fout(driver.c_str());
  73. if (!fout)
  74. {
  75. std::string err = "Could not create file ";
  76. err += driver;
  77. err += " for cmCreateTestSourceList command.";
  78. this->SetError(err.c_str());
  79. return false;
  80. }
  81. // Create the test driver file
  82. fout <<
  83. "#include <ctype.h>\n"
  84. "#include <stdio.h>\n"
  85. "#include <string.h>\n"
  86. "#include <stdlib.h>\n"
  87. "\n";
  88. fout <<
  89. "#if defined(_MSC_VER) && defined(_DEBUG)\n"
  90. "/* MSVC debug hook to prevent dialogs when running from DART. */\n"
  91. "# include <crtdbg.h>\n"
  92. "static int TestDriverDebugReport(int type, char* message, int* retVal)\n"
  93. "{\n"
  94. " (void)type; (void)retVal;\n"
  95. " fprintf(stderr, message);\n"
  96. " exit(1);\n"
  97. " return 0;\n"
  98. "}\n"
  99. "#endif\n";
  100. if(extraInclude.size())
  101. {
  102. fout << "#include \"" << extraInclude << "\"\n";
  103. }
  104. fout <<
  105. "\n"
  106. "/* Forward declare test functions. */\n"
  107. "\n";
  108. std::vector<std::string>::iterator testsBegin = i;
  109. std::vector<std::string> tests_func_name;
  110. // The rest of the arguments consist of a list of test source files.
  111. // Sadly, they can be in directories. Let's find a unique function
  112. // name for the corresponding test, and push it to the tests_func_name
  113. // list.
  114. // For the moment:
  115. // - replace spaces ' ', ':' and '/' with underscores '_'
  116. for(i = testsBegin; i != tests.end(); ++i)
  117. {
  118. if(*i == "EXTRA_INCLUDE")
  119. {
  120. break;
  121. }
  122. std::string func_name;
  123. if (cmSystemTools::GetFilenamePath(*i).size() > 0)
  124. {
  125. func_name = cmSystemTools::GetFilenamePath(*i) + "/" +
  126. cmSystemTools::GetFilenameWithoutLastExtension(*i);
  127. }
  128. else
  129. {
  130. func_name = cmSystemTools::GetFilenameWithoutLastExtension(*i);
  131. }
  132. cmSystemTools::ConvertToUnixSlashes(func_name);
  133. cmSystemTools::ReplaceString(func_name, " ", "_");
  134. cmSystemTools::ReplaceString(func_name, "/", "_");
  135. cmSystemTools::ReplaceString(func_name, ":", "_");
  136. tests_func_name.push_back(func_name);
  137. fout << "int " << func_name << "(int, char*[]);\n";
  138. }
  139. fout <<
  140. "\n"
  141. "/* Create map. */\n"
  142. "\n"
  143. "typedef int (*MainFuncPointer)(int , char*[]);\n"
  144. "typedef struct\n"
  145. "{\n"
  146. " const char* name;\n"
  147. " MainFuncPointer func;\n"
  148. "} functionMapEntry;\n"
  149. "\n"
  150. "functionMapEntry cmakeGeneratedFunctionMapEntries[] = {\n";
  151. int numTests = 0;
  152. std::vector<std::string>::iterator j;
  153. for(i = testsBegin, j = tests_func_name.begin(); i != tests.end(); ++i, ++j)
  154. {
  155. std::string func_name;
  156. if (cmSystemTools::GetFilenamePath(*i).size() > 0)
  157. {
  158. func_name = cmSystemTools::GetFilenamePath(*i) + "/" +
  159. cmSystemTools::GetFilenameWithoutLastExtension(*i);
  160. }
  161. else
  162. {
  163. func_name = cmSystemTools::GetFilenameWithoutLastExtension(*i);
  164. }
  165. fout <<
  166. " {\n"
  167. " \"" << func_name << "\",\n"
  168. " " << *j << "\n"
  169. " },\n";
  170. numTests++;
  171. }
  172. fout <<
  173. "};\n"
  174. "\n"
  175. "/* Allocate and create a lowercased copy of string\n"
  176. " (note that it has to be free'd manually) */\n"
  177. "\n"
  178. "char* lowercase(const char *string)\n"
  179. "{\n"
  180. " char *new_string, *p;\n"
  181. " new_string = (char *)malloc(sizeof(char) * (size_t)(strlen(string) + 1));\n"
  182. " if (!new_string)\n"
  183. " {\n"
  184. " return NULL;\n"
  185. " }\n"
  186. " strcpy(new_string, string);\n"
  187. " p = new_string;\n"
  188. " while (*p != 0)\n"
  189. " {\n"
  190. " *p = (char)tolower(*p);\n"
  191. " ++p;\n"
  192. " }\n"
  193. " return new_string;\n"
  194. "}\n"
  195. "\n"
  196. "int main(int ac, char *av[])\n"
  197. "{\n"
  198. " int i, NumTests, testNum, partial_match;\n"
  199. " char *arg, *test_name;\n"
  200. " \n"
  201. "#if defined(_MSC_VER) && defined(_DEBUG)\n"
  202. " /* If running from DART, put in debug hook. */\n"
  203. " if(getenv(\"DART_TEST_FROM_DART\"))\n"
  204. " {\n"
  205. " _CrtSetReportHook(TestDriverDebugReport);\n"
  206. " }\n"
  207. "#endif\n"
  208. " \n"
  209. " NumTests = " << numTests << ";\n"
  210. " \n"
  211. " /* If no test name was given */\n";
  212. if(function.size())
  213. {
  214. fout << " /* process command line with user function. */\n"
  215. << " " << function << "(&ac, &av);\n";
  216. }
  217. fout <<
  218. " if (ac < 2)\n"
  219. " {\n"
  220. " /* Ask for a test. */\n"
  221. " printf(\"Available tests:\\n\");\n"
  222. " for (i =0; i < NumTests; ++i)\n"
  223. " {\n"
  224. " printf(\"%3d. %s\\n\", i, cmakeGeneratedFunctionMapEntries[i].name);\n"
  225. " }\n"
  226. " printf(\"To run a test, enter the test number: \");\n"
  227. " testNum = 0;\n"
  228. " scanf(\"%d\", &testNum);\n"
  229. " if (testNum >= NumTests)\n"
  230. " {\n"
  231. " printf(\"%3d is an invalid test number.\\n\", testNum);\n"
  232. " return -1;\n"
  233. " }\n"
  234. " return (*cmakeGeneratedFunctionMapEntries[testNum].func)(ac-1, av+1);\n"
  235. " }\n"
  236. " \n"
  237. " /* If partial match is requested. */\n"
  238. " partial_match = (strcmp(av[1], \"-R\") == 0) ? 1 : 0;\n"
  239. " if (partial_match && ac < 3)\n"
  240. " {\n"
  241. " printf(\"-R needs an additional parameter.\\n\");\n"
  242. " return -1;\n"
  243. " }\n"
  244. " \n"
  245. " arg = lowercase(av[1 + partial_match]);\n"
  246. " for (i =0; i < NumTests; ++i)\n"
  247. " {\n"
  248. " test_name = lowercase(cmakeGeneratedFunctionMapEntries[i].name);\n"
  249. " if (partial_match && strstr(test_name, arg) != NULL)\n"
  250. " {\n"
  251. " free(arg);\n"
  252. " free(test_name);\n"
  253. " return (*cmakeGeneratedFunctionMapEntries[i].func)(ac - 2, av + 2);\n"
  254. " }\n"
  255. " else if (!partial_match && strcmp(test_name, arg) == 0)\n"
  256. " {\n"
  257. " free(arg);\n"
  258. " free(test_name);\n"
  259. " return (*cmakeGeneratedFunctionMapEntries[i].func)(ac - 1, av + 1);\n"
  260. " }\n"
  261. " free(test_name);\n"
  262. " }\n"
  263. " free(arg);\n"
  264. " \n"
  265. " /* Nothing was run, display the test names. */\n"
  266. " printf(\"Available tests:\\n\");\n"
  267. " for (i =0; i < NumTests; ++i)\n"
  268. " {\n"
  269. " printf(\"%3d. %s\\n\", i, cmakeGeneratedFunctionMapEntries[i].name);\n"
  270. " }\n"
  271. " printf(\"Failed: %s is an invalid test name.\\n\", av[1]);\n"
  272. " \n"
  273. " return -1;\n"
  274. "}\n";
  275. fout.close();
  276. // Create the source list
  277. cmSourceFile cfile;
  278. std::string sourceListValue;
  279. cfile.SetProperty("ABSTRACT","0");
  280. cfile.SetName(cmSystemTools::GetFilenameWithoutExtension(args[1]).c_str(),
  281. m_Makefile->GetCurrentOutputDirectory(),
  282. cmSystemTools::GetFilenameExtension(args[1]).c_str()+1,
  283. false);
  284. m_Makefile->AddSource(cfile);
  285. sourceListValue = args[1];
  286. for(i = testsBegin; i != tests.end(); ++i)
  287. {
  288. cmSourceFile icfile;
  289. icfile.SetProperty("ABSTRACT","0");
  290. icfile.SetName(i->c_str(),
  291. m_Makefile->GetCurrentDirectory(),
  292. m_Makefile->GetSourceExtensions(),
  293. m_Makefile->GetHeaderExtensions());
  294. m_Makefile->AddSource(icfile);
  295. sourceListValue += ";";
  296. sourceListValue += *i;
  297. }
  298. m_Makefile->AddDefinition(sourceList, sourceListValue.c_str());
  299. return true;
  300. }