Edit and continue is not compatible with the coroutine code. Previously, it was disabled in the tinsel project only, but now that the coroutine code has been moved into common, we need to disable edit and continue in the scummvm project instead
533 lines
24 KiB
C++
533 lines
24 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "msbuild.h"
|
|
|
|
#include <fstream>
|
|
#include <algorithm>
|
|
|
|
namespace CreateProjectTool {
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// MSBuild Provider (Visual Studio 2010)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
MSBuildProvider::MSBuildProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, const int version)
|
|
: MSVCProvider(global_warnings, project_warnings, version) {
|
|
|
|
}
|
|
|
|
const char *MSBuildProvider::getProjectExtension() {
|
|
return ".vcxproj";
|
|
}
|
|
|
|
const char *MSBuildProvider::getPropertiesExtension() {
|
|
return ".props";
|
|
}
|
|
|
|
int MSBuildProvider::getVisualStudioVersion() {
|
|
return 2010;
|
|
}
|
|
|
|
namespace {
|
|
|
|
inline void outputConfiguration(std::ostream &project, const std::string &config, const std::string &platform) {
|
|
project << "\t\t<ProjectConfiguration Include=\"" << config << "|" << platform << "\">\n"
|
|
"\t\t\t<Configuration>" << config << "</Configuration>\n"
|
|
"\t\t\t<Platform>" << platform << "</Platform>\n"
|
|
"\t\t</ProjectConfiguration>\n";
|
|
}
|
|
|
|
inline void outputConfigurationType(const BuildSetup &setup, std::ostream &project, const std::string &name, const std::string &config) {
|
|
project << "\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='" << config << "'\" Label=\"Configuration\">\n"
|
|
"\t\t<ConfigurationType>" << ((name == setup.projectName || setup.devTools) ? "Application" : "StaticLibrary") << "</ConfigurationType>\n"
|
|
"\t</PropertyGroup>\n";
|
|
}
|
|
|
|
inline void outputProperties(std::ostream &project, const std::string &config, const std::string &properties) {
|
|
project << "\t<ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='" << config << "'\" Label=\"PropertySheets\">\n"
|
|
"\t\t<Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n"
|
|
"\t\t<Import Project=\"" << properties << "\" />\n"
|
|
"\t</ImportGroup>\n";
|
|
}
|
|
|
|
} // End of anonymous namespace
|
|
|
|
void MSBuildProvider::createProjectFile(const std::string &name, const std::string &uuid, const BuildSetup &setup, const std::string &moduleDir,
|
|
const StringList &includeList, const StringList &excludeList) {
|
|
const std::string projectFile = setup.outputDir + '/' + name + getProjectExtension();
|
|
std::ofstream project(projectFile.c_str());
|
|
if (!project)
|
|
error("Could not open \"" + projectFile + "\" for writing");
|
|
|
|
project << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
|
|
"<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n"
|
|
"\t<ItemGroup Label=\"ProjectConfigurations\">\n";
|
|
|
|
outputConfiguration(project, "Debug", "Win32");
|
|
outputConfiguration(project, "Debug", "x64");
|
|
outputConfiguration(project, "Analysis", "Win32");
|
|
outputConfiguration(project, "Analysis", "x64");
|
|
outputConfiguration(project, "Release", "Win32");
|
|
outputConfiguration(project, "Release", "x64");
|
|
|
|
project << "\t</ItemGroup>\n";
|
|
|
|
// Project name & Guid
|
|
project << "\t<PropertyGroup Label=\"Globals\">\n"
|
|
"\t\t<ProjectGuid>{" << uuid << "}</ProjectGuid>\n"
|
|
"\t\t<RootNamespace>" << name << "</RootNamespace>\n"
|
|
"\t\t<Keyword>Win32Proj</Keyword>\n"
|
|
"\t</PropertyGroup>\n";
|
|
|
|
// Shared configuration
|
|
project << "\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n";
|
|
|
|
outputConfigurationType(setup, project, name, "Release|Win32");
|
|
outputConfigurationType(setup, project, name, "Analysis|Win32");
|
|
outputConfigurationType(setup, project, name, "Debug|Win32");
|
|
outputConfigurationType(setup, project, name, "Release|x64");
|
|
outputConfigurationType(setup, project, name, "Analysis|x64");
|
|
outputConfigurationType(setup, project, name, "Debug|x64");
|
|
|
|
project << "\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n"
|
|
"\t<ImportGroup Label=\"ExtensionSettings\">\n"
|
|
"\t</ImportGroup>\n";
|
|
|
|
outputProperties(project, "Release|Win32", setup.projectDescription + "_Release.props");
|
|
outputProperties(project, "Analysis|Win32", setup.projectDescription + "_Analysis.props");
|
|
outputProperties(project, "Debug|Win32", setup.projectDescription + "_Debug.props");
|
|
outputProperties(project, "Release|x64", setup.projectDescription + "_Release64.props");
|
|
outputProperties(project, "Analysis|x64", setup.projectDescription + "_Analysis64.props");
|
|
outputProperties(project, "Debug|x64", setup.projectDescription + "_Debug64.props");
|
|
|
|
project << "\t<PropertyGroup Label=\"UserMacros\" />\n";
|
|
|
|
// Project-specific settings (analysis uses debug properties)
|
|
outputProjectSettings(project, name, setup, false, true, false);
|
|
outputProjectSettings(project, name, setup, false, true, true);
|
|
outputProjectSettings(project, name, setup, true, true, false);
|
|
outputProjectSettings(project, name, setup, false, false, false);
|
|
outputProjectSettings(project, name, setup, false, false, true);
|
|
outputProjectSettings(project, name, setup, true, false, false);
|
|
|
|
// Files
|
|
std::string modulePath;
|
|
if (!moduleDir.compare(0, setup.srcDir.size(), setup.srcDir)) {
|
|
modulePath = moduleDir.substr(setup.srcDir.size());
|
|
if (!modulePath.empty() && modulePath.at(0) == '/')
|
|
modulePath.erase(0, 1);
|
|
}
|
|
|
|
if (modulePath.size())
|
|
addFilesToProject(moduleDir, project, includeList, excludeList, setup.filePrefix + '/' + modulePath);
|
|
else
|
|
addFilesToProject(moduleDir, project, includeList, excludeList, setup.filePrefix);
|
|
|
|
// Output references for the main project
|
|
if (name == setup.projectName)
|
|
writeReferences(setup, project);
|
|
|
|
project << "\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n"
|
|
"\t<ImportGroup Label=\"ExtensionTargets\">\n"
|
|
"\t</ImportGroup>\n"
|
|
"</Project>\n";
|
|
|
|
// Output filter file if necessary
|
|
createFiltersFile(setup, name);
|
|
}
|
|
|
|
void MSBuildProvider::createFiltersFile(const BuildSetup &setup, const std::string &name) {
|
|
// No filters => no need to create a filter file
|
|
if (_filters.empty())
|
|
return;
|
|
|
|
// Sort all list alphabetically
|
|
_filters.sort();
|
|
_compileFiles.sort();
|
|
_includeFiles.sort();
|
|
_otherFiles.sort();
|
|
_resourceFiles.sort();
|
|
_asmFiles.sort();
|
|
|
|
const std::string filtersFile = setup.outputDir + '/' + name + getProjectExtension() + ".filters";
|
|
std::ofstream filters(filtersFile.c_str());
|
|
if (!filters)
|
|
error("Could not open \"" + filtersFile + "\" for writing");
|
|
|
|
filters << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
|
|
"<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n";
|
|
|
|
// Output the list of filters
|
|
filters << "\t<ItemGroup>\n";
|
|
for (std::list<std::string>::iterator filter = _filters.begin(); filter != _filters.end(); ++filter) {
|
|
filters << "\t\t<Filter Include=\"" << *filter << "\">\n"
|
|
"\t\t\t<UniqueIdentifier>" << createUUID() << "</UniqueIdentifier>\n"
|
|
"\t\t</Filter>\n";
|
|
}
|
|
filters << "\t</ItemGroup>\n";
|
|
|
|
// Output files
|
|
outputFilter(filters, _compileFiles, "ClCompile");
|
|
outputFilter(filters, _includeFiles, "ClInclude");
|
|
outputFilter(filters, _otherFiles, "None");
|
|
outputFilter(filters, _resourceFiles, "ResourceCompile");
|
|
outputFilter(filters, _asmFiles, "CustomBuild");
|
|
|
|
filters << "</Project>";
|
|
}
|
|
|
|
void MSBuildProvider::outputFilter(std::ostream &filters, const FileEntries &files, const std::string &action) {
|
|
if (!files.empty()) {
|
|
filters << "\t<ItemGroup>\n";
|
|
for (FileEntries::const_iterator entry = files.begin(), end = files.end(); entry != end; ++entry) {
|
|
if ((*entry).filter != "") {
|
|
filters << "\t\t<" << action << " Include=\"" << (*entry).path << "\">\n"
|
|
"\t\t\t<Filter>" << (*entry).filter << "</Filter>\n"
|
|
"\t\t</" << action << ">\n";
|
|
} else {
|
|
filters << "\t\t<" << action << " Include=\"" << (*entry).path << "\" />\n";
|
|
}
|
|
}
|
|
filters << "\t</ItemGroup>\n";
|
|
}
|
|
}
|
|
|
|
void MSBuildProvider::writeReferences(const BuildSetup &setup, std::ofstream &output) {
|
|
output << "\t<ItemGroup>\n";
|
|
|
|
for (UUIDMap::const_iterator i = _uuidMap.begin(); i != _uuidMap.end(); ++i) {
|
|
if (i->first == setup.projectName)
|
|
continue;
|
|
|
|
output << "\t<ProjectReference Include=\"" << i->first << ".vcxproj\">\n"
|
|
"\t\t<Project>{" << i->second << "}</Project>\n"
|
|
"\t</ProjectReference>\n";
|
|
}
|
|
|
|
output << "\t</ItemGroup>\n";
|
|
}
|
|
|
|
void MSBuildProvider::outputProjectSettings(std::ofstream &project, const std::string &name, const BuildSetup &setup, bool isRelease, bool isWin32, bool enableAnalysis) {
|
|
const std::string configuration = (enableAnalysis ? "Analysis" : (isRelease ? "Release" : "Debug"));
|
|
|
|
// Check for project-specific warnings:
|
|
std::map<std::string, StringList>::iterator warningsIterator = _projectWarnings.find(name);
|
|
|
|
// Nothing to add here, move along!
|
|
if (!setup.devTools && name != setup.projectName && name != "sword25" && name != "scummvm" && name != "grim" && warningsIterator == _projectWarnings.end())
|
|
return;
|
|
|
|
std::string warnings = "";
|
|
if (warningsIterator != _projectWarnings.end())
|
|
for (StringList::const_iterator i = warningsIterator->second.begin(); i != warningsIterator->second.end(); ++i)
|
|
warnings += *i + ';';
|
|
|
|
project << "\t<ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='" << configuration << "|" << (isWin32 ? "Win32" : "x64") << "'\">\n"
|
|
"\t\t<ClCompile>\n";
|
|
|
|
// Compile configuration
|
|
if (setup.devTools || name == setup.projectName || name == "sword25" || name == "grim") {
|
|
project << "\t\t\t<DisableLanguageExtensions>false</DisableLanguageExtensions>\n";
|
|
} else {
|
|
if (name == "scummvm" && !isRelease)
|
|
project << "\t\t\t<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n";
|
|
|
|
if (warningsIterator != _projectWarnings.end())
|
|
project << "\t\t\t<DisableSpecificWarnings>" << warnings << ";%(DisableSpecificWarnings)</DisableSpecificWarnings>\n";
|
|
}
|
|
|
|
project << "\t\t</ClCompile>\n";
|
|
|
|
// Link configuration for main project
|
|
if (name == setup.projectName || setup.devTools) {
|
|
std::string libraries;
|
|
|
|
for (StringList::const_iterator i = setup.libraries.begin(); i != setup.libraries.end(); ++i)
|
|
libraries += *i + ".lib;";
|
|
|
|
project << "\t\t<Link>\n"
|
|
"\t\t\t<OutputFile>$(OutDir)" << (setup.devTools ? name : setup.projectName) << ".exe</OutputFile>\n"
|
|
"\t\t\t<AdditionalDependencies>" << libraries << "%(AdditionalDependencies)</AdditionalDependencies>\n"
|
|
"\t\t</Link>\n";
|
|
|
|
if (!setup.devTools && setup.runBuildEvents) {
|
|
project << "\t\t<PreBuildEvent>\n"
|
|
"\t\t\t<Message>Generate revision</Message>\n"
|
|
"\t\t\t<Command>" << getPreBuildEvent() << "</Command>\n"
|
|
"\t\t</PreBuildEvent>\n";
|
|
|
|
// Copy data files to the build folder
|
|
project << "\t\t<PostBuildEvent>\n"
|
|
"\t\t\t<Message>Copy data files to the build folder</Message>\n"
|
|
"\t\t\t<Command>" << getPostBuildEvent(isWin32, setup.createInstaller) << "</Command>\n"
|
|
"\t\t</PostBuildEvent>\n";
|
|
}
|
|
}
|
|
|
|
project << "\t</ItemDefinitionGroup>\n";
|
|
}
|
|
|
|
void MSBuildProvider::outputGlobalPropFile(const BuildSetup &setup, std::ofstream &properties, int bits, const StringList &defines, const std::string &prefix, bool runBuildEvents) {
|
|
|
|
std::string warnings;
|
|
for (StringList::const_iterator i = _globalWarnings.begin(); i != _globalWarnings.end(); ++i)
|
|
warnings += *i + ';';
|
|
|
|
std::string definesList;
|
|
for (StringList::const_iterator i = defines.begin(); i != defines.end(); ++i)
|
|
definesList += *i + ';';
|
|
|
|
// Add define to include revision header
|
|
if (runBuildEvents)
|
|
definesList += REVISION_DEFINE ";";
|
|
|
|
properties << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
|
|
"<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n"
|
|
"\t<PropertyGroup>\n"
|
|
"\t\t<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>\n"
|
|
"\t\t<_PropertySheetDisplayName>" << setup.projectDescription << "_Global</_PropertySheetDisplayName>\n"
|
|
"\t\t<ExecutablePath>$(" << LIBS_DEFINE << ")\\bin;$(ExecutablePath)</ExecutablePath>\n"
|
|
"\t\t<LibraryPath>$(" << LIBS_DEFINE << ")\\lib\\" << (bits == 32 ? "x86" : "x64") << ";$(LibraryPath)</LibraryPath>\n"
|
|
"\t\t<IncludePath>$(" << LIBS_DEFINE << ")\\include;$(IncludePath)</IncludePath>\n"
|
|
"\t\t<OutDir>$(Configuration)" << bits << "\\</OutDir>\n"
|
|
"\t\t<IntDir>$(Configuration)" << bits << "/$(ProjectName)\\</IntDir>\n"
|
|
"\t</PropertyGroup>\n"
|
|
"\t<ItemDefinitionGroup>\n"
|
|
"\t\t<ClCompile>\n"
|
|
"\t\t\t<DisableLanguageExtensions>true</DisableLanguageExtensions>\n"
|
|
"\t\t\t<DisableSpecificWarnings>" << warnings << ";%(DisableSpecificWarnings)</DisableSpecificWarnings>\n"
|
|
"\t\t\t<AdditionalIncludeDirectories>$(" << LIBS_DEFINE << ")\\include;" << prefix << ";" << prefix << "\\engines;$(TargetDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n"
|
|
"\t\t\t<PreprocessorDefinitions>" << definesList << "%(PreprocessorDefinitions)</PreprocessorDefinitions>\n"
|
|
"\t\t\t<ExceptionHandling>" << (setup.devTools ? "Sync" : "") << "</ExceptionHandling>\n";
|
|
|
|
#if NEEDS_RTTI
|
|
properties << "\t\t\t<RuntimeTypeInfo>true</RuntimeTypeInfo>\n";
|
|
#else
|
|
properties << "\t\t\t<RuntimeTypeInfo>false</RuntimeTypeInfo>\n";
|
|
#endif
|
|
|
|
properties << "\t\t\t<WarningLevel>Level4</WarningLevel>\n"
|
|
"\t\t\t<TreatWarningAsError>false</TreatWarningAsError>\n"
|
|
"\t\t\t<CompileAs>Default</CompileAs>\n"
|
|
"\t\t</ClCompile>\n"
|
|
"\t\t<Link>\n"
|
|
"\t\t\t<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\n"
|
|
"\t\t\t<SubSystem>Console</SubSystem>\n";
|
|
|
|
if (!setup.devTools)
|
|
properties << "\t\t\t<EntryPointSymbol>WinMainCRTStartup</EntryPointSymbol>\n";
|
|
|
|
properties << "\t\t</Link>\n"
|
|
"\t\t<ResourceCompile>\n"
|
|
"\t\t\t<AdditionalIncludeDirectories>" << prefix << ";%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n"
|
|
"\t\t</ResourceCompile>\n"
|
|
"\t</ItemDefinitionGroup>\n"
|
|
"</Project>\n";
|
|
|
|
properties.flush();
|
|
}
|
|
|
|
void MSBuildProvider::createBuildProp(const BuildSetup &setup, bool isRelease, bool isWin32, bool enableAnalysis) {
|
|
const std::string outputType = (enableAnalysis ? "Analysis" : (isRelease ? "Release" : "Debug"));
|
|
const std::string outputBitness = (isWin32 ? "32" : "64");
|
|
|
|
std::ofstream properties((setup.outputDir + '/' + setup.projectDescription + "_" + outputType + (isWin32 ? "" : "64") + getPropertiesExtension()).c_str());
|
|
if (!properties)
|
|
error("Could not open \"" + setup.outputDir + '/' + setup.projectDescription + "_" + outputType + (isWin32 ? "" : "64") + getPropertiesExtension() + "\" for writing");
|
|
|
|
properties << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
|
|
"<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n"
|
|
"\t<ImportGroup Label=\"PropertySheets\">\n"
|
|
"\t\t<Import Project=\"" << setup.projectDescription << "_Global" << (isWin32 ? "" : "64") << ".props\" />\n"
|
|
"\t</ImportGroup>\n"
|
|
"\t<PropertyGroup>\n"
|
|
"\t\t<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>\n"
|
|
"\t\t<_PropertySheetDisplayName>" << setup.projectDescription << "_" << outputType << outputBitness << "</_PropertySheetDisplayName>\n"
|
|
"\t\t<LinkIncremental>" << (isRelease ? "false" : "true") << "</LinkIncremental>\n"
|
|
"\t</PropertyGroup>\n"
|
|
"\t<ItemDefinitionGroup>\n"
|
|
"\t\t<ClCompile>\n";
|
|
|
|
if (isRelease) {
|
|
properties << "\t\t\t<IntrinsicFunctions>true</IntrinsicFunctions>\n"
|
|
"\t\t\t<WholeProgramOptimization>true</WholeProgramOptimization>\n"
|
|
"\t\t\t<PreprocessorDefinitions>WIN32;RELEASE_BUILD;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n"
|
|
"\t\t\t<StringPooling>true</StringPooling>\n"
|
|
"\t\t\t<BufferSecurityCheck>false</BufferSecurityCheck>\n"
|
|
"\t\t\t<DebugInformationFormat></DebugInformationFormat>\n"
|
|
"\t\t\t<RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n"
|
|
"\t\t\t<EnablePREfast>" << (enableAnalysis ? "true" : "false") << "</EnablePREfast>\n"
|
|
"\t\t</ClCompile>\n"
|
|
"\t\t<Link>\n"
|
|
"\t\t\t<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\n"
|
|
"\t\t\t<SetChecksum>true</SetChecksum>\n";
|
|
} else {
|
|
properties << "\t\t\t<Optimization>Disabled</Optimization>\n"
|
|
"\t\t\t<PreprocessorDefinitions>WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n"
|
|
"\t\t\t<MinimalRebuild>true</MinimalRebuild>\n"
|
|
"\t\t\t<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n"
|
|
"\t\t\t<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n"
|
|
"\t\t\t<FunctionLevelLinking>true</FunctionLevelLinking>\n"
|
|
"\t\t\t<TreatWarningAsError>false</TreatWarningAsError>\n"
|
|
"\t\t\t<DebugInformationFormat>" << (isWin32 ? "EditAndContinue" : "ProgramDatabase") << "</DebugInformationFormat>\n" // For x64 format Edit and continue is not supported, thus we default to Program Database
|
|
"\t\t\t<EnablePREfast>" << (enableAnalysis ? "true" : "false") << "</EnablePREfast>\n"
|
|
"\t\t</ClCompile>\n"
|
|
"\t\t<Link>\n"
|
|
"\t\t\t<GenerateDebugInformation>true</GenerateDebugInformation>\n"
|
|
"\t\t\t<IgnoreSpecificDefaultLibraries>libcmt.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\n";
|
|
}
|
|
|
|
properties << "\t\t</Link>\n"
|
|
"\t</ItemDefinitionGroup>\n"
|
|
"</Project>\n";
|
|
|
|
properties.flush();
|
|
properties.close();
|
|
}
|
|
|
|
bool hasEnding(std::string const &fullString, std::string const &ending) {
|
|
if (fullString.length() > ending.length()) {
|
|
return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
|
|
inline void outputNasmCommand(std::ostream &projectFile, const std::string &config, const std::string &prefix) {
|
|
projectFile << "\t\t\t<Command Condition=\"'$(Configuration)|$(Platform)'=='" << config << "|Win32'\">nasm.exe -f win32 -g -o \"$(IntDir)" << prefix << "%(Filename).obj\" \"%(FullPath)\"</Command>\n"
|
|
"\t\t\t<Outputs Condition=\"'$(Configuration)|$(Platform)'=='" << config << "|Win32'\">$(IntDir)" << prefix << "%(Filename).obj;%(Outputs)</Outputs>\n";
|
|
}
|
|
|
|
} // End of anonymous namespace
|
|
|
|
void MSBuildProvider::writeFileListToProject(const FileNode &dir, std::ofstream &projectFile, const int, const StringList &duplicate,
|
|
const std::string &objPrefix, const std::string &filePrefix) {
|
|
// Reset lists
|
|
_filters.clear();
|
|
_compileFiles.clear();
|
|
_includeFiles.clear();
|
|
_otherFiles.clear();
|
|
_resourceFiles.clear();
|
|
_asmFiles.clear();
|
|
|
|
// Compute the list of files
|
|
_filters.push_back(""); // init filters
|
|
computeFileList(dir, duplicate, objPrefix, filePrefix);
|
|
_filters.pop_back(); // remove last empty filter
|
|
|
|
// Output compile files
|
|
if (!_compileFiles.empty()) {
|
|
projectFile << "\t<ItemGroup>\n";
|
|
for (std::list<FileEntry>::const_iterator entry = _compileFiles.begin(); entry != _compileFiles.end(); ++entry) {
|
|
const bool isDuplicate = (std::find(duplicate.begin(), duplicate.end(), (*entry).name + ".o") != duplicate.end());
|
|
|
|
// Deal with duplicated file names
|
|
if (isDuplicate) {
|
|
projectFile << "\t\t<ClCompile Include=\"" << (*entry).path << "\">\n"
|
|
"\t\t\t<ObjectFileName>$(IntDir)" << (*entry).prefix << "%(Filename).obj</ObjectFileName>\n";
|
|
|
|
projectFile << "\t\t</ClCompile>\n";
|
|
} else {
|
|
projectFile << "\t\t<ClCompile Include=\"" << (*entry).path << "\" />\n";
|
|
}
|
|
}
|
|
projectFile << "\t</ItemGroup>\n";
|
|
}
|
|
|
|
// Output include, other and resource files
|
|
outputFiles(projectFile, _includeFiles, "ClInclude");
|
|
outputFiles(projectFile, _otherFiles, "None");
|
|
outputFiles(projectFile, _resourceFiles, "ResourceCompile");
|
|
|
|
// Output asm files
|
|
if (!_asmFiles.empty()) {
|
|
projectFile << "\t<ItemGroup>\n";
|
|
for (std::list<FileEntry>::const_iterator entry = _asmFiles.begin(); entry != _asmFiles.end(); ++entry) {
|
|
|
|
const bool isDuplicate = (std::find(duplicate.begin(), duplicate.end(), (*entry).name + ".o") != duplicate.end());
|
|
|
|
projectFile << "\t\t<CustomBuild Include=\"" << (*entry).path << "\">\n"
|
|
"\t\t\t<FileType>Document</FileType>\n";
|
|
|
|
outputNasmCommand(projectFile, "Debug", (isDuplicate ? (*entry).prefix : ""));
|
|
outputNasmCommand(projectFile, "Analysis", (isDuplicate ? (*entry).prefix : ""));
|
|
outputNasmCommand(projectFile, "Release", (isDuplicate ? (*entry).prefix : ""));
|
|
|
|
projectFile << "\t\t</CustomBuild>\n";
|
|
}
|
|
projectFile << "\t</ItemGroup>\n";
|
|
}
|
|
}
|
|
|
|
void MSBuildProvider::outputFiles(std::ostream &projectFile, const FileEntries &files, const std::string &action) {
|
|
if (!files.empty()) {
|
|
projectFile << "\t<ItemGroup>\n";
|
|
for (FileEntries::const_iterator entry = files.begin(), end = files.end(); entry != end; ++entry) {
|
|
projectFile << "\t\t<" << action << " Include=\"" << (*entry).path << "\" />\n";
|
|
}
|
|
projectFile << "\t</ItemGroup>\n";
|
|
}
|
|
}
|
|
|
|
void MSBuildProvider::computeFileList(const FileNode &dir, const StringList &duplicate, const std::string &objPrefix, const std::string &filePrefix) {
|
|
for (FileNode::NodeList::const_iterator i = dir.children.begin(); i != dir.children.end(); ++i) {
|
|
const FileNode *node = *i;
|
|
|
|
if (!node->children.empty()) {
|
|
// Update filter
|
|
std::string _currentFilter = _filters.back();
|
|
_filters.back().append((_filters.back() == "" ? "" : "\\") + node->name);
|
|
|
|
computeFileList(*node, duplicate, objPrefix + node->name + '_', filePrefix + node->name + '/');
|
|
|
|
// Reset filter
|
|
_filters.push_back(_currentFilter);
|
|
} else {
|
|
// Filter files by extension
|
|
std::string name, ext;
|
|
splitFilename(node->name, name, ext);
|
|
|
|
FileEntry entry;
|
|
entry.name = name;
|
|
entry.path = convertPathToWin(filePrefix + node->name);
|
|
entry.filter = _filters.back();
|
|
entry.prefix = objPrefix;
|
|
|
|
if (ext == "cpp" || ext == "c")
|
|
_compileFiles.push_back(entry);
|
|
else if (ext == "h")
|
|
_includeFiles.push_back(entry);
|
|
else if (ext == "rc")
|
|
_resourceFiles.push_back(entry);
|
|
else if (ext == "asm")
|
|
_asmFiles.push_back(entry);
|
|
else
|
|
_otherFiles.push_back(entry);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // End of CreateProjectTool namespace
|