cmCreateTestSourceList.cxx 4.7 KB

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