1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmTestGenerator.h"
#include <ostream>
#include <utility>
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmLocalGenerator.h"
#include "cmOutputConverter.h"
#include "cmProperty.h"
#include "cmPropertyMap.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
#include "cmTest.h"
cmTestGenerator::cmTestGenerator(
cmTest* test, std::vector<std::string> const& configurations)
: cmScriptGenerator("CTEST_CONFIGURATION_TYPE", configurations)
, Test(test)
{
this->ActionsPerConfig = !test->GetOldStyle();
this->TestGenerated = false;
this->LG = nullptr;
}
cmTestGenerator::~cmTestGenerator()
{
}
void cmTestGenerator::Compute(cmLocalGenerator* lg)
{
this->LG = lg;
}
bool cmTestGenerator::TestsForConfig(const std::string& config)
{
return this->GeneratesForConfig(config);
}
cmTest* cmTestGenerator::GetTest() const
{
return this->Test;
}
void cmTestGenerator::GenerateScriptConfigs(std::ostream& os, Indent indent)
{
// Create the tests.
this->cmScriptGenerator::GenerateScriptConfigs(os, indent);
}
void cmTestGenerator::GenerateScriptActions(std::ostream& os, Indent indent)
{
if (this->ActionsPerConfig) {
// This is the per-config generation in a single-configuration
// build generator case. The superclass will call our per-config
// method.
this->cmScriptGenerator::GenerateScriptActions(os, indent);
} else {
// This is an old-style test, so there is only one config.
// assert(this->Test->GetOldStyle());
this->GenerateOldStyle(os, indent);
}
}
void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
const std::string& config,
Indent indent)
{
this->TestGenerated = true;
// Set up generator expression evaluation context.
cmGeneratorExpression ge(this->Test->GetBacktrace());
// Start the test command.
os << indent << "add_test(" << this->Test->GetName() << " ";
// Get the test command line to be executed.
std::vector<std::string> const& command = this->Test->GetCommand();
// Check whether the command executable is a target whose name is to
// be translated.
std::string exe = command[0];
cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(exe);
if (target && target->GetType() == cmStateEnums::EXECUTABLE) {
// Use the target file on disk.
exe = target->GetFullPath(config);
// Prepend with the emulator when cross compiling if required.
const char* emulator = target->GetProperty("CROSSCOMPILING_EMULATOR");
if (emulator != nullptr) {
std::vector<std::string> emulatorWithArgs;
cmSystemTools::ExpandListArgument(emulator, emulatorWithArgs);
std::string emulatorExe(emulatorWithArgs[0]);
cmSystemTools::ConvertToUnixSlashes(emulatorExe);
os << cmOutputConverter::EscapeForCMake(emulatorExe) << " ";
for (std::vector<std::string>::const_iterator ei =
emulatorWithArgs.begin() + 1;
ei != emulatorWithArgs.end(); ++ei) {
os << cmOutputConverter::EscapeForCMake(*ei) << " ";
}
}
} else {
// Use the command name given.
exe = ge.Parse(exe)->Evaluate(this->LG, config);
cmSystemTools::ConvertToUnixSlashes(exe);
}
// Generate the command line with full escapes.
os << cmOutputConverter::EscapeForCMake(exe);
for (std::vector<std::string>::const_iterator ci = command.begin() + 1;
ci != command.end(); ++ci) {
os << " "
<< cmOutputConverter::EscapeForCMake(
ge.Parse(*ci)->Evaluate(this->LG, config));
}
// Finish the test command.
os << ")\n";
// Output properties for the test.
cmPropertyMap& pm = this->Test->GetProperties();
if (!pm.empty()) {
os << indent << "set_tests_properties(" << this->Test->GetName()
<< " PROPERTIES ";
for (auto const& i : pm) {
os << " " << i.first << " "
<< cmOutputConverter::EscapeForCMake(
ge.Parse(i.second.GetValue())->Evaluate(this->LG, config));
}
os << ")" << std::endl;
}
}
void cmTestGenerator::GenerateScriptNoConfig(std::ostream& os, Indent indent)
{
os << indent << "add_test(" << this->Test->GetName() << " NOT_AVAILABLE)\n";
}
bool cmTestGenerator::NeedsScriptNoConfig() const
{
return (this->TestGenerated && // test generated for at least one config
this->ActionsPerConfig && // test is config-aware
this->Configurations.empty() && // test runs in all configs
!this->ConfigurationTypes->empty()); // config-dependent command
}
void cmTestGenerator::GenerateOldStyle(std::ostream& fout, Indent indent)
{
this->TestGenerated = true;
// Get the test command line to be executed.
std::vector<std::string> const& command = this->Test->GetCommand();
std::string exe = command[0];
cmSystemTools::ConvertToUnixSlashes(exe);
fout << indent;
fout << "add_test(";
fout << this->Test->GetName() << " \"" << exe << "\"";
for (std::vector<std::string>::const_iterator argit = command.begin() + 1;
argit != command.end(); ++argit) {
// Just double-quote all arguments so they are re-parsed
// correctly by the test system.
fout << " \"";
for (char c : *argit) {
// Escape quotes within arguments. We should escape
// backslashes too but we cannot because it makes the result
// inconsistent with previous behavior of this command.
if (c == '"') {
fout << '\\';
}
fout << c;
}
fout << "\"";
}
fout << ")" << std::endl;
// Output properties for the test.
cmPropertyMap& pm = this->Test->GetProperties();
if (!pm.empty()) {
fout << indent << "set_tests_properties(" << this->Test->GetName()
<< " PROPERTIES ";
for (auto const& i : pm) {
fout << " " << i.first << " "
<< cmOutputConverter::EscapeForCMake(i.second.GetValue());
}
fout << ")" << std::endl;
}
}
|