Introduce "generator expressions" to add_test()
[cmake.git] / Source / cmLocalVisualStudioGenerator.cxx
blobe59293e36c50297b1796dfb1d4b4e187ad585423
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmLocalVisualStudioGenerator.cxx,v $
5 Language: C++
6 Date: $Date: 2009-07-10 13:12:37 $
7 Version: $Revision: 1.18 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmLocalVisualStudioGenerator.h"
18 #include "cmGlobalGenerator.h"
19 #include "cmMakefile.h"
20 #include "cmSourceFile.h"
21 #include "cmSystemTools.h"
22 #include "windows.h"
24 //----------------------------------------------------------------------------
25 cmLocalVisualStudioGenerator::cmLocalVisualStudioGenerator()
27 this->WindowsShell = true;
28 this->WindowsVSIDE = true;
29 this->NeedXMLEscape = false;
32 //----------------------------------------------------------------------------
33 cmLocalVisualStudioGenerator::~cmLocalVisualStudioGenerator()
37 //----------------------------------------------------------------------------
38 cmsys::auto_ptr<cmCustomCommand>
39 cmLocalVisualStudioGenerator::MaybeCreateImplibDir(cmTarget& target,
40 const char* config)
42 cmsys::auto_ptr<cmCustomCommand> pcc;
44 // If an executable exports symbols then VS wants to create an
45 // import library but forgets to create the output directory.
46 if(target.GetType() != cmTarget::EXECUTABLE) { return pcc; }
47 std::string outDir = target.GetDirectory(config, false);
48 std::string impDir = target.GetDirectory(config, true);
49 if(impDir == outDir) { return pcc; }
51 // Add a pre-build event to create the directory.
52 cmCustomCommandLine command;
53 command.push_back(this->Makefile->GetRequiredDefinition("CMAKE_COMMAND"));
54 command.push_back("-E");
55 command.push_back("make_directory");
56 command.push_back(impDir);
57 std::vector<std::string> no_output;
58 std::vector<std::string> no_depends;
59 cmCustomCommandLines commands;
60 commands.push_back(command);
61 pcc.reset(new cmCustomCommand(no_output, no_depends, commands, 0, 0));
62 pcc->SetEscapeOldStyle(false);
63 pcc->SetEscapeAllowMakeVars(true);
64 return pcc;
67 //----------------------------------------------------------------------------
68 bool cmLocalVisualStudioGenerator::SourceFileCompiles(const cmSourceFile* sf)
70 // Identify the language of the source file.
71 if(const char* lang = this->GetSourceFileLanguage(*sf))
73 // Check whether this source will actually be compiled.
74 return (!sf->GetCustomCommand() &&
75 !sf->GetPropertyAsBool("HEADER_FILE_ONLY") &&
76 !sf->GetPropertyAsBool("EXTERNAL_OBJECT"));
78 else
80 // Unknown source file language. Assume it will not be compiled.
81 return false;
85 //----------------------------------------------------------------------------
86 void cmLocalVisualStudioGenerator::CountObjectNames(
87 const std::vector<cmSourceGroup>& groups,
88 std::map<cmStdString, int>& counts)
90 for(unsigned int i = 0; i < groups.size(); ++i)
92 cmSourceGroup sg = groups[i];
93 std::vector<const cmSourceFile*> const& srcs = sg.GetSourceFiles();
94 for(std::vector<const cmSourceFile*>::const_iterator s = srcs.begin();
95 s != srcs.end(); ++s)
97 const cmSourceFile* sf = *s;
98 if(this->SourceFileCompiles(sf))
100 std::string objectName = cmSystemTools::LowerCase(
101 cmSystemTools::GetFilenameWithoutLastExtension(
102 sf->GetFullPath()));
103 objectName += ".obj";
104 counts[objectName] += 1;
107 this->CountObjectNames(sg.GetGroupChildren(), counts);
111 //----------------------------------------------------------------------------
112 void cmLocalVisualStudioGenerator::InsertNeedObjectNames(
113 const std::vector<cmSourceGroup>& groups,
114 std::map<cmStdString, int>& count)
116 for(unsigned int i = 0; i < groups.size(); ++i)
118 cmSourceGroup sg = groups[i];
119 std::vector<const cmSourceFile*> const& srcs = sg.GetSourceFiles();
120 for(std::vector<const cmSourceFile*>::const_iterator s = srcs.begin();
121 s != srcs.end(); ++s)
123 const cmSourceFile* sf = *s;
124 if(this->SourceFileCompiles(sf))
126 std::string objectName = cmSystemTools::LowerCase(
127 cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath()));
128 objectName += ".obj";
129 if(count[objectName] > 1)
131 this->NeedObjectName.insert(sf);
135 this->InsertNeedObjectNames(sg.GetGroupChildren(), count);
140 //----------------------------------------------------------------------------
141 void cmLocalVisualStudioGenerator::ComputeObjectNameRequirements
142 (std::vector<cmSourceGroup> const& sourceGroups)
144 // Clear the current set of requirements.
145 this->NeedObjectName.clear();
147 // Count the number of object files with each name. Note that
148 // windows file names are not case sensitive.
149 std::map<cmStdString, int> objectNameCounts;
150 this->CountObjectNames(sourceGroups, objectNameCounts);
152 // For all source files producing duplicate names we need unique
153 // object name computation.
154 this->InsertNeedObjectNames(sourceGroups, objectNameCounts);
157 //----------------------------------------------------------------------------
158 std::string
159 cmLocalVisualStudioGenerator
160 ::ConstructScript(const cmCustomCommandLines& commandLines,
161 const char* workingDirectory,
162 const char* configName,
163 bool escapeOldStyle,
164 bool escapeAllowMakeVars,
165 const char* newline_text)
167 // Avoid leading or trailing newlines.
168 const char* newline = "";
170 // Store the script in a string.
171 std::string script;
172 if(workingDirectory)
174 // Change the working directory.
175 script += newline;
176 newline = newline_text;
177 script += "cd ";
178 script += this->Convert(workingDirectory, START_OUTPUT, SHELL);
180 // Change the working drive.
181 if(workingDirectory[0] && workingDirectory[1] == ':')
183 script += newline;
184 newline = newline_text;
185 script += workingDirectory[0];
186 script += workingDirectory[1];
189 // for visual studio IDE add extra stuff to the PATH
190 // if CMAKE_MSVCIDE_RUN_PATH is set.
191 if(this->Makefile->GetDefinition("MSVC_IDE"))
193 const char* extraPath =
194 this->Makefile->GetDefinition("CMAKE_MSVCIDE_RUN_PATH");
195 if(extraPath)
197 script += newline;
198 newline = newline_text;
199 script += "set PATH=";
200 script += extraPath;
201 script += ";%PATH%";
204 // Write each command on a single line.
205 for(cmCustomCommandLines::const_iterator cl = commandLines.begin();
206 cl != commandLines.end(); ++cl)
208 // Start a new line.
209 script += newline;
210 newline = newline_text;
212 // Start with the command name.
213 const cmCustomCommandLine& commandLine = *cl;
214 std::string commandName = this->GetRealLocation(commandLine[0].c_str(),
215 configName);
216 if(!workingDirectory)
218 script += this->Convert(commandName.c_str(),START_OUTPUT,SHELL);
220 else
222 script += this->Convert(commandName.c_str(),NONE,SHELL);
225 // Add the arguments.
226 for(unsigned int j=1;j < commandLine.size(); ++j)
228 script += " ";
229 if(escapeOldStyle)
231 script += this->EscapeForShellOldStyle(commandLine[j].c_str());
233 else
235 if(this->NeedXMLEscape)
237 std::string arg = commandLine[j];
238 cmSystemTools::ReplaceString(arg, "&", "&amp;");
239 cmSystemTools::ReplaceString(arg, "<", "&lt;");
240 cmSystemTools::ReplaceString(arg, ">", "&gt;");
241 if(arg.find(" ") != arg.npos)
243 std::string q("\"");
244 arg = q + arg +q;
246 script += arg;
247 //script += this->EscapeForShell(arg.c_str(),
248 //escapeAllowMakeVars);
250 else
252 script += this->EscapeForShell(commandLine[j].c_str(),
253 escapeAllowMakeVars);
258 return script;