1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-16 05:26:58 +08:00

VS: Write ZERO_CHECK.proj for VS19 and above

For VS 19 and above, switch the format of project file to
`VsProjectType::proj` for ZERO_CHECK target. The `ZERO_CHECK.proj`
consists of primitive MSBuild commands only and has no dependency on any
other targets or props files. This proj file is written as a
`ProjectReference` for other targets, but is not written to the sln
file.
This commit is contained in:
Sumit Bhardwaj
2021-12-24 22:38:13 -08:00
parent cc8f5a7dbe
commit a334f1b906
4 changed files with 241 additions and 34 deletions

View File

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

View File

@@ -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; }

View File

@@ -50,6 +50,24 @@
#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 "";
}
}
}
struct cmIDEFlagTable;
static void ConvertToWindowsSlash(std::string& s);
@@ -235,31 +253,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";
case VsProjectType::proj:
return ".proj";
default:
return ".vcxproj";
}
}
static std::string computeProjectFileExtension(cmGeneratorTarget const* t)
{
return computeProjectFileExtension(computeProjectType(t));
}
cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator(
cmGeneratorTarget* target, cmGlobalVisualStudio10Generator* gg)
: GeneratorTarget(target)
@@ -354,10 +347,10 @@ std::ostream& cmVisualStudio10TargetGenerator::Elem::WriteString(
void cmVisualStudio10TargetGenerator::Generate()
{
this->ProjectType = computeProjectType(this->GeneratorTarget);
this->ProjectType = this->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) {
@@ -418,10 +411,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);
@@ -952,6 +947,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");
@@ -1667,11 +1701,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);
@@ -1869,7 +1908,7 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
// Write out group file
std::string path = cmStrCat(
this->LocalGenerator->GetCurrentBinaryDirectory(), '/', this->Name,
computeProjectFileExtension(this->GeneratorTarget), ".filters");
this->ComputeProjectFileExtension(this->GeneratorTarget), ".filters");
cmGeneratedFileStream fout(path);
fout.SetCopyIfDifferent(true);
char magic[] = { char(0xEF), char(0xBB), char(0xBF) };
@@ -3024,6 +3063,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
{
@@ -4552,7 +4719,7 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences(Elem& e0)
path = *p;
} else {
path = cmStrCat(lg->GetCurrentBinaryDirectory(), '/', dt->GetName(),
computeProjectFileExtension(dt));
this->ComputeProjectFileExtension(dt));
}
ConvertToWindowsSlash(path);
Elem e2(e1, "ProjectReference");
@@ -5406,6 +5573,26 @@ std::string cmVisualStudio10TargetGenerator::GetCMakeFilePath(
return path;
}
std::string cmVisualStudio10TargetGenerator::ComputeProjectFileExtension(
cmGeneratorTarget const* t) const
{
return getProjectFileExtension(this->ComputeProjectType(t));
}
VsProjectType cmVisualStudio10TargetGenerator::ComputeProjectType(
cmGeneratorTarget const* t) const
{
if (this->GlobalGenerator->GetVersion() >=
cmGlobalVisualStudioGenerator::VSVersion::VS16 &&
t->GetName() == CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
return VsProjectType::proj;
}
if (t->IsCSharpOnly()) {
return VsProjectType::csproj;
}
return VsProjectType::vcxproj;
}
void cmVisualStudio10TargetGenerator::WriteStdOutEncodingUtf8(Elem& e1)
{
if (this->GlobalGenerator->IsUtf8EncodingSupported()) {

View File

@@ -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);
@@ -275,4 +282,7 @@ private:
void ParseSettingsProperty(const std::string& settingsPropertyValue,
ConfigToSettings& toolSettings);
std::string GetCMakeFilePath(const char* name) const;
std::string ComputeProjectFileExtension(cmGeneratorTarget const* t) const;
VsProjectType ComputeProjectType(cmGeneratorTarget const* t) const;
};