/// <summary> /// Generates project files for Visual Studio: '.vcxproj' and '.vcxproj.filter'. /// </summary> /// <param name="project">Parsed project object.</param> /// <returns>Path to Visual Studio '.vcxproj file'.</returns> public sealed override string GenerateProjectFiles(Project project) { var vcxProjPath = Path.Combine(base.GenerateProjectFiles(project), project.Name) + ".vcxproj"; try { // For build tools the best was is to load a GUID from project files: this causes exceptions // in Visual Studio when reloading of solution, and all opened tabs would be terminated. project.Misc.GUID = QueryGuidFromProject(vcxProjPath); } catch (Exception) { project.Misc.GUID = CreateMsBuildGuid(); } // ========================================================================================== // Generating VCXPROJ files. // ========================================================================================== using (var vcxProj = new XmlTextWriter(vcxProjPath, null) { Formatting = Formatting.Indented, Indentation = 1, IndentChar = '\t' }) { vcxProj.WriteStartDocument(); vcxProj.WriteComment("Generated by GoddamnBuildSystem. Please, do not edit this file manually."); vcxProj./**/ WriteStartElement("Project", c_MsBuild2003Namespace); vcxProj./**//**/ WriteAttributeString("ToolsVersion", c_ToolsVersion); vcxProj./**//**/ WriteAttributeString("DefaultTargets", "Build"); // ------------------------------------------------------------------------------------------ // Defining list of configurations. // ------------------------------------------------------------------------------------------ vcxProj.WriteStartElement("ItemGroup"); vcxProj./**/ WriteAttributeString("Label", "ProjectConfigurations"); foreach (var platform in TargetInfo.EnumerateAllPlatforms()) { var platformString = ConvertPlatformToMsBuildPlatform(platform); foreach (var configuration in TargetInfo.EnumerateAllConfigurations()) { var configurationName = string.Concat(configuration, platform); vcxProj./**/ WriteStartElement("ProjectConfiguration"); vcxProj./**//**/ WriteAttributeString("Include", configurationName + '|' + platformString); vcxProj./**//**/ WriteElementString("Configuration", configurationName); vcxProj./**//**/ WriteElementString("Platform", platformString); vcxProj./**/ WriteEndElement(); } } vcxProj.WriteEndElement(); // ------------------------------------------------------------------------------------------ // Defining list of source files. // ------------------------------------------------------------------------------------------ foreach (var platform in TargetInfo.EnumerateAllPlatforms()) { var platformString = ConvertPlatformToMsBuildPlatform(platform); foreach (var configuration in TargetInfo.EnumerateAllConfigurations()) { var configurationName = string.Concat(configuration, platform); vcxProj.WriteStartElement("ItemGroup"); vcxProj.WriteAttributeStringFormat("Condition", @"'$(Configuration)|$(Platform)'=='{0}|{1}'", configurationName, platformString); foreach (var projectSource in project.Files[platform, configuration]) { vcxProj.WriteStartElement(ConvertFileTypeToVcxProjElement(projectSource.FileType)); vcxProj.WriteAttributeString("Include", projectSource.FilePath); vcxProj.WriteEndElement(); } vcxProj.WriteEndElement(); } } // ------------------------------------------------------------------------------------------ // Overriding global project properties. // ------------------------------------------------------------------------------------------ vcxProj.WriteStartElement("PropertyGroup"); vcxProj./**/ WriteElementString("ProjectGuid", project.Misc.GUID); vcxProj./**/ WriteElementString("RootNamespace", project.Name); vcxProj./**/ WriteElementString("MinimumVisualStudioVersion", "14.0"); vcxProj.WriteEndElement(); foreach (var platform in TargetInfo.EnumerateAllPlatforms()) { var platformString = ConvertPlatformToMsBuildPlatform(platform); foreach (var configuration in TargetInfo.EnumerateAllConfigurations()) { var configurationName = string.Concat(configuration, platform); vcxProj.WriteStartElement("PropertyGroup"); vcxProj./**/ WriteAttributeStringFormat("Condition", "'$(Configuration)|$(Platform)'=='{0}|{1}'", configurationName, platformString); vcxProj./**/ WriteAttributeString("Label", "Globals"); vcxProj./**/ WriteElementString("WindowsTargetPlatformVersion", "10.0.16299.0"); if (platform == TargetPlatform.XboxOne) { vcxProj./**/ WriteElementString("AppContainerApplication", "true"); vcxProj./**/ WriteElementString("ApplicationType", "Windows Store"); vcxProj./**/ WriteElementString("WindowsTargetPlatformVersion", "10.0.16299.0"); vcxProj./**/ WriteElementString("WindowsTargetPlatformMinVersion", "10.0.10586.0"); vcxProj./**/ WriteElementString("ApplicationTypeRevision", "10"); } vcxProj.WriteEndElement(); } } // ------------------------------------------------------------------------------------------ // Overriding main configuration properties. // ------------------------------------------------------------------------------------------ foreach (var platform in TargetInfo.EnumerateAllPlatforms()) { var platformString = ConvertPlatformToMsBuildPlatform(platform); var platformToolset = "v141"; foreach (var configuration in TargetInfo.EnumerateAllConfigurations()) { var configurationName = string.Concat(configuration, platform); vcxProj.WriteStartElement("PropertyGroup"); vcxProj./**/ WriteAttributeStringFormat("Condition", "'$(Configuration)|$(Platform)'=='{0}|{1}'", configurationName, platformString); vcxProj./**/ WriteAttributeString("Label", "Configuration"); vcxProj./**/ WriteElementString("PlatformToolset", platformToolset); if (IsPlatformNativelySupported(platform)) { vcxProj./**/ WriteElementString("ConfigurationType", project.BuildType[platform, configuration].ToString()); vcxProj./**/ WriteElementString("CharacterSet", "Unicode"); } else { vcxProj./**/ WriteElementString("ConfigurationType", "Makefile"); } vcxProj.WriteEndElement(); } } vcxProj.WriteStartElement("Import"); vcxProj./**/ WriteAttributeString("Project", @"$(VCTargetsPath)\Microsoft.Cpp.Default.props"); vcxProj.WriteEndElement(); vcxProj.WriteStartElement("Import"); vcxProj./**/ WriteAttributeString("Project", @"$(VCTargetsPath)\Microsoft.Cpp.props"); vcxProj.WriteEndElement(); vcxProj.WriteStartElement("ImportGroup"); vcxProj./**/ WriteAttributeString("Label", "ExtensionSettings"); vcxProj./**/ WriteStartElement("Import"); vcxProj./**//**/ WriteAttributeString("Project", @"$(VCTargetsPath)\BuildCustomizations\masm.props"); vcxProj./**/ WriteEndElement(); vcxProj.WriteEndElement(); vcxProj.WriteStartElement("PropertyGroup"); vcxProj./**/ WriteAttributeString("Label", "UserMacros"); vcxProj.WriteEndElement(); vcxProj.WriteStartElement("PropertyGroup"); vcxProj./**/ WriteElementString("NMakeForcedIncludes", "$(NMakeForcedIncludes)"); vcxProj./**/ WriteElementString("NMakeAssemblySearchPath", "$(NMakeAssemblySearchPath)"); vcxProj./**/ WriteElementString("NMakeForcedUsingAssemblies", "$(NMakeForcedUsingAssemblies)"); vcxProj.WriteEndElement(); // ------------------------------------------------------------------------------------------ // Overriding VC++ compiler and linker properties OR NMake commands.. // ------------------------------------------------------------------------------------------ foreach (var platform in TargetInfo.EnumerateAllPlatforms()) { var platformInfo = TargetPlatformInfo.Get(platform); var platformString = ConvertPlatformToMsBuildPlatform(platform); // Building list of header directories. var includePathes = project.GenerateIncludePaths(platform, TargetConfiguration.Debug); var standardLibrariesPaths = platformInfo.GenerateStandardIncludePaths(); if (string.IsNullOrEmpty(standardLibrariesPaths)) { standardLibrariesPaths = "$(NMakeIncludeSearchPath)"; } foreach (var configuration in TargetInfo.EnumerateAllConfigurations()) { var configurationInfo = TargetConfigurationInfo.Get(configuration); // Defining macros.. //var macros = project.GenerateMacros(platform, configuration); //var standardMacros = platformInfo.GenerateStandardMacrosList(); //if (string.IsNullOrEmpty(standardMacros)) //{ // standardMacros = "$(NMakePreprocessorDefinitions)"; //} // Collecting linked libraries.. var linkedLibraries = project.GenerateLinkedLibrariesPaths(platform, configuration); var standardLinkedLibraries = platformInfo.GenerateStandardLinkedLibrariesPaths(); if (string.IsNullOrEmpty(standardLinkedLibraries)) { standardLinkedLibraries = ""; } standardLinkedLibraries += "%(AdditionalDependencies)"; var configurationName = string.Concat(configuration, platform); var outputPath = project.OutputPath[platform, configuration]; vcxProj.WriteStartElement("ImportGroup"); vcxProj./**/ WriteAttributeStringFormat("Condition", "'$(Configuration)|$(Platform)'=='{0}|{1}'", configurationName, platformString); vcxProj./**/ WriteAttributeString("Label", "PropertySheets"); vcxProj./**/ WriteStartElement("Import"); vcxProj./**//**/ WriteAttributeString("Project", @"$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"); vcxProj./**//**/ WriteAttributeString("Condition", @"exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')"); vcxProj./**//**/ WriteAttributeString("Label", "LocalAppDataPlatform"); vcxProj./**/ WriteEndElement(); vcxProj.WriteEndElement(); if (IsPlatformNativelySupported(platform)) { // ------------------------------------------------------------------------------------------ // Defining VC++ compiler and linker properties. // ------------------------------------------------------------------------------------------ // Include paths.. vcxProj.WriteStartElement("PropertyGroup"); vcxProj./**/ WriteAttributeStringFormat("Condition", "'$(Configuration)|$(Platform)'=='{0}|{1}'", configurationName, platformString); vcxProj./**/ WriteElementString("IncludePath", includePathes + "$(IncludePath)"); vcxProj./**/ WriteElementString("OutDir", Path.GetDirectoryName(outputPath) + Path.DirectorySeparatorChar); vcxProj./**/ WriteElementString("TargetName", Path.GetFileNameWithoutExtension(outputPath)); vcxProj.WriteEndElement(); // Compiler properties.. vcxProj.WriteStartElement("ItemDefinitionGroup"); vcxProj./**/ WriteAttributeStringFormat("Condition", "'$(Configuration)|$(Platform)'=='{0}|{1}'", configurationName, platformString); vcxProj./**/ WriteStartElement("ClCompile"); vcxProj./**//**/ WriteElementString("FavorSizeOrSpeed", "Speed"); vcxProj./**//**/ WriteElementString("PrecompiledHeader", "NotUsing"); vcxProj./**//**/ WriteElementString("CallingConvention", "FastCall"); vcxProj./**//**/ WriteElementString("WarningLevel", "Level" + TargetCppCompilerInformation.WarningLevel); vcxProj./**//**/ WriteElementString("TreatWarningAsError", TargetCppCompilerInformation.WarningsAreErrors.ToString()); //vcxProj./**//**/WriteElementString("PreprocessorDefinitions", macros + "%(PreprocessorDefinition)"); vcxProj./**//**/ WriteElementString("Optimization", configurationInfo.Optimize ? "Full" : "Disabled"); if (configurationInfo.IsDebug) { vcxProj.WriteElementString("RuntimeLibrary", "MultiThreadedDebugDLL"); } if (!platformInfo.RequiresRtti) { vcxProj.WriteElementString("RuntimeTypeInfo", "false"); } if (!platformInfo.RequiresExceptions) { //vcxProj.WriteElementString("ExceptionHandling", "false"); } vcxProj./**/ WriteEndElement(); // </ VC++ COMPILER PROPERTIES // Linker properties. vcxProj./**/ WriteStartElement("Link"); vcxProj./**//**/ WriteElementString("AdditionalDependencies", linkedLibraries + standardLinkedLibraries); vcxProj./**//**/ WriteElementString("GenerateDebugInformation", configurationInfo.GenerateDebugInformation.ToString().ToLowerInvariant()); if (project.BuildType[platform, configuration] == ProjectBuildType.DynamicLibrary) { vcxProj./**//**/ WriteElementString("ImportLibrary", project.ImportLibraryOutputPath[platform, configuration]); } vcxProj./**/ WriteEndElement(); vcxProj.WriteEndElement(); } else { // ------------------------------------------------------------------------------------------ // Defining NMake properties.. // ------------------------------------------------------------------------------------------ var nmakeCommand = $"\"{System.Reflection.Assembly.GetExecutingAssembly().Location}\" --compile-project \"{project.Source}\" {platform} {configuration} "; vcxProj.WriteStartElement("PropertyGroup"); vcxProj./**/ WriteAttributeStringFormat("Condition", "'$(Configuration)|$(Platform)'=='{0}|{1}'", configurationName, platformString); vcxProj./**/ WriteElementString("OutDir", Path.GetDirectoryName(outputPath) + Path.DirectorySeparatorChar); vcxProj./**/ WriteElementString("NMakeOutput", outputPath); //vcxProj./**/WriteElementString("NMakePreprocessorDefinitions", macros + standardMacros + ";GD_PLATFORNOT_WINDOWS=1"); vcxProj./**/ WriteElementString("NMakeIncludeSearchPath", includePathes + standardLibrariesPaths); vcxProj./**/ WriteElementString("NMakeBuildCommandLine", nmakeCommand); vcxProj./**/ WriteElementString("NMakeReBuildCommandLine", nmakeCommand + "Rebuild"); vcxProj./**/ WriteElementString("NMakeCleanCommandLine", nmakeCommand + "Clean"); vcxProj.WriteEndElement(); } } } vcxProj.WriteStartElement("Import"); vcxProj./**/ WriteAttributeString("Project", @"$(VCTargetsPath)\Microsoft.Cpp.targets"); vcxProj.WriteEndElement(); vcxProj.WriteStartElement("ImportGroup"); vcxProj./**/ WriteAttributeString("Label", "ExtensionSettings"); vcxProj./**/ WriteStartElement("Import"); vcxProj./**//**/ WriteAttributeString("Project", @"$(VCTargetsPath)\BuildCustomizations\masm.targets"); vcxProj./**/ WriteEndElement(); vcxProj.WriteEndElement(); vcxProj./**/ WriteEndElement(); vcxProj.WriteEndDocument(); } // ========================================================================================== // Generating VCPROJ.FILTERS files. // ========================================================================================== var vcxProjFiltersPath = vcxProjPath + ".filters"; using (var vcxProjFilters = new XmlTextWriter(vcxProjFiltersPath, null) { Formatting = Formatting.Indented, Indentation = 1, IndentChar = '\t' }) { vcxProjFilters.WriteStartDocument(); vcxProjFilters./**/ WriteStartElement("Project", c_MsBuild2003Namespace); vcxProjFilters./**/ WriteAttributeString("ToolsVersion", c_ToolsFiltersVersion); var projectFoldersCache = new HashSet <string>(); foreach (var projectSourceFile in project.Files[TargetPlatform.Any, TargetConfiguration.Any]) { var projectSourceFileDirectory = Path.GetDirectoryName(projectSourceFile.FilePath); string projectSourceFilter; // Checking if this source can have a filter: it is located in project directory and it not in it's root. // We also add "Source" to each filter to separate configuration and source files. if (projectSourceFileDirectory != null && projectSourceFileDirectory.StartsWith(project.SourcesFilterOrigin, StringComparison.InvariantCultureIgnoreCase) && projectSourceFileDirectory.Length > project.SourcesFilterOrigin.Length + 1) { projectSourceFilter = "Source\\" + projectSourceFileDirectory.Substring(project.SourcesFilterOrigin.Length + 1); var projectSourceFilterIter = projectSourceFilter; while (!projectFoldersCache.Contains(projectSourceFilterIter) && !string.IsNullOrEmpty(projectSourceFilterIter)) { // ------------------------------------------------------------------------------------------ // Defining group of filters. // ------------------------------------------------------------------------------------------ vcxProjFilters.WriteStartElement("ItemGroup"); vcxProjFilters./**/ WriteStartElement("Filter"); vcxProjFilters./**//**/ WriteAttributeString("Include", projectSourceFilterIter); vcxProjFilters./**//**/ WriteElementString("UniqueIdentifier", CreateMsBuildGuid()); vcxProjFilters./**/ WriteEndElement(); vcxProjFilters.WriteEndElement(); projectFoldersCache.Add(projectSourceFilterIter); projectSourceFilterIter = Path.GetDirectoryName(projectSourceFilterIter); } } else { projectSourceFilter = "Source"; } // ------------------------------------------------------------------------------------------ // Defining source's filters. // ------------------------------------------------------------------------------------------ vcxProjFilters.WriteStartElement("ItemGroup"); vcxProjFilters./**/ WriteStartElement(ConvertFileTypeToVcxProjElement(projectSourceFile.FileType)); vcxProjFilters./**//**/ WriteAttributeString("Include", projectSourceFile.FilePath); vcxProjFilters./**//**/ WriteElementString("Filter", projectSourceFilter); vcxProjFilters./**/ WriteEndElement(); vcxProjFilters.WriteEndElement(); } vcxProjFilters./**/ WriteEndElement(); vcxProjFilters.WriteEndDocument(); } return(vcxProjPath); }