1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmLocalVisualStudioGenerator.cxx,v $
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"
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
,
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);
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"));
80 // Unknown source file language. Assume it will not be compiled.
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();
97 const cmSourceFile
* sf
= *s
;
98 if(this->SourceFileCompiles(sf
))
100 std::string objectName
= cmSystemTools::LowerCase(
101 cmSystemTools::GetFilenameWithoutLastExtension(
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 //----------------------------------------------------------------------------
159 cmLocalVisualStudioGenerator
160 ::ConstructScript(const cmCustomCommandLines
& commandLines
,
161 const char* workingDirectory
,
162 const char* configName
,
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.
174 // Change the working directory.
176 newline
= newline_text
;
178 script
+= this->Convert(workingDirectory
, START_OUTPUT
, SHELL
);
180 // Change the working drive.
181 if(workingDirectory
[0] && workingDirectory
[1] == ':')
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");
198 newline
= newline_text
;
199 script
+= "set PATH=";
204 // Write each command on a single line.
205 for(cmCustomCommandLines::const_iterator cl
= commandLines
.begin();
206 cl
!= commandLines
.end(); ++cl
)
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(),
216 if(!workingDirectory
)
218 script
+= this->Convert(commandName
.c_str(),START_OUTPUT
,SHELL
);
222 script
+= this->Convert(commandName
.c_str(),NONE
,SHELL
);
225 // Add the arguments.
226 for(unsigned int j
=1;j
< commandLine
.size(); ++j
)
231 script
+= this->EscapeForShellOldStyle(commandLine
[j
].c_str());
235 if(this->NeedXMLEscape
)
237 std::string arg
= commandLine
[j
];
238 cmSystemTools::ReplaceString(arg
, "&", "&");
239 cmSystemTools::ReplaceString(arg
, "<", "<");
240 cmSystemTools::ReplaceString(arg
, ">", ">");
241 if(arg
.find(" ") != arg
.npos
)
247 //script += this->EscapeForShell(arg.c_str(),
248 //escapeAllowMakeVars);
252 script
+= this->EscapeForShell(commandLine
[j
].c_str(),
253 escapeAllowMakeVars
);