cmCreateTestSourceList.cxx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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
  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 = cmStrCat(cmSystemTools::GetFilenamePath(*i), '/',
  74. cmSystemTools::GetFilenameWithoutLastExtension(*i));
  75. } else {
  76. func_name = cmSystemTools::GetFilenameWithoutLastExtension(*i);
  77. }
  78. cmSystemTools::ConvertToUnixSlashes(func_name);
  79. func_name = cmSystemTools::MakeCidentifier(func_name);
  80. bool already_declared =
  81. std::find(tests_func_name.begin(), tests_func_name.end(), func_name) !=
  82. tests_func_name.end();
  83. tests_func_name.push_back(func_name);
  84. if (!already_declared) {
  85. forwardDeclareCode += cmStrCat("int ", func_name, "(int, char*[]);\n");
  86. }
  87. }
  88. std::string functionMapCode;
  89. std::vector<std::string>::iterator j;
  90. for (i = testsBegin, j = tests_func_name.begin(); i != tests.end();
  91. ++i, ++j) {
  92. std::string func_name;
  93. if (!cmSystemTools::GetFilenamePath(*i).empty()) {
  94. func_name = cmStrCat(cmSystemTools::GetFilenamePath(*i), '/',
  95. cmSystemTools::GetFilenameWithoutLastExtension(*i));
  96. } else {
  97. func_name = cmSystemTools::GetFilenameWithoutLastExtension(*i);
  98. }
  99. functionMapCode += " {\n"
  100. " \"";
  101. functionMapCode += func_name;
  102. functionMapCode += "\",\n"
  103. " ";
  104. functionMapCode += *j;
  105. functionMapCode += "\n"
  106. " },\n";
  107. }
  108. if (!extraInclude.empty()) {
  109. mf.AddDefinition("CMAKE_TESTDRIVER_EXTRA_INCLUDES", extraInclude);
  110. }
  111. if (!function.empty()) {
  112. mf.AddDefinition("CMAKE_TESTDRIVER_ARGVC_FUNCTION", function);
  113. }
  114. mf.AddDefinition("CMAKE_FORWARD_DECLARE_TESTS", forwardDeclareCode);
  115. mf.AddDefinition("CMAKE_FUNCTION_TABLE_ENTRIES", functionMapCode);
  116. bool res = true;
  117. if (!mf.ConfigureFile(configFile, driver, false, true, false)) {
  118. res = false;
  119. }
  120. // Construct the source list.
  121. std::string sourceListValue;
  122. {
  123. cmSourceFile* sf = mf.GetOrCreateSource(driver);
  124. sf->SetProperty("ABSTRACT", "0");
  125. sourceListValue = driver;
  126. }
  127. for (i = testsBegin; i != tests.end(); ++i) {
  128. cmSourceFile* sf = mf.GetOrCreateSource(*i);
  129. sf->SetProperty("ABSTRACT", "0");
  130. sourceListValue += ';';
  131. sourceListValue += *i;
  132. }
  133. mf.AddDefinition(sourceList, sourceListValue);
  134. return res;
  135. }