|
|
@@ -0,0 +1,196 @@
|
|
|
+/*=========================================================================
|
|
|
+
|
|
|
+ Program: CMake - Cross-Platform Makefile Generator
|
|
|
+ Module: $RCSfile$
|
|
|
+ Language: C++
|
|
|
+ Date: $Date$
|
|
|
+ Version: $Revision$
|
|
|
+
|
|
|
+ Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
|
|
|
+ See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
|
|
|
+
|
|
|
+ This software is distributed WITHOUT ANY WARRANTY; without even
|
|
|
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
|
+ PURPOSE. See the above copyright notices 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("^\\$<TARGET"
|
|
|
+ "(|_SONAME|_LINKER)" // File with what purpose?
|
|
|
+ "_FILE(|_NAME|_DIR):" // Filename component.
|
|
|
+ "([A-Za-z0-9_-]+)" // Target name.
|
|
|
+ ">$");
|
|
|
+}
|
|
|
+
|
|
|
+//----------------------------------------------------------------------------
|
|
|
+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, "$<CONFIGURATION>") == 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;
|
|
|
+}
|