1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmLocalVisualStudioGenerator.cxx,v $
6 Date: $Date: 2009-09-07 14:11:15 $
7 Version: $Revision: 1.19 $
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;
31 //----------------------------------------------------------------------------
32 cmLocalVisualStudioGenerator::~cmLocalVisualStudioGenerator()
36 //----------------------------------------------------------------------------
37 cmsys::auto_ptr
<cmCustomCommand
>
38 cmLocalVisualStudioGenerator::MaybeCreateImplibDir(cmTarget
& target
,
41 cmsys::auto_ptr
<cmCustomCommand
> pcc
;
43 // If an executable exports symbols then VS wants to create an
44 // import library but forgets to create the output directory.
45 if(target
.GetType() != cmTarget::EXECUTABLE
) { return pcc
; }
46 std::string outDir
= target
.GetDirectory(config
, false);
47 std::string impDir
= target
.GetDirectory(config
, true);
48 if(impDir
== outDir
) { return pcc
; }
50 // Add a pre-build event to create the directory.
51 cmCustomCommandLine command
;
52 command
.push_back(this->Makefile
->GetRequiredDefinition("CMAKE_COMMAND"));
53 command
.push_back("-E");
54 command
.push_back("make_directory");
55 command
.push_back(impDir
);
56 std::vector
<std::string
> no_output
;
57 std::vector
<std::string
> no_depends
;
58 cmCustomCommandLines commands
;
59 commands
.push_back(command
);
60 pcc
.reset(new cmCustomCommand(no_output
, no_depends
, commands
, 0, 0));
61 pcc
->SetEscapeOldStyle(false);
62 pcc
->SetEscapeAllowMakeVars(true);
66 //----------------------------------------------------------------------------
67 bool cmLocalVisualStudioGenerator::SourceFileCompiles(const cmSourceFile
* sf
)
69 // Identify the language of the source file.
70 if(const char* lang
= this->GetSourceFileLanguage(*sf
))
72 // Check whether this source will actually be compiled.
73 return (!sf
->GetCustomCommand() &&
74 !sf
->GetPropertyAsBool("HEADER_FILE_ONLY") &&
75 !sf
->GetPropertyAsBool("EXTERNAL_OBJECT"));
79 // Unknown source file language. Assume it will not be compiled.
84 //----------------------------------------------------------------------------
85 void cmLocalVisualStudioGenerator::CountObjectNames(
86 const std::vector
<cmSourceGroup
>& groups
,
87 std::map
<cmStdString
, int>& counts
)
89 for(unsigned int i
= 0; i
< groups
.size(); ++i
)
91 cmSourceGroup sg
= groups
[i
];
92 std::vector
<const cmSourceFile
*> const& srcs
= sg
.GetSourceFiles();
93 for(std::vector
<const cmSourceFile
*>::const_iterator s
= srcs
.begin();
96 const cmSourceFile
* sf
= *s
;
97 if(this->SourceFileCompiles(sf
))
99 std::string objectName
= cmSystemTools::LowerCase(
100 cmSystemTools::GetFilenameWithoutLastExtension(
102 objectName
+= ".obj";
103 counts
[objectName
] += 1;
106 this->CountObjectNames(sg
.GetGroupChildren(), counts
);
110 //----------------------------------------------------------------------------
111 void cmLocalVisualStudioGenerator::InsertNeedObjectNames(
112 const std::vector
<cmSourceGroup
>& groups
,
113 std::map
<cmStdString
, int>& count
)
115 for(unsigned int i
= 0; i
< groups
.size(); ++i
)
117 cmSourceGroup sg
= groups
[i
];
118 std::vector
<const cmSourceFile
*> const& srcs
= sg
.GetSourceFiles();
119 for(std::vector
<const cmSourceFile
*>::const_iterator s
= srcs
.begin();
120 s
!= srcs
.end(); ++s
)
122 const cmSourceFile
* sf
= *s
;
123 if(this->SourceFileCompiles(sf
))
125 std::string objectName
= cmSystemTools::LowerCase(
126 cmSystemTools::GetFilenameWithoutLastExtension(sf
->GetFullPath()));
127 objectName
+= ".obj";
128 if(count
[objectName
] > 1)
130 this->NeedObjectName
.insert(sf
);
134 this->InsertNeedObjectNames(sg
.GetGroupChildren(), count
);
139 //----------------------------------------------------------------------------
140 void cmLocalVisualStudioGenerator::ComputeObjectNameRequirements
141 (std::vector
<cmSourceGroup
> const& sourceGroups
)
143 // Clear the current set of requirements.
144 this->NeedObjectName
.clear();
146 // Count the number of object files with each name. Note that
147 // windows file names are not case sensitive.
148 std::map
<cmStdString
, int> objectNameCounts
;
149 this->CountObjectNames(sourceGroups
, objectNameCounts
);
151 // For all source files producing duplicate names we need unique
152 // object name computation.
153 this->InsertNeedObjectNames(sourceGroups
, objectNameCounts
);
156 //----------------------------------------------------------------------------
158 cmLocalVisualStudioGenerator
159 ::ConstructScript(const cmCustomCommandLines
& commandLines
,
160 const char* workingDirectory
,
161 const char* configName
,
163 bool escapeAllowMakeVars
,
164 const char* newline_text
)
166 // Avoid leading or trailing newlines.
167 const char* newline
= "";
169 // Store the script in a string.
173 // Change the working directory.
175 newline
= newline_text
;
177 script
+= this->Convert(workingDirectory
, START_OUTPUT
, SHELL
);
179 // Change the working drive.
180 if(workingDirectory
[0] && workingDirectory
[1] == ':')
183 newline
= newline_text
;
184 script
+= workingDirectory
[0];
185 script
+= workingDirectory
[1];
188 // for visual studio IDE add extra stuff to the PATH
189 // if CMAKE_MSVCIDE_RUN_PATH is set.
190 if(this->Makefile
->GetDefinition("MSVC_IDE"))
192 const char* extraPath
=
193 this->Makefile
->GetDefinition("CMAKE_MSVCIDE_RUN_PATH");
197 newline
= newline_text
;
198 script
+= "set PATH=";
203 // Write each command on a single line.
204 for(cmCustomCommandLines::const_iterator cl
= commandLines
.begin();
205 cl
!= commandLines
.end(); ++cl
)
209 newline
= newline_text
;
211 // Start with the command name.
212 const cmCustomCommandLine
& commandLine
= *cl
;
213 std::string commandName
= this->GetRealLocation(commandLine
[0].c_str(),
215 if(!workingDirectory
)
217 script
+= this->Convert(commandName
.c_str(),START_OUTPUT
,SHELL
);
221 script
+= this->Convert(commandName
.c_str(),NONE
,SHELL
);
224 // Add the arguments.
225 for(unsigned int j
=1;j
< commandLine
.size(); ++j
)
230 script
+= this->EscapeForShellOldStyle(commandLine
[j
].c_str());
234 script
+= this->EscapeForShell(commandLine
[j
].c_str(),
235 escapeAllowMakeVars
);