/*============================================================================ CMake - Cross Platform Makefile Generator Copyright 2000-2009 Kitware, Inc., Insight Software Consortium Distributed under the OSI-approved BSD License (the "License"); see accompanying file Copyright.txt for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more information. ============================================================================*/ #include "cmGeneratorExpression.h" #include "cmMakefile.h" #include "cmTarget.h" //---------------------------------------------------------------------------- cmGeneratorExpression::cmGeneratorExpression( cmMakefile* mf, const char* config, cmListFileBacktrace const& backtrace): Makefile(mf), Config(config), Backtrace(backtrace) { this->TargetInfo.compile("^\\$$"); } //---------------------------------------------------------------------------- const char* cmGeneratorExpression::Process(std::string const& input) { return this->Process(input.c_str()); } //---------------------------------------------------------------------------- const char* cmGeneratorExpression::Process(const char* input) { this->Data.clear(); // We construct and evaluate expressions directly in the output // buffer. Each expression is replaced by its own output value // after evaluation. A stack of barriers records the starting // indices of open (pending) expressions. for(const char* c = input; *c; ++c) { if(c[0] == '$' && c[1] == '<') { this->Barriers.push(this->Data.size()); this->Data.push_back('$'); this->Data.push_back('<'); c += 1; } else if(c[0] == '>' && !this->Barriers.empty()) { this->Data.push_back('>'); if(!this->Evaluate()) { break; } this->Barriers.pop(); } else { this->Data.push_back(c[0]); } } // Return a null-terminated output value. this->Data.push_back('\0'); return &*this->Data.begin(); } //---------------------------------------------------------------------------- bool cmGeneratorExpression::Evaluate() { // The top-most barrier points at the beginning of the expression. size_t barrier = this->Barriers.top(); // Construct a null-terminated representation of the expression. this->Data.push_back('\0'); const char* expr = &*(this->Data.begin()+barrier); // Evaluate the expression. std::string result; if(this->Evaluate(expr, result)) { // Success. Replace the expression with its evaluation result. this->Data.erase(this->Data.begin()+barrier, this->Data.end()); this->Data.insert(this->Data.end(), result.begin(), result.end()); return true; } else { // Failure. Report the error message. cmOStringStream e; e << "Error evaluating generator expression:\n" << " " << expr << "\n" << result; this->Makefile->GetCMakeInstance() ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(), this->Backtrace); return false; } } //---------------------------------------------------------------------------- bool cmGeneratorExpression::Evaluate(const char* expr, std::string& result) { if(this->TargetInfo.find(expr)) { if(!this->EvaluateTargetInfo(result)) { return false; } } else if(strcmp(expr, "$") == 0) { result = this->Config? this->Config : ""; } else { result = "Expression syntax not recognized."; return false; } return true; } //---------------------------------------------------------------------------- bool cmGeneratorExpression::EvaluateTargetInfo(std::string& result) { // Lookup the referenced target. std::string name = this->TargetInfo.match(3); cmTarget* target = this->Makefile->FindTargetToUse(name.c_str()); if(!target) { result = "No target \"" + name + "\""; return false; } if(target->GetType() >= cmTarget::UTILITY && target->GetType() != cmTarget::UNKNOWN_LIBRARY) { result = "Target \"" + name + "\" is not an executable or library."; return false; } // Lookup the target file with the given purpose. std::string purpose = this->TargetInfo.match(1); if(purpose == "") { // The target implementation file (.so.1.2, .dll, .exe, .a). result = target->GetFullPath(this->Config, false, true); } else if(purpose == "_LINKER") { // The file used to link to the target (.so, .lib, .a). if(!target->IsLinkable()) { result = ("TARGET_LINKER_FILE is allowed only for libraries and " "executables with ENABLE_EXPORTS."); return false; } result = target->GetFullPath(this->Config, target->HasImportLibrary()); } else if(purpose == "_SONAME") { // The target soname file (.so.1). if(target->IsDLLPlatform()) { result = "TARGET_SONAME_FILE is not allowed for DLL target platforms."; return false; } if(target->GetType() != cmTarget::SHARED_LIBRARY) { result = "TARGET_SONAME_FILE is allowed only for SHARED libraries."; return false; } result = target->GetDirectory(this->Config); result += "/"; result += target->GetSOName(this->Config); } // Extract the requested portion of the full path. std::string part = this->TargetInfo.match(2); if(part == "_NAME") { result = cmSystemTools::GetFilenameName(result); } else if(part == "_DIR") { result = cmSystemTools::GetFilenamePath(result); } return true; }