cmCreateTestSourceList.cxx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmCreateTestSourceList.h"
  4. #include <algorithm>
  5. #include "cmMakefile.h"
  6. #include "cmSourceFile.h"
  7. #include "cmStringAlgorithms.h"
  8. #include "cmSystemTools.h"
  9. class cmExecutionStatus;
  10. // cmCreateTestSourceList
  11. bool cmCreateTestSourceList::InitialPass(std::vector<std::string> const& args,
  12. cmExecutionStatus&)
  13. {
  14. if (args.size() < 3) {
  15. this->SetError("called with wrong number of arguments.");
  16. return false;
  17. }
  18. auto i = args.begin();
  19. std::string extraInclude;
  20. std::string function;
  21. std::vector<std::string> tests;
  22. // extract extra include and function ot
  23. for (; i != args.end(); i++) {
  24. if (*i == "EXTRA_INCLUDE") {
  25. ++i;
  26. if (i == args.end()) {
  27. this->SetError("incorrect arguments to EXTRA_INCLUDE");
  28. return false;
  29. }
  30. extraInclude = cmStrCat("#include \"", *i, "\"\n");
  31. } else if (*i == "FUNCTION") {
  32. ++i;
  33. if (i == args.end()) {
  34. this->SetError("incorrect arguments to FUNCTION");
  35. return false;
  36. }
  37. function = cmStrCat(*i, "(&ac, &av);\n");
  38. } else {
  39. tests.push_back(*i);
  40. }
  41. }
  42. i = tests.begin();
  43. // Name of the source list
  44. const char* sourceList = i->c_str();
  45. ++i;
  46. // Name of the test driver
  47. // make sure they specified an extension
  48. if (cmSystemTools::GetFilenameExtension(*i).size() < 2) {
  49. this->SetError(
  50. "You must specify a file extension for the test driver file.");
  51. return false;
  52. }
  53. std::string driver =
  54. cmStrCat(this->Makefile->GetCurrentBinaryDirectory(), '/', *i);
  55. ++i;
  56. std::string configFile = cmSystemTools::GetCMakeRoot();
  57. configFile += "/Templates/TestDriver.cxx.in";
  58. // Create the test driver file
  59. auto testsBegin = i;
  60. std::vector<std::string> tests_func_name;
  61. // The rest of the arguments consist of a list of test source files.
  62. // Sadly, they can be in directories. Let's find a unique function
  63. // name for the corresponding test, and push it to the tests_func_name
  64. // list.
  65. // For the moment:
  66. // - replace spaces ' ', ':' and '/' with underscores '_'
  67. std::string forwardDeclareCode;
  68. for (i = testsBegin; i != tests.end(); ++i) {
  69. if (*i == "EXTRA_INCLUDE") {
  70. break;
  71. }
  72. std::string func_name;
  73. if (!cmSystemTools::GetFilenamePath(*i).empty()) {
  74. func_name = cmSystemTools::GetFilenamePath(*i) + "/" +
  75. cmSystemTools::GetFilenameWithoutLastExtension(*i);
  76. } else {
  77. func_name = cmSystemTools::GetFilenameWithoutLastExtension(*i);
  78. }
  79. cmSystemTools::ConvertToUnixSlashes(func_name);
  80. std::replace(func_name.begin(), func_name.end(), ' ', '_');
  81. std::replace(func_name.begin(), func_name.end(), '/', '_');
  82. std::replace(func_name.begin(), func_name.end(), ':', '_');
  83. tests_func_name.push_back(func_name);
  84. forwardDeclareCode += "int ";
  85. forwardDeclareCode += func_name;
  86. forwardDeclareCode += "(int, char*[]);\n";
  87. }
  88. std::string functionMapCode;
  89. int numTests = 0;
  90. std::vector<std::string>::iterator j;
  91. for (i = testsBegin, j = tests_func_name.begin(); i != tests.end();
  92. ++i, ++j) {
  93. std::string func_name;
  94. if (!cmSystemTools::GetFilenamePath(*i).empty()) {
  95. func_name = cmSystemTools::GetFilenamePath(*i) + "/" +
  96. cmSystemTools::GetFilenameWithoutLastExtension(*i);
  97. } else {
  98. func_name = cmSystemTools::GetFilenameWithoutLastExtension(*i);
  99. }
  100. functionMapCode += " {\n"
  101. " \"";
  102. functionMapCode += func_name;
  103. functionMapCode += "\",\n"
  104. " ";
  105. functionMapCode += *j;
  106. functionMapCode += "\n"
  107. " },\n";
  108. numTests++;
  109. }
  110. if (!extraInclude.empty()) {
  111. this->Makefile->AddDefinition("CMAKE_TESTDRIVER_EXTRA_INCLUDES",
  112. extraInclude);
  113. }
  114. if (!function.empty()) {
  115. this->Makefile->AddDefinition("CMAKE_TESTDRIVER_ARGVC_FUNCTION", function);
  116. }
  117. this->Makefile->AddDefinition("CMAKE_FORWARD_DECLARE_TESTS",
  118. forwardDeclareCode);
  119. this->Makefile->AddDefinition("CMAKE_FUNCTION_TABLE_ENTIRES",
  120. functionMapCode);
  121. bool res = true;
  122. if (!this->Makefile->ConfigureFile(configFile, driver, false, true, false)) {
  123. res = false;
  124. }
  125. // Construct the source list.
  126. std::string sourceListValue;
  127. {
  128. cmSourceFile* sf = this->Makefile->GetOrCreateSource(driver);
  129. sf->SetProperty("ABSTRACT", "0");
  130. sourceListValue = args[1];
  131. }
  132. for (i = testsBegin; i != tests.end(); ++i) {
  133. cmSourceFile* sf = this->Makefile->GetOrCreateSource(*i);
  134. sf->SetProperty("ABSTRACT", "0");
  135. sourceListValue += ";";
  136. sourceListValue += *i;
  137. }
  138. this->Makefile->AddDefinition(sourceList, sourceListValue);
  139. return res;
  140. }