f65add19bf23d2436de4f0af394b2120c3d0880f
[platform/upstream/cmake.git] / Source / cmLocalVisualStudio7Generator.cxx
1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3 #include "cmLocalVisualStudio7Generator.h"
4
5 #include <algorithm>
6 #include <cassert>
7 #include <cstring>
8 #include <functional>
9 #include <sstream>
10 #include <utility>
11
12 #include <cm/memory>
13 #include <cmext/algorithm>
14
15 #include <windows.h>
16
17 #include <cm3p/expat.h>
18
19 #include "cmsys/FStream.hxx"
20
21 #include "cmComputeLinkInformation.h"
22 #include "cmCustomCommand.h"
23 #include "cmCustomCommandGenerator.h"
24 #include "cmCustomCommandLines.h"
25 #include "cmGeneratedFileStream.h"
26 #include "cmGeneratorExpression.h"
27 #include "cmGeneratorTarget.h"
28 #include "cmGlobalGenerator.h"
29 #include "cmGlobalVisualStudio7Generator.h"
30 #include "cmGlobalVisualStudioGenerator.h"
31 #include "cmListFileCache.h"
32 #include "cmMakefile.h"
33 #include "cmOutputConverter.h"
34 #include "cmPolicies.h"
35 #include "cmSourceFile.h"
36 #include "cmSourceGroup.h"
37 #include "cmStateTypes.h"
38 #include "cmStringAlgorithms.h"
39 #include "cmSystemTools.h"
40 #include "cmTarget.h"
41 #include "cmTargetDepend.h"
42 #include "cmValue.h"
43 #include "cmVsProjectType.h"
44 #include "cmXMLParser.h"
45 #include "cmake.h"
46
47 static bool cmLVS7G_IsFAT(const char* dir);
48
49 class cmLocalVisualStudio7GeneratorInternals
50 {
51 public:
52   cmLocalVisualStudio7GeneratorInternals(cmLocalVisualStudio7Generator* e)
53     : LocalGenerator(e)
54   {
55   }
56   using ItemVector = cmComputeLinkInformation::ItemVector;
57   void OutputLibraries(std::ostream& fout, ItemVector const& libs);
58   void OutputObjects(std::ostream& fout, cmGeneratorTarget* t,
59                      std::string const& config, const char* isep = 0);
60
61 private:
62   cmLocalVisualStudio7Generator* LocalGenerator;
63 };
64
65 class cmLocalVisualStudio7Generator::AllConfigSources
66 {
67 public:
68   std::vector<cmGeneratorTarget::AllConfigSource> Sources;
69   std::map<cmSourceFile const*, size_t> Index;
70 };
71
72 extern cmVS7FlagTable cmLocalVisualStudio7GeneratorFlagTable[];
73
74 cmLocalVisualStudio7Generator::cmLocalVisualStudio7Generator(
75   cmGlobalGenerator* gg, cmMakefile* mf)
76   : cmLocalVisualStudioGenerator(gg, mf)
77   , Internal(cm::make_unique<cmLocalVisualStudio7GeneratorInternals>(this))
78 {
79 }
80
81 cmLocalVisualStudio7Generator::~cmLocalVisualStudio7Generator() = default;
82
83 void cmLocalVisualStudio7Generator::AddHelperCommands()
84 {
85   // Now create GUIDs for targets
86   const auto& tgts = this->GetGeneratorTargets();
87   for (const auto& l : tgts) {
88     if (!l->IsInBuildSystem()) {
89       continue;
90     }
91     cmValue path = l->GetProperty("EXTERNAL_MSPROJECT");
92     if (path) {
93       this->ReadAndStoreExternalGUID(l->GetName(), path->c_str());
94     }
95   }
96
97   this->FixGlobalTargets();
98 }
99
100 void cmLocalVisualStudio7Generator::Generate()
101 {
102   // Create the project file for each target.
103   for (cmGeneratorTarget* gt :
104        this->GlobalGenerator->GetLocalGeneratorTargetsInOrder(this)) {
105     if (!gt->IsInBuildSystem() || gt->GetProperty("EXTERNAL_MSPROJECT")) {
106       continue;
107     }
108
109     auto& gtVisited = this->GetSourcesVisited(gt);
110     auto& deps = this->GlobalGenerator->GetTargetDirectDepends(gt);
111     for (auto& d : deps) {
112       // Take the union of visited source files of custom commands
113       auto depVisited = this->GetSourcesVisited(d);
114       gtVisited.insert(depVisited.begin(), depVisited.end());
115     }
116
117     this->GenerateTarget(gt);
118   }
119
120   this->WriteStampFiles();
121 }
122
123 void cmLocalVisualStudio7Generator::FixGlobalTargets()
124 {
125   // Visual Studio .NET 2003 Service Pack 1 will not run post-build
126   // commands for targets in which no sources are built.  Add dummy
127   // rules to force these targets to build.
128   const auto& tgts = this->GetGeneratorTargets();
129   for (auto& l : tgts) {
130     if (l->GetType() == cmStateEnums::GLOBAL_TARGET) {
131       cmCustomCommandLines force_commands =
132         cmMakeSingleCommandLine({ "cd", "." });
133       std::string force = cmStrCat(this->GetCurrentBinaryDirectory(),
134                                    "/CMakeFiles/", l->GetName(), "_force");
135       if (cmSourceFile* sf =
136             this->Makefile->GetOrCreateGeneratedSource(force)) {
137         sf->SetProperty("SYMBOLIC", "1");
138       }
139       auto cc = cm::make_unique<cmCustomCommand>();
140       cc->SetOutputs(force);
141       cc->SetCommandLines(force_commands);
142       cc->SetComment(" ");
143       cc->SetCMP0116Status(cmPolicies::NEW);
144       if (cmSourceFile* file =
145             this->AddCustomCommandToOutput(std::move(cc), true)) {
146         l->AddSource(file->ResolveFullPath());
147       }
148     }
149   }
150 }
151
152 void cmLocalVisualStudio7Generator::WriteStampFiles()
153 {
154   // Touch a timestamp file used to determine when the project file is
155   // out of date.
156   std::string stampName =
157     cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles");
158   cmSystemTools::MakeDirectory(stampName);
159   stampName += "/generate.stamp";
160   cmsys::ofstream stamp(stampName.c_str());
161   stamp << "# CMake generation timestamp file for this directory.\n";
162
163   // Create a helper file so CMake can determine when it is run
164   // through the rule created by CreateVCProjBuildRule whether it
165   // really needs to regenerate the project.  This file lists its own
166   // dependencies.  If any file listed in it is newer than itself then
167   // CMake must rerun.  Otherwise the project files are up to date and
168   // the stamp file can just be touched.
169   std::string depName = cmStrCat(stampName, ".depend");
170   cmsys::ofstream depFile(depName.c_str());
171   depFile << "# CMake generation dependency list for this directory.\n";
172
173   std::vector<std::string> listFiles(this->Makefile->GetListFiles());
174   cmake* cm = this->GlobalGenerator->GetCMakeInstance();
175   if (cm->DoWriteGlobVerifyTarget()) {
176     listFiles.push_back(cm->GetGlobVerifyStamp());
177   }
178
179   // Sort the list of input files and remove duplicates.
180   std::sort(listFiles.begin(), listFiles.end(), std::less<std::string>());
181   std::vector<std::string>::iterator new_end =
182     std::unique(listFiles.begin(), listFiles.end());
183   listFiles.erase(new_end, listFiles.end());
184
185   for (const std::string& lf : listFiles) {
186     depFile << lf << "\n";
187   }
188 }
189
190 void cmLocalVisualStudio7Generator::GenerateTarget(cmGeneratorTarget* target)
191 {
192   std::string const& lname = target->GetName();
193   cmGlobalVisualStudioGenerator* gg =
194     static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator);
195   this->FortranProject = gg->TargetIsFortranOnly(target);
196   this->WindowsCEProject = gg->TargetsWindowsCE();
197
198   // Intel Fortran for VS10 uses VS9 format ".vfproj" files.
199   cmGlobalVisualStudioGenerator::VSVersion realVersion = gg->GetVersion();
200   if (this->FortranProject &&
201       gg->GetVersion() >= cmGlobalVisualStudioGenerator::VSVersion::VS10) {
202     gg->SetVersion(cmGlobalVisualStudioGenerator::VSVersion::VS9);
203   }
204
205   // add to the list of projects
206   target->Target->SetProperty("GENERATOR_FILE_NAME", lname);
207   // create the dsp.cmake file
208   std::string fname;
209   fname = cmStrCat(this->GetCurrentBinaryDirectory(), '/', lname);
210   if (this->FortranProject) {
211     fname += ".vfproj";
212   } else {
213     fname += ".vcproj";
214   }
215
216   // Generate the project file and replace it atomically with
217   // copy-if-different.  We use a separate timestamp so that the IDE
218   // does not reload project files unnecessarily.
219   cmGeneratedFileStream fout(fname.c_str());
220   fout.SetCopyIfDifferent(true);
221   this->WriteVCProjFile(fout, lname, target);
222   if (fout.Close()) {
223     this->GlobalGenerator->FileReplacedDuringGenerate(fname);
224   }
225
226   gg->SetVersion(realVersion);
227 }
228
229 cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule()
230 {
231   if (this->GlobalGenerator->GlobalSettingIsOn(
232         "CMAKE_SUPPRESS_REGENERATION")) {
233     return nullptr;
234   }
235
236   std::string makefileIn =
237     cmStrCat(this->GetCurrentSourceDirectory(), "/CMakeLists.txt");
238   if (cmSourceFile* file = this->Makefile->GetSource(makefileIn)) {
239     if (file->GetCustomCommand()) {
240       return file;
241     }
242   }
243   if (!cmSystemTools::FileExists(makefileIn)) {
244     return nullptr;
245   }
246
247   std::vector<std::string> listFiles = this->Makefile->GetListFiles();
248   cmake* cm = this->GlobalGenerator->GetCMakeInstance();
249   if (cm->DoWriteGlobVerifyTarget()) {
250     listFiles.push_back(cm->GetGlobVerifyStamp());
251   }
252
253   // Sort the list of input files and remove duplicates.
254   std::sort(listFiles.begin(), listFiles.end(), std::less<std::string>());
255   std::vector<std::string>::iterator new_end =
256     std::unique(listFiles.begin(), listFiles.end());
257   listFiles.erase(new_end, listFiles.end());
258
259   std::string argS = cmStrCat("-S", this->GetSourceDirectory());
260   std::string argB = cmStrCat("-B", this->GetBinaryDirectory());
261   std::string stampName =
262     cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles/generate.stamp");
263   cmCustomCommandLines commandLines =
264     cmMakeSingleCommandLine({ cmSystemTools::GetCMakeCommand(), argS, argB,
265                               "--check-stamp-file", stampName });
266   std::string comment = cmStrCat("Building Custom Rule ", makefileIn);
267   auto cc = cm::make_unique<cmCustomCommand>();
268   cc->SetOutputs(stampName);
269   cc->SetMainDependency(makefileIn);
270   cc->SetDepends(listFiles);
271   cc->SetCommandLines(commandLines);
272   cc->SetComment(comment.c_str());
273   cc->SetCMP0116Status(cmPolicies::NEW);
274   cc->SetEscapeOldStyle(false);
275   cc->SetStdPipesUTF8(true);
276   this->AddCustomCommandToOutput(std::move(cc), true);
277   if (cmSourceFile* file = this->Makefile->GetSource(makefileIn)) {
278     // Finalize the source file path now since we're adding this after
279     // the generator validated all project-named sources.
280     file->ResolveFullPath();
281     return file;
282   } else {
283     cmSystemTools::Error("Error adding rule for " + makefileIn);
284     return nullptr;
285   }
286 }
287
288 void cmLocalVisualStudio7Generator::WriteConfigurations(
289   std::ostream& fout, std::vector<std::string> const& configs,
290   const std::string& libName, cmGeneratorTarget* target)
291 {
292   fout << "\t<Configurations>\n";
293   for (std::string const& config : configs) {
294     this->WriteConfiguration(fout, config, libName, target);
295   }
296   fout << "\t</Configurations>\n";
297 }
298 cmVS7FlagTable cmLocalVisualStudio7GeneratorFortranFlagTable[] = {
299   { "Preprocess", "fpp", "Run Preprocessor on files", "preprocessYes", 0 },
300   { "Preprocess", "nofpp", "Run Preprocessor on files", "preprocessNo", 0 },
301   { "SuppressStartupBanner", "nologo", "SuppressStartupBanner", "true", 0 },
302   { "SourceFileFormat", "fixed", "Use Fixed Format", "fileFormatFixed", 0 },
303   { "SourceFileFormat", "free", "Use Free Format", "fileFormatFree", 0 },
304   { "DebugInformationFormat", "debug:full", "full debug", "debugEnabled", 0 },
305   { "DebugInformationFormat", "debug:minimal", "line numbers",
306     "debugLineInfoOnly", 0 },
307   { "Optimization", "Od", "disable optimization", "optimizeDisabled", 0 },
308   { "Optimization", "O1", "min space", "optimizeMinSpace", 0 },
309   { "Optimization", "O3", "full optimize", "optimizeFull", 0 },
310   { "GlobalOptimizations", "Og", "global optimize", "true", 0 },
311   { "InlineFunctionExpansion", "Ob0", "", "expandDisable", 0 },
312   { "InlineFunctionExpansion", "Ob1", "", "expandOnlyInline", 0 },
313   { "FavorSizeOrSpeed", "Os", "", "favorSize", 0 },
314   { "OmitFramePointers", "Oy-", "", "false", 0 },
315   { "OptimizeForProcessor", "GB", "", "procOptimizeBlended", 0 },
316   { "OptimizeForProcessor", "G5", "", "procOptimizePentium", 0 },
317   { "OptimizeForProcessor", "G6", "", "procOptimizePentiumProThruIII", 0 },
318   { "UseProcessorExtensions", "QzxK", "", "codeForStreamingSIMD", 0 },
319   { "OptimizeForProcessor", "QaxN", "", "codeForPentium4", 0 },
320   { "OptimizeForProcessor", "QaxB", "", "codeForPentiumM", 0 },
321   { "OptimizeForProcessor", "QaxP", "", "codeForCodeNamedPrescott", 0 },
322   { "OptimizeForProcessor", "QaxT", "", "codeForCore2Duo", 0 },
323   { "OptimizeForProcessor", "QxK", "", "codeExclusivelyStreamingSIMD", 0 },
324   { "OptimizeForProcessor", "QxN", "", "codeExclusivelyPentium4", 0 },
325   { "OptimizeForProcessor", "QxB", "", "codeExclusivelyPentiumM", 0 },
326   { "OptimizeForProcessor", "QxP", "", "codeExclusivelyCodeNamedPrescott", 0 },
327   { "OptimizeForProcessor", "QxT", "", "codeExclusivelyCore2Duo", 0 },
328   { "OptimizeForProcessor", "QxO", "", "codeExclusivelyCore2StreamingSIMD",
329     0 },
330   { "OptimizeForProcessor", "QxS", "", "codeExclusivelyCore2StreamingSIMD4",
331     0 },
332   { "OpenMP", "Qopenmp", "", "OpenMPParallelCode", 0 },
333   { "OpenMP", "Qopenmp-stubs", "", "OpenMPSequentialCode", 0 },
334   { "Traceback", "traceback", "", "true", 0 },
335   { "Traceback", "notraceback", "", "false", 0 },
336   { "FloatingPointExceptionHandling", "fpe:0", "", "fpe0", 0 },
337   { "FloatingPointExceptionHandling", "fpe:1", "", "fpe1", 0 },
338   { "FloatingPointExceptionHandling", "fpe:3", "", "fpe3", 0 },
339
340   { "MultiProcessorCompilation", "MP", "", "true",
341     cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
342   { "ProcessorNumber", "MP", "Multi-processor Compilation", "",
343     cmVS7FlagTable::UserValueRequired },
344
345   { "ModulePath", "module:", "", "", cmVS7FlagTable::UserValueRequired },
346   { "LoopUnrolling", "Qunroll:", "", "", cmVS7FlagTable::UserValueRequired },
347   { "AutoParallelThreshold", "Qpar-threshold:", "", "",
348     cmVS7FlagTable::UserValueRequired },
349   { "HeapArrays", "heap-arrays:", "", "", cmVS7FlagTable::UserValueRequired },
350   { "ObjectText", "bintext:", "", "", cmVS7FlagTable::UserValueRequired },
351   { "Parallelization", "Qparallel", "", "true", 0 },
352   { "PrefetchInsertion", "Qprefetch-", "", "false", 0 },
353   { "BufferedIO", "assume:buffered_io", "", "true", 0 },
354   { "CallingConvention", "iface:stdcall", "", "callConventionStdCall", 0 },
355   { "CallingConvention", "iface:cref", "", "callConventionCRef", 0 },
356   { "CallingConvention", "iface:stdref", "", "callConventionStdRef", 0 },
357   { "CallingConvention", "iface:stdcall", "", "callConventionStdCall", 0 },
358   { "CallingConvention", "iface:cvf", "", "callConventionCVF", 0 },
359   { "EnableRecursion", "recursive", "", "true", 0 },
360   { "ReentrantCode", "reentrancy", "", "true", 0 },
361   // done up to Language
362   { "", "", "", "", 0 }
363 };
364 // fill the table here currently the comment field is not used for
365 // anything other than documentation NOTE: Make sure the longer
366 // commandFlag comes FIRST!
367 cmVS7FlagTable cmLocalVisualStudio7GeneratorFlagTable[] = {
368   // option flags (some flags map to the same option)
369   { "BasicRuntimeChecks", "GZ", "Stack frame checks", "1", 0 },
370   { "BasicRuntimeChecks", "RTCsu", "Both stack and uninitialized checks", "3",
371     0 },
372   { "BasicRuntimeChecks", "RTCs", "Stack frame checks", "1", 0 },
373   { "BasicRuntimeChecks", "RTCu", "Uninitialized Variables ", "2", 0 },
374   { "BasicRuntimeChecks", "RTC1", "Both stack and uninitialized checks", "3",
375     0 },
376   { "DebugInformationFormat", "Z7", "debug format", "1", 0 },
377   { "DebugInformationFormat", "Zd", "debug format", "2", 0 },
378   { "DebugInformationFormat", "Zi", "debug format", "3", 0 },
379   { "DebugInformationFormat", "ZI", "debug format", "4", 0 },
380   { "EnableEnhancedInstructionSet", "arch:SSE2", "Use sse2 instructions", "2",
381     0 },
382   { "EnableEnhancedInstructionSet", "arch:SSE", "Use sse instructions", "1",
383     0 },
384   { "FloatingPointModel", "fp:precise", "Use precise floating point model",
385     "0", 0 },
386   { "FloatingPointModel", "fp:strict", "Use strict floating point model", "1",
387     0 },
388   { "FloatingPointModel", "fp:fast", "Use fast floating point model", "2", 0 },
389   { "FavorSizeOrSpeed", "Ot", "Favor fast code", "1", 0 },
390   { "FavorSizeOrSpeed", "Os", "Favor small code", "2", 0 },
391   { "CompileAs", "TC", "Compile as c code", "1", 0 },
392   { "CompileAs", "TP", "Compile as c++ code", "2", 0 },
393   { "Optimization", "Od", "Non Debug", "0", 0 },
394   { "Optimization", "O1", "Min Size", "1", 0 },
395   { "Optimization", "O2", "Max Speed", "2", 0 },
396   { "Optimization", "Ox", "Max Optimization", "3", 0 },
397   { "OptimizeForProcessor", "GB", "Blended processor mode", "0", 0 },
398   { "OptimizeForProcessor", "G5", "Pentium", "1", 0 },
399   { "OptimizeForProcessor", "G6", "PPro PII PIII", "2", 0 },
400   { "OptimizeForProcessor", "G7", "Pentium 4 or Athlon", "3", 0 },
401   { "InlineFunctionExpansion", "Ob0", "no inlines", "0", 0 },
402   { "InlineFunctionExpansion", "Ob1", "when inline keyword", "1", 0 },
403   { "InlineFunctionExpansion", "Ob2", "any time you can inline", "2", 0 },
404   { "RuntimeLibrary", "MTd", "Multithreaded debug", "1", 0 },
405   { "RuntimeLibrary", "MT", "Multithreaded", "0", 0 },
406   { "RuntimeLibrary", "MDd", "Multithreaded dll debug", "3", 0 },
407   { "RuntimeLibrary", "MD", "Multithreaded dll", "2", 0 },
408   { "RuntimeLibrary", "MLd", "Single Thread debug", "5", 0 },
409   { "RuntimeLibrary", "ML", "Single Thread", "4", 0 },
410   { "StructMemberAlignment", "Zp16", "struct align 16 byte ", "5", 0 },
411   { "StructMemberAlignment", "Zp1", "struct align 1 byte ", "1", 0 },
412   { "StructMemberAlignment", "Zp2", "struct align 2 byte ", "2", 0 },
413   { "StructMemberAlignment", "Zp4", "struct align 4 byte ", "3", 0 },
414   { "StructMemberAlignment", "Zp8", "struct align 8 byte ", "4", 0 },
415   { "WarningLevel", "W0", "Warning level", "0", 0 },
416   { "WarningLevel", "W1", "Warning level", "1", 0 },
417   { "WarningLevel", "W2", "Warning level", "2", 0 },
418   { "WarningLevel", "W3", "Warning level", "3", 0 },
419   { "WarningLevel", "W4", "Warning level", "4", 0 },
420   { "DisableSpecificWarnings", "wd", "Disable specific warnings", "",
421     cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
422
423   // Precompiled header and related options.  Note that the
424   // UsePrecompiledHeader entries are marked as "Continue" so that the
425   // corresponding PrecompiledHeaderThrough entry can be found.
426   { "UsePrecompiledHeader", "Yc", "Create Precompiled Header", "1",
427     cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
428   { "PrecompiledHeaderThrough", "Yc", "Precompiled Header Name", "",
429     cmVS7FlagTable::UserValueRequired },
430   { "UsePrecompiledHeader", "Y-", "Don't use precompiled header", "0", 0 },
431   { "PrecompiledHeaderFile", "Fp", "Generated Precompiled Header", "",
432     cmVS7FlagTable::UserValue },
433   // The YX and Yu options are in a per-global-generator table because
434   // their values differ based on the VS IDE version.
435   { "ForcedIncludeFiles", "FI", "Forced include files", "",
436     cmVS7FlagTable::UserValueRequired | cmVS7FlagTable::SemicolonAppendable },
437
438   { "AssemblerListingLocation", "Fa", "ASM List Location", "",
439     cmVS7FlagTable::UserValue },
440   { "ProgramDataBaseFileName", "Fd", "Program Database File Name", "",
441     cmVS7FlagTable::UserValue },
442
443   // boolean flags
444   { "BufferSecurityCheck", "GS", "Buffer security check", "true", 0 },
445   { "BufferSecurityCheck", "GS-", "Turn off Buffer security check", "false",
446     0 },
447   { "Detect64BitPortabilityProblems", "Wp64",
448     "Detect 64-bit Portability Problems", "true", 0 },
449   { "EnableFiberSafeOptimizations", "GT", "Enable Fiber-safe Optimizations",
450     "true", 0 },
451   { "EnableFunctionLevelLinking", "Gy", "EnableFunctionLevelLinking", "true",
452     0 },
453   { "EnableIntrinsicFunctions", "Oi", "EnableIntrinsicFunctions", "true", 0 },
454   { "GlobalOptimizations", "Og", "Global Optimize", "true", 0 },
455   { "ImproveFloatingPointConsistency", "Op", "ImproveFloatingPointConsistency",
456     "true", 0 },
457   { "MinimalRebuild", "Gm", "minimal rebuild", "true", 0 },
458   { "OmitFramePointers", "Oy", "OmitFramePointers", "true", 0 },
459   { "OptimizeForWindowsApplication", "GA", "Optimize for windows", "true", 0 },
460   { "RuntimeTypeInfo", "GR", "Turn on Run time type information for c++",
461     "true", 0 },
462   { "RuntimeTypeInfo", "GR-", "Turn off Run time type information for c++",
463     "false", 0 },
464   { "SmallerTypeCheck", "RTCc", "smaller type check", "true", 0 },
465   { "SuppressStartupBanner", "nologo", "SuppressStartupBanner", "true", 0 },
466   { "WholeProgramOptimization", "GL", "Enables whole program optimization",
467     "true", 0 },
468   { "WholeProgramOptimization", "GL-", "Disables whole program optimization",
469     "false", 0 },
470   { "WarnAsError", "WX", "Treat warnings as errors", "true", 0 },
471   { "BrowseInformation", "FR", "Generate browse information", "1", 0 },
472   { "StringPooling", "GF", "Enable StringPooling", "true", 0 },
473   { "", "", "", "", 0 }
474 };
475
476 cmVS7FlagTable cmLocalVisualStudio7GeneratorLinkFlagTable[] = {
477   // option flags (some flags map to the same option)
478   { "GenerateManifest", "MANIFEST:NO", "disable manifest generation", "false",
479     0 },
480   { "GenerateManifest", "MANIFEST", "enable manifest generation", "true", 0 },
481   { "LinkIncremental", "INCREMENTAL:NO", "link incremental", "1", 0 },
482   { "LinkIncremental", "INCREMENTAL:YES", "link incremental", "2", 0 },
483   { "CLRUnmanagedCodeCheck", "CLRUNMANAGEDCODECHECK:NO", "", "false", 0 },
484   { "CLRUnmanagedCodeCheck", "CLRUNMANAGEDCODECHECK", "", "true", 0 },
485   { "DataExecutionPrevention", "NXCOMPAT:NO",
486     "Not known to work with Windows Data Execution Prevention", "1", 0 },
487   { "DataExecutionPrevention", "NXCOMPAT",
488     "Known to work with Windows Data Execution Prevention", "2", 0 },
489   { "DelaySign", "DELAYSIGN:NO", "", "false", 0 },
490   { "DelaySign", "DELAYSIGN", "", "true", 0 },
491   { "EntryPointSymbol", "ENTRY:", "sets the starting address", "",
492     cmVS7FlagTable::UserValue },
493   { "IgnoreDefaultLibraryNames", "NODEFAULTLIB:", "default libs to ignore", "",
494     cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
495   { "IgnoreAllDefaultLibraries", "NODEFAULTLIB", "ignore all default libs",
496     "true", 0 },
497   { "FixedBaseAddress", "FIXED:NO", "Generate a relocation section", "1", 0 },
498   { "FixedBaseAddress", "FIXED", "Image must be loaded at a fixed address",
499     "2", 0 },
500   { "EnableCOMDATFolding", "OPT:NOICF", "Do not remove redundant COMDATs", "1",
501     0 },
502   { "EnableCOMDATFolding", "OPT:ICF", "Remove redundant COMDATs", "2", 0 },
503   { "ResourceOnlyDLL", "NOENTRY", "Create DLL with no entry point", "true",
504     0 },
505   { "OptimizeReferences", "OPT:NOREF", "Keep unreferenced data", "1", 0 },
506   { "OptimizeReferences", "OPT:REF", "Eliminate unreferenced data", "2", 0 },
507   { "Profile", "PROFILE", "", "true", 0 },
508   { "RandomizedBaseAddress", "DYNAMICBASE:NO",
509     "Image may not be rebased at load-time", "1", 0 },
510   { "RandomizedBaseAddress", "DYNAMICBASE",
511     "Image may be rebased at load-time", "2", 0 },
512   { "SetChecksum", "RELEASE", "Enable setting checksum in header", "true", 0 },
513   { "SupportUnloadOfDelayLoadedDLL", "DELAY:UNLOAD", "", "true", 0 },
514   { "TargetMachine", "MACHINE:I386", "Machine x86", "1", 0 },
515   { "TargetMachine", "MACHINE:X86", "Machine x86", "1", 0 },
516   { "TargetMachine", "MACHINE:AM33", "Machine AM33", "2", 0 },
517   { "TargetMachine", "MACHINE:ARM", "Machine ARM", "3", 0 },
518   { "TargetMachine", "MACHINE:EBC", "Machine EBC", "4", 0 },
519   { "TargetMachine", "MACHINE:IA64", "Machine IA64", "5", 0 },
520   { "TargetMachine", "MACHINE:M32R", "Machine M32R", "6", 0 },
521   { "TargetMachine", "MACHINE:MIPS", "Machine MIPS", "7", 0 },
522   { "TargetMachine", "MACHINE:MIPS16", "Machine MIPS16", "8", 0 },
523   { "TargetMachine", "MACHINE:MIPSFPU)", "Machine MIPSFPU", "9", 0 },
524   { "TargetMachine", "MACHINE:MIPSFPU16", "Machine MIPSFPU16", "10", 0 },
525   { "TargetMachine", "MACHINE:MIPSR41XX", "Machine MIPSR41XX", "11", 0 },
526   { "TargetMachine", "MACHINE:SH3", "Machine SH3", "12", 0 },
527   { "TargetMachine", "MACHINE:SH3DSP", "Machine SH3DSP", "13", 0 },
528   { "TargetMachine", "MACHINE:SH4", "Machine SH4", "14", 0 },
529   { "TargetMachine", "MACHINE:SH5", "Machine SH5", "15", 0 },
530   { "TargetMachine", "MACHINE:THUMB", "Machine THUMB", "16", 0 },
531   { "TargetMachine", "MACHINE:X64", "Machine x64", "17", 0 },
532   { "TargetMachine", "MACHINE:ARM64", "Machine ARM64", "18", 0 },
533   { "TurnOffAssemblyGeneration", "NOASSEMBLY",
534     "No assembly even if CLR information is present in objects.", "true", 0 },
535   { "ModuleDefinitionFile", "DEF:", "add an export def file", "",
536     cmVS7FlagTable::UserValue },
537   { "GenerateMapFile", "MAP", "enable generation of map file", "true", 0 },
538   { "", "", "", "", 0 }
539 };
540
541 cmVS7FlagTable cmLocalVisualStudio7GeneratorFortranLinkFlagTable[] = {
542   { "LinkIncremental", "INCREMENTAL:NO", "link incremental",
543     "linkIncrementalNo", 0 },
544   { "LinkIncremental", "INCREMENTAL:YES", "link incremental",
545     "linkIncrementalYes", 0 },
546   { "EnableCOMDATFolding", "OPT:NOICF", "Do not remove redundant COMDATs",
547     "optNoFolding", 0 },
548   { "EnableCOMDATFolding", "OPT:ICF", "Remove redundant COMDATs", "optFolding",
549     0 },
550   { "OptimizeReferences", "OPT:NOREF", "Keep unreferenced data",
551     "optNoReferences", 0 },
552   { "OptimizeReferences", "OPT:REF", "Eliminate unreferenced data",
553     "optReferences", 0 },
554   { "", "", "", "", 0 }
555 };
556
557 // Helper class to write build event <Tool .../> elements.
558 class cmLocalVisualStudio7Generator::EventWriter
559 {
560 public:
561   EventWriter(cmLocalVisualStudio7Generator* lg, const std::string& config,
562               std::ostream& os)
563     : LG(lg)
564     , Config(config)
565     , Stream(os)
566     , First(true)
567   {
568   }
569   void Start(const char* tool)
570   {
571     this->First = true;
572     this->Stream << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"";
573   }
574   void Finish()
575   {
576     // If any commands were generated, finish constructing them.
577     if (!this->First) {
578       std::string finishScript =
579         this->LG->FinishConstructScript(VsProjectType::vcxproj);
580       this->Stream << this->LG->EscapeForXML(finishScript) << "\"";
581     }
582
583     this->Stream << "/>\n";
584   }
585   void Write(std::vector<cmCustomCommand> const& ccs)
586   {
587     for (cmCustomCommand const& command : ccs) {
588       this->Write(command);
589     }
590   }
591   void Write(cmCustomCommand const& cc)
592   {
593     cmCustomCommandGenerator ccg(cc, this->Config, this->LG);
594     if (this->First) {
595       const char* comment = ccg.GetComment();
596       if (comment && *comment) {
597         this->Stream << "\nDescription=\"" << this->LG->EscapeForXML(comment)
598                      << "\"";
599       }
600       this->Stream << "\nCommandLine=\"";
601       this->First = false;
602     } else {
603       this->Stream << this->LG->EscapeForXML("\n");
604     }
605     std::string script = this->LG->ConstructScript(ccg);
606     this->Stream << this->LG->EscapeForXML(script);
607   }
608
609 private:
610   cmLocalVisualStudio7Generator* LG;
611   std::string Config;
612   std::ostream& Stream;
613   bool First;
614 };
615
616 void cmLocalVisualStudio7Generator::WriteConfiguration(
617   std::ostream& fout, const std::string& configName,
618   const std::string& libName, cmGeneratorTarget* target)
619 {
620   std::string mfcFlag;
621   if (cmValue p = this->Makefile->GetDefinition("CMAKE_MFC_FLAG")) {
622     mfcFlag = cmGeneratorExpression::Evaluate(*p, this, configName);
623   } else {
624     mfcFlag = "0";
625   }
626   cmGlobalVisualStudio7Generator* gg =
627     static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
628   fout << "\t\t<Configuration\n"
629        << "\t\t\tName=\"" << configName << "|" << gg->GetPlatformName()
630        << "\"\n";
631   // This is an internal type to Visual Studio, it seems that:
632   // 4 == static library
633   // 2 == dll
634   // 1 == executable
635   // 10 == utility
636   const char* configType = "10";
637   const char* projectType = 0;
638   bool targetBuilds = true;
639
640   switch (target->GetType()) {
641     case cmStateEnums::OBJECT_LIBRARY:
642       targetBuilds = false; // no manifest tool for object library
643       CM_FALLTHROUGH;
644     case cmStateEnums::STATIC_LIBRARY:
645       projectType = "typeStaticLibrary";
646       configType = "4";
647       break;
648     case cmStateEnums::SHARED_LIBRARY:
649     case cmStateEnums::MODULE_LIBRARY:
650       projectType = "typeDynamicLibrary";
651       configType = "2";
652       break;
653     case cmStateEnums::EXECUTABLE:
654       configType = "1";
655       break;
656     case cmStateEnums::UTILITY:
657     case cmStateEnums::GLOBAL_TARGET:
658     case cmStateEnums::INTERFACE_LIBRARY:
659       configType = "10";
660       CM_FALLTHROUGH;
661     case cmStateEnums::UNKNOWN_LIBRARY:
662       targetBuilds = false;
663       break;
664   }
665   if (this->FortranProject && projectType) {
666     configType = projectType;
667   }
668   std::string flags;
669   std::string langForClCompile;
670   if (target->GetType() <= cmStateEnums::OBJECT_LIBRARY) {
671     const std::string& linkLanguage =
672       (this->FortranProject ? std::string("Fortran")
673                             : target->GetLinkerLanguage(configName));
674     if (linkLanguage.empty()) {
675       cmSystemTools::Error(
676         "CMake can not determine linker language for target: " +
677         target->GetName());
678       return;
679     }
680     langForClCompile = linkLanguage;
681     if (langForClCompile == "C" || langForClCompile == "CXX" ||
682         langForClCompile == "Fortran") {
683       this->AddLanguageFlags(flags, target, langForClCompile, configName);
684     }
685     // set the correct language
686     if (linkLanguage == "C") {
687       flags += " /TC ";
688     }
689     if (linkLanguage == "CXX") {
690       flags += " /TP ";
691     }
692
693     // Add the target-specific flags.
694     this->AddCompileOptions(flags, target, langForClCompile, configName);
695
696     // Check IPO related warning/error.
697     target->IsIPOEnabled(linkLanguage, configName);
698   }
699
700   if (this->FortranProject) {
701     switch (cmOutputConverter::GetFortranFormat(
702       target->GetSafeProperty("Fortran_FORMAT"))) {
703       case cmOutputConverter::FortranFormatFixed:
704         flags += " -fixed";
705         break;
706       case cmOutputConverter::FortranFormatFree:
707         flags += " -free";
708         break;
709       default:
710         break;
711     }
712
713     switch (cmOutputConverter::GetFortranPreprocess(
714       target->GetSafeProperty("Fortran_PREPROCESS"))) {
715       case cmOutputConverter::FortranPreprocess::Needed:
716         flags += " -fpp";
717         break;
718       case cmOutputConverter::FortranPreprocess::NotNeeded:
719         flags += " -nofpp";
720         break;
721       default:
722         break;
723     }
724   }
725
726   // Get preprocessor definitions for this directory.
727   std::string defineFlags = this->Makefile->GetDefineFlags();
728   Options::Tool t = Options::Compiler;
729   cmVS7FlagTable const* table = cmLocalVisualStudio7GeneratorFlagTable;
730   if (this->FortranProject) {
731     t = Options::FortranCompiler;
732     table = cmLocalVisualStudio7GeneratorFortranFlagTable;
733   }
734   Options targetOptions(this, t, table, gg->ExtraFlagTable);
735   targetOptions.FixExceptionHandlingDefault();
736   targetOptions.AddFlag("AssemblerListingLocation", "$(IntDir)\\");
737   targetOptions.Parse(flags);
738   targetOptions.Parse(defineFlags);
739   targetOptions.ParseFinish();
740   if (!langForClCompile.empty()) {
741     std::vector<std::string> targetDefines;
742     target->GetCompileDefinitions(targetDefines, configName, langForClCompile);
743     targetOptions.AddDefines(targetDefines);
744
745     std::vector<std::string> targetIncludes;
746     this->GetIncludeDirectories(targetIncludes, target, langForClCompile,
747                                 configName);
748     targetOptions.AddIncludes(targetIncludes);
749   }
750   targetOptions.SetVerboseMakefile(
751     this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"));
752
753   // Add a definition for the configuration name.
754   std::string configDefine = cmStrCat("CMAKE_INTDIR=\"", configName, '"');
755   targetOptions.AddDefine(configDefine);
756
757   // Add the export symbol definition for shared library objects.
758   if (const std::string* exportMacro = target->GetExportMacro()) {
759     targetOptions.AddDefine(*exportMacro);
760   }
761
762   // The intermediate directory name consists of a directory for the
763   // target and a subdirectory for the configuration name.
764   std::string intermediateDir =
765     cmStrCat(this->GetTargetDirectory(target), '/', configName);
766
767   if (target->GetType() < cmStateEnums::UTILITY) {
768     std::string const& outDir =
769       target->GetType() == cmStateEnums::OBJECT_LIBRARY
770       ? intermediateDir
771       : target->GetDirectory(configName);
772     /* clang-format off */
773     fout << "\t\t\tOutputDirectory=\""
774          << this->ConvertToXMLOutputPathSingle(outDir) << "\"\n";
775     /* clang-format on */
776   }
777
778   /* clang-format off */
779   fout << "\t\t\tIntermediateDirectory=\""
780        << this->ConvertToXMLOutputPath(intermediateDir)
781        << "\"\n"
782        << "\t\t\tConfigurationType=\"" << configType << "\"\n"
783        << "\t\t\tUseOfMFC=\"" << mfcFlag << "\"\n"
784        << "\t\t\tATLMinimizesCRunTimeLibraryUsage=\"false\"\n";
785   /* clang-format on */
786
787   if (this->FortranProject) {
788     // Intel Fortran >= 15.0 uses TargetName property.
789     std::string const targetNameFull = target->GetFullName(configName);
790     std::string const targetName =
791       cmSystemTools::GetFilenameWithoutLastExtension(targetNameFull);
792     std::string const targetExt =
793       target->GetType() == cmStateEnums::OBJECT_LIBRARY
794       ? ".lib"
795       : cmSystemTools::GetFilenameLastExtension(targetNameFull);
796     /* clang-format off */
797     fout <<
798       "\t\t\tTargetName=\"" << this->EscapeForXML(targetName) << "\"\n"
799       "\t\t\tTargetExt=\"" << this->EscapeForXML(targetExt) << "\"\n"
800       ;
801     /* clang-format on */
802   }
803
804   // If unicode is enabled change the character set to unicode, if not
805   // then default to MBCS.
806   if (targetOptions.UsingUnicode()) {
807     fout << "\t\t\tCharacterSet=\"1\">\n";
808   } else if (targetOptions.UsingSBCS()) {
809     fout << "\t\t\tCharacterSet=\"0\">\n";
810   } else {
811     fout << "\t\t\tCharacterSet=\"2\">\n";
812   }
813   const char* tool = "VCCLCompilerTool";
814   if (this->FortranProject) {
815     tool = "VFFortranCompilerTool";
816   }
817   fout << "\t\t\t<Tool\n"
818        << "\t\t\t\tName=\"" << tool << "\"\n";
819   if (this->FortranProject) {
820     cmValue target_mod_dir = target->GetProperty("Fortran_MODULE_DIRECTORY");
821     std::string modDir;
822     if (target_mod_dir) {
823       modDir = this->MaybeRelativeToCurBinDir(*target_mod_dir);
824     } else {
825       modDir = ".";
826     }
827     fout << "\t\t\t\tModulePath=\"" << this->ConvertToXMLOutputPath(modDir)
828          << "\\$(ConfigurationName)\"\n";
829   }
830   targetOptions.OutputAdditionalIncludeDirectories(
831     fout, 4, this->FortranProject ? "Fortran" : langForClCompile);
832   targetOptions.OutputFlagMap(fout, 4);
833   targetOptions.OutputPreprocessorDefinitions(fout, 4, langForClCompile);
834   fout << "\t\t\t\tObjectFile=\"$(IntDir)\\\"\n";
835   if (target->GetType() <= cmStateEnums::OBJECT_LIBRARY) {
836     // Specify the compiler program database file if configured.
837     std::string pdb = target->GetCompilePDBPath(configName);
838     if (!pdb.empty()) {
839       fout << "\t\t\t\tProgramDataBaseFileName=\""
840            << this->ConvertToXMLOutputPathSingle(pdb) << "\"\n";
841     }
842   }
843   fout << "/>\n"; // end of <Tool Name=VCCLCompilerTool
844   if (gg->IsMasmEnabled() && !this->FortranProject) {
845     Options masmOptions(this, Options::MasmCompiler, 0, 0);
846     /* clang-format off */
847     fout <<
848       "\t\t\t<Tool\n"
849       "\t\t\t\tName=\"MASM\"\n"
850       ;
851     /* clang-format on */
852     targetOptions.OutputAdditionalIncludeDirectories(fout, 4, "ASM_MASM");
853     // Use same preprocessor definitions as VCCLCompilerTool.
854     targetOptions.OutputPreprocessorDefinitions(fout, 4, "ASM_MASM");
855     masmOptions.OutputFlagMap(fout, 4);
856     /* clang-format off */
857     fout <<
858       "\t\t\t\tObjectFile=\"$(IntDir)\\\"\n"
859       "\t\t\t/>\n";
860     /* clang-format on */
861   }
862   tool = "VCCustomBuildTool";
863   if (this->FortranProject) {
864     tool = "VFCustomBuildTool";
865   }
866   fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"/>\n";
867   tool = "VCResourceCompilerTool";
868   if (this->FortranProject) {
869     tool = "VFResourceCompilerTool";
870   }
871   fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"\n";
872   targetOptions.OutputAdditionalIncludeDirectories(fout, 4, "RC");
873   // add the -D flags to the RC tool
874   targetOptions.OutputPreprocessorDefinitions(fout, 4, "RC");
875   fout << "\t\t\t/>\n";
876   tool = "VCMIDLTool";
877   if (this->FortranProject) {
878     tool = "VFMIDLTool";
879   }
880   fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"\n";
881   targetOptions.OutputAdditionalIncludeDirectories(fout, 4, "MIDL");
882   fout << "\t\t\t\tMkTypLibCompatible=\"false\"\n";
883   if (gg->GetPlatformName() == "x64") {
884     fout << "\t\t\t\tTargetEnvironment=\"3\"\n";
885   } else if (gg->GetPlatformName() == "ia64") {
886     fout << "\t\t\t\tTargetEnvironment=\"2\"\n";
887   } else {
888     fout << "\t\t\t\tTargetEnvironment=\"1\"\n";
889   }
890   fout << "\t\t\t\tGenerateStublessProxies=\"true\"\n";
891   fout << "\t\t\t\tTypeLibraryName=\"$(InputName).tlb\"\n";
892   fout << "\t\t\t\tOutputDirectory=\"$(IntDir)\"\n";
893   fout << "\t\t\t\tHeaderFileName=\"$(InputName).h\"\n";
894   fout << "\t\t\t\tDLLDataFileName=\"\"\n";
895   fout << "\t\t\t\tInterfaceIdentifierFileName=\"$(InputName)_i.c\"\n";
896   fout << "\t\t\t\tProxyFileName=\"$(InputName)_p.c\"/>\n";
897   // end of <Tool Name=VCMIDLTool
898
899   // Add manifest tool settings.
900   if (targetBuilds) {
901     const char* manifestTool = "VCManifestTool";
902     if (this->FortranProject) {
903       manifestTool = "VFManifestTool";
904     }
905     /* clang-format off */
906     fout <<
907       "\t\t\t<Tool\n"
908       "\t\t\t\tName=\"" << manifestTool << "\"";
909     /* clang-format on */
910
911     std::vector<cmSourceFile const*> manifest_srcs;
912     target->GetManifests(manifest_srcs, configName);
913     if (!manifest_srcs.empty()) {
914       fout << "\n\t\t\t\tAdditionalManifestFiles=\"";
915       for (cmSourceFile const* manifest : manifest_srcs) {
916         std::string m = manifest->GetFullPath();
917         fout << this->ConvertToXMLOutputPath(m) << ";";
918       }
919       fout << "\"";
920     }
921
922     // Check if we need the FAT32 workaround.
923     // Check the filesystem type where the target will be written.
924     if (cmLVS7G_IsFAT(target->GetDirectory(configName).c_str())) {
925       // Add a flag telling the manifest tool to use a workaround
926       // for FAT32 file systems, which can cause an empty manifest
927       // to be embedded into the resulting executable.  See CMake
928       // bug #2617.
929       fout << "\n\t\t\t\tUseFAT32Workaround=\"true\"";
930     }
931     fout << "/>\n";
932   }
933
934   this->OutputTargetRules(fout, configName, target, libName);
935   this->OutputBuildTool(fout, configName, target, targetOptions);
936   this->OutputDeploymentDebuggerTool(fout, configName, target);
937   fout << "\t\t</Configuration>\n";
938 }
939
940 std::string cmLocalVisualStudio7Generator::GetBuildTypeLinkerFlags(
941   std::string rootLinkerFlags, const std::string& configName)
942 {
943   std::string configTypeUpper = cmSystemTools::UpperCase(configName);
944   std::string extraLinkOptionsBuildTypeDef =
945     rootLinkerFlags + "_" + configTypeUpper;
946
947   const std::string& extraLinkOptionsBuildType =
948     this->Makefile->GetRequiredDefinition(extraLinkOptionsBuildTypeDef);
949
950   return extraLinkOptionsBuildType;
951 }
952
953 void cmLocalVisualStudio7Generator::OutputBuildTool(
954   std::ostream& fout, const std::string& configName, cmGeneratorTarget* target,
955   const Options& targetOptions)
956 {
957   cmGlobalVisualStudio7Generator* gg =
958     static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
959   std::string temp;
960   std::string extraLinkOptions;
961   if (target->GetType() == cmStateEnums::EXECUTABLE) {
962     extraLinkOptions =
963       this->Makefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS") + " " +
964       GetBuildTypeLinkerFlags("CMAKE_EXE_LINKER_FLAGS", configName);
965   }
966   if (target->GetType() == cmStateEnums::SHARED_LIBRARY) {
967     extraLinkOptions =
968       this->Makefile->GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS") +
969       " " + GetBuildTypeLinkerFlags("CMAKE_SHARED_LINKER_FLAGS", configName);
970   }
971   if (target->GetType() == cmStateEnums::MODULE_LIBRARY) {
972     extraLinkOptions =
973       this->Makefile->GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS") +
974       " " + GetBuildTypeLinkerFlags("CMAKE_MODULE_LINKER_FLAGS", configName);
975   }
976
977   cmValue targetLinkFlags = target->GetProperty("LINK_FLAGS");
978   if (targetLinkFlags) {
979     extraLinkOptions += " ";
980     extraLinkOptions += *targetLinkFlags;
981   }
982   std::string configTypeUpper = cmSystemTools::UpperCase(configName);
983   std::string linkFlagsConfig = cmStrCat("LINK_FLAGS_", configTypeUpper);
984   targetLinkFlags = target->GetProperty(linkFlagsConfig);
985   if (targetLinkFlags) {
986     extraLinkOptions += " ";
987     extraLinkOptions += *targetLinkFlags;
988   }
989
990   std::vector<std::string> opts;
991   target->GetLinkOptions(opts, configName,
992                          target->GetLinkerLanguage(configName));
993   // LINK_OPTIONS are escaped.
994   this->AppendCompileOptions(extraLinkOptions, opts);
995
996   Options linkOptions(this, Options::Linker);
997   if (this->FortranProject) {
998     linkOptions.AddTable(cmLocalVisualStudio7GeneratorFortranLinkFlagTable);
999   }
1000   linkOptions.AddTable(cmLocalVisualStudio7GeneratorLinkFlagTable);
1001
1002   linkOptions.Parse(extraLinkOptions);
1003   cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
1004     target->GetModuleDefinitionInfo(configName);
1005   if (mdi && !mdi->DefFile.empty()) {
1006     std::string defFile =
1007       this->ConvertToOutputFormat(mdi->DefFile, cmOutputConverter::SHELL);
1008     linkOptions.AddFlag("ModuleDefinitionFile", defFile);
1009   }
1010
1011   switch (target->GetType()) {
1012     case cmStateEnums::UNKNOWN_LIBRARY:
1013       break;
1014     case cmStateEnums::OBJECT_LIBRARY: {
1015       std::string libpath =
1016         cmStrCat(this->GetTargetDirectory(target), '/', configName, '/',
1017                  target->GetName(), ".lib");
1018       const char* tool =
1019         this->FortranProject ? "VFLibrarianTool" : "VCLibrarianTool";
1020       fout << "\t\t\t<Tool\n"
1021            << "\t\t\t\tName=\"" << tool << "\"\n";
1022       fout << "\t\t\t\tOutputFile=\""
1023            << this->ConvertToXMLOutputPathSingle(libpath) << "\"/>\n";
1024       break;
1025     }
1026     case cmStateEnums::STATIC_LIBRARY: {
1027       std::string targetNameFull = target->GetFullName(configName);
1028       std::string libpath =
1029         cmStrCat(target->GetDirectory(configName), '/', targetNameFull);
1030       const char* tool = "VCLibrarianTool";
1031       if (this->FortranProject) {
1032         tool = "VFLibrarianTool";
1033       }
1034       fout << "\t\t\t<Tool\n"
1035            << "\t\t\t\tName=\"" << tool << "\"\n";
1036
1037       if (this->FortranProject) {
1038         std::ostringstream libdeps;
1039         this->Internal->OutputObjects(libdeps, target, configName);
1040         if (!libdeps.str().empty()) {
1041           fout << "\t\t\t\tAdditionalDependencies=\"" << libdeps.str()
1042                << "\"\n";
1043         }
1044       }
1045       std::string libflags;
1046       this->GetStaticLibraryFlags(
1047         libflags, configName, target->GetLinkerLanguage(configName), target);
1048       if (!libflags.empty()) {
1049         fout << "\t\t\t\tAdditionalOptions=\"" << this->EscapeForXML(libflags)
1050              << "\"\n";
1051       }
1052       fout << "\t\t\t\tOutputFile=\""
1053            << this->ConvertToXMLOutputPathSingle(libpath) << "\"/>\n";
1054       break;
1055     }
1056     case cmStateEnums::SHARED_LIBRARY:
1057     case cmStateEnums::MODULE_LIBRARY: {
1058       cmGeneratorTarget::Names targetNames =
1059         target->GetLibraryNames(configName);
1060
1061       // Compute the link library and directory information.
1062       cmComputeLinkInformation* pcli = target->GetLinkInformation(configName);
1063       if (!pcli) {
1064         return;
1065       }
1066       cmComputeLinkInformation& cli = *pcli;
1067       std::string linkLanguage = cli.GetLinkLanguage();
1068
1069       // Compute the variable name to lookup standard libraries for this
1070       // language.
1071       std::string standardLibsVar =
1072         cmStrCat("CMAKE_", linkLanguage, "_STANDARD_LIBRARIES");
1073       const char* tool = "VCLinkerTool";
1074       if (this->FortranProject) {
1075         tool = "VFLinkerTool";
1076       }
1077       fout << "\t\t\t<Tool\n"
1078            << "\t\t\t\tName=\"" << tool << "\"\n";
1079       if (!gg->NeedLinkLibraryDependencies(target)) {
1080         fout << "\t\t\t\tLinkLibraryDependencies=\"false\"\n";
1081       }
1082       // Use the NOINHERIT macro to avoid getting VS project default
1083       // libraries which may be set by the user to something bad.
1084       fout << "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) "
1085            << this->Makefile->GetSafeDefinition(standardLibsVar);
1086       if (this->FortranProject) {
1087         this->Internal->OutputObjects(fout, target, configName, " ");
1088       }
1089       fout << " ";
1090       this->Internal->OutputLibraries(fout, cli.GetItems());
1091       fout << "\"\n";
1092       temp =
1093         cmStrCat(target->GetDirectory(configName), '/', targetNames.Output);
1094       fout << "\t\t\t\tOutputFile=\""
1095            << this->ConvertToXMLOutputPathSingle(temp) << "\"\n";
1096       this->WriteTargetVersionAttribute(fout, target);
1097       linkOptions.OutputFlagMap(fout, 4);
1098       fout << "\t\t\t\tAdditionalLibraryDirectories=\"";
1099       this->OutputLibraryDirectories(fout, cli.GetDirectories());
1100       fout << "\"\n";
1101       temp =
1102         cmStrCat(target->GetPDBDirectory(configName), '/', targetNames.PDB);
1103       fout << "\t\t\t\tProgramDatabaseFile=\""
1104            << this->ConvertToXMLOutputPathSingle(temp) << "\"\n";
1105       if (targetOptions.IsDebug()) {
1106         fout << "\t\t\t\tGenerateDebugInformation=\"true\"\n";
1107       }
1108       if (this->WindowsCEProject) {
1109         if (this->GetVersion() <
1110             cmGlobalVisualStudioGenerator::VSVersion::VS9) {
1111           fout << "\t\t\t\tSubSystem=\"9\"\n";
1112         } else {
1113           fout << "\t\t\t\tSubSystem=\"8\"\n";
1114         }
1115       }
1116       std::string stackVar = cmStrCat("CMAKE_", linkLanguage, "_STACK_SIZE");
1117       cmValue stackVal = this->Makefile->GetDefinition(stackVar);
1118       if (stackVal) {
1119         fout << "\t\t\t\tStackReserveSize=\"" << *stackVal << "\"\n";
1120       }
1121       if (!targetNames.ImportLibrary.empty()) {
1122         temp = cmStrCat(target->GetDirectory(
1123                           configName, cmStateEnums::ImportLibraryArtifact),
1124                         '/', targetNames.ImportLibrary);
1125         fout << "\t\t\t\tImportLibrary=\""
1126              << this->ConvertToXMLOutputPathSingle(temp) << "\"";
1127       }
1128       if (this->FortranProject) {
1129         fout << "\n\t\t\t\tLinkDLL=\"true\"";
1130       }
1131       fout << "/>\n";
1132     } break;
1133     case cmStateEnums::EXECUTABLE: {
1134       cmGeneratorTarget::Names targetNames =
1135         target->GetExecutableNames(configName);
1136
1137       // Compute the link library and directory information.
1138       cmComputeLinkInformation* pcli = target->GetLinkInformation(configName);
1139       if (!pcli) {
1140         return;
1141       }
1142       cmComputeLinkInformation& cli = *pcli;
1143       std::string linkLanguage = cli.GetLinkLanguage();
1144
1145       bool isWin32Executable = target->IsWin32Executable(configName);
1146
1147       // Compute the variable name to lookup standard libraries for this
1148       // language.
1149       std::string standardLibsVar =
1150         cmStrCat("CMAKE_", linkLanguage, "_STANDARD_LIBRARIES");
1151       const char* tool = "VCLinkerTool";
1152       if (this->FortranProject) {
1153         tool = "VFLinkerTool";
1154       }
1155       fout << "\t\t\t<Tool\n"
1156            << "\t\t\t\tName=\"" << tool << "\"\n";
1157       if (!gg->NeedLinkLibraryDependencies(target)) {
1158         fout << "\t\t\t\tLinkLibraryDependencies=\"false\"\n";
1159       }
1160       // Use the NOINHERIT macro to avoid getting VS project default
1161       // libraries which may be set by the user to something bad.
1162       fout << "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) "
1163            << this->Makefile->GetSafeDefinition(standardLibsVar);
1164       if (this->FortranProject) {
1165         this->Internal->OutputObjects(fout, target, configName, " ");
1166       }
1167       fout << " ";
1168       this->Internal->OutputLibraries(fout, cli.GetItems());
1169       fout << "\"\n";
1170       temp =
1171         cmStrCat(target->GetDirectory(configName), '/', targetNames.Output);
1172       fout << "\t\t\t\tOutputFile=\""
1173            << this->ConvertToXMLOutputPathSingle(temp) << "\"\n";
1174       this->WriteTargetVersionAttribute(fout, target);
1175       linkOptions.OutputFlagMap(fout, 4);
1176       fout << "\t\t\t\tAdditionalLibraryDirectories=\"";
1177       this->OutputLibraryDirectories(fout, cli.GetDirectories());
1178       fout << "\"\n";
1179       std::string path = this->ConvertToXMLOutputPathSingle(
1180         target->GetPDBDirectory(configName));
1181       fout << "\t\t\t\tProgramDatabaseFile=\"" << path << "/"
1182            << targetNames.PDB << "\"\n";
1183       if (targetOptions.IsDebug()) {
1184         fout << "\t\t\t\tGenerateDebugInformation=\"true\"\n";
1185       }
1186       if (this->WindowsCEProject) {
1187         if (this->GetVersion() <
1188             cmGlobalVisualStudioGenerator::VSVersion::VS9) {
1189           fout << "\t\t\t\tSubSystem=\"9\"\n";
1190         } else {
1191           fout << "\t\t\t\tSubSystem=\"8\"\n";
1192         }
1193
1194         if (!linkOptions.GetFlag("EntryPointSymbol")) {
1195           const char* entryPointSymbol = targetOptions.UsingUnicode()
1196             ? (isWin32Executable ? "wWinMainCRTStartup" : "mainWCRTStartup")
1197             : (isWin32Executable ? "WinMainCRTStartup" : "mainACRTStartup");
1198           fout << "\t\t\t\tEntryPointSymbol=\"" << entryPointSymbol << "\"\n";
1199         }
1200       } else if (this->FortranProject) {
1201         fout << "\t\t\t\tSubSystem=\""
1202              << (isWin32Executable ? "subSystemWindows" : "subSystemConsole")
1203              << "\"\n";
1204       } else {
1205         fout << "\t\t\t\tSubSystem=\"" << (isWin32Executable ? "2" : "1")
1206              << "\"\n";
1207       }
1208       std::string stackVar = cmStrCat("CMAKE_", linkLanguage, "_STACK_SIZE");
1209       cmValue stackVal = this->Makefile->GetDefinition(stackVar);
1210       if (stackVal) {
1211         fout << "\t\t\t\tStackReserveSize=\"" << *stackVal << "\"";
1212       }
1213       temp = cmStrCat(
1214         target->GetDirectory(configName, cmStateEnums::ImportLibraryArtifact),
1215         '/', targetNames.ImportLibrary);
1216       fout << "\t\t\t\tImportLibrary=\""
1217            << this->ConvertToXMLOutputPathSingle(temp) << "\"/>\n";
1218       break;
1219     }
1220     case cmStateEnums::UTILITY:
1221     case cmStateEnums::GLOBAL_TARGET:
1222     case cmStateEnums::INTERFACE_LIBRARY:
1223       break;
1224   }
1225 }
1226
1227 static std::string cmLocalVisualStudio7GeneratorEscapeForXML(
1228   const std::string& s)
1229 {
1230   std::string ret = s;
1231   cmSystemTools::ReplaceString(ret, "&", "&amp;");
1232   cmSystemTools::ReplaceString(ret, "\"", "&quot;");
1233   cmSystemTools::ReplaceString(ret, "<", "&lt;");
1234   cmSystemTools::ReplaceString(ret, ">", "&gt;");
1235   cmSystemTools::ReplaceString(ret, "\n", "&#x0D;&#x0A;");
1236   return ret;
1237 }
1238
1239 static std::string GetEscapedPropertyIfValueNotNULL(const char* propertyValue)
1240 {
1241   return propertyValue == nullptr
1242     ? std::string()
1243     : cmLocalVisualStudio7GeneratorEscapeForXML(propertyValue);
1244 }
1245
1246 void cmLocalVisualStudio7Generator::OutputDeploymentDebuggerTool(
1247   std::ostream& fout, std::string const& config, cmGeneratorTarget* target)
1248 {
1249   if (this->WindowsCEProject) {
1250     cmValue dir = target->GetProperty("DEPLOYMENT_REMOTE_DIRECTORY");
1251     cmValue additionalFiles =
1252       target->GetProperty("DEPLOYMENT_ADDITIONAL_FILES");
1253
1254     if (!dir && !additionalFiles) {
1255       return;
1256     }
1257
1258     fout << "\t\t\t<DeploymentTool\n"
1259             "\t\t\t\tForceDirty=\"-1\"\n"
1260             "\t\t\t\tRemoteDirectory=\""
1261          << GetEscapedPropertyIfValueNotNULL(dir->c_str())
1262          << "\"\n"
1263             "\t\t\t\tRegisterOutput=\"0\"\n"
1264             "\t\t\t\tAdditionalFiles=\""
1265          << GetEscapedPropertyIfValueNotNULL(additionalFiles->c_str())
1266          << "\"/>\n";
1267
1268     if (dir) {
1269       std::string const exe = *dir + "\\" + target->GetFullName(config);
1270
1271       fout << "\t\t\t<DebuggerTool\n"
1272               "\t\t\t\tRemoteExecutable=\""
1273            << this->EscapeForXML(exe)
1274            << "\"\n"
1275               "\t\t\t\tArguments=\"\"\n"
1276               "\t\t\t/>\n";
1277     }
1278   }
1279 }
1280
1281 void cmLocalVisualStudio7Generator::WriteTargetVersionAttribute(
1282   std::ostream& fout, cmGeneratorTarget* gt)
1283 {
1284   int major;
1285   int minor;
1286   gt->GetTargetVersion(major, minor);
1287   fout << "\t\t\t\tVersion=\"" << major << "." << minor << "\"\n";
1288 }
1289
1290 void cmLocalVisualStudio7GeneratorInternals::OutputLibraries(
1291   std::ostream& fout, ItemVector const& libs)
1292 {
1293   cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
1294   for (auto const& lib : libs) {
1295     if (lib.IsPath == cmComputeLinkInformation::ItemIsPath::Yes) {
1296       std::string rel = lg->MaybeRelativeToCurBinDir(lib.Value.Value);
1297       rel = lg->ConvertToXMLOutputPath(rel);
1298       fout << (lib.HasFeature() ? lib.GetFormattedItem(rel).Value : rel)
1299            << " ";
1300     } else if (!lib.Target ||
1301                lib.Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
1302       fout << lib.Value.Value << " ";
1303     }
1304   }
1305 }
1306
1307 void cmLocalVisualStudio7GeneratorInternals::OutputObjects(
1308   std::ostream& fout, cmGeneratorTarget* gt, std::string const& configName,
1309   const char* isep)
1310 {
1311   // VS < 8 does not support per-config source locations so we
1312   // list object library content on the link line instead.
1313   cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
1314
1315   std::vector<cmSourceFile const*> objs;
1316   gt->GetExternalObjects(objs, configName);
1317
1318   const char* sep = isep ? isep : "";
1319   for (cmSourceFile const* obj : objs) {
1320     if (!obj->GetObjectLibrary().empty()) {
1321       std::string const& objFile = obj->GetFullPath();
1322       std::string rel = lg->MaybeRelativeToCurBinDir(objFile);
1323       fout << sep << lg->ConvertToXMLOutputPath(rel);
1324       sep = " ";
1325     }
1326   }
1327 }
1328
1329 void cmLocalVisualStudio7Generator::OutputLibraryDirectories(
1330   std::ostream& fout, std::vector<std::string> const& dirs)
1331 {
1332   const char* comma = "";
1333   for (std::string dir : dirs) {
1334     // Remove any trailing slash and skip empty paths.
1335     if (dir.back() == '/') {
1336       dir = dir.substr(0, dir.size() - 1);
1337     }
1338     if (dir.empty()) {
1339       continue;
1340     }
1341
1342     // Switch to a relative path specification if it is shorter.
1343     if (cmSystemTools::FileIsFullPath(dir)) {
1344       std::string rel = this->MaybeRelativeToCurBinDir(dir);
1345       if (rel.size() < dir.size()) {
1346         dir = rel;
1347       }
1348     }
1349
1350     // First search a configuration-specific subdirectory and then the
1351     // original directory.
1352     fout << comma
1353          << this->ConvertToXMLOutputPath(dir + "/$(ConfigurationName)") << ","
1354          << this->ConvertToXMLOutputPath(dir);
1355     comma = ",";
1356   }
1357 }
1358
1359 void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout,
1360                                                     const std::string& libName,
1361                                                     cmGeneratorTarget* target)
1362 {
1363   std::vector<std::string> configs =
1364     this->Makefile->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
1365
1366   // We may be modifying the source groups temporarily, so make a copy.
1367   std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups();
1368
1369   AllConfigSources sources;
1370   sources.Sources = target->GetAllConfigSources();
1371
1372   // Add CMakeLists.txt file with rule to re-run CMake for user convenience.
1373   if (target->GetType() != cmStateEnums::GLOBAL_TARGET &&
1374       target->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
1375     if (cmSourceFile* sf = this->CreateVCProjBuildRule()) {
1376       cmGeneratorTarget::AllConfigSource acs;
1377       acs.Source = sf;
1378       acs.Kind = cmGeneratorTarget::SourceKindCustomCommand;
1379       for (size_t ci = 0; ci < configs.size(); ++ci) {
1380         acs.Configs.push_back(ci);
1381       }
1382       bool haveCMakeLists = false;
1383       for (cmGeneratorTarget::AllConfigSource& si : sources.Sources) {
1384         if (si.Source == sf) {
1385           haveCMakeLists = true;
1386           // Replace the explicit source reference with our generated one.
1387           si = acs;
1388           break;
1389         }
1390       }
1391       if (!haveCMakeLists) {
1392         sources.Sources.emplace_back(std::move(acs));
1393       }
1394     }
1395   }
1396
1397   for (size_t si = 0; si < sources.Sources.size(); ++si) {
1398     cmSourceFile const* sf = sources.Sources[si].Source;
1399     sources.Index[sf] = si;
1400     if (!sf->GetObjectLibrary().empty()) {
1401       if (this->FortranProject) {
1402         // Intel Fortran does not support per-config source locations
1403         // so we list object library content on the link line instead.
1404         // See OutputObjects.
1405         continue;
1406       }
1407     }
1408     // Add the file to the list of sources.
1409     std::string const source = sf->GetFullPath();
1410     cmSourceGroup* sourceGroup =
1411       this->Makefile->FindSourceGroup(source, sourceGroups);
1412     sourceGroup->AssignSource(sf);
1413   }
1414
1415   // open the project
1416   this->WriteProjectStart(fout, libName, target, sourceGroups);
1417   // write the configuration information
1418   this->WriteConfigurations(fout, configs, libName, target);
1419
1420   fout << "\t<Files>\n";
1421
1422   // Loop through every source group.
1423   for (unsigned int i = 0; i < sourceGroups.size(); ++i) {
1424     cmSourceGroup sg = sourceGroups[i];
1425     this->WriteGroup(&sg, target, fout, libName, configs, sources);
1426   }
1427
1428   fout << "\t</Files>\n";
1429
1430   // Write the VCProj file's footer.
1431   this->WriteVCProjFooter(fout, target);
1432 }
1433
1434 struct cmLVS7GFileConfig
1435 {
1436   std::string ObjectName;
1437   std::string CompileFlags;
1438   std::string CompileDefs;
1439   std::string CompileDefsConfig;
1440   std::string AdditionalDeps;
1441   std::string IncludeDirs;
1442   bool ExcludedFromBuild;
1443 };
1444
1445 class cmLocalVisualStudio7GeneratorFCInfo
1446 {
1447 public:
1448   cmLocalVisualStudio7GeneratorFCInfo(
1449     cmLocalVisualStudio7Generator* lg, cmGeneratorTarget* target,
1450     cmGeneratorTarget::AllConfigSource const& acs,
1451     std::vector<std::string> const& configs);
1452   std::map<std::string, cmLVS7GFileConfig> FileConfigMap;
1453 };
1454
1455 cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
1456   cmLocalVisualStudio7Generator* lg, cmGeneratorTarget* gt,
1457   cmGeneratorTarget::AllConfigSource const& acs,
1458   std::vector<std::string> const& configs)
1459 {
1460   cmSourceFile const& sf = *acs.Source;
1461   std::string objectName;
1462   if (gt->HasExplicitObjectName(&sf)) {
1463     objectName = gt->GetObjectName(&sf);
1464   }
1465
1466   // Compute per-source, per-config information.
1467   size_t ci = 0;
1468   for (std::string const& config : configs) {
1469     std::string configUpper = cmSystemTools::UpperCase(config);
1470     cmLVS7GFileConfig fc;
1471
1472     std::string lang =
1473       lg->GlobalGenerator->GetLanguageFromExtension(sf.GetExtension().c_str());
1474     const std::string& sourceLang = lg->GetSourceFileLanguage(sf);
1475     bool needForceLang = false;
1476     // source file does not match its extension language
1477     if (lang != sourceLang) {
1478       needForceLang = true;
1479       lang = sourceLang;
1480     }
1481
1482     cmGeneratorExpressionInterpreter genexInterpreter(lg, config, gt, lang);
1483
1484     bool needfc = false;
1485     if (!objectName.empty()) {
1486       fc.ObjectName = objectName;
1487       needfc = true;
1488     }
1489     const std::string COMPILE_FLAGS("COMPILE_FLAGS");
1490     if (cmValue cflags = sf.GetProperty(COMPILE_FLAGS)) {
1491       fc.CompileFlags = genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS);
1492       needfc = true;
1493     }
1494     const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
1495     if (cmValue coptions = sf.GetProperty(COMPILE_OPTIONS)) {
1496       lg->AppendCompileOptions(
1497         fc.CompileFlags,
1498         genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS));
1499       needfc = true;
1500     }
1501     // Add precompile headers compile options.
1502     const std::string pchSource = gt->GetPchSource(config, lang);
1503     if (!pchSource.empty() && !sf.GetProperty("SKIP_PRECOMPILE_HEADERS")) {
1504       std::string pchOptions;
1505       if (sf.GetFullPath() == pchSource) {
1506         pchOptions = gt->GetPchCreateCompileOptions(config, lang);
1507       } else {
1508         pchOptions = gt->GetPchUseCompileOptions(config, lang);
1509       }
1510
1511       lg->AppendCompileOptions(
1512         fc.CompileFlags,
1513         genexInterpreter.Evaluate(pchOptions, COMPILE_OPTIONS));
1514       needfc = true;
1515     }
1516
1517     if (lg->FortranProject) {
1518       switch (cmOutputConverter::GetFortranPreprocess(
1519         sf.GetSafeProperty("Fortran_PREPROCESS"))) {
1520         case cmOutputConverter::FortranPreprocess::Needed:
1521           fc.CompileFlags = cmStrCat("-fpp ", fc.CompileFlags);
1522           needfc = true;
1523           break;
1524         case cmOutputConverter::FortranPreprocess::NotNeeded:
1525           fc.CompileFlags = cmStrCat("-nofpp ", fc.CompileFlags);
1526           needfc = true;
1527           break;
1528         default:
1529           break;
1530       }
1531
1532       switch (cmOutputConverter::GetFortranFormat(
1533         sf.GetSafeProperty("Fortran_FORMAT"))) {
1534         case cmOutputConverter::FortranFormatFixed:
1535           fc.CompileFlags = "-fixed " + fc.CompileFlags;
1536           needfc = true;
1537           break;
1538         case cmOutputConverter::FortranFormatFree:
1539           fc.CompileFlags = "-free " + fc.CompileFlags;
1540           needfc = true;
1541           break;
1542         default:
1543           break;
1544       }
1545     }
1546     const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
1547     if (cmValue cdefs = sf.GetProperty(COMPILE_DEFINITIONS)) {
1548       fc.CompileDefs = genexInterpreter.Evaluate(*cdefs, COMPILE_DEFINITIONS);
1549       needfc = true;
1550     }
1551     std::string defPropName = cmStrCat("COMPILE_DEFINITIONS_", configUpper);
1552     if (cmValue ccdefs = sf.GetProperty(defPropName)) {
1553       fc.CompileDefsConfig =
1554         genexInterpreter.Evaluate(*ccdefs, COMPILE_DEFINITIONS);
1555       needfc = true;
1556     }
1557
1558     const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
1559     if (cmValue cincs = sf.GetProperty(INCLUDE_DIRECTORIES)) {
1560       fc.IncludeDirs = genexInterpreter.Evaluate(*cincs, INCLUDE_DIRECTORIES);
1561       needfc = true;
1562     }
1563
1564     // Check for extra object-file dependencies.
1565     if (cmValue deps = sf.GetProperty("OBJECT_DEPENDS")) {
1566       std::vector<std::string> depends = cmExpandedList(*deps);
1567       const char* sep = "";
1568       for (const std::string& d : depends) {
1569         fc.AdditionalDeps += sep;
1570         fc.AdditionalDeps += lg->ConvertToXMLOutputPath(d);
1571         sep = ";";
1572         needfc = true;
1573       }
1574     }
1575
1576     const std::string& linkLanguage = gt->GetLinkerLanguage(config);
1577     // If HEADER_FILE_ONLY is set, we must suppress this generation in
1578     // the project file
1579     fc.ExcludedFromBuild = sf.GetPropertyAsBool("HEADER_FILE_ONLY") ||
1580       !cm::contains(acs.Configs, ci) ||
1581       (gt->GetPropertyAsBool("UNITY_BUILD") &&
1582        sf.GetProperty("UNITY_SOURCE_FILE") &&
1583        !sf.GetPropertyAsBool("SKIP_UNITY_BUILD_INCLUSION"));
1584     if (fc.ExcludedFromBuild) {
1585       needfc = true;
1586     }
1587
1588     // if the source file does not match the linker language
1589     // then force c or c++
1590     if (needForceLang || (linkLanguage != lang)) {
1591       if (lang == "CXX") {
1592         // force a C++ file type
1593         fc.CompileFlags += " /TP ";
1594         needfc = true;
1595       } else if (lang == "C") {
1596         // force to c
1597         fc.CompileFlags += " /TC ";
1598         needfc = true;
1599       }
1600     }
1601
1602     if (needfc) {
1603       this->FileConfigMap[config] = fc;
1604     }
1605     ++ci;
1606   }
1607 }
1608
1609 std::string cmLocalVisualStudio7Generator::ComputeLongestObjectDirectory(
1610   cmGeneratorTarget const* target) const
1611 {
1612   std::vector<std::string> configs =
1613     target->Target->GetMakefile()->GetGeneratorConfigs(
1614       cmMakefile::ExcludeEmptyConfig);
1615
1616   // Compute the maximum length configuration name.
1617   std::string config_max;
1618   for (std::vector<std::string>::iterator i = configs.begin();
1619        i != configs.end(); ++i) {
1620     if (i->size() > config_max.size()) {
1621       config_max = *i;
1622     }
1623   }
1624
1625   // Compute the maximum length full path to the intermediate
1626   // files directory for any configuration.  This is used to construct
1627   // object file names that do not produce paths that are too long.
1628   std::string dir_max =
1629     cmStrCat(this->GetCurrentBinaryDirectory(), '/',
1630              this->GetTargetDirectory(target), '/', config_max, '/');
1631   return dir_max;
1632 }
1633
1634 bool cmLocalVisualStudio7Generator::WriteGroup(
1635   const cmSourceGroup* sg, cmGeneratorTarget* target, std::ostream& fout,
1636   const std::string& libName, std::vector<std::string> const& configs,
1637   AllConfigSources const& sources)
1638 {
1639   cmGlobalVisualStudio7Generator* gg =
1640     static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
1641   const std::vector<const cmSourceFile*>& sourceFiles = sg->GetSourceFiles();
1642   std::vector<cmSourceGroup> const& children = sg->GetGroupChildren();
1643
1644   // Write the children to temporary output.
1645   bool hasChildrenWithSources = false;
1646   std::ostringstream tmpOut;
1647   for (unsigned int i = 0; i < children.size(); ++i) {
1648     if (this->WriteGroup(&children[i], target, tmpOut, libName, configs,
1649                          sources)) {
1650       hasChildrenWithSources = true;
1651     }
1652   }
1653
1654   // If the group is empty, don't write it at all.
1655   if (sourceFiles.empty() && !hasChildrenWithSources) {
1656     return false;
1657   }
1658
1659   // If the group has a name, write the header.
1660   std::string const& name = sg->GetName();
1661   if (!name.empty()) {
1662     this->WriteVCProjBeginGroup(fout, name.c_str(), "");
1663   }
1664
1665   auto& sourcesVisited = this->GetSourcesVisited(target);
1666
1667   // Loop through each source in the source group.
1668   for (const cmSourceFile* sf : sourceFiles) {
1669     std::string source = sf->GetFullPath();
1670
1671     if (source != libName || target->GetType() == cmStateEnums::UTILITY ||
1672         target->GetType() == cmStateEnums::GLOBAL_TARGET ||
1673         target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
1674       // Look up the source kind and configs.
1675       std::map<cmSourceFile const*, size_t>::const_iterator map_it =
1676         sources.Index.find(sf);
1677       // The map entry must exist because we populated it earlier.
1678       assert(map_it != sources.Index.end());
1679       cmGeneratorTarget::AllConfigSource const& acs =
1680         sources.Sources[map_it->second];
1681
1682       FCInfo fcinfo(this, target, acs, configs);
1683
1684       fout << "\t\t\t<File\n";
1685       std::string d = this->ConvertToXMLOutputPathSingle(source);
1686       // Tell MS-Dev what the source is.  If the compiler knows how to
1687       // build it, then it will.
1688       fout << "\t\t\t\tRelativePath=\"" << d << "\">\n";
1689       if (cmCustomCommand const* command = sf->GetCustomCommand()) {
1690         if (sourcesVisited.insert(sf).second) {
1691           this->WriteCustomRule(fout, configs, source.c_str(), *command,
1692                                 fcinfo);
1693         }
1694       } else if (!fcinfo.FileConfigMap.empty()) {
1695         const char* aCompilerTool = "VCCLCompilerTool";
1696         std::string ppLang = "CXX";
1697         if (this->FortranProject) {
1698           aCompilerTool = "VFFortranCompilerTool";
1699         }
1700         std::string const& lang = sf->GetLanguage();
1701         std::string ext = sf->GetExtension();
1702         ext = cmSystemTools::LowerCase(ext);
1703         if (ext == "idl") {
1704           aCompilerTool = "VCMIDLTool";
1705           if (this->FortranProject) {
1706             aCompilerTool = "VFMIDLTool";
1707           }
1708         }
1709         if (ext == "rc") {
1710           aCompilerTool = "VCResourceCompilerTool";
1711           ppLang = "RC";
1712           if (this->FortranProject) {
1713             aCompilerTool = "VFResourceCompilerTool";
1714           }
1715         }
1716         if (ext == "def") {
1717           aCompilerTool = "VCCustomBuildTool";
1718           if (this->FortranProject) {
1719             aCompilerTool = "VFCustomBuildTool";
1720           }
1721         }
1722         if (gg->IsMasmEnabled() && !this->FortranProject &&
1723             lang == "ASM_MASM") {
1724           aCompilerTool = "MASM";
1725         }
1726         if (acs.Kind == cmGeneratorTarget::SourceKindExternalObject) {
1727           aCompilerTool = "VCCustomBuildTool";
1728         }
1729         for (auto const& fci : fcinfo.FileConfigMap) {
1730           cmLVS7GFileConfig const& fc = fci.second;
1731           fout << "\t\t\t\t<FileConfiguration\n"
1732                << "\t\t\t\t\tName=\"" << fci.first << "|"
1733                << gg->GetPlatformName() << "\"";
1734           if (fc.ExcludedFromBuild) {
1735             fout << " ExcludedFromBuild=\"true\"";
1736           }
1737           fout << ">\n";
1738           fout << "\t\t\t\t\t<Tool\n"
1739                << "\t\t\t\t\tName=\"" << aCompilerTool << "\"\n";
1740           if (!fc.CompileFlags.empty() || !fc.CompileDefs.empty() ||
1741               !fc.CompileDefsConfig.empty() || !fc.IncludeDirs.empty()) {
1742             Options::Tool tool = Options::Compiler;
1743             cmVS7FlagTable const* table =
1744               cmLocalVisualStudio7GeneratorFlagTable;
1745             if (this->FortranProject) {
1746               tool = Options::FortranCompiler;
1747               table = cmLocalVisualStudio7GeneratorFortranFlagTable;
1748             }
1749             Options fileOptions(this, tool, table, gg->ExtraFlagTable);
1750             fileOptions.Parse(fc.CompileFlags);
1751             fileOptions.AddDefines(fc.CompileDefs);
1752             fileOptions.AddDefines(fc.CompileDefsConfig);
1753             // validate source level include directories
1754             std::vector<std::string> includes;
1755             this->AppendIncludeDirectories(includes, fc.IncludeDirs, *sf);
1756             fileOptions.AddIncludes(includes);
1757             fileOptions.OutputFlagMap(fout, 5);
1758             fileOptions.OutputAdditionalIncludeDirectories(
1759               fout, 5,
1760               ppLang == "CXX" && this->FortranProject ? "Fortran" : ppLang);
1761             fileOptions.OutputPreprocessorDefinitions(fout, 5, ppLang);
1762           }
1763           if (!fc.AdditionalDeps.empty()) {
1764             fout << "\t\t\t\t\tAdditionalDependencies=\"" << fc.AdditionalDeps
1765                  << "\"\n";
1766           }
1767           if (!fc.ObjectName.empty()) {
1768             fout << "\t\t\t\t\tObjectFile=\"$(IntDir)/" << fc.ObjectName
1769                  << "\"\n";
1770           }
1771           fout << "\t\t\t\t\t/>\n"
1772                << "\t\t\t\t</FileConfiguration>\n";
1773         }
1774       }
1775       fout << "\t\t\t</File>\n";
1776     }
1777   }
1778
1779   // If the group has children with source files, write the children.
1780   if (hasChildrenWithSources) {
1781     fout << tmpOut.str();
1782   }
1783
1784   // If the group has a name, write the footer.
1785   if (!name.empty()) {
1786     this->WriteVCProjEndGroup(fout);
1787   }
1788
1789   return true;
1790 }
1791
1792 void cmLocalVisualStudio7Generator::WriteCustomRule(
1793   std::ostream& fout, std::vector<std::string> const& configs,
1794   const char* source, const cmCustomCommand& command, FCInfo& fcinfo)
1795 {
1796   cmGlobalVisualStudio7Generator* gg =
1797     static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
1798
1799   // Write the rule for each configuration.
1800   const char* compileTool = "VCCLCompilerTool";
1801   if (this->FortranProject) {
1802     compileTool = "VFCLCompilerTool";
1803   }
1804   const char* customTool = "VCCustomBuildTool";
1805   if (this->FortranProject) {
1806     customTool = "VFCustomBuildTool";
1807   }
1808   for (std::string const& config : configs) {
1809     cmCustomCommandGenerator ccg(command, config, this);
1810     cmLVS7GFileConfig const& fc = fcinfo.FileConfigMap[config];
1811     fout << "\t\t\t\t<FileConfiguration\n";
1812     fout << "\t\t\t\t\tName=\"" << config << "|" << gg->GetPlatformName()
1813          << "\">\n";
1814     if (!fc.CompileFlags.empty()) {
1815       fout << "\t\t\t\t\t<Tool\n"
1816            << "\t\t\t\t\tName=\"" << compileTool << "\"\n"
1817            << "\t\t\t\t\tAdditionalOptions=\""
1818            << this->EscapeForXML(fc.CompileFlags) << "\"/>\n";
1819     }
1820
1821     std::string comment = this->ConstructComment(ccg);
1822     std::string script = this->ConstructScript(ccg);
1823     if (this->FortranProject) {
1824       cmSystemTools::ReplaceString(script, "$(Configuration)", config);
1825     }
1826     script += this->FinishConstructScript(VsProjectType::vcxproj);
1827     /* clang-format off */
1828     fout << "\t\t\t\t\t<Tool\n"
1829          << "\t\t\t\t\tName=\"" << customTool << "\"\n"
1830          << "\t\t\t\t\tDescription=\""
1831          << this->EscapeForXML(comment) << "\"\n"
1832          << "\t\t\t\t\tCommandLine=\""
1833          << this->EscapeForXML(script) << "\"\n"
1834          << "\t\t\t\t\tAdditionalDependencies=\"";
1835     /* clang-format on */
1836     if (ccg.GetDepends().empty()) {
1837       // There are no real dependencies.  Produce an artificial one to
1838       // make sure the rule runs reliably.
1839       if (!cmSystemTools::FileExists(source)) {
1840         cmsys::ofstream depout(source);
1841         depout << "Artificial dependency for a custom command.\n";
1842       }
1843       fout << this->ConvertToXMLOutputPath(source);
1844     } else {
1845       // Write out the dependencies for the rule.
1846       for (std::string const& d : ccg.GetDepends()) {
1847         // Get the real name of the dependency in case it is a CMake target.
1848         std::string dep;
1849         if (this->GetRealDependency(d, config, dep)) {
1850           fout << this->ConvertToXMLOutputPath(dep) << ";";
1851         }
1852       }
1853     }
1854     fout << "\"\n";
1855     fout << "\t\t\t\t\tOutputs=\"";
1856     if (ccg.GetOutputs().empty()) {
1857       fout << source << "_force";
1858     } else {
1859       // Write a rule for the output generated by this command.
1860       const char* sep = "";
1861       for (std::string const& output : ccg.GetOutputs()) {
1862         fout << sep << this->ConvertToXMLOutputPathSingle(output);
1863         sep = ";";
1864       }
1865     }
1866     fout << "\"/>\n";
1867     fout << "\t\t\t\t</FileConfiguration>\n";
1868   }
1869 }
1870
1871 void cmLocalVisualStudio7Generator::WriteVCProjBeginGroup(std::ostream& fout,
1872                                                           const char* group,
1873                                                           const char*)
1874 {
1875   /* clang-format off */
1876   fout << "\t\t<Filter\n"
1877        << "\t\t\tName=\"" << group << "\"\n"
1878        << "\t\t\tFilter=\"\">\n";
1879   /* clang-format on */
1880 }
1881
1882 void cmLocalVisualStudio7Generator::WriteVCProjEndGroup(std::ostream& fout)
1883 {
1884   fout << "\t\t</Filter>\n";
1885 }
1886
1887 // look for custom rules on a target and collect them together
1888 void cmLocalVisualStudio7Generator::OutputTargetRules(
1889   std::ostream& fout, const std::string& configName, cmGeneratorTarget* target,
1890   const std::string& /*libName*/)
1891 {
1892   if (target->GetType() > cmStateEnums::GLOBAL_TARGET) {
1893     return;
1894   }
1895   EventWriter event(this, configName, fout);
1896
1897   // Add pre-build event.
1898   const char* tool =
1899     this->FortranProject ? "VFPreBuildEventTool" : "VCPreBuildEventTool";
1900   event.Start(tool);
1901   event.Write(target->GetPreBuildCommands());
1902   event.Finish();
1903
1904   // Add pre-link event.
1905   tool = this->FortranProject ? "VFPreLinkEventTool" : "VCPreLinkEventTool";
1906   event.Start(tool);
1907   bool addedPrelink = false;
1908   cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
1909     target->GetModuleDefinitionInfo(configName);
1910   if (mdi && mdi->DefFileGenerated) {
1911     addedPrelink = true;
1912     std::vector<cmCustomCommand> commands = target->GetPreLinkCommands();
1913     cmGlobalVisualStudioGenerator* gg =
1914       static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator);
1915     gg->AddSymbolExportCommand(target, commands, configName);
1916     event.Write(commands);
1917   }
1918   if (!addedPrelink) {
1919     event.Write(target->GetPreLinkCommands());
1920   }
1921   std::unique_ptr<cmCustomCommand> pcc(
1922     this->MaybeCreateImplibDir(target, configName, this->FortranProject));
1923   if (pcc.get()) {
1924     event.Write(*pcc);
1925   }
1926   event.Finish();
1927
1928   // Add post-build event.
1929   tool =
1930     this->FortranProject ? "VFPostBuildEventTool" : "VCPostBuildEventTool";
1931   event.Start(tool);
1932   event.Write(target->GetPostBuildCommands());
1933   event.Finish();
1934 }
1935
1936 void cmLocalVisualStudio7Generator::WriteProjectSCC(std::ostream& fout,
1937                                                     cmGeneratorTarget* target)
1938 {
1939   // if we have all the required Source code control tags
1940   // then add that to the project
1941   cmValue vsProjectname = target->GetProperty("VS_SCC_PROJECTNAME");
1942   cmValue vsLocalpath = target->GetProperty("VS_SCC_LOCALPATH");
1943   cmValue vsProvider = target->GetProperty("VS_SCC_PROVIDER");
1944
1945   if (vsProvider && vsLocalpath && vsProjectname) {
1946     /* clang-format off */
1947     fout << "\tSccProjectName=\"" << *vsProjectname << "\"\n"
1948          << "\tSccLocalPath=\"" << *vsLocalpath << "\"\n"
1949          << "\tSccProvider=\"" << *vsProvider << "\"\n";
1950     /* clang-format on */
1951
1952     cmValue vsAuxPath = target->GetProperty("VS_SCC_AUXPATH");
1953     if (vsAuxPath) {
1954       fout << "\tSccAuxPath=\"" << *vsAuxPath << "\"\n";
1955     }
1956   }
1957 }
1958
1959 void cmLocalVisualStudio7Generator::WriteProjectStartFortran(
1960   std::ostream& fout, const std::string& libName, cmGeneratorTarget* target)
1961 {
1962
1963   cmGlobalVisualStudio7Generator* gg =
1964     static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
1965   /* clang-format off */
1966   fout << "<?xml version=\"1.0\" encoding = \""
1967        << gg->Encoding() << "\"?>\n"
1968        << "<VisualStudioProject\n"
1969        << "\tProjectCreator=\"Intel Fortran\"\n"
1970        << "\tVersion=\"" << gg->GetIntelProjectVersion() << "\"\n";
1971   /* clang-format on */
1972   cmValue p = target->GetProperty("VS_KEYWORD");
1973   const char* keyword = p ? p->c_str() : "Console Application";
1974   const char* projectType = 0;
1975   switch (target->GetType()) {
1976     case cmStateEnums::OBJECT_LIBRARY:
1977     case cmStateEnums::STATIC_LIBRARY:
1978       projectType = "typeStaticLibrary";
1979       if (keyword) {
1980         keyword = "Static Library";
1981       }
1982       break;
1983     case cmStateEnums::SHARED_LIBRARY:
1984     case cmStateEnums::MODULE_LIBRARY:
1985       projectType = "typeDynamicLibrary";
1986       if (!keyword) {
1987         keyword = "Dll";
1988       }
1989       break;
1990     case cmStateEnums::EXECUTABLE:
1991       if (!keyword) {
1992         keyword = "Console Application";
1993       }
1994       projectType = 0;
1995       break;
1996     case cmStateEnums::UTILITY:
1997     case cmStateEnums::GLOBAL_TARGET:
1998     case cmStateEnums::INTERFACE_LIBRARY:
1999     case cmStateEnums::UNKNOWN_LIBRARY:
2000       break;
2001   }
2002   if (projectType) {
2003     fout << "\tProjectType=\"" << projectType << "\"\n";
2004   }
2005   this->WriteProjectSCC(fout, target);
2006   /* clang-format off */
2007   fout<< "\tKeyword=\"" << keyword << "\">\n"
2008        << "\tProjectGUID=\"{" << gg->GetGUID(libName) << "}\">\n"
2009        << "\t<Platforms>\n"
2010        << "\t\t<Platform\n\t\t\tName=\"" << gg->GetPlatformName() << "\"/>\n"
2011        << "\t</Platforms>\n";
2012   /* clang-format on */
2013 }
2014
2015 void cmLocalVisualStudio7Generator::WriteProjectStart(
2016   std::ostream& fout, const std::string& libName, cmGeneratorTarget* target,
2017   std::vector<cmSourceGroup>&)
2018 {
2019   if (this->FortranProject) {
2020     this->WriteProjectStartFortran(fout, libName, target);
2021     return;
2022   }
2023
2024   cmGlobalVisualStudio7Generator* gg =
2025     static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
2026
2027   /* clang-format off */
2028   fout << "<?xml version=\"1.0\" encoding = \""
2029        << gg->Encoding() << "\"?>\n"
2030        << "<VisualStudioProject\n"
2031        << "\tProjectType=\"Visual C++\"\n";
2032   /* clang-format on */
2033   fout << "\tVersion=\"" << (static_cast<uint16_t>(gg->GetVersion()) / 10)
2034        << ".00\"\n";
2035   cmValue p = target->GetProperty("PROJECT_LABEL");
2036   const std::string projLabel = p ? *p : libName;
2037   p = target->GetProperty("VS_KEYWORD");
2038   const std::string keyword = p ? *p : "Win32Proj";
2039   fout << "\tName=\"" << projLabel << "\"\n";
2040   fout << "\tProjectGUID=\"{" << gg->GetGUID(libName) << "}\"\n";
2041   this->WriteProjectSCC(fout, target);
2042   if (cmValue targetFrameworkVersion =
2043         target->GetProperty("VS_DOTNET_TARGET_FRAMEWORK_VERSION")) {
2044     fout << "\tTargetFrameworkVersion=\"" << *targetFrameworkVersion << "\"\n";
2045   }
2046   /* clang-format off */
2047   fout << "\tKeyword=\"" << keyword << "\">\n"
2048        << "\t<Platforms>\n"
2049        << "\t\t<Platform\n\t\t\tName=\"" << gg->GetPlatformName() << "\"/>\n"
2050        << "\t</Platforms>\n";
2051   /* clang-format on */
2052   if (gg->IsMasmEnabled()) {
2053     /* clang-format off */
2054     fout <<
2055       "\t<ToolFiles>\n"
2056       "\t\t<DefaultToolFile\n"
2057       "\t\t\tFileName=\"masm.rules\"\n"
2058       "\t\t/>\n"
2059       "\t</ToolFiles>\n"
2060       ;
2061     /* clang-format on */
2062   }
2063 }
2064
2065 void cmLocalVisualStudio7Generator::WriteVCProjFooter(
2066   std::ostream& fout, cmGeneratorTarget* target)
2067 {
2068   fout << "\t<Globals>\n";
2069
2070   for (std::string const& key : target->GetPropertyKeys()) {
2071     if (cmHasLiteralPrefix(key, "VS_GLOBAL_")) {
2072       std::string name = key.substr(10);
2073       if (!name.empty()) {
2074         /* clang-format off */
2075         fout << "\t\t<Global\n"
2076              << "\t\t\tName=\"" << name << "\"\n"
2077              << "\t\t\tValue=\"" << target->GetProperty(key) << "\"\n"
2078              << "\t\t/>\n";
2079         /* clang-format on */
2080       }
2081     }
2082   }
2083
2084   fout << "\t</Globals>\n"
2085        << "</VisualStudioProject>\n";
2086 }
2087
2088 std::string cmLocalVisualStudio7Generator::EscapeForXML(const std::string& s)
2089 {
2090   return cmLocalVisualStudio7GeneratorEscapeForXML(s);
2091 }
2092
2093 std::string cmLocalVisualStudio7Generator::ConvertToXMLOutputPath(
2094   const std::string& path)
2095 {
2096   std::string ret =
2097     this->ConvertToOutputFormat(path, cmOutputConverter::SHELL);
2098   cmSystemTools::ReplaceString(ret, "&", "&amp;");
2099   cmSystemTools::ReplaceString(ret, "\"", "&quot;");
2100   cmSystemTools::ReplaceString(ret, "<", "&lt;");
2101   cmSystemTools::ReplaceString(ret, ">", "&gt;");
2102   return ret;
2103 }
2104
2105 std::string cmLocalVisualStudio7Generator::ConvertToXMLOutputPathSingle(
2106   const std::string& path)
2107 {
2108   std::string ret =
2109     this->ConvertToOutputFormat(path, cmOutputConverter::SHELL);
2110   cmSystemTools::ReplaceString(ret, "\"", "");
2111   cmSystemTools::ReplaceString(ret, "&", "&amp;");
2112   cmSystemTools::ReplaceString(ret, "<", "&lt;");
2113   cmSystemTools::ReplaceString(ret, ">", "&gt;");
2114   return ret;
2115 }
2116
2117 void cmVS7GeneratorOptions::OutputFlag(std::ostream& fout, int indent,
2118                                        const std::string& flag,
2119                                        const std::string& content)
2120 {
2121   fout.fill('\t');
2122   fout.width(indent);
2123   // write an empty string to get the fill level indent to print
2124   fout << "";
2125   fout << flag << "=\"";
2126   fout << cmLocalVisualStudio7GeneratorEscapeForXML(content);
2127   fout << "\"\n";
2128 }
2129
2130 // This class is used to parse an existing vs 7 project
2131 // and extract the GUID
2132 class cmVS7XMLParser : public cmXMLParser
2133 {
2134 public:
2135   virtual void EndElement(const std::string& /* name */) {}
2136   virtual void StartElement(const std::string& name, const char** atts)
2137   {
2138     // once the GUID is found do nothing
2139     if (!this->GUID.empty()) {
2140       return;
2141     }
2142     int i = 0;
2143     if ("VisualStudioProject" == name) {
2144       while (atts[i]) {
2145         if (strcmp(atts[i], "ProjectGUID") == 0) {
2146           if (atts[i + 1]) {
2147             this->GUID = atts[i + 1];
2148             if (this->GUID[0] == '{') {
2149               // remove surrounding curly brackets
2150               this->GUID = this->GUID.substr(1, this->GUID.size() - 2);
2151             }
2152           } else {
2153             this->GUID.clear();
2154           }
2155           return;
2156         }
2157         ++i;
2158       }
2159     }
2160   }
2161   int InitializeParser()
2162   {
2163     int ret = cmXMLParser::InitializeParser();
2164     if (ret == 0) {
2165       return ret;
2166     }
2167     // visual studio projects have a strange encoding, but it is
2168     // really utf-8
2169     XML_SetEncoding(static_cast<XML_Parser>(this->Parser), "utf-8");
2170     return 1;
2171   }
2172   std::string GUID;
2173 };
2174
2175 void cmLocalVisualStudio7Generator::ReadAndStoreExternalGUID(
2176   const std::string& name, const char* path)
2177 {
2178   cmVS7XMLParser parser;
2179   parser.ParseFile(path);
2180   // if we can not find a GUID then we will generate one later
2181   if (parser.GUID.empty()) {
2182     return;
2183   }
2184   std::string guidStoreName = cmStrCat(name, "_GUID_CMAKE");
2185   // save the GUID in the cache
2186   this->GlobalGenerator->GetCMakeInstance()->AddCacheEntry(
2187     guidStoreName, parser.GUID, "Stored GUID", cmStateEnums::INTERNAL);
2188 }
2189
2190 std::string cmLocalVisualStudio7Generator::GetTargetDirectory(
2191   cmGeneratorTarget const* target) const
2192 {
2193   std::string dir = cmStrCat(target->GetName(), ".dir");
2194   return dir;
2195 }
2196
2197 static bool cmLVS7G_IsFAT(const char* dir)
2198 {
2199   if (dir[0] && dir[1] == ':') {
2200     char volRoot[4] = "_:/";
2201     volRoot[0] = dir[0];
2202     char fsName[16];
2203     if (GetVolumeInformationA(volRoot, 0, 0, 0, 0, 0, fsName, 16) &&
2204         strstr(fsName, "FAT") != 0) {
2205       return true;
2206     }
2207   }
2208   return false;
2209 }