1
/*============================================================================
2
CMake - Cross Platform Makefile Generator
3
Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
5
Distributed under the OSI-approved BSD License (the "License");
6
see accompanying file Copyright.txt for details.
8
This software is distributed WITHOUT ANY WARRANTY; without even the
9
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
See the License for more information.
11
============================================================================*/
12
#include "cmGeneratorExpression.h"
14
#include "cmMakefile.h"
17
//----------------------------------------------------------------------------
18
cmGeneratorExpression::cmGeneratorExpression(
19
cmMakefile* mf, const char* config,
20
cmListFileBacktrace const& backtrace):
21
Makefile(mf), Config(config), Backtrace(backtrace)
23
this->TargetInfo.compile("^\\$<TARGET"
24
"(|_SONAME|_LINKER)" // File with what purpose?
25
"_FILE(|_NAME|_DIR):" // Filename component.
26
"([A-Za-z0-9_-]+)" // Target name.
30
//----------------------------------------------------------------------------
31
const char* cmGeneratorExpression::Process(std::string const& input)
33
return this->Process(input.c_str());
36
//----------------------------------------------------------------------------
37
const char* cmGeneratorExpression::Process(const char* input)
41
// We construct and evaluate expressions directly in the output
42
// buffer. Each expression is replaced by its own output value
43
// after evaluation. A stack of barriers records the starting
44
// indices of open (pending) expressions.
45
for(const char* c = input; *c; ++c)
47
if(c[0] == '$' && c[1] == '<')
49
this->Barriers.push(this->Data.size());
50
this->Data.push_back('$');
51
this->Data.push_back('<');
54
else if(c[0] == '>' && !this->Barriers.empty())
56
this->Data.push_back('>');
57
if(!this->Evaluate()) { break; }
62
this->Data.push_back(c[0]);
66
// Return a null-terminated output value.
67
this->Data.push_back('\0');
68
return &*this->Data.begin();
71
//----------------------------------------------------------------------------
72
bool cmGeneratorExpression::Evaluate()
74
// The top-most barrier points at the beginning of the expression.
75
size_t barrier = this->Barriers.top();
77
// Construct a null-terminated representation of the expression.
78
this->Data.push_back('\0');
79
const char* expr = &*(this->Data.begin()+barrier);
81
// Evaluate the expression.
83
if(this->Evaluate(expr, result))
85
// Success. Replace the expression with its evaluation result.
86
this->Data.erase(this->Data.begin()+barrier, this->Data.end());
87
this->Data.insert(this->Data.end(), result.begin(), result.end());
92
// Failure. Report the error message.
94
e << "Error evaluating generator expression:\n"
95
<< " " << expr << "\n"
97
this->Makefile->GetCMakeInstance()
98
->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
104
//----------------------------------------------------------------------------
105
bool cmGeneratorExpression::Evaluate(const char* expr, std::string& result)
107
if(this->TargetInfo.find(expr))
109
if(!this->EvaluateTargetInfo(result))
114
else if(strcmp(expr, "$<CONFIGURATION>") == 0)
116
result = this->Config? this->Config : "";
120
result = "Expression syntax not recognized.";
126
//----------------------------------------------------------------------------
127
bool cmGeneratorExpression::EvaluateTargetInfo(std::string& result)
129
// Lookup the referenced target.
130
std::string name = this->TargetInfo.match(3);
131
cmTarget* target = this->Makefile->FindTargetToUse(name.c_str());
134
result = "No target \"" + name + "\"";
137
if(target->GetType() >= cmTarget::UTILITY &&
138
target->GetType() != cmTarget::UNKNOWN_LIBRARY)
140
result = "Target \"" + name + "\" is not an executable or library.";
144
// Lookup the target file with the given purpose.
145
std::string purpose = this->TargetInfo.match(1);
148
// The target implementation file (.so.1.2, .dll, .exe, .a).
149
result = target->GetFullPath(this->Config, false, true);
151
else if(purpose == "_LINKER")
153
// The file used to link to the target (.so, .lib, .a).
154
if(!target->IsLinkable())
156
result = ("TARGET_LINKER_FILE is allowed only for libraries and "
157
"executables with ENABLE_EXPORTS.");
160
result = target->GetFullPath(this->Config, target->HasImportLibrary());
162
else if(purpose == "_SONAME")
164
// The target soname file (.so.1).
165
if(target->IsDLLPlatform())
167
result = "TARGET_SONAME_FILE is not allowed for DLL target platforms.";
170
if(target->GetType() != cmTarget::SHARED_LIBRARY)
172
result = "TARGET_SONAME_FILE is allowed only for SHARED libraries.";
175
result = target->GetDirectory(this->Config);
177
result += target->GetSOName(this->Config);
180
// Extract the requested portion of the full path.
181
std::string part = this->TargetInfo.match(2);
184
result = cmSystemTools::GetFilenameName(result);
186
else if(part == "_DIR")
188
result = cmSystemTools::GetFilenamePath(result);