Browse Source

Merge topic 'vs-zero_check-proj'

925da7d428 VS: Write ZERO_CHECK.proj for VS19 and above
11b8366e55 VS: Introduce IsInSolution to check whether a target is in sln file
0682cd3657 VS: Add proj as a project type to VsProjectType
6ab2c40c17 cmGlobalVisualStudio7Generator: Drop unused method

Acked-by: Kitware Robot <[email protected]>
Merge-request: !6891
Brad King 3 years ago
parent
commit
2ac3db2d42

+ 7 - 0
Source/cmGlobalVisualStudio10Generator.cxx

@@ -1286,6 +1286,13 @@ cmGlobalVisualStudio10Generator::GenerateBuildCommand(
   return makeCommands;
 }
 
+bool cmGlobalVisualStudio10Generator::IsInSolution(
+  const cmGeneratorTarget* gt) const
+{
+  return gt->IsInBuildSystem() &&
+    gt->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET;
+}
+
 bool cmGlobalVisualStudio10Generator::Find64BitTools(cmMakefile* mf)
 {
   if (this->DefaultPlatformToolset == "v100") {

+ 2 - 0
Source/cmGlobalVisualStudio10Generator.h

@@ -118,6 +118,8 @@ public:
     return this->WindowsTargetPlatformVersion;
   }
 
+  bool IsInSolution(const cmGeneratorTarget* gt) const override;
+
   /** Return true if building for WindowsCE */
   bool TargetsWindowsCE() const override { return this->SystemIsWindowsCE; }
 

+ 2 - 18
Source/cmGlobalVisualStudio7Generator.cxx

@@ -359,7 +359,7 @@ void cmGlobalVisualStudio7Generator::WriteTargetConfigurations(
   // loop over again and write out configurations for each target
   // in the solution
   for (cmGeneratorTarget const* target : projectTargets) {
-    if (!target->IsInBuildSystem()) {
+    if (!this->IsInSolution(target)) {
       continue;
     }
     cmValue expath = target->GetProperty("EXTERNAL_MSPROJECT");
@@ -396,7 +396,7 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution(
   VisualStudioFolders.clear();
 
   for (cmGeneratorTarget const* target : projectTargets) {
-    if (!target->IsInBuildSystem()) {
+    if (!this->IsInSolution(target)) {
       continue;
     }
     bool written = false;
@@ -458,22 +458,6 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution(
   }
 }
 
-void cmGlobalVisualStudio7Generator::WriteTargetDepends(
-  std::ostream& fout, OrderedTargetDependSet const& projectTargets)
-{
-  for (cmGeneratorTarget const* target : projectTargets) {
-    if (!target->IsInBuildSystem()) {
-      continue;
-    }
-    cmValue vcprojName = target->GetProperty("GENERATOR_FILE_NAME");
-    if (vcprojName) {
-      std::string dir =
-        target->GetLocalGenerator()->GetCurrentSourceDirectory();
-      this->WriteProjectDepends(fout, *vcprojName, dir, target);
-    }
-  }
-}
-
 void cmGlobalVisualStudio7Generator::WriteFolders(std::ostream& fout)
 {
   cm::string_view const prefix = "CMAKE_FOLDER_GUID_";

+ 0 - 2
Source/cmGlobalVisualStudio7Generator.h

@@ -148,8 +148,6 @@ protected:
   virtual void WriteTargetsToSolution(
     std::ostream& fout, cmLocalGenerator* root,
     OrderedTargetDependSet const& projectTargets);
-  virtual void WriteTargetDepends(
-    std::ostream& fout, OrderedTargetDependSet const& projectTargets);
   virtual void WriteTargetConfigurations(
     std::ostream& fout, std::vector<std::string> const& configs,
     OrderedTargetDependSet const& projectTargets);

+ 1 - 1
Source/cmGlobalVisualStudio8Generator.cxx

@@ -392,7 +392,7 @@ void cmGlobalVisualStudio8Generator::WriteProjectDepends(
   TargetDependSet const& unordered = this->GetTargetDirectDepends(gt);
   OrderedTargetDependSet depends(unordered, std::string());
   for (cmTargetDepend const& i : depends) {
-    if (!i->IsInBuildSystem()) {
+    if (!this->IsInSolution(i)) {
       continue;
     }
     std::string guid = this->GetGUID(i->GetName());

+ 6 - 0
Source/cmGlobalVisualStudioGenerator.cxx

@@ -837,6 +837,12 @@ bool cmGlobalVisualStudioGenerator::TargetIsFortranOnly(
   return languages.size() == 1 && *languages.begin() == "Fortran";
 }
 
+bool cmGlobalVisualStudioGenerator::IsInSolution(
+  const cmGeneratorTarget* gt) const
+{
+  return gt->IsInBuildSystem();
+}
+
 bool cmGlobalVisualStudioGenerator::TargetCompare::operator()(
   cmGeneratorTarget const* l, cmGeneratorTarget const* r) const
 {

+ 3 - 0
Source/cmGlobalVisualStudioGenerator.h

@@ -98,6 +98,9 @@ public:
   // return true if target is fortran only
   bool TargetIsFortranOnly(const cmGeneratorTarget* gt);
 
+  // return true if target should be included in solution.
+  virtual bool IsInSolution(const cmGeneratorTarget* gt) const;
+
   /** Get the top-level registry key for this VS version.  */
   std::string GetRegistryBase();
 

+ 1 - 1
Source/cmLocalVisualStudioGenerator.cxx

@@ -252,7 +252,7 @@ std::string cmLocalVisualStudioGenerator::FinishConstructScript(
   // Store the script in a string.
   std::string script;
 
-  if (useLocal && projectType == VsProjectType::csproj) {
+  if (useLocal && projectType != VsProjectType::vcxproj) {
     // This label is not provided by MSBuild for C# projects.
     script += newline;
     script += this->GetReportErrorLabel();

+ 227 - 29
Source/cmVisualStudio10TargetGenerator.cxx

@@ -50,6 +50,40 @@
 #include "cmValue.h"
 #include "cmVisualStudioGeneratorOptions.h"
 
+namespace {
+std::string getProjectFileExtension(VsProjectType projectType)
+{
+  switch (projectType) {
+    case VsProjectType::csproj:
+      return ".csproj";
+    case VsProjectType::proj:
+      return ".proj";
+    case VsProjectType::vcxproj:
+      return ".vcxproj";
+    // Valid inputs shouldn't reach here. This default is needed so that all
+    // paths return value (C4715).
+    default:
+      return "";
+  }
+}
+
+VsProjectType computeProjectType(cmGeneratorTarget const* t)
+{
+  if (t->GetName() == CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
+    return VsProjectType::proj;
+  }
+  if (t->IsCSharpOnly()) {
+    return VsProjectType::csproj;
+  }
+  return VsProjectType::vcxproj;
+}
+
+std::string computeProjectFileExtension(cmGeneratorTarget const* t)
+{
+  return getProjectFileExtension(computeProjectType(t));
+}
+}
+
 struct cmIDEFlagTable;
 
 static void ConvertToWindowsSlash(std::string& s);
@@ -235,29 +269,6 @@ static bool cmVS10IsTargetsFile(std::string const& path)
   return cmSystemTools::Strucmp(ext.c_str(), ".targets") == 0;
 }
 
-static VsProjectType computeProjectType(cmGeneratorTarget const* t)
-{
-  if (t->IsCSharpOnly()) {
-    return VsProjectType::csproj;
-  }
-  return VsProjectType::vcxproj;
-}
-
-static std::string computeProjectFileExtension(VsProjectType projectType)
-{
-  switch (projectType) {
-    case VsProjectType::csproj:
-      return ".csproj";
-    default:
-      return ".vcxproj";
-  }
-}
-
-static std::string computeProjectFileExtension(cmGeneratorTarget const* t)
-{
-  return computeProjectFileExtension(computeProjectType(t));
-}
-
 cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator(
   cmGeneratorTarget* target, cmGlobalVisualStudio10Generator* gg)
   : GeneratorTarget(target)
@@ -355,7 +366,7 @@ void cmVisualStudio10TargetGenerator::Generate()
   this->ProjectType = computeProjectType(this->GeneratorTarget);
   this->Managed = this->ProjectType == VsProjectType::csproj;
   const std::string ProjectFileExtension =
-    computeProjectFileExtension(this->ProjectType);
+    getProjectFileExtension(this->ProjectType);
 
   if (this->ProjectType == VsProjectType::csproj &&
       this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) {
@@ -416,10 +427,12 @@ void cmVisualStudio10TargetGenerator::Generate()
   char magic[] = { char(0xEF), char(0xBB), char(0xBF) };
   BuildFileStream.write(magic, 3);
 
-  if (this->ProjectType == VsProjectType::csproj &&
-      this->GeneratorTarget->IsDotNetSdkTarget() &&
-      this->GlobalGenerator->GetVersion() >=
-        cmGlobalVisualStudioGenerator::VSVersion::VS16) {
+  if (this->ProjectType == VsProjectType::proj) {
+    this->WriteZeroCheckProj(BuildFileStream);
+  } else if (this->ProjectType == VsProjectType::csproj &&
+             this->GeneratorTarget->IsDotNetSdkTarget() &&
+             this->GlobalGenerator->GetVersion() >=
+               cmGlobalVisualStudioGenerator::VSVersion::VS16) {
     this->WriteSdkStyleProjectFile(BuildFileStream);
   } else {
     this->WriteClassicMsBuildProjectFile(BuildFileStream);
@@ -681,6 +694,8 @@ void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile(
           .Attribute("Project", VS10_CSharp_DEFAULT_PROPS)
           .Attribute("Condition", "Exists('" VS10_CSharp_DEFAULT_PROPS "')");
         break;
+      default:
+        break;
     }
 
     this->WriteProjectConfigurationValues(e0);
@@ -737,6 +752,8 @@ void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile(
         case VsProjectType::csproj:
           props = VS10_CSharp_USER_PROPS;
           break;
+        default:
+          break;
       }
       if (cmValue p = this->GeneratorTarget->GetProperty("VS_USER_PROPS")) {
         props = *p;
@@ -779,6 +796,8 @@ void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile(
           Elem(e0, "Import").Attribute("Project", VS10_CSharp_TARGETS);
         }
         break;
+      default:
+        break;
     }
 
     this->WriteTargetSpecificReferences(e0);
@@ -944,6 +963,45 @@ void cmVisualStudio10TargetGenerator::WriteSdkStyleProjectFile(
   this->WriteProjectReferences(e0);
 }
 
+void cmVisualStudio10TargetGenerator::WriteZeroCheckProj(
+  cmGeneratedFileStream& BuildFileStream)
+{
+  // ZERO_CHECK.proj is an XML file without any imports or targets. This is a
+  // ProjectReference for other targets and therefore, it needs to follow the
+  // ProjectReference protocol as documented here:
+  // https://github.com/dotnet/msbuild/blob/main/documentation/ProjectReference-Protocol.md
+  //
+  // We implement MSBuild target Build from WriteCustomCommand which calls
+  // WriteZeroCheckBuildTarget after setting up the command generator. MSBuild
+  // target Clean is a no-op as we do all the work for ZERO_CHECK on Build.
+  // MSBuild target GetTargetPath is needed and is no-op.
+  // MSBuild targets GetNativeManifest and GetCopyToOutputDirectoryItems are
+  // needed for MSBuild versions below 15.7 and are no-op. MSBuild target
+  // BeforeBuild is needed for supporting GLOBs.
+  BuildFileStream << "<?xml version=\"1.0\" encoding=\""
+                  << this->GlobalGenerator->Encoding() << "\"?>";
+  {
+    Elem e0(BuildFileStream, "Project");
+    e0.Attribute("DefaultTargets", "Build");
+    e0.Attribute("ToolsVersion", this->GlobalGenerator->GetToolsVersion());
+    e0.Attribute("xmlns",
+                 "http://schemas.microsoft.com/developer/msbuild/2003");
+
+    this->WriteCustomCommands(e0);
+
+    for (const char* targetName :
+         { "Clean", "GetTargetPath", "GetNativeManifest",
+           "GetCopyToOutputDirectoryItems" }) {
+      {
+        Elem e1(e0, "Target");
+        e1.Attribute("Name", targetName);
+      }
+    }
+
+    this->WriteZeroCheckBeforeBuildTarget(e0);
+  }
+}
+
 void cmVisualStudio10TargetGenerator::WriteCommonPropertyGroupGlobals(Elem& e1)
 {
   e1.Attribute("Label", "Globals");
@@ -1659,11 +1717,16 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule(
       }
     }
   }
+  if (this->ProjectType == VsProjectType::proj) {
+    this->WriteZeroCheckBuildTarget(e0, command, source);
+    return;
+  }
+
   cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
 
   std::unique_ptr<Elem> spe1;
   std::unique_ptr<Elem> spe2;
-  if (this->ProjectType != VsProjectType::csproj) {
+  if (this->ProjectType == VsProjectType::vcxproj) {
     spe1 = cm::make_unique<Elem>(e0, "ItemGroup");
     spe2 = cm::make_unique<Elem>(*spe1, "CustomBuild");
     this->WriteSource(*spe2, source);
@@ -3016,6 +3079,134 @@ void cmVisualStudio10TargetGenerator::OutputLinkIncremental(
   }
 }
 
+void cmVisualStudio10TargetGenerator::WriteZeroCheckBuildTarget(
+  cmVisualStudio10TargetGenerator::Elem& e0, const cmCustomCommand& command,
+  const cmSourceFile* source)
+{
+  cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
+
+  Elem e1(e0, "Target");
+  e1.Attribute("Name", "Build");
+
+  std::string noConfig{};
+  cmCustomCommandGenerator ccg{ command, noConfig, lg, true };
+  std::string comment = lg->ConstructComment(ccg);
+  comment = cmVS10EscapeComment(comment);
+  std::string script = lg->ConstructScript(ccg);
+  bool symbolic = false;
+  // input files for custom command
+  std::stringstream additional_inputs;
+  {
+    const char* sep = "";
+    if (this->ProjectType == VsProjectType::proj) {
+      // List explicitly the path to primary input.
+      std::string sourceFullPath = source->GetFullPath();
+      ConvertToWindowsSlash(sourceFullPath);
+      additional_inputs << sourceFullPath;
+      sep = ";";
+    }
+
+    // Avoid listing an input more than once.
+    std::set<std::string> unique_inputs;
+    // The source is either implicitly an input or has been added above.
+    unique_inputs.insert(source->GetFullPath());
+
+    for (std::string const& d : ccg.GetDepends()) {
+      std::string dep;
+      if (lg->GetRealDependency(d, noConfig, dep)) {
+        if (!unique_inputs.insert(dep).second) {
+          // already listed
+          continue;
+        }
+        ConvertToWindowsSlash(dep);
+        additional_inputs << sep << dep;
+        sep = ";";
+        if (!symbolic) {
+          if (cmSourceFile* sf = this->Makefile->GetSource(
+                dep, cmSourceFileLocationKind::Known)) {
+            symbolic = sf->GetPropertyAsBool("SYMBOLIC");
+          }
+        }
+      }
+    }
+  }
+  // output files for custom command
+  std::stringstream outputs;
+  {
+    const char* sep = "";
+    for (std::string const& o : ccg.GetOutputs()) {
+      std::string out = o;
+      ConvertToWindowsSlash(out);
+      outputs << sep << out;
+      sep = ";";
+      if (!symbolic) {
+        if (cmSourceFile* sf =
+              this->Makefile->GetSource(o, cmSourceFileLocationKind::Known)) {
+          symbolic = sf->GetPropertyAsBool("SYMBOLIC");
+        }
+      }
+    }
+  }
+  script += lg->FinishConstructScript(this->ProjectType);
+
+  e1.Attribute("Inputs", cmVS10EscapeAttr(additional_inputs.str()));
+  e1.Attribute("Outputs", cmVS10EscapeAttr(outputs.str()));
+
+  e1.SetHasElements();
+
+  if (!comment.empty()) {
+    Elem(e1, "Message").Attribute("Text", comment);
+  }
+  Elem(e1, "Exec").Attribute("Command", script);
+}
+
+void cmVisualStudio10TargetGenerator::WriteZeroCheckBeforeBuildTarget(
+  cmVisualStudio10TargetGenerator::Elem& e0)
+{
+  const auto& commands = this->GeneratorTarget->GetPreBuildCommands();
+  if (commands.empty()) {
+    return;
+  }
+
+  {
+    Elem e1(e0, "Target");
+    e1.Attribute("Name", "BeforeBuild");
+    e1.Attribute("BeforeTargets", "Build");
+
+    cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
+    std::string script;
+    const char* pre = "";
+    std::string comment;
+    for (cmCustomCommand const& cc : commands) {
+      cmCustomCommandGenerator ccg(cc, std::string{}, lg);
+      if (!ccg.HasOnlyEmptyCommandLines()) {
+        comment += pre;
+        comment += lg->ConstructComment(ccg);
+        script += pre;
+        pre = "\n";
+        script += lg->ConstructScript(ccg);
+      }
+    }
+
+    if (script.empty()) {
+      return;
+    }
+
+    script += lg->FinishConstructScript(this->ProjectType);
+    comment = cmVS10EscapeComment(comment);
+    std::string strippedComment = comment;
+    strippedComment.erase(
+      std::remove(strippedComment.begin(), strippedComment.end(), '\t'),
+      strippedComment.end());
+
+    e1.SetHasElements();
+    if (!comment.empty() && !strippedComment.empty()) {
+      Elem(e1, "Message").Attribute("Text", comment);
+    }
+    Elem(e1, "Exec").Attribute("Command", script);
+  }
+}
+
 std::vector<std::string> cmVisualStudio10TargetGenerator::GetIncludes(
   std::string const& config, std::string const& lang) const
 {
@@ -3057,6 +3248,8 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
         cm::make_unique<Options>(this->LocalGenerator, Options::CSharpCompiler,
                                  gg->GetCSharpFlagTable());
       break;
+    default:
+      break;
   }
   Options& clOptions = *pOptions;
 
@@ -3182,6 +3375,8 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
         return def.find('=') != std::string::npos;
       });
       break;
+    default:
+      break;
   }
   clOptions.AddDefines(targetDefines);
 
@@ -4308,6 +4503,9 @@ void cmVisualStudio10TargetGenerator::AddLibraries(
               this->AdditionalUsingDirectories[config].insert(
                 cmSystemTools::GetFilenamePath(location));
               break;
+            default:
+              // In .proj files, we wouldn't be referencing libraries.
+              break;
           }
         }
       }

+ 7 - 0
Source/cmVisualStudio10TargetGenerator.h

@@ -264,6 +264,13 @@ private:
   void WriteClassicMsBuildProjectFile(cmGeneratedFileStream& BuildFileStream);
   void WriteSdkStyleProjectFile(cmGeneratedFileStream& BuildFileStream);
 
+  void WriteZeroCheckProj(cmGeneratedFileStream& BuildFileStream);
+  void WriteZeroCheckBuildTarget(cmVisualStudio10TargetGenerator::Elem& e0,
+                                 const cmCustomCommand& command,
+                                 const cmSourceFile* source);
+  void WriteZeroCheckBeforeBuildTarget(
+    cmVisualStudio10TargetGenerator::Elem& e0);
+
   void WriteCommonPropertyGroupGlobals(
     cmVisualStudio10TargetGenerator::Elem& e1);
 

+ 2 - 1
Source/cmVsProjectType.h

@@ -7,5 +7,6 @@
 enum class VsProjectType
 {
   vcxproj,
-  csproj
+  csproj,
+  proj,
 };