1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3 #pragma once
4 
5 #include "cmConfigure.h" // IWYU pragma: keep
6 
7 #include <iosfwd>
8 #include <map>
9 #include <set>
10 #include <string>
11 #include <vector>
12 
13 #include "cmGlobalGenerator.h"
14 #include "cmTargetDepend.h"
15 
16 class cmCustomCommand;
17 class cmGeneratorTarget;
18 class cmLocalGenerator;
19 class cmMakefile;
20 class cmake;
21 
22 /** \class cmGlobalVisualStudioGenerator
23  * \brief Base class for global Visual Studio generators.
24  *
25  * cmGlobalVisualStudioGenerator provides functionality common to all
26  * global Visual Studio generators.
27  */
28 class cmGlobalVisualStudioGenerator : public cmGlobalGenerator
29 {
30 public:
31   /** Known versions of Visual Studio.  */
32   enum VSVersion
33   {
34     VS9 = 90,
35     VS10 = 100,
36     VS11 = 110,
37     VS12 = 120,
38     /* VS13 = 130 was skipped */
39     VS14 = 140,
40     VS15 = 150,
41     VS16 = 160,
42     VS17 = 170
43   };
44 
45   virtual ~cmGlobalVisualStudioGenerator();
46 
47   VSVersion GetVersion() const;
48   void SetVersion(VSVersion v);
49 
50   /** Is the installed VS an Express edition?  */
IsExpressEdition()51   bool IsExpressEdition() const { return this->ExpressEdition; }
52 
53   void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
54                       bool optional) override;
55 
56   bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf) override;
57 
58   /**
59    * Get the name of the target platform (architecture) for which we generate.
60    * The names are as defined by VS, e.g. "Win32", "x64", "Itanium", "ARM".
61    */
62   std::string const& GetPlatformName() const;
63 
64   /**
65    * Configure CMake's Visual Studio macros file into the user's Visual
66    * Studio macros directory.
67    */
68   virtual void ConfigureCMakeVisualStudioMacros();
69 
70   /**
71    * Where does this version of Visual Studio look for macros for the
72    * current user? Returns the empty string if this version of Visual
73    * Studio does not implement support for VB macros.
74    */
75   virtual std::string GetUserMacrosDirectory();
76 
77   /**
78    * What is the reg key path to "vsmacros" for this version of Visual
79    * Studio?
80    */
81   virtual std::string GetUserMacrosRegKeyBase();
82 
83   enum MacroName
84   {
85     MacroReload,
86     MacroStop
87   };
88 
89   /**
90    * Call the ReloadProjects macro if necessary based on
91    * GetFilesReplacedDuringGenerate results.
92    */
93   void CallVisualStudioMacro(MacroName m, const std::string& vsSolutionFile);
94 
95   // return true if target is fortran only
96   bool TargetIsFortranOnly(const cmGeneratorTarget* gt);
97 
98   /** Get the top-level registry key for this VS version.  */
99   std::string GetRegistryBase();
100 
101   /** Get the top-level registry key for the given VS version.  */
102   static std::string GetRegistryBase(const char* version);
103 
104   /** Return true if the generated build tree may contain multiple builds.
105       i.e. "Can I build Debug and Release in the same tree?" */
IsMultiConfig()106   bool IsMultiConfig() const override { return true; }
107 
108   /** Return true if building for Windows CE */
TargetsWindowsCE()109   virtual bool TargetsWindowsCE() const { return false; }
110 
IsIncludeExternalMSProjectSupported()111   bool IsIncludeExternalMSProjectSupported() const override { return true; }
112 
113   /** Get encoding used by generator for generated source files
114    */
GetMakefileEncoding()115   codecvt::Encoding GetMakefileEncoding() const override
116   {
117     return codecvt::ANSI;
118   }
119 
120   class TargetSet : public std::set<cmGeneratorTarget const*>
121   {
122   };
123   class TargetCompare
124   {
125     std::string First;
126 
127   public:
TargetCompare(std::string const & first)128     TargetCompare(std::string const& first)
129       : First(first)
130     {
131     }
132     bool operator()(cmGeneratorTarget const* l,
133                     cmGeneratorTarget const* r) const;
134   };
135   class OrderedTargetDependSet;
136 
137   bool FindMakeProgram(cmMakefile*) override;
138 
139   std::string ExpandCFGIntDir(const std::string& str,
140                               const std::string& config) const override;
141 
142   void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override;
143 
144   std::string GetStartupProjectName(cmLocalGenerator const* root) const;
145 
146   void AddSymbolExportCommand(cmGeneratorTarget*,
147                               std::vector<cmCustomCommand>& commands,
148                               std::string const& configName);
149 
150   bool Open(const std::string& bindir, const std::string& projectName,
151             bool dryRun) override;
152 
IsVisualStudio()153   bool IsVisualStudio() const override { return true; }
154 
155 protected:
156   cmGlobalVisualStudioGenerator(cmake* cm,
157                                 std::string const& platformInGeneratorName);
158 
159   void AddExtraIDETargets() override;
160 
161   // Does this VS version link targets to each other if there are
162   // dependencies in the SLN file?  This was done for VS versions
163   // below 8.
VSLinksDependencies()164   virtual bool VSLinksDependencies() const { return true; }
165 
166   const char* GetIDEVersion() const;
167 
168   void WriteSLNHeader(std::ostream& fout);
169 
170   bool ComputeTargetDepends() override;
171   class VSDependSet : public std::set<std::string>
172   {
173   };
174   class VSDependMap : public std::map<cmGeneratorTarget const*, VSDependSet>
175   {
176   };
177   VSDependMap VSTargetDepends;
178   void ComputeVSTargetDepends(cmGeneratorTarget*);
179 
180   bool CheckTargetLinks(cmGeneratorTarget& target, const std::string& name);
181   std::string GetUtilityForTarget(cmGeneratorTarget& target,
182                                   const std::string&);
183   virtual std::string WriteUtilityDepend(cmGeneratorTarget const*) = 0;
184   std::string GetUtilityDepend(const cmGeneratorTarget* target);
185   using UtilityDependsMap = std::map<cmGeneratorTarget const*, std::string>;
186   UtilityDependsMap UtilityDepends;
187 
188 protected:
189   VSVersion Version;
190   bool ExpressEdition;
191 
192   std::string GeneratorPlatform;
193   std::string DefaultPlatformName;
194   bool PlatformInGeneratorName = false;
195 
196 private:
197   virtual std::string GetVSMakeProgram() = 0;
PrintCompilerAdvice(std::ostream &,std::string const &,cmValue)198   void PrintCompilerAdvice(std::ostream&, std::string const&,
199                            cmValue) const override
200   {
201   }
202 
203   void FollowLinkDepends(cmGeneratorTarget const* target,
204                          std::set<cmGeneratorTarget const*>& linked);
205 
206   class TargetSetMap : public std::map<cmGeneratorTarget*, TargetSet>
207   {
208   };
209   TargetSetMap TargetLinkClosure;
210   void FillLinkClosure(const cmGeneratorTarget* target, TargetSet& linked);
211   TargetSet const& GetTargetLinkClosure(cmGeneratorTarget* target);
212 };
213 
214 class cmGlobalVisualStudioGenerator::OrderedTargetDependSet
215   : public std::multiset<cmTargetDepend,
216                          cmGlobalVisualStudioGenerator::TargetCompare>
217 {
218   using derived = std::multiset<cmTargetDepend,
219                                 cmGlobalVisualStudioGenerator::TargetCompare>;
220 
221 public:
222   using TargetDependSet = cmGlobalGenerator::TargetDependSet;
223   using TargetSet = cmGlobalVisualStudioGenerator::TargetSet;
224   OrderedTargetDependSet(TargetDependSet const&, std::string const& first);
225   OrderedTargetDependSet(TargetSet const&, std::string const& first);
226 };
227