Ticket #7741: 0004-create_msvc-Add-MSVC10-support.patch

File 0004-create_msvc-Add-MSVC10-support.patch, 25.2 KB (added by Templier, 16 years ago)

4 - Add MSVC10 support

  • tools/create_msvc/create_msvc.cpp

    From 3c6b9138af257d3b524ec58690e412ae989e9ec3 Mon Sep 17 00:00:00 2001
    From: Julien <littleboy@users.sourceforge.net>
    Date: Sat, 26 Dec 2009 02:30:07 -0500
    Subject: [PATCH 4/7] create_msvc: Add MSVC10 support
    
    ---
     tools/create_msvc/create_msvc.cpp |  509 ++++++++++++++++++++++++++++++++++++-
     1 files changed, 506 insertions(+), 3 deletions(-)
    
    diff --git a/tools/create_msvc/create_msvc.cpp b/tools/create_msvc/create_msvc.cpp
    index a276a57..b2d692f 100644
    a b public:  
    290290        const int getVisualStudioVersion();
    291291};
    292292
     293class MSBuildProvider : public ProjectProvider {
     294public:
     295        MSBuildProvider(const int version, std::string global_warnings, std::map<std::string, std::string> project_warnings);
     296
     297        void createProjectFile(const std::string &name, const std::string &uuid, const BuildSetup &setup, const std::string &moduleDir,
     298                               const StringList &includeList, const StringList &excludeList);
     299
     300        void outputProjectSettings(std::ofstream &project, const std::string &name, const BuildSetup &setup, bool isRelease, bool isWin32);
     301
     302        void writeFileListToProject(const FileNode &dir, std::ofstream &projectFile, const int indentation,
     303                                    const StringList &duplicate, const std::string &objPrefix, const std::string &filePrefix);
     304
     305        void writeReferences(std::ofstream &output);
     306
     307        void outputGlobalPropFile(std::ofstream &properties, int bits, const std::string &defines, const std::string &prefix);
     308
     309        void createBuildProp(const BuildSetup &setup, bool isRelease, bool isWin32);
     310
     311        const char *getProjectExtension();
     312        const char *getPropertiesExtension();
     313        int getVisualStudioVersion();
     314
     315private:
     316        struct FileEntry {
     317                std::string name;
     318                std::string path;
     319                std::string filter;
     320                std::string prefix;
     321
     322                bool operator < (const FileEntry& rhs) {
     323                        return path.compare(rhs.path) == -1;    // Not exactly right for alphabetical order, but good enough
     324                }
     325        };
     326        typedef std::list<FileEntry> FileEntries;
     327
     328        std::list<std::string> _filters; // list of filters (we need to create a GUID for each filter id)
     329        FileEntries _compileFiles;
     330        FileEntries _includeFiles;
     331        FileEntries _otherFiles;
     332        FileEntries _asmFiles;
     333        FileEntries _resourceFiles;
     334
     335        void computeFileList(const FileNode &dir, const StringList &duplicate, const std::string &objPrefix, const std::string &filePrefix);
     336        void createFiltersFile(const BuildSetup &setup, const std::string &name);
     337};
     338
    293339} // End of anonymous namespace
    294340
    295341int main(int argc, char *argv[]) {
    int main(int argc, char *argv[]) {  
    346392
    347393                        msvcVersion = atoi(argv[++i]);
    348394
    349                         if (msvcVersion != 8 && msvcVersion != 9) {
     395                        if (msvcVersion != 8 && msvcVersion != 9 && msvcVersion != 10) {
    350396                                std::cerr << "ERROR: Unsupported version: \"" << msvcVersion << "\" passed to \"--msvc-version\"!\n";
    351397                                return -1;
    352398                        }
    int main(int argc, char *argv[]) {  
    455501        projectWarnings["lure"] = "4189;4355";
    456502        projectWarnings["kyra"] = "4355";
    457503
    458         ProjectProvider *provider = new VisualStudioProvider(msvcVersion, globalWarnings, projectWarnings);
     504        ProjectProvider *provider = NULL;
     505
     506        if (msvcVersion == 8 || msvcVersion == 9)
     507                provider = new VisualStudioProvider(msvcVersion, globalWarnings, projectWarnings);
     508        else
     509                provider = new MSBuildProvider(msvcVersion, globalWarnings, projectWarnings);
    459510
    460511        provider->createMSVCProject(setup);
    461512
    void displayHelp(const char *exe) {  
    500551                " --msvc-version version   set the targeted MSVC version. Possible values:\n"
    501552                "                           8 stands for \"Visual Studio 2005\"\n"
    502553                "                           9 stands for \"Visual Studio 2008\"\n"
     554                "                           10 stands for \"Visual Studio 2010\"\n"
    503555                "                           The default is \"9\", thus \"Visual Studio 2008\"\n"
    504556                " --file-prefix prefix     allow overwriting of relative file prefix in the\n"
    505557                "                          MSVC project files. By default the prefix is the\n"
    void ProjectProvider::createScummVMSolution(const BuildSetup &setup) {  
    925977
    926978        solution << "Project(\"{" << solutionUUID << "}\") = \"scummvm\", \"scummvm" << getProjectExtension() << "\", \"{" << svmProjectUUID << "}\"\n";
    927979
    928         writeReferences(solution);
     980        // Project dependencies are moved to vcxproj files in Visual Studio 2010
     981        if (_version < 10)
     982                writeReferences(solution);
    929983
    930984        solution << "EndProject\n";
    931985
    void VisualStudioProvider::writeFileListToProject(const FileNode &dir, std::ofst  
    16911745                projectFile << getIndent(indentation + 1) << "</Filter>\n";
    16921746}
    16931747
     1748//////////////////////////////////////////////////////////////////////////
     1749// MSBuild Provider (Visual Studio 2010)
     1750//////////////////////////////////////////////////////////////////////////
     1751
     1752MSBuildProvider::MSBuildProvider(const int version, std::string global_warnings, std::map<std::string, std::string> project_warnings)
     1753        : ProjectProvider(version, global_warnings, project_warnings) {
     1754
     1755}
     1756
     1757const char *MSBuildProvider::getProjectExtension() {
     1758        return ".vcxproj";
     1759}
     1760
     1761const char *MSBuildProvider::getPropertiesExtension() {
     1762        return ".props";
     1763}
     1764
     1765int MSBuildProvider::getVisualStudioVersion() {
     1766        return 2010;
     1767}
     1768
     1769#define OUTPUT_CONFIGURATION_MSBUILD(config, platform) \
     1770        project << "\t\t<ProjectConfiguration Include=\"" << config << "|" << platform << "\">\n" \
     1771                   "\t\t\t<Configuration>" << config << "</Configuration>\n" \
     1772                   "\t\t\t<Platform>" << platform << "</Platform>\n" \
     1773                   "\t\t</ProjectConfiguration>\n"
     1774
     1775#define OUTPUT_CONFIGURATION_TYPE_MSBUILD(config) \
     1776        project << "\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='" << config << "'\" Label=\"Configuration\">\n" \
     1777                   "\t\t<ConfigurationType>" << (name == "scummvm" ? "Application" : "StaticLibrary") << "</ConfigurationType>\n" \
     1778                   "\t</PropertyGroup>\n"
     1779
     1780#define OUTPUT_PROPERTIES_MSBUILD(config, properties) \
     1781        project << "\t<ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='" << config << "'\" Label=\"PropertySheets\">\n" \
     1782                   "\t\t<Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" />\n" \
     1783                   "\t\t<Import Project=\"" << properties << "\" />\n" \
     1784                   "\t</ImportGroup>\n"
     1785
     1786void MSBuildProvider::createProjectFile(const std::string &name, const std::string &uuid, const BuildSetup &setup, const std::string &moduleDir,
     1787                                        const StringList &includeList, const StringList &excludeList) {
     1788
     1789        const std::string projectFile = setup.outputDir + '/' + name + getProjectExtension();
     1790        std::ofstream project(projectFile.c_str());
     1791        if (!project)
     1792                error("Could not open \"" + projectFile + "\" for writing");
     1793
     1794        project << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
     1795                   "<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n"
     1796                   "\t<ItemGroup Label=\"ProjectConfigurations\">\n";
     1797
     1798        OUTPUT_CONFIGURATION_MSBUILD("Debug", "Win32");
     1799        OUTPUT_CONFIGURATION_MSBUILD("Debug", "x64");
     1800        OUTPUT_CONFIGURATION_MSBUILD("Release", "Win32");
     1801        OUTPUT_CONFIGURATION_MSBUILD("Release", "x64");
     1802
     1803        project << "\t</ItemGroup>\n";
     1804
     1805        // Project name & Guid
     1806        project << "\t<PropertyGroup Label=\"Globals\">\n"
     1807                   "\t\t<ProjectGuid>" << uuid << "</ProjectGuid>\n"
     1808                   "\t\t<RootNamespace>" << name << "</RootNamespace>\n"
     1809                   "\t\t<Keyword>Win32Proj</Keyword>\n"
     1810                   "\t</PropertyGroup>\n";
     1811
     1812        // Shared configuration
     1813        project << "\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n";
     1814
     1815        OUTPUT_CONFIGURATION_TYPE_MSBUILD("Release|Win32");
     1816        OUTPUT_CONFIGURATION_TYPE_MSBUILD("Debug|Win32");
     1817        OUTPUT_CONFIGURATION_TYPE_MSBUILD("Release|x64");
     1818        OUTPUT_CONFIGURATION_TYPE_MSBUILD("Debug|x64");
     1819
     1820        project << "\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n"
     1821                   "\t<ImportGroup Label=\"ExtensionSettings\">\n"
     1822                   "\t</ImportGroup>\n";
     1823
     1824        OUTPUT_PROPERTIES_MSBUILD("Release|Win32", "ScummVM_Release.props");
     1825        OUTPUT_PROPERTIES_MSBUILD("Debug|Win32", "ScummVM_Debug.props");
     1826        OUTPUT_PROPERTIES_MSBUILD("Release|x64", "ScummVM_Release64.props");
     1827        OUTPUT_PROPERTIES_MSBUILD("Debug|x64", "ScummVM_Debug64.props");
     1828
     1829        project << "\t<PropertyGroup Label=\"UserMacros\" />\n";
     1830
     1831        // Project version number
     1832        project << "\t<PropertyGroup>\n"
     1833                   "\t\t<_ProjectFileVersion>10.0.21006.1</_ProjectFileVersion>\n"; // FIXME: update temporary entry _ProjectFileVersion
     1834
     1835        if (name == "scummvm")
     1836                project << "<ExecutablePath>$(SCUMMVM_LIBS)\\bin;$(VCInstallDir)bin;$(WindowsSdkDir)bin\\NETFX 4.0 Tools;$(WindowsSdkDir)bin;$(VSInstallDir)Common7\\Tools\\bin;$(VSInstallDir)Common7\\tools;$(VSInstallDir)Common7\\ide;$(ProgramFiles)\\HTML Help Workshop;$(FrameworkSDKDir)\\bin;$(MSBuildToolsPath32);$(VSInstallDir);$(SystemRoot)\\SysWow64;$(FxCopDir);$(PATH)</ExecutablePath>\n"
     1837                           "<IncludePath>$(SCUMMVM_LIBS)\\include;$(VCInstallDir)include;$(VCInstallDir)atlmfc\\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\\include;</IncludePath>\n"
     1838                           "<LibraryPath>$(SCUMMVM_LIBS)\\lib;$(VCInstallDir)lib;$(VCInstallDir)atlmfc\\lib;$(WindowsSdkDir)lib;$(FrameworkSDKDir)\\lib</LibraryPath>\n";
     1839
     1840        project << "\t</PropertyGroup>\n";
     1841
     1842        // Project-specific settings
     1843        outputProjectSettings(project, name, setup, false, true);
     1844        outputProjectSettings(project, name, setup, true, true);
     1845        outputProjectSettings(project, name, setup, false, false);
     1846        outputProjectSettings(project, name, setup, true, false);
     1847
     1848        // Files
     1849        std::string modulePath;
     1850        if (!moduleDir.compare(0, setup.srcDir.size(), setup.srcDir)) {
     1851                modulePath = moduleDir.substr(setup.srcDir.size());
     1852                if (!modulePath.empty() && modulePath.at(0) == '/')
     1853                        modulePath.erase(0, 1);
     1854        }
     1855
     1856        if (modulePath.size())
     1857                addFilesToProject(moduleDir, project, includeList, excludeList, setup.filePrefix + '/' + modulePath);
     1858        else
     1859                addFilesToProject(moduleDir, project, includeList, excludeList, setup.filePrefix);
     1860
     1861        // Output references for scummvm project
     1862        if (name == "scummvm")
     1863                writeReferences(project);
     1864
     1865        project << "\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n"
     1866                   "\t<ImportGroup Label=\"ExtensionTargets\">\n"
     1867                   "\t</ImportGroup>\n"
     1868                   "</Project>\n";
     1869
     1870        // Output filter file if necessary
     1871        createFiltersFile(setup, name);
     1872}
     1873
     1874#define OUTPUT_FILTER_MSBUILD(files, action) \
     1875        if (!files.empty()) { \
     1876                filters << "\t<ItemGroup>\n"; \
     1877                for (std::list<FileEntry>::const_iterator entry = files.begin(); entry != files.end(); ++entry) { \
     1878                        if ((*entry).filter != "") { \
     1879                                filters << "\t\t<" action " Include=\"" << (*entry).path << "\">\n" \
     1880                                           "\t\t\t<Filter>" << (*entry).filter << "</Filter>\n" \
     1881                                           "\t\t</" action ">\n"; \
     1882                        } else { \
     1883                                filters << "\t\t<" action " Include=\"" << (*entry).path << "\" />\n"; \
     1884                        } \
     1885                } \
     1886                filters << "\t</ItemGroup>\n"; \
     1887        }
     1888
     1889void MSBuildProvider::createFiltersFile(const BuildSetup &setup, const std::string &name) {
     1890        // No filters => no need to create a filter file
     1891        if (_filters.empty())
     1892                return;
     1893
     1894        // Sort all list alphabetically
     1895        _filters.sort();
     1896        _compileFiles.sort();
     1897        _includeFiles.sort();
     1898        _otherFiles.sort();
     1899        _resourceFiles.sort();
     1900        _asmFiles.sort();
     1901
     1902        const std::string filtersFile = setup.outputDir + '/' + name + getProjectExtension() + ".filters";
     1903        std::ofstream filters(filtersFile.c_str());
     1904        if (!filters)
     1905                error("Could not open \"" + filtersFile + "\" for writing");
     1906
     1907        filters << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
     1908                   "<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n";
     1909
     1910        // Output the list of filters
     1911        filters << "\t<ItemGroup>\n";
     1912        for (std::list<std::string>::iterator filter = _filters.begin(); filter != _filters.end(); ++filter) {
     1913                filters << "\t\t<Filter Include=\"" << *filter << "\">\n"
     1914                           "\t\t\t<UniqueIdentifier>" << createUUID() << "</UniqueIdentifier>\n"
     1915                           "\t\t</Filter>\n";
     1916        }
     1917        filters << "\t</ItemGroup>\n";
     1918
     1919        // Output files
     1920        OUTPUT_FILTER_MSBUILD(_compileFiles, "ClCompile")
     1921        OUTPUT_FILTER_MSBUILD(_includeFiles, "ClInclude")
     1922        OUTPUT_FILTER_MSBUILD(_otherFiles, "None")
     1923        OUTPUT_FILTER_MSBUILD(_resourceFiles, "ResourceCompile")
     1924        OUTPUT_FILTER_MSBUILD(_asmFiles, "CustomBuild")
     1925
     1926        filters << "</Project>";
     1927}
     1928
     1929void MSBuildProvider::writeReferences(std::ofstream &output) {
     1930        output << "\t<ItemGroup>\n";
     1931
     1932        for (UUIDMap::const_iterator i = _uuidMap.begin(); i != _uuidMap.end(); ++i) {
     1933                if (i->first == "scummvm")
     1934                        continue;
     1935
     1936                output << "\t<ProjectReference Include=\"" << i->first << ".vcxproj\">\n"
     1937                          "\t\t<Project>{" << i->second << "}</Project>\n"
     1938                          "\t</ProjectReference>\n";
     1939        }
     1940
     1941        output << "\t</ItemGroup>\n";
     1942}
     1943
     1944void MSBuildProvider::outputProjectSettings(std::ofstream &project, const std::string &name, const BuildSetup &setup, bool isRelease, bool isWin32) {
     1945
     1946        // Check for project-specific warnings:
     1947        std::map<std::string, std::string>::iterator warnings = _projectWarnings.find(name);
     1948
     1949        // Nothing to add here, move along!
     1950        if (name != "scummvm" && name != "tinsel" && warnings == _projectWarnings.end())
     1951                return;
     1952
     1953        project << "\t<ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='" << (isRelease ? "Release" : "Debug") << "|" << (isWin32 ? "Win32" : "x64") << "'\">\n"
     1954                   "\t\t<ClCompile>\n";
     1955
     1956        // Compile configuration
     1957        if (name == "scummvm") {
     1958                project << "\t\t\t<DisableLanguageExtensions>false</DisableLanguageExtensions>\n";
     1959        } else {
     1960                if (name == "tinsel" && !isRelease)
     1961                        project << "\t\t\t<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n";
     1962
     1963                if (warnings != _projectWarnings.end())
     1964                        project << "\t\t\t<DisableSpecificWarnings>" << warnings->second << ";%(DisableSpecificWarnings)</DisableSpecificWarnings>\n";
     1965        }
     1966
     1967        project << "\t\t</ClCompile>\n";
     1968
     1969        // Link configuration for scummvm project
     1970        if (name == "scummvm") {
     1971                std::string libraries;
     1972
     1973                for (StringList::const_iterator i = setup.libraries.begin(); i != setup.libraries.end(); ++i)
     1974                        libraries += *i + ';';
     1975
     1976                project << "\t\t<Link>\n"
     1977                           "\t\t\t<OutputFile>$(OutDir)scummvm.exe</OutputFile>\n"
     1978                           "\t\t\t<AdditionalDependencies>" << libraries << "%(AdditionalDependencies)</AdditionalDependencies>\n"
     1979                           "\t\t</Link>\n";
     1980        }
     1981
     1982        project << "\t</ItemDefinitionGroup>\n";
     1983}
     1984
     1985void MSBuildProvider::outputGlobalPropFile(std::ofstream &properties, int bits, const std::string &defines, const std::string &prefix) {
     1986        // FIXME: update temporary entries _ProjectFileVersion & _PropertySheetDisplayName
     1987        properties << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
     1988                      "<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n"
     1989                      "<PropertyGroup>\n"
     1990                      "<_ProjectFileVersion>10.0.21006.1</_ProjectFileVersion>\n"
     1991                      "<_PropertySheetDisplayName>ScummVM_Global</_PropertySheetDisplayName>\n"
     1992                      "<OutDir>$(Configuration)" << bits << "\\</OutDir>\n"
     1993                      "<IntDir>$(Configuration)" << bits << "/$(ProjectName)\\</IntDir>\n"
     1994                      "</PropertyGroup>\n"
     1995                      "<ItemDefinitionGroup>\n"
     1996                      "<ClCompile>\n"
     1997                      "<DisableLanguageExtensions>true</DisableLanguageExtensions>\n"
     1998                      "<DisableSpecificWarnings>" << _globalWarnings << ";%(DisableSpecificWarnings)</DisableSpecificWarnings>\n"
     1999                      "<AdditionalIncludeDirectories>" << prefix << ";" << prefix << "\\engines;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n"
     2000                      "<PreprocessorDefinitions>" << defines << ";%(PreprocessorDefinitions)</PreprocessorDefinitions>\n"
     2001                      "<ExceptionHandling>\n"
     2002                      "</ExceptionHandling>\n"
     2003                      "<RuntimeTypeInfo>false</RuntimeTypeInfo>\n"
     2004                      "<WarningLevel>Level4</WarningLevel>\n"
     2005                      "<TreatWarningAsError>false</TreatWarningAsError>\n"
     2006                      "<CompileAs>Default</CompileAs>\n"
     2007                      "</ClCompile>\n"
     2008                      "<Link>\n"
     2009                      "<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\n"
     2010                      "<SubSystem>Console</SubSystem>\n"
     2011                      "<EntryPointSymbol>WinMainCRTStartup</EntryPointSymbol>\n"
     2012                      "</Link>\n"
     2013                      "<ResourceCompile>\n"
     2014                      "<PreprocessorDefinitions>HAS_INCLUDE_SET;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n"
     2015                      "<AdditionalIncludeDirectories>" << prefix << ";%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n"
     2016                      "</ResourceCompile>\n"
     2017                      "</ItemDefinitionGroup>\n"
     2018                      "</Project>\n";
     2019
     2020        properties.flush();
     2021}
     2022
     2023void MSBuildProvider::createBuildProp(const BuildSetup &setup, bool isRelease, bool isWin32) {
     2024        const std::string outputType = (isRelease ? "Release" : "Debug");
     2025        const std::string outputBitness = (isWin32 ? "32" : "64");
     2026
     2027        std::ofstream properties((setup.outputDir + '/' + "ScummVM_" + outputType + (isWin32 ? "" : "64") + getPropertiesExtension()).c_str());
     2028        if (!properties)
     2029                error("Could not open \"" + setup.outputDir + '/' + "ScummVM_" + outputType + (isWin32 ? "" : "64") + getPropertiesExtension() + "\" for writing");
     2030
     2031        // FIXME: update temporary entries _ProjectFileVersion & _PropertySheetDisplayName
     2032        properties << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
     2033                      "<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n"
     2034                      "\t<ImportGroup Label=\"PropertySheets\">\n"
     2035                      "\t\t<Import Project=\"ScummVM_Global" << (isWin32 ? "" : "64") << ".props\" />\n"
     2036                      "\t</ImportGroup>\n"
     2037                      "\t<PropertyGroup>\n"
     2038                      "\t\t<_ProjectFileVersion>10.0.21006.1</_ProjectFileVersion>\n"
     2039                      "\t\t<_PropertySheetDisplayName>ScummVM_" << outputType << outputBitness << "</_PropertySheetDisplayName>\n"
     2040                      "\t\t<LinkIncremental>" << (isRelease ? "false" : "true") << "</LinkIncremental>\n"
     2041                      "\t</PropertyGroup>\n"
     2042                      "\t<ItemDefinitionGroup>\n"
     2043                      "\t\t<ClCompile>\n";
     2044
     2045        if (isRelease) {
     2046                properties << "\t\t\t<IntrinsicFunctions>true</IntrinsicFunctions>\n"
     2047                              "\t\t\t<WholeProgramOptimization>true</WholeProgramOptimization>\n"
     2048                              "\t\t\t<PreprocessorDefinitions>WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n"
     2049                              "\t\t\t<StringPooling>true</StringPooling>\n"
     2050                              "\t\t\t<BufferSecurityCheck>false</BufferSecurityCheck>\n"
     2051                              "\t\t\t<DebugInformationFormat></DebugInformationFormat>\n"
     2052                              "\t\t</ClCompile>\n"
     2053                              "\t\t<Link>\n"
     2054                              "\t\t\t<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\n"
     2055                              "\t\t\t<SetChecksum>true</SetChecksum>\n";
     2056        } else {
     2057                properties << "\t\t\t<Optimization>Disabled</Optimization>\n"
     2058                              "\t\t\t<PreprocessorDefinitions>WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n"
     2059                              "\t\t\t<MinimalRebuild>true</MinimalRebuild>\n"
     2060                              "\t\t\t<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n"
     2061                              "\t\t\t<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n"
     2062                              "\t\t\t<FunctionLevelLinking>true</FunctionLevelLinking>\n"
     2063                              "\t\t\t<TreatWarningAsError>false</TreatWarningAsError>\n"
     2064                              "\t\t\t<DebugInformationFormat>" << (isWin32 ? "EditAndContinue" : "ProgramDatabase") << "</DebugInformationFormat>\n" // For x64 format Edit and continue is not supported, thus we default to Program Database
     2065                              "\t\t</ClCompile>\n"
     2066                              "\t\t<Link>\n"
     2067                              "\t\t\t<GenerateDebugInformation>true</GenerateDebugInformation>\n"
     2068                              "\t\t\t<IgnoreSpecificDefaultLibraries>libcmt.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\n";
     2069        }
     2070
     2071        properties << "\t\t</Link>\n"
     2072                      "\t</ItemDefinitionGroup>\n"
     2073                      "</Project>\n";
     2074
     2075        properties.flush();
     2076        properties.close();
     2077}
     2078
     2079#define OUTPUT_NASM_COMMAND_MSBUILD(config) \
     2080        projectFile << "\t\t\t<Command Condition=\"'$(Configuration)|$(Platform)'=='" << config << "|Win32'\">nasm.exe -f win32 -g -o \"$(IntDir)" << (isDuplicate ? (*entry).prefix : "") << "%(FileName).obj\" \"%(FullPath)\"</Command>\n" \
     2081                       "\t\t\t<Outputs Condition=\"'$(Configuration)|$(Platform)'=='" << config << "|Win32'\">$(IntDir)" << (isDuplicate ? (*entry).prefix : "") << "%(FileName).obj;%(Outputs)</Outputs>\n";
     2082
     2083#define OUPUT_OBJECT_FILENAME_MSBUILD(config, platform, prefix) \
     2084        projectFile << "\t\t<ObjectFileName Condition=\"'$(Configuration)|$(Platform)'=='" << config << "|" << platform << "'\">$(IntDir)" << prefix << "%(FileName).obj</ObjectFileName>\n" \
     2085                       "\t\t<XMLDocumentationFileName Condition=\"'$(Configuration)|$(Platform)'=='" << config << "|" << platform << "'\">$(IntDir)" << prefix << "%(FileName).xdc</XMLDocumentationFileName>\n";
     2086
     2087#define OUPUT_FILES_MSBUILD(files, action) \
     2088        if (!files.empty()) { \
     2089                projectFile << "\t<ItemGroup>\n"; \
     2090                for (std::list<FileEntry>::const_iterator entry = files.begin(); entry != files.end(); ++entry) { \
     2091                        projectFile << "\t\t<" action " Include=\"" << (*entry).path << "\" />\n"; \
     2092                } \
     2093                projectFile << "\t</ItemGroup>\n"; \
     2094        }
     2095
     2096void MSBuildProvider::writeFileListToProject(const FileNode &dir, std::ofstream &projectFile, const int, const StringList &duplicate,
     2097                                             const std::string &objPrefix, const std::string &filePrefix) {
     2098
     2099        // Reset lists
     2100        _filters.clear();
     2101        _compileFiles.clear();
     2102        _includeFiles.clear();
     2103        _otherFiles.clear();
     2104        _resourceFiles.clear();
     2105        _asmFiles.clear();
     2106
     2107        // Compute the list of files
     2108        _filters.push_back(""); // init filters
     2109        computeFileList(dir, duplicate, objPrefix, filePrefix);
     2110        _filters.pop_back();    // remove last empty filter
     2111
     2112        // Output compile files
     2113        if (!_compileFiles.empty()) {
     2114                projectFile << "\t<ItemGroup>\n";
     2115                for (std::list<FileEntry>::const_iterator entry = _compileFiles.begin(); entry != _compileFiles.end(); ++entry) {
     2116                        const bool isDuplicate = (std::find(duplicate.begin(), duplicate.end(), (*entry).name + ".o") != duplicate.end());
     2117
     2118                        // Deal with duplicated file names
     2119                        if (isDuplicate) {
     2120                                projectFile << "\t\t<ClCompile Include=\"" << (*entry).path << "\">\n";
     2121                                OUPUT_OBJECT_FILENAME_MSBUILD("Debug", "Win32", (*entry).prefix)
     2122                                OUPUT_OBJECT_FILENAME_MSBUILD("Debug", "x64", (*entry).prefix)
     2123                                OUPUT_OBJECT_FILENAME_MSBUILD("Release", "Win32", (*entry).prefix)
     2124                                OUPUT_OBJECT_FILENAME_MSBUILD("Release", "x64", (*entry).prefix)
     2125                                projectFile << "\t\t</ClCompile>\n";
     2126                        } else {
     2127                                projectFile << "\t\t<ClCompile Include=\"" << (*entry).path << "\" />\n";
     2128                        }
     2129                }
     2130                projectFile << "\t</ItemGroup>\n";
     2131        }
     2132
     2133        // Output include, other and resource files
     2134        OUPUT_FILES_MSBUILD(_includeFiles, "ClInclude")
     2135        OUPUT_FILES_MSBUILD(_otherFiles, "None")
     2136        OUPUT_FILES_MSBUILD(_resourceFiles, "ResourceCompile")
     2137
     2138        // Output asm files
     2139        if (!_asmFiles.empty()) {
     2140                projectFile << "\t<ItemGroup>\n";
     2141                for (std::list<FileEntry>::const_iterator entry = _asmFiles.begin(); entry != _asmFiles.end(); ++entry) {
     2142
     2143                        const bool isDuplicate = (std::find(duplicate.begin(), duplicate.end(), (*entry).name + ".o") != duplicate.end());
     2144
     2145                        projectFile << "\t\t<CustomBuild Include=\"" << (*entry).path << "\">\n"
     2146                                       "\t\t\t<FileType>Document</FileType>\n";
     2147
     2148                        OUTPUT_NASM_COMMAND_MSBUILD("Debug")
     2149                        OUTPUT_NASM_COMMAND_MSBUILD("Release")
     2150
     2151                        projectFile << "\t\t</CustomBuild>\n";
     2152                }
     2153                projectFile << "\t</ItemGroup>\n";
     2154        }
     2155}
     2156
     2157void MSBuildProvider::computeFileList(const FileNode &dir, const StringList &duplicate, const std::string &objPrefix, const std::string &filePrefix) {
     2158
     2159        for (FileNode::NodeList::const_iterator i = dir.children.begin(); i != dir.children.end(); ++i) {
     2160                const FileNode *node = *i;
     2161
     2162                if (!node->children.empty()) {
     2163                        // Update filter
     2164                        std::string _currentFilter = _filters.back();
     2165                        _filters.back().append((_filters.back() == "" ? "" : "\\") + node->name);
     2166
     2167                        computeFileList(*node, duplicate, objPrefix + node->name + '_', filePrefix + node->name + '/');
     2168
     2169                        // Reset filter
     2170                        _filters.push_back(_currentFilter);
     2171                } else {
     2172                        // Filter files by extension
     2173                        std::string name, ext;
     2174                        splitFilename(node->name, name, ext);
     2175
     2176                        FileEntry entry;
     2177                        entry.name = name;
     2178                        entry.path = convertPathToWin(filePrefix + node->name);
     2179                        entry.filter = _filters.back();
     2180                        entry.prefix = objPrefix;
     2181
     2182                        if (ext == "cpp" || ext == "c") {
     2183                                _compileFiles.push_back(entry);
     2184                        } else if (ext == "h") {
     2185                                _includeFiles.push_back(entry);
     2186                        } else if (ext == "rc") {
     2187                                _resourceFiles.push_back(entry);
     2188                        } else if (ext == "asm") {
     2189                                _asmFiles.push_back(entry);
     2190                        } else {
     2191                                _otherFiles.push_back(entry);
     2192                        }
     2193                }
     2194        }
     2195}
     2196
    16942197} // End of anonymous namespace
    16952198
    16962199void error(const std::string &message) {