All known preprocessor definitions from the compiler are now exposed to Rider language server through MSBuild .props files in order to fix most error squiggles caused by missing or invalid definitions. This should fix some common errors like unable to resolve C++ and C standard library types and macros like `assert`.
464 lines
27 KiB
C#
464 lines
27 KiB
C#
// Copyright (c) Wojciech Figat. All rights reserved.
|
|
|
|
using Flax.Build.NativeCpp;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
namespace Flax.Build.Projects.VisualStudio
|
|
{
|
|
/// <summary>
|
|
/// The Visual Studio project generator for C++ projects (.vcxproj).
|
|
/// </summary>
|
|
/// <seealso cref="Flax.Build.Projects.VisualStudio.VisualStudioProjectGenerator" />
|
|
public class VCProjectGenerator : VisualStudioProjectGenerator
|
|
{
|
|
/// <summary>
|
|
/// Gets the project file platform toolset version.
|
|
/// </summary>
|
|
public string ProjectFilePlatformToolsetVersion
|
|
{
|
|
get
|
|
{
|
|
switch (Version)
|
|
{
|
|
case VisualStudioVersion.VisualStudio2015: return "v140";
|
|
case VisualStudioVersion.VisualStudio2017: return "v141";
|
|
case VisualStudioVersion.VisualStudio2019: return "v142";
|
|
case VisualStudioVersion.VisualStudio2022: return "v143";
|
|
case VisualStudioVersion.VisualStudio2026: return "v145";
|
|
}
|
|
return string.Empty;
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public VCProjectGenerator(VisualStudioVersion version)
|
|
: base(version)
|
|
{
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override string ProjectFileExtension => "vcxproj";
|
|
|
|
/// <inheritdoc />
|
|
public override TargetType? Type => TargetType.NativeCpp;
|
|
|
|
private static string FixPath(string path)
|
|
{
|
|
if (path.Contains(' '))
|
|
{
|
|
path = "\"" + path + "\"";
|
|
}
|
|
return path;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override void GenerateProject(Project project, string solutionPath, bool isMainProject)
|
|
{
|
|
var vcProjectFileContent = new StringBuilder();
|
|
var vcFiltersFileContent = new StringBuilder();
|
|
var vcUserFileContent = new StringBuilder();
|
|
|
|
var vsProject = (VisualStudioProject)project;
|
|
var projectFileToolVersion = ProjectFileToolVersion;
|
|
var projectFilePlatformToolsetVersion = ProjectFilePlatformToolsetVersion;
|
|
var projectDirectory = Path.GetDirectoryName(project.Path);
|
|
var filtersDirectory = project.SourceFolderPath;
|
|
|
|
// Try to reuse the existing project guid from existing files
|
|
vsProject.ProjectGuid = GetProjectGuid(vsProject.Path, vsProject.Name);
|
|
if (vsProject.ProjectGuid == Guid.Empty)
|
|
vsProject.ProjectGuid = GetProjectGuid(solutionPath, vsProject.Name);
|
|
if (vsProject.ProjectGuid == Guid.Empty)
|
|
vsProject.ProjectGuid = Guid.NewGuid();
|
|
|
|
// Header
|
|
vcProjectFileContent.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
|
|
vcProjectFileContent.AppendLine(string.Format("<Project DefaultTargets=\"Build\" ToolsVersion=\"{0}\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">", projectFileToolVersion));
|
|
|
|
vcFiltersFileContent.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
|
|
vcFiltersFileContent.AppendLine(string.Format("<Project ToolsVersion=\"{0}\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">", projectFileToolVersion));
|
|
|
|
vcUserFileContent.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
|
|
vcUserFileContent.AppendLine(string.Format("<Project ToolsVersion=\"{0}\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">", projectFileToolVersion));
|
|
|
|
// Project configurations
|
|
vcProjectFileContent.AppendLine(" <ItemGroup Label=\"ProjectConfigurations\">");
|
|
foreach (var configuration in project.Configurations)
|
|
{
|
|
vcProjectFileContent.AppendLine(string.Format(" <ProjectConfiguration Include=\"{0}\">", configuration.Name));
|
|
vcProjectFileContent.AppendLine(string.Format(" <Configuration>{0}</Configuration>", configuration.Text));
|
|
vcProjectFileContent.AppendLine(string.Format(" <Platform>{0}</Platform>", configuration.ArchitectureName));
|
|
vcProjectFileContent.AppendLine(" </ProjectConfiguration>");
|
|
}
|
|
vcProjectFileContent.AppendLine(" </ItemGroup>");
|
|
|
|
var platforms = vsProject.Configurations.Select(x => Platform.GetPlatform(x.Platform)).Distinct();
|
|
foreach (var platform in platforms)
|
|
{
|
|
if (platform is IVisualStudioProjectCustomizer customizer)
|
|
customizer.WriteVisualStudioBegin(vsProject, platform, vcProjectFileContent, vcFiltersFileContent, vcUserFileContent);
|
|
}
|
|
|
|
// Globals
|
|
vcProjectFileContent.AppendLine(" <PropertyGroup Label=\"Globals\">");
|
|
vcProjectFileContent.AppendLine(string.Format(" <ProjectGuid>{0}</ProjectGuid>", vsProject.ProjectGuid.ToString("B").ToUpperInvariant()));
|
|
vcProjectFileContent.AppendLine(string.Format(" <RootNamespace>{0}</RootNamespace>", project.BaseName));
|
|
vcProjectFileContent.AppendLine(string.Format(" <PlatformToolset>{0}</PlatformToolset>", projectFilePlatformToolsetVersion));
|
|
vcProjectFileContent.AppendLine(string.Format(" <MinimumVisualStudioVersion>{0}</MinimumVisualStudioVersion>", projectFileToolVersion));
|
|
vcProjectFileContent.AppendLine(" <TargetRuntime>Native</TargetRuntime>");
|
|
vcProjectFileContent.AppendLine(" <CharacterSet>Unicode</CharacterSet>");
|
|
vcProjectFileContent.AppendLine(" <Keyword>MakeFileProj</Keyword>");
|
|
if (Version >= VisualStudioVersion.VisualStudio2022)
|
|
vcProjectFileContent.AppendLine(" <ResolveNuGetPackages>false</ResolveNuGetPackages>");
|
|
vcProjectFileContent.AppendLine(" <VCTargetsPath Condition=\"$(Configuration.Contains('Linux'))\">./</VCTargetsPath>");
|
|
vcProjectFileContent.AppendLine(" <VCTargetsPath Condition=\"$(Configuration.Contains('Mac'))\">./</VCTargetsPath>");
|
|
vcProjectFileContent.AppendLine(" </PropertyGroup>");
|
|
|
|
// Default properties
|
|
vcProjectFileContent.AppendLine(" <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />");
|
|
|
|
// Per configuration options
|
|
foreach (var configuration in project.Configurations)
|
|
{
|
|
vcProjectFileContent.AppendLine(string.Format(" <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='{0}'\" Label=\"Configuration\">", configuration.Name));
|
|
vcProjectFileContent.AppendLine(" <ConfigurationType>Makefile</ConfigurationType>");
|
|
vcProjectFileContent.AppendLine(string.Format(" <PlatformToolset>{0}</PlatformToolset>", projectFilePlatformToolsetVersion));
|
|
vcProjectFileContent.AppendLine(" </PropertyGroup>");
|
|
}
|
|
|
|
// Other properties
|
|
vcProjectFileContent.AppendLine(" <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />");
|
|
vcProjectFileContent.AppendLine(" <ImportGroup Label=\"ExtensionSettings\" />");
|
|
|
|
// Per configuration property sheets
|
|
foreach (var configuration in project.Configurations)
|
|
{
|
|
vcProjectFileContent.AppendLine(string.Format(" <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='{0}'\" Label=\"PropertySheets\">", configuration.Name));
|
|
vcProjectFileContent.AppendLine(" <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />");
|
|
vcProjectFileContent.AppendLine(" </ImportGroup>");
|
|
}
|
|
|
|
// User macros
|
|
vcProjectFileContent.AppendLine(" <PropertyGroup Label=\"UserMacros\" />");
|
|
|
|
// Per configuration options
|
|
var buildToolPath = Path.ChangeExtension(Utilities.MakePathRelativeTo(typeof(Builder).Assembly.Location, projectDirectory), null);
|
|
var preprocessorDefinitions = new HashSet<string>();
|
|
var includePaths = new HashSet<string>();
|
|
foreach (var configuration in project.Configurations)
|
|
{
|
|
var platform = Platform.GetPlatform(configuration.Platform);
|
|
var toolchain = platform.GetToolchain(configuration.Architecture);
|
|
var target = configuration.Target;
|
|
var targetBuildOptions = configuration.TargetBuildOptions;
|
|
|
|
preprocessorDefinitions.Clear();
|
|
foreach (var e in targetBuildOptions.CompileEnv.PreprocessorDefinitions)
|
|
preprocessorDefinitions.Add(e);
|
|
|
|
includePaths.Clear();
|
|
foreach (var e in targetBuildOptions.CompileEnv.IncludePaths)
|
|
includePaths.Add(e);
|
|
|
|
var outputTargetFilePath = target.GetOutputFilePath(targetBuildOptions, project.OutputType);
|
|
|
|
// Build command for the build tool
|
|
var cmdLine = string.Format("{0} -log -mutex -workspace={1} -arch={2} -configuration={3} -platform={4} -buildTargets={5}",
|
|
FixPath(buildToolPath),
|
|
FixPath(project.WorkspaceRootPath),
|
|
configuration.Architecture,
|
|
configuration.Configuration,
|
|
configuration.Platform,
|
|
target.Name);
|
|
Configuration.PassArgs(ref cmdLine);
|
|
|
|
vcProjectFileContent.AppendLine(string.Format(" <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='{0}'\">", configuration.Name));
|
|
if (platform is IVisualStudioProjectCustomizer customizer)
|
|
customizer.WriteVisualStudioBuildProperties(vsProject, platform, toolchain, configuration, vcProjectFileContent, vcFiltersFileContent, vcUserFileContent);
|
|
vcProjectFileContent.AppendLine(string.Format(" <IntDir>{0}</IntDir>", targetBuildOptions.IntermediateFolder));
|
|
vcProjectFileContent.AppendLine(string.Format(" <OutDir>{0}</OutDir>", targetBuildOptions.OutputFolder));
|
|
if (includePaths.Count != 0)
|
|
vcProjectFileContent.AppendLine(string.Format(" <IncludePath>$(IncludePath);{0}</IncludePath>", string.Join(";", includePaths)));
|
|
else
|
|
vcProjectFileContent.AppendLine(" <IncludePath />");
|
|
vcProjectFileContent.AppendLine(" <ReferencePath />");
|
|
vcProjectFileContent.AppendLine(" <LibraryPath />");
|
|
vcProjectFileContent.AppendLine(" <LibraryWPath />");
|
|
vcProjectFileContent.AppendLine(" <SourcePath />");
|
|
vcProjectFileContent.AppendLine(" <ExcludePath />");
|
|
vcProjectFileContent.AppendLine(string.Format(" <NMakeBuildCommandLine>{0} -build</NMakeBuildCommandLine>", cmdLine));
|
|
vcProjectFileContent.AppendLine(string.Format(" <NMakeReBuildCommandLine>{0} -rebuild</NMakeReBuildCommandLine>", cmdLine));
|
|
vcProjectFileContent.AppendLine(string.Format(" <NMakeCleanCommandLine>{0} -clean</NMakeCleanCommandLine>", cmdLine));
|
|
vcProjectFileContent.AppendLine(string.Format(" <NMakeOutput>{0}</NMakeOutput>", outputTargetFilePath));
|
|
|
|
if (preprocessorDefinitions.Count != 0)
|
|
vcProjectFileContent.AppendLine(string.Format(" <NMakePreprocessorDefinitions>$(NMakePreprocessorDefinitions);{0}</NMakePreprocessorDefinitions>", string.Join(";", preprocessorDefinitions)));
|
|
|
|
if (includePaths.Count != 0)
|
|
vcProjectFileContent.AppendLine(string.Format(" <NMakeIncludeSearchPath>$(NMakeIncludeSearchPath);{0}</NMakeIncludeSearchPath>", string.Join(";", includePaths)));
|
|
|
|
var additionalOptions = new List<string>();
|
|
additionalOptions.Add("$(AdditionalOptions)");
|
|
switch (configuration.TargetBuildOptions.CompileEnv.CppVersion)
|
|
{
|
|
case CppVersion.Cpp14:
|
|
additionalOptions.Add("/std:c++14");
|
|
break;
|
|
case CppVersion.Cpp17:
|
|
additionalOptions.Add("/std:c++17");
|
|
break;
|
|
case CppVersion.Cpp20:
|
|
additionalOptions.Add("/std:c++20");
|
|
break;
|
|
case CppVersion.Latest:
|
|
additionalOptions.Add("/std:c++latest");
|
|
break;
|
|
}
|
|
|
|
vcProjectFileContent.AppendLine(string.Format(" <AdditionalOptions>{0}</AdditionalOptions>", string.Join(" ", additionalOptions)));
|
|
|
|
vcProjectFileContent.AppendLine(" </PropertyGroup>");
|
|
}
|
|
|
|
// Files and folders
|
|
vcProjectFileContent.AppendLine(" <ItemGroup>");
|
|
vcFiltersFileContent.AppendLine(" <ItemGroup>");
|
|
|
|
var files = new List<string>();
|
|
if (project.SourceFiles != null)
|
|
files.AddRange(project.SourceFiles);
|
|
if (project.SourceDirectories != null)
|
|
{
|
|
foreach (var folder in project.SourceDirectories)
|
|
{
|
|
files.AddRange(Directory.GetFiles(folder, "*", SearchOption.AllDirectories));
|
|
}
|
|
}
|
|
|
|
var filterDirectories = new HashSet<string>();
|
|
foreach (var file in files)
|
|
{
|
|
string fileType;
|
|
if (file.EndsWith(".h", StringComparison.OrdinalIgnoreCase) || file.EndsWith(".inl", StringComparison.OrdinalIgnoreCase) || file.EndsWith(".hpp", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
fileType = "ClInclude";
|
|
}
|
|
else if (file.EndsWith(".cpp", StringComparison.OrdinalIgnoreCase) || file.EndsWith(".cc", StringComparison.OrdinalIgnoreCase) || file.EndsWith(".c", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
fileType = "ClCompile";
|
|
}
|
|
else if (file.EndsWith(".rc", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
fileType = "ResourceCompile";
|
|
}
|
|
else if (file.EndsWith(".manifest", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
fileType = "Manifest";
|
|
}
|
|
else if (file.EndsWith(".cs", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
// C# files are added to .csproj
|
|
continue;
|
|
}
|
|
else if (file.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
// Skip C# project files
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
fileType = "None";
|
|
}
|
|
|
|
var projectPath = Utilities.MakePathRelativeTo(file, projectDirectory);
|
|
vcProjectFileContent.AppendLine(string.Format(" <{0} Include=\"{1}\"/>", fileType, projectPath));
|
|
|
|
string filterPath = Utilities.MakePathRelativeTo(file, filtersDirectory);
|
|
int lastSeparatorIdx = filterPath.LastIndexOf(Path.DirectorySeparatorChar);
|
|
filterPath = lastSeparatorIdx == -1 ? string.Empty : filterPath.Substring(0, lastSeparatorIdx);
|
|
if (!string.IsNullOrWhiteSpace(filterPath))
|
|
{
|
|
// Add directories to the filters for this file
|
|
string pathRemaining = filterPath;
|
|
if (!filterDirectories.Contains(pathRemaining))
|
|
{
|
|
List<string> allDirectoriesInPath = new List<string>();
|
|
string currentPath = string.Empty;
|
|
while (true)
|
|
{
|
|
if (pathRemaining.Length > 0)
|
|
{
|
|
int slashIndex = pathRemaining.IndexOf(Path.DirectorySeparatorChar);
|
|
string splitDirectory;
|
|
if (slashIndex != -1)
|
|
{
|
|
splitDirectory = pathRemaining.Substring(0, slashIndex);
|
|
pathRemaining = pathRemaining.Substring(splitDirectory.Length + 1);
|
|
}
|
|
else
|
|
{
|
|
splitDirectory = pathRemaining;
|
|
pathRemaining = string.Empty;
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(currentPath))
|
|
{
|
|
currentPath += Path.DirectorySeparatorChar;
|
|
}
|
|
|
|
currentPath += splitDirectory;
|
|
|
|
allDirectoriesInPath.Add(currentPath);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < allDirectoriesInPath.Count; i++)
|
|
{
|
|
string leadingDirectory = allDirectoriesInPath[i];
|
|
if (!filterDirectories.Contains(leadingDirectory))
|
|
{
|
|
filterDirectories.Add(leadingDirectory);
|
|
|
|
string filterGuid = Guid.NewGuid().ToString("B").ToUpperInvariant();
|
|
vcFiltersFileContent.AppendLine(string.Format(" <Filter Include=\"{0}\">", leadingDirectory));
|
|
vcFiltersFileContent.AppendLine(string.Format(" <UniqueIdentifier>{0}</UniqueIdentifier>", filterGuid));
|
|
vcFiltersFileContent.AppendLine(" </Filter>");
|
|
}
|
|
}
|
|
}
|
|
|
|
vcFiltersFileContent.AppendLine(string.Format(" <{0} Include=\"{1}\">", fileType, projectPath));
|
|
vcFiltersFileContent.AppendLine(string.Format(" <Filter>{0}</Filter>", filterPath));
|
|
vcFiltersFileContent.AppendLine(string.Format(" </{0}>", fileType));
|
|
}
|
|
else
|
|
{
|
|
vcFiltersFileContent.AppendLine(string.Format(" <{0} Include=\"{1}\" />", fileType, projectPath));
|
|
}
|
|
}
|
|
|
|
vcProjectFileContent.AppendLine(" </ItemGroup>");
|
|
vcFiltersFileContent.AppendLine(" </ItemGroup>");
|
|
|
|
{
|
|
// IntelliSense information
|
|
vcProjectFileContent.AppendLine(" <PropertyGroup>");
|
|
vcProjectFileContent.AppendLine(string.Format(" <NMakePreprocessorDefinitions>$(NMakePreprocessorDefinitions){0}</NMakePreprocessorDefinitions>", (project.Defines.Count > 0 ? (";" + string.Join(";", project.Defines)) : "")));
|
|
vcProjectFileContent.AppendLine(string.Format(" <NMakeIncludeSearchPath>$(NMakeIncludeSearchPath){0}</NMakeIncludeSearchPath>", (project.SearchPaths.Length > 0 ? (";" + string.Join(";", project.SearchPaths)) : "")));
|
|
vcProjectFileContent.AppendLine(" <NMakeForcedIncludes>$(NMakeForcedIncludes)</NMakeForcedIncludes>");
|
|
vcProjectFileContent.AppendLine(" <NMakeAssemblySearchPath>$(NMakeAssemblySearchPath)</NMakeAssemblySearchPath>");
|
|
vcProjectFileContent.AppendLine(" <NMakeForcedUsingAssemblies>$(NMakeForcedUsingAssemblies)</NMakeForcedUsingAssemblies>");
|
|
vcProjectFileContent.AppendLine(" <AdditionalOptions>$(AdditionalOptions)</AdditionalOptions>");
|
|
vcProjectFileContent.AppendLine(" </PropertyGroup>");
|
|
}
|
|
|
|
foreach (var platform in platforms)
|
|
{
|
|
if (platform is IVisualStudioProjectCustomizer customizer)
|
|
customizer.WriteVisualStudioEnd(vsProject, platform, vcProjectFileContent, vcFiltersFileContent, vcUserFileContent);
|
|
}
|
|
|
|
// End
|
|
vcProjectFileContent.AppendLine(" <ItemDefinitionGroup>");
|
|
vcProjectFileContent.AppendLine(" </ItemDefinitionGroup>");
|
|
vcProjectFileContent.AppendLine(" <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />");
|
|
vcProjectFileContent.AppendLine(" <ImportGroup Label=\"ExtensionTargets\">");
|
|
vcProjectFileContent.AppendLine(" </ImportGroup>");
|
|
vcProjectFileContent.AppendLine("</Project>");
|
|
|
|
vcFiltersFileContent.AppendLine("</Project>");
|
|
|
|
vcUserFileContent.AppendLine("</Project>");
|
|
|
|
if (platforms.Any(x => x.Target == TargetPlatform.Linux || x.Target == TargetPlatform.Mac))
|
|
{
|
|
var editorPath = Utilities.NormalizePath(Path.Combine(Globals.EngineRoot, Platform.GetEditorBinaryDirectory(), "$(Configuration.Split('.')[2])", $"FlaxEditor{Utilities.GetPlatformExecutableExt()}")).Replace('\\', '/');
|
|
var debuggerProjectPath = Globals.Project.Name == "Flax" ? "" : Globals.Project.ProjectFolderPath;
|
|
var debuggerWorkingDirectory = Globals.Project.ProjectFolderPath;
|
|
|
|
// Override MSBuild .targets file with one that runs NMake commands (workaround for Rider not finding "Microsoft.Cpp.Default.props" file)
|
|
var cppTargetsFileContent = new StringBuilder();
|
|
cppTargetsFileContent.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
|
|
cppTargetsFileContent.AppendLine("<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\" TreatAsLocalProperty=\"Platform\">");
|
|
cppTargetsFileContent.AppendLine(" <Import Project=\"Rider.Workarounds.Cpp.props\"/>");
|
|
cppTargetsFileContent.AppendLine(" <Target Name=\"Build\">");
|
|
cppTargetsFileContent.AppendLine(" <Exec Command='$(NMakeBuildCommandLine)'/>");
|
|
cppTargetsFileContent.AppendLine(" </Target>");
|
|
cppTargetsFileContent.AppendLine(" <Target Name=\"Rebuild\">");
|
|
cppTargetsFileContent.AppendLine(" <Exec Command='$(NMakeReBuildCommandLine)'/>");
|
|
cppTargetsFileContent.AppendLine(" </Target>");
|
|
cppTargetsFileContent.AppendLine(" <Target Name=\"Clean\">");
|
|
cppTargetsFileContent.AppendLine(" <Exec Command='$(NMakeCleanCommandLine)'/>");
|
|
cppTargetsFileContent.AppendLine(" </Target>");
|
|
cppTargetsFileContent.AppendLine(" <PropertyGroup>");
|
|
cppTargetsFileContent.AppendLine(" <TargetExt></TargetExt>");
|
|
cppTargetsFileContent.AppendLine(" <TargetName>$(RootNamespace)$(Configuration.Split('.')[0])</TargetName>");
|
|
cppTargetsFileContent.AppendLine(" <TargetPath>$(OutDir)/$(TargetName)$(TargetExt)</TargetPath>");
|
|
if (!string.IsNullOrEmpty(debuggerProjectPath))
|
|
cppTargetsFileContent.AppendLine(string.Format(" <LocalDebuggerCommandArguments>-project \"{0}\"</LocalDebuggerCommandArguments>", debuggerProjectPath));
|
|
else
|
|
cppTargetsFileContent.AppendLine(" <LocalDebuggerCommandArguments></LocalDebuggerCommandArguments>");
|
|
cppTargetsFileContent.AppendLine(string.Format(" <LocalDebuggerCommand>{0}</LocalDebuggerCommand>", editorPath));
|
|
cppTargetsFileContent.AppendLine(string.Format(" <LocalDebuggerWorkingDirectory>{0}</LocalDebuggerWorkingDirectory>", debuggerWorkingDirectory));
|
|
cppTargetsFileContent.AppendLine(" </PropertyGroup>");
|
|
cppTargetsFileContent.AppendLine("</Project>");
|
|
|
|
// Workarounds for Rider language server to not show errors over well known symbols
|
|
Dictionary<string, string> preprocessor = new Dictionary<string, string>()
|
|
{
|
|
{"__attribute__(x)", ""},
|
|
{"__null", "0"},
|
|
{"__extension__", ""},
|
|
{"__asm__", "__asm"},
|
|
{"_SIZE_T", "1"},
|
|
};
|
|
// Undefine hardcoded MSVC definitions
|
|
HashSet<string> undefine = new HashSet<string>()
|
|
{
|
|
"_MSC_VER",
|
|
"_MSC_EXTENSIONS",
|
|
"_M_IX86",
|
|
"_WIN32",
|
|
};
|
|
|
|
// Expose all known preprocessor definitions known by the compiler to language server
|
|
var clangDefinitions = Utilities.ReadProcessOutput("clang++", "-dM -E -x c++ /dev/null");
|
|
foreach (var (def, val) in clangDefinitions.Split('\n').Select(x => (x.Split(' ')[1], x.Split(' ')[2])))
|
|
preprocessor.Add(def, val);
|
|
|
|
var workaroundsFileContent = new StringBuilder();
|
|
workaroundsFileContent.AppendLine($"<?xml version=\"1.0\" encoding=\"utf-8\"?>");
|
|
workaroundsFileContent.AppendLine($"<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\" TreatAsLocalProperty=\"Platform\">");
|
|
workaroundsFileContent.AppendLine($" <ItemDefinitionGroup>");
|
|
workaroundsFileContent.AppendLine($" <ClCompile>");
|
|
workaroundsFileContent.AppendLine($" <AdditionalOptions>{string.Join(' ', undefine.Select(x => $"/U {x}"))} %(AdditionalOptions)</AdditionalOptions>");
|
|
workaroundsFileContent.AppendLine($" </ClCompile>");
|
|
workaroundsFileContent.AppendLine($" </ItemDefinitionGroup>");
|
|
workaroundsFileContent.AppendLine($" <PropertyGroup>");
|
|
workaroundsFileContent.AppendLine($" <NMakeIncludeSearchPath>/usr/include/c++/16/aarch64-redhat-linux/;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>");
|
|
workaroundsFileContent.AppendLine($" <NMakePreprocessorDefinitions>{string.Join(';', preprocessor.Select(x => $"{x.Key}={x.Value}"))};$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>");
|
|
workaroundsFileContent.AppendLine($" </PropertyGroup>");
|
|
workaroundsFileContent.AppendLine($"</Project>");
|
|
|
|
Utilities.WriteFileIfChanged(Path.Combine(projectDirectory, "Microsoft.Cpp.targets"), cppTargetsFileContent.ToString());
|
|
Utilities.WriteFileIfChanged(Path.Combine(projectDirectory, "Microsoft.Cpp.Default.props"), vcUserFileContent.ToString());
|
|
Utilities.WriteFileIfChanged(Path.Combine(projectDirectory, "Microsoft.Cpp.props"), vcUserFileContent.ToString());
|
|
Utilities.WriteFileIfChanged(Path.Combine(projectDirectory, "Rider.Workarounds.Cpp.props"), workaroundsFileContent.ToString());
|
|
}
|
|
|
|
// Save the files
|
|
Utilities.WriteFileIfChanged(project.Path, vcProjectFileContent.ToString());
|
|
Utilities.WriteFileIfChanged(project.Path + ".filters", vcFiltersFileContent.ToString());
|
|
Utilities.WriteFileIfChanged(project.Path + ".user", vcUserFileContent.ToString());
|
|
}
|
|
}
|
|
}
|