void cmVisualStudio10TargetGenerator::Generate()

in Source/cmVisualStudio10TargetGenerator.cxx [320:831]


void cmVisualStudio10TargetGenerator::Generate()
{
  const std::string ProjectFileExtension =
    computeProjectFileExtension(this->GeneratorTarget);
  if (ProjectFileExtension == ".vcxproj") {
    this->ProjectType = vcxproj;
    this->Managed = false;
  } else if (ProjectFileExtension == ".csproj") {
    if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) {
      std::string message = "The C# target \"" +
        this->GeneratorTarget->GetName() +
        "\" is of type STATIC_LIBRARY. This is discouraged (and may be "
        "disabled in future). Make it a SHARED library instead.";
      this->Makefile->IssueMessage(MessageType::DEPRECATION_WARNING, message);
    }
    this->ProjectType = csproj;
    this->Managed = true;
  }

  if (this->Android &&
      this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE &&
      !this->GeneratorTarget->Target->IsAndroidGuiExecutable()) {
    this->GlobalGenerator->AddAndroidExecutableWarning(this->Name);
  }

  // Tell the global generator the name of the project file
  this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME",
                                             this->Name);
  this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME_EXT",
                                             ProjectFileExtension);
  this->DotNetHintReferences.clear();
  this->AdditionalUsingDirectories.clear();
  if (this->GeneratorTarget->GetType() <= cmStateEnums::OBJECT_LIBRARY) {
    if (!this->ComputeClOptions()) {
      return;
    }
    if (!this->ComputeRcOptions()) {
      return;
    }
    if (!this->ComputeCudaOptions()) {
      return;
    }
    if (!this->ComputeCudaLinkOptions()) {
      return;
    }
    if (!this->ComputeMasmOptions()) {
      return;
    }
    if (!this->ComputeNasmOptions()) {
      return;
    }
    if (!this->ComputeLinkOptions()) {
      return;
    }
    if (!this->ComputeLibOptions()) {
      return;
    }
  }
  std::string path =
    cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), '/',
             this->Name, ProjectFileExtension);
  cmGeneratedFileStream BuildFileStream(path);
  const std::string PathToProjectFile = path;
  BuildFileStream.SetCopyIfDifferent(true);

  // Write the encoding header into the file
  char magic[] = { char(0xEF), char(0xBB), char(0xBF) };
  BuildFileStream.write(magic, 3);
  BuildFileStream << "<?xml version=\"1.0\" encoding=\""
                  << this->GlobalGenerator->Encoding() << "\"?>";
  {
    Elem e0(BuildFileStream, "Project");
    e0.Attribute("DefaultTargets", "Build");
    const char* toolsVersion = this->GlobalGenerator->GetToolsVersion();
    if (this->GlobalGenerator->GetVersion() ==
          cmGlobalVisualStudioGenerator::VS12 &&
        this->GlobalGenerator->TargetsWindowsCE()) {
      toolsVersion = "4.0";
    }
    e0.Attribute("ToolsVersion", toolsVersion);
    e0.Attribute("xmlns",
                 "http://schemas.microsoft.com/developer/msbuild/2003");

    if (this->NsightTegra) {
      Elem e1(e0, "PropertyGroup");
      e1.Attribute("Label", "NsightTegraProject");
      const unsigned int nsightTegraMajorVersion = this->NsightTegraVersion[0];
      const unsigned int nsightTegraMinorVersion = this->NsightTegraVersion[1];
      if (nsightTegraMajorVersion >= 2) {
        if (nsightTegraMajorVersion > 3 ||
            (nsightTegraMajorVersion == 3 && nsightTegraMinorVersion >= 1)) {
          e1.Element("NsightTegraProjectRevisionNumber", "11");
        } else {
          // Nsight Tegra 2.0 uses project revision 9.
          e1.Element("NsightTegraProjectRevisionNumber", "9");
        }
        // Tell newer versions to upgrade silently when loading.
        e1.Element("NsightTegraUpgradeOnceWithoutPrompt", "true");
      } else {
        // Require Nsight Tegra 1.6 for JCompile support.
        e1.Element("NsightTegraProjectRevisionNumber", "7");
      }
    }

    if (const char* hostArch =
          this->GlobalGenerator->GetPlatformToolsetHostArchitecture()) {
      Elem e1(e0, "PropertyGroup");
      e1.Element("PreferredToolArchitecture", hostArch);
    }

    if (this->ProjectType != csproj) {
      this->WriteProjectConfigurations(e0);
    }

    {
      Elem e1(e0, "PropertyGroup");
      e1.Attribute("Label", "Globals");
      e1.Element("ProjectGuid", "{" + this->GUID + "}");

      if ((this->MSTools || this->Android) &&
          this->GeneratorTarget->IsInBuildSystem()) {
        this->WriteApplicationTypeSettings(e1);
        this->VerifyNecessaryFiles();
      }

      cmValue vsProjectTypes =
        this->GeneratorTarget->GetProperty("VS_GLOBAL_PROJECT_TYPES");
      if (vsProjectTypes) {
        const char* tagName = "ProjectTypes";
        if (this->ProjectType == csproj) {
          tagName = "ProjectTypeGuids";
        }
        e1.Element(tagName, *vsProjectTypes);
      }

      cmValue vsProjectName =
        this->GeneratorTarget->GetProperty("VS_SCC_PROJECTNAME");
      cmValue vsLocalPath =
        this->GeneratorTarget->GetProperty("VS_SCC_LOCALPATH");
      cmValue vsProvider =
        this->GeneratorTarget->GetProperty("VS_SCC_PROVIDER");

      if (vsProjectName && vsLocalPath && vsProvider) {
        e1.Element("SccProjectName", *vsProjectName);
        e1.Element("SccLocalPath", *vsLocalPath);
        e1.Element("SccProvider", *vsProvider);

        cmValue vsAuxPath =
          this->GeneratorTarget->GetProperty("VS_SCC_AUXPATH");
        if (vsAuxPath) {
          e1.Element("SccAuxPath", *vsAuxPath);
        }
      }

      if (this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT")) {
        e1.Element("WinMDAssembly", "true");
      }

      cmValue vsGlobalKeyword =
        this->GeneratorTarget->GetProperty("VS_GLOBAL_KEYWORD");
      if (!vsGlobalKeyword) {
        if (this->GlobalGenerator->TargetsAndroid()) {
          e1.Element("Keyword", "Android");
        } else {
          e1.Element("Keyword", "Win32Proj");
        }
      } else {
        e1.Element("Keyword", *vsGlobalKeyword);
      }

      cmValue vsGlobalRootNamespace =
        this->GeneratorTarget->GetProperty("VS_GLOBAL_ROOTNAMESPACE");
      if (vsGlobalRootNamespace) {
        e1.Element("RootNamespace", *vsGlobalRootNamespace);
      }

      if (!this->BuildAsX) {
        e1.Element("Platform", this->Platform);
      }
      e1.Element("Platform", this->Platform);
      cmValue projLabel = this->GeneratorTarget->GetProperty("PROJECT_LABEL");
      e1.Element("ProjectName", projLabel ? projLabel : this->Name);
      {
        cm::optional<std::string> targetFramework;
        cm::optional<std::string> targetFrameworkVersion;
        cm::optional<std::string> targetFrameworkIdentifier;
        cm::optional<std::string> targetFrameworkTargetsVersion;
        if (cmValue tf =
              this->GeneratorTarget->GetProperty("DOTNET_TARGET_FRAMEWORK")) {
          targetFramework = *tf;
        } else if (cmValue vstfVer = this->GeneratorTarget->GetProperty(
                     "VS_DOTNET_TARGET_FRAMEWORK_VERSION")) {
          // FIXME: Someday, add a deprecation warning for VS_* property.
          targetFrameworkVersion = *vstfVer;
        } else if (cmValue tfVer = this->GeneratorTarget->GetProperty(
                     "DOTNET_TARGET_FRAMEWORK_VERSION")) {
          targetFrameworkVersion = *tfVer;
        } else if (this->ProjectType == csproj) {
          targetFrameworkVersion =
            this->GlobalGenerator->GetTargetFrameworkVersion();
        }
        if (this->ProjectType == vcxproj &&
            this->GlobalGenerator->TargetsWindowsCE()) {
          e1.Element("EnableRedirectPlatform", "true");
          e1.Element("RedirectPlatformValue", this->Platform);
        }
        if (this->ProjectType == csproj) {
          if (this->GlobalGenerator->TargetsWindowsCE()) {
            // FIXME: These target VS_TARGET_FRAMEWORK* target properties
            // are undocumented settings only ever supported for WinCE.
            // We need a better way to control these in general.
            if (cmValue tfId = this->GeneratorTarget->GetProperty(
                  "VS_TARGET_FRAMEWORK_IDENTIFIER")) {
              targetFrameworkIdentifier = *tfId;
            }
            if (cmValue tfTargetsVer = this->GeneratorTarget->GetProperty(
                  "VS_TARGET_FRAMEWORKS_TARGET_VERSION")) {
              targetFrameworkTargetsVersion = *tfTargetsVer;
            }
          }
          if (!targetFrameworkIdentifier) {
            targetFrameworkIdentifier =
              this->GlobalGenerator->GetTargetFrameworkIdentifier();
          }
          if (!targetFrameworkTargetsVersion) {
            targetFrameworkTargetsVersion =
              this->GlobalGenerator->GetTargetFrameworkTargetsVersion();
          }
        }
        if (targetFramework) {
          if (targetFramework->find(';') != std::string::npos) {
            e1.Element("TargetFrameworks", *targetFramework);
          } else {
            e1.Element("TargetFramework", *targetFramework);
          }
        }
        if (targetFrameworkVersion) {
          e1.Element("TargetFrameworkVersion", *targetFrameworkVersion);
        }
        if (targetFrameworkIdentifier) {
          e1.Element("TargetFrameworkIdentifier", *targetFrameworkIdentifier);
        }
        if (targetFrameworkTargetsVersion) {
          e1.Element("TargetFrameworkTargetsVersion",
                     *targetFrameworkTargetsVersion);
        }
        if (!this->GlobalGenerator->GetPlatformToolsetCudaCustomDirString()
               .empty()) {
          e1.Element(
            "CudaToolkitCustomDir",
            this->GlobalGenerator->GetPlatformToolsetCudaCustomDirString() +
              this->GlobalGenerator->GetPlatformToolsetCudaNvccSubdirString());
        }
      }

      // Disable the project upgrade prompt that is displayed the first time a
      // project using an older toolset version is opened in a newer version of
      // the IDE (respected by VS 2013 and above).
      if (this->GlobalGenerator->GetVersion() >=
          cmGlobalVisualStudioGenerator::VS12) {
        e1.Element("VCProjectUpgraderObjectName", "NoUpgrade");
      }

      if (const char* vcTargetsPath =
            this->GlobalGenerator->GetCustomVCTargetsPath()) {
        e1.Element("VCTargetsPath", vcTargetsPath);
      }

      std::vector<std::string> keys = this->GeneratorTarget->GetPropertyKeys();
      for (std::string const& keyIt : keys) {
        static const cm::string_view prefix = "VS_GLOBAL_";
        if (!cmHasPrefix(keyIt, prefix))
          continue;
        cm::string_view globalKey =
          cm::string_view(keyIt).substr(prefix.length());
        // Skip invalid or separately-handled properties.
        if (globalKey.empty() || globalKey == "PROJECT_TYPES" ||
            globalKey == "ROOTNAMESPACE" || globalKey == "KEYWORD") {
          continue;
        }
        cmValue value = this->GeneratorTarget->GetProperty(keyIt);
        if (!value)
          continue;
        e1.Element(globalKey, *value);
      }

      if (this->Managed) {
        if (this->LocalGenerator->GetVersion() >=
            cmGlobalVisualStudioGenerator::VS17) {
          e1.Element("ManagedAssembly", "true");
        }
        std::string outputType;
        switch (this->GeneratorTarget->GetType()) {
          case cmStateEnums::OBJECT_LIBRARY:
          case cmStateEnums::STATIC_LIBRARY:
          case cmStateEnums::SHARED_LIBRARY:
            outputType = "Library";
            break;
          case cmStateEnums::MODULE_LIBRARY:
            outputType = "Module";
            break;
          case cmStateEnums::EXECUTABLE: {
            auto const win32 =
              this->GeneratorTarget->GetSafeProperty("WIN32_EXECUTABLE");
            if (win32.find("$<") != std::string::npos) {
              this->Makefile->IssueMessage(
                MessageType::FATAL_ERROR,
                cmStrCat(
                  "Target \"", this->GeneratorTarget->GetName(),
                  "\" has a generator expression in its WIN32_EXECUTABLE "
                  "property. This is not supported on managed executables."));
              return;
            }
            if (cmIsOn(win32)) {
              outputType = "WinExe";
            } else {
              outputType = "Exe";
            }
          } break;
          case cmStateEnums::UTILITY:
          case cmStateEnums::INTERFACE_LIBRARY:
          case cmStateEnums::GLOBAL_TARGET:
            outputType = "Utility";
            break;
          case cmStateEnums::UNKNOWN_LIBRARY:
            break;
        }
        e1.Element("OutputType", outputType);
        e1.Element("AppDesignerFolder", "Properties");
      }
    }

    switch (this->ProjectType) {
      case vcxproj: {
        std::string const& props =
          this->GlobalGenerator->GetPlatformToolsetVersionProps();
        if (!props.empty()) {
          Elem(e0, "Import").Attribute("Project", props);
        }
        Elem(e0, "Import").Attribute("Project", VS10_CXX_DEFAULT_PROPS);
      } break;
      case csproj:
        Elem(e0, "Import")
          .Attribute("Project", VS10_CSharp_DEFAULT_PROPS)
          .Attribute("Condition", "Exists('" VS10_CSharp_DEFAULT_PROPS "')");
        break;
    }

    this->WriteProjectConfigurationValues(e0);

    if (this->ProjectType == vcxproj) {
      Elem(e0, "Import").Attribute("Project", VS10_CXX_PROPS);
    }
    {
      Elem e1(e0, "ImportGroup");
      e1.Attribute("Label", "ExtensionSettings");
      e1.SetHasElements();

      if (this->GlobalGenerator->IsCudaEnabled()) {
        auto customDir =
          this->GlobalGenerator->GetPlatformToolsetCudaCustomDirString();
        std::string cudaPath = customDir.empty()
          ? "$(VCTargetsPath)\\BuildCustomizations\\"
          : customDir +
            this->GlobalGenerator
              ->GetPlatformToolsetCudaVSIntegrationSubdirString() +
            "extras\\visual_studio_integration\\MSBuildExtensions\\";
        Elem(e1, "Import")
          .Attribute("Project",
                     std::move(cudaPath) + "CUDA " +
                       this->GlobalGenerator->GetPlatformToolsetCuda() +
                       ".props");
      }
      if (this->GlobalGenerator->IsMasmEnabled()) {
        Elem(e1, "Import")
          .Attribute("Project",
                     "$(VCTargetsPath)\\BuildCustomizations\\masm.props");
      }
      if (this->GlobalGenerator->IsNasmEnabled()) {
        // Always search in the standard modules location.
        std::string propsTemplate =
          GetCMakeFilePath("Templates/MSBuild/nasm.props.in");

        std::string propsLocal =
          cmStrCat(this->DefaultArtifactDir, "\\nasm.props");
        ConvertToWindowsSlash(propsLocal);
        this->Makefile->ConfigureFile(propsTemplate, propsLocal, false, true,
                                      true);
        Elem(e1, "Import").Attribute("Project", propsLocal);
      }
    }
    {
      Elem e1(e0, "ImportGroup");
      e1.Attribute("Label", "PropertySheets");
      std::string props;
      switch (this->ProjectType) {
        case vcxproj:
          props = VS10_CXX_USER_PROPS;
          break;
        case csproj:
          props = VS10_CSharp_USER_PROPS;
          break;
      }
      if (cmValue p = this->GeneratorTarget->GetProperty("VS_USER_PROPS")) {
        props = *p;
      }
      if (!props.empty()) {
        ConvertToWindowsSlash(props);
        Elem(e1, "Import")
          .Attribute("Project", props)
          .Attribute("Condition", "exists('" + props + "')")
          .Attribute("Label", "LocalAppDataPlatform");
      }

      this->WritePlatformExtensions(e1);
    }

    this->WriteDotNetDocumentationFile(e0);
    Elem(e0, "PropertyGroup").Attribute("Label", "UserMacros");
    this->WriteWinRTPackageCertificateKeyFile(e0);
    this->WritePathAndIncrementalLinkOptions(e0);
    this->WriteCEDebugProjectConfigurationValues(e0);
    this->WriteItemDefinitionGroups(e0);
    this->WriteCustomCommands(e0);
    this->WriteAllSources(e0);
    this->WriteDotNetReferences(e0);
    this->WritePackageReferences(e0);
    this->WriteImports(e0);
    this->WriteEmbeddedResourceGroup(e0);
    this->WriteXamlFilesGroup(e0);
    this->WriteWinRTReferences(e0);
    this->WriteProjectReferences(e0);
    this->WriteSDKReferences(e0);
    switch (this->ProjectType) {
      case vcxproj:
        Elem(e0, "Import").Attribute("Project", VS10_CXX_TARGETS);
        break;
      case csproj:
        if (this->GlobalGenerator->TargetsWindowsCE()) {
          Elem(e0, "Import").Attribute("Project", VS10_CSharp_NETCF_TARGETS);
        } else {
          Elem(e0, "Import").Attribute("Project", VS10_CSharp_TARGETS);
        }
        break;
    }

    this->WriteTargetSpecificReferences(e0);
    {
      Elem e1(e0, "ImportGroup");
      e1.Attribute("Label", "ExtensionTargets");
      e1.SetHasElements();
      this->WriteTargetsFileReferences(e1);
      if (this->GlobalGenerator->IsCudaEnabled()) {
        auto customDir =
          this->GlobalGenerator->GetPlatformToolsetCudaCustomDirString();
        std::string cudaPath = customDir.empty()
          ? "$(VCTargetsPath)\\BuildCustomizations\\"
          : customDir +
            this->GlobalGenerator
              ->GetPlatformToolsetCudaVSIntegrationSubdirString() +
            "extras\\visual_studio_integration\\MSBuildExtensions\\";
        Elem(e1, "Import")
          .Attribute("Project",
                     std::move(cudaPath) + "CUDA " +
                       this->GlobalGenerator->GetPlatformToolsetCuda() +
                       ".targets");
      }
      if (this->GlobalGenerator->IsMasmEnabled()) {
        Elem(e1, "Import")
          .Attribute("Project",
                     "$(VCTargetsPath)\\BuildCustomizations\\masm.targets");
      }
      if (this->GlobalGenerator->IsNasmEnabled()) {
        std::string nasmTargets =
          GetCMakeFilePath("Templates/MSBuild/nasm.targets");
        Elem(e1, "Import").Attribute("Project", nasmTargets);
      }
    }
    if (this->ProjectType == vcxproj && this->HaveCustomCommandDepfile) {
      std::string depfileTargets =
        GetCMakeFilePath("Templates/MSBuild/CustomBuildDepFile.targets");
      Elem(e0, "Import").Attribute("Project", depfileTargets);
    }
    if (this->ProjectType == csproj) {
      for (std::string const& c : this->Configurations) {
        Elem e1(e0, "PropertyGroup");
        e1.Attribute("Condition", "'$(Configuration)' == '" + c + "'");
        e1.SetHasElements();
        this->WriteEvents(e1, c);
      }
      // make sure custom commands are executed before build (if necessary)
      {
        Elem e1(e0, "PropertyGroup");
        std::ostringstream oss;
        oss << "\n";
        for (std::string const& i : this->CSharpCustomCommandNames) {
          oss << "      " << i << ";\n";
        }
        oss << "      "
            << "$(BuildDependsOn)\n";
        e1.Element("BuildDependsOn", oss.str());
      }
    }
  }

  if (BuildFileStream.Close()) {
    this->GlobalGenerator->FileReplacedDuringGenerate(PathToProjectFile);
  }

  // The groups are stored in a separate file for VS 10
  this->WriteGroups();
}