diff options
Diffstat (limited to 'devtools/create_project')
22 files changed, 4606 insertions, 0 deletions
diff --git a/devtools/create_project/codeblocks.cpp b/devtools/create_project/codeblocks.cpp new file mode 100644 index 0000000000..d803fb0a37 --- /dev/null +++ b/devtools/create_project/codeblocks.cpp @@ -0,0 +1,263 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "codeblocks.h" + +#include <fstream> + +namespace CreateProjectTool { + +CodeBlocksProvider::CodeBlocksProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, const int version) + : ProjectProvider(global_warnings, project_warnings, version) { +} + +void CodeBlocksProvider::createWorkspace(const BuildSetup &setup) { + std::ofstream workspace((setup.outputDir + '/' + "scummvm.workspace").c_str()); + if (!workspace) + error("Could not open \"" + setup.outputDir + '/' + "scummvm.workspace\" for writing"); + + workspace << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n" + "<CodeBlocks_workspace_file>\n"; + + workspace << "\t<Workspace title=\"ScummVM\">\n"; + + writeReferences(workspace); + + // Note we assume that the UUID map only includes UUIDs for enabled engines! + for (UUIDMap::const_iterator i = _uuidMap.begin(); i != _uuidMap.end(); ++i) { + if (i->first == "scummvm") + continue; + + workspace << "\t\t<Project filename=\"" << i->first << ".cbp\" />\n"; + } + + workspace << "\t</Workspace>\n" + "</CodeBlocks_workspace_file>"; +} + +// HACK We need to pre-process library names +// since the MSVC and mingw precompiled +// librarie have different names :( +std::string processLibraryName(std::string name) { + // Remove "_static" in lib name + size_t pos = name.find("_static"); + if (pos != std::string::npos) + return name.replace(pos, 7, ""); + + // Replace "zlib" by "libz" + if (name == "zlib") + return "libz"; + + return name; +} + +void CodeBlocksProvider::createProjectFile(const std::string &name, const std::string &, 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\" standalone=\"yes\" ?>\n" + "<CodeBlocks_project_file>\n" + "\t<FileVersion major=\"1\" minor=\"6\" />\n" + "\t<Project>\n" + "\t\t<Option title=\"" << name << "\" />\n" + "\t\t<Option pch_mode=\"2\" />\n" + "\t\t<Option compiler=\"gcc\" />\n" + "\t\t<Build>\n"; + + if (name == "scummvm") { + std::string libraries; + + for (StringList::const_iterator i = setup.libraries.begin(); i != setup.libraries.end(); ++i) + libraries += processLibraryName(*i) + ".a;"; + + project << "\t\t\t<Target title=\"default\">\n" + "\t\t\t\t<Option output=\"scummvm\\scummvm\" prefix_auto=\"1\" extension_auto=\"1\" />\n" + "\t\t\t\t<Option object_output=\"scummvm\" />\n" + "\t\t\t\t<Option external_deps=\"" << libraries /* + list of engines scummvm\engines\name\name.a */ << "\" />\n" + "\t\t\t\t<Option type=\"1\" />\n" + "\t\t\t\t<Option compiler=\"gcc\" />\n" + "\t\t\t\t<Option parameters=\"-d 8 --debugflags=parser\" />\n" + "\t\t\t\t<Option projectIncludeDirsRelation=\"2\" />\n"; + + ////////////////////////////////////////////////////////////////////////// + // Compiler + project << "\t\t\t\t<Compiler>\n"; + + writeWarnings(name, project); + writeDefines(setup.defines, project); + + project << "\t\t\t\t\t<Add directory=\"$(SCUMMVM_LIBS)include\" />\n" + "\t\t\t\t\t<Add directory=\"$(SCUMMVM_LIBS)include\\SDL\" />\n" + "\t\t\t\t\t<Add directory=\"..\\..\\engines\" />\n" + "\t\t\t\t\t<Add directory=\"..\\..\\common\" />\n" + "\t\t\t\t\t<Add directory=\"..\\..\" />\n" + "\t\t\t\t</Compiler>\n"; + + ////////////////////////////////////////////////////////////////////////// + // Linker + project << "\t\t\t\t<Linker>\n"; + + for (StringList::const_iterator i = setup.libraries.begin(); i != setup.libraries.end(); ++i) + project << "\t\t\t\t\t<Add library=\"" << processLibraryName(*i) << "\" />\n"; + + for (UUIDMap::const_iterator i = _uuidMap.begin(); i != _uuidMap.end(); ++i) { + if (i->first == "scummvm") + continue; + + project << "\t\t\t\t\t<Add library=\"scummvm\\engines\\" << i->first << "\\lib" << i->first << ".a\" />\n"; + } + + project << "\t\t\t\t\t<Add directory=\"$(SCUMMVM_LIBS)lib\\mingw\" />\n" + "\t\t\t\t\t<Add directory=\"$(SCUMMVM_LIBS)lib\" />\n" + "\t\t\t\t</Linker>\n"; + + ////////////////////////////////////////////////////////////////////////// + // Resource compiler + project << "\t\t\t\t<ResourceCompiler>\n" + "\t\t\t\t\t<Add directory=\"..\\..\\dists\" />\n" + "\t\t\t\t\t<Add directory=\"..\\..\\..\\scummvm\" />\n" + "\t\t\t\t</ResourceCompiler>\n" + "\t\t\t</Target>\n" + "\t\t</Build>\n"; + + + + } else { + project << "\t\t\t<Target title=\"default\">\n" + "\t\t\t\t<Option output=\"scummvm\\engines\\" << name << "\\lib" << name << "\" prefix_auto=\"1\" extension_auto=\"1\" />\n" + "\t\t\t\t<Option working_dir=\"\" />\n" + "\t\t\t\t<Option object_output=\"scummvm\" />\n" + "\t\t\t\t<Option type=\"2\" />\n" + "\t\t\t\t<Option compiler=\"gcc\" />\n" + "\t\t\t\t<Option createDefFile=\"1\" />\n" + "\t\t\t\t<Compiler>\n"; + + writeWarnings(name, project); + writeDefines(setup.defines, project); + + project << "\t\t\t\t\t<Add option=\"-g\" />\n" + "\t\t\t\t\t<Add directory=\"..\\..\\engines\" />\n" + "\t\t\t\t\t<Add directory=\"..\\..\\..\\scummvm\" />\n"; + + // Sword2.5 engine needs theora and vorbis includes + if (name == "sword25") + project << "\t\t\t\t\t<Add directory=\"$(SCUMMVM_LIBS)include\" />\n"; + + project << "\t\t\t\t</Compiler>\n" + "\t\t\t</Target>\n" + "\t\t</Build>\n"; + } + + 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); + + + project << "\t\t<Extensions>\n" + "\t\t\t<code_completion />\n" + "\t\t\t<debugger />\n" + "\t\t</Extensions>\n" + "\t</Project>\n" + "</CodeBlocks_project_file>"; + +} + +void CodeBlocksProvider::writeWarnings(const std::string &name, std::ofstream &output) const { + + // Global warnings + for (StringList::const_iterator i = _globalWarnings.begin(); i != _globalWarnings.end(); ++i) + output << "\t\t\t\t\t<Add option=\"" << *i << "\" />\n"; + + // Check for project-specific warnings: + std::map<std::string, StringList>::iterator warningsIterator = _projectWarnings.find(name); + if (warningsIterator != _projectWarnings.end()) + for (StringList::const_iterator i = warningsIterator->second.begin(); i != warningsIterator->second.end(); ++i) + output << "\t\t\t\t\t<Add option=\"" << *i << "\" />\n"; + +} + +void CodeBlocksProvider::writeDefines(const StringList &defines, std::ofstream &output) const { + for (StringList::const_iterator i = defines.begin(); i != defines.end(); ++i) + output << "\t\t\t\t\t<Add option=\"-D" << *i << "\" />\n"; +} + +void CodeBlocksProvider::writeFileListToProject(const FileNode &dir, std::ofstream &projectFile, const int indentation, + 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()) { + writeFileListToProject(*node, projectFile, indentation + 1, duplicate, objPrefix + node->name + '_', filePrefix + node->name + '/'); + } else { + std::string name, ext; + splitFilename(node->name, name, ext); + + if (ext == "rc") { + projectFile << "\t\t<Unit filename=\"" << convertPathToWin(filePrefix + node->name) << "\">\n" + "\t\t\t<Option compilerVar=\"WINDRES\" />\n" + "\t\t</Unit>\n"; + } else if (ext == "asm") { + projectFile << "\t\t<Unit filename=\"" << convertPathToWin(filePrefix + node->name) << "\">\n" + "\t\t\t<Option compiler=\"gcc\" use=\"1\" buildCommand=\"$(SCUMMVM_LIBS)bin/nasm.exe -f win32 -g $file -o $object\" />" + "\t\t</Unit>\n"; + } else { + projectFile << "\t\t<Unit filename=\"" << convertPathToWin(filePrefix + node->name) << "\" />\n"; + } + } + } +} + +void CodeBlocksProvider::writeReferences(std::ofstream &output) { + output << "\t\t<Project filename=\"scummvm.cbp\" active=\"1\">\n"; + + for (UUIDMap::const_iterator i = _uuidMap.begin(); i != _uuidMap.end(); ++i) { + if (i->first == "scummvm") + continue; + + output << "\t\t\t<Depends filename=\"" << i->first << ".cbp\" />\n"; + } + + output << "\t\t</Project>\n"; +} + +const char *CodeBlocksProvider::getProjectExtension() { + return ".cbp"; +} + + +} // End of CreateProjectTool namespace diff --git a/devtools/create_project/codeblocks.h b/devtools/create_project/codeblocks.h new file mode 100644 index 0000000000..ba75daeafd --- /dev/null +++ b/devtools/create_project/codeblocks.h @@ -0,0 +1,60 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef TOOLS_CREATE_PROJECT_CODEBLOCKS_H +#define TOOLS_CREATE_PROJECT_CODEBLOCKS_H + +#include "create_project.h" + +namespace CreateProjectTool { + +class CodeBlocksProvider : public ProjectProvider { +public: + CodeBlocksProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, const int version = 0); + +protected: + + void createWorkspace(const BuildSetup &setup); + + void createOtherBuildFiles(const BuildSetup &) {} + + void createProjectFile(const std::string &name, const std::string &uuid, const BuildSetup &setup, const std::string &moduleDir, + const StringList &includeList, const StringList &excludeList); + + void writeFileListToProject(const FileNode &dir, std::ofstream &projectFile, const int indentation, + const StringList &duplicate, const std::string &objPrefix, const std::string &filePrefix); + + void writeReferences(std::ofstream &output); + + const char *getProjectExtension(); + +private: + void writeWarnings(const std::string &name, std::ofstream &output) const; + void writeDefines(const StringList &defines, std::ofstream &output) const; +}; + +} // End of CreateProjectTool namespace + +#endif // TOOLS_CREATE_PROJECT_CODEBLOCKS_H diff --git a/devtools/create_project/codeblocks/create_project.cbp b/devtools/create_project/codeblocks/create_project.cbp new file mode 100644 index 0000000000..9078ddcd51 --- /dev/null +++ b/devtools/create_project/codeblocks/create_project.cbp @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<CodeBlocks_project_file> + <FileVersion major="1" minor="6" /> + <Project> + <Option title="create_project" /> + <Option pch_mode="2" /> + <Option compiler="gcc" /> + <Build> + <Target title="Debug"> + <Option output="bin\Debug\create_project" prefix_auto="1" extension_auto="1" /> + <Option object_output="obj\Debug\" /> + <Option type="1" /> + <Option compiler="gcc" /> + <Compiler> + <Add option="-g" /> + </Compiler> + <Linker> + <Add library="rpcrt4" /> + </Linker> + </Target> + <Target title="Release"> + <Option output="bin\Release\create_project" prefix_auto="1" extension_auto="1" /> + <Option object_output="obj\Release\" /> + <Option type="1" /> + <Option compiler="gcc" /> + <Compiler> + <Add option="-O2" /> + </Compiler> + <Linker> + <Add option="-s" /> + <Add library="rpcrt4" /> + </Linker> + </Target> + </Build> + <Compiler> + <Add option="-Wall" /> + <Add option="-fexceptions" /> + </Compiler> + <Unit filename="..\codeblocks.cpp" /> + <Unit filename="..\codeblocks.h" /> + <Unit filename="..\create_project.cpp" /> + <Unit filename="..\create_project.h" /> + <Unit filename="..\msbuild.cpp" /> + <Unit filename="..\msbuild.h" /> + <Unit filename="..\msvc.cpp" /> + <Unit filename="..\msvc.h" /> + <Unit filename="..\visualstudio.cpp" /> + <Unit filename="..\visualstudio.h" /> + <Extensions> + <code_completion /> + <envvars /> + <debugger /> + <lib_finder disable_auto="1" /> + </Extensions> + </Project> +</CodeBlocks_project_file> diff --git a/devtools/create_project/create_project.cpp b/devtools/create_project/create_project.cpp new file mode 100644 index 0000000000..b896e85131 --- /dev/null +++ b/devtools/create_project/create_project.cpp @@ -0,0 +1,1230 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +// HACK to allow building with the SDL backend on MinGW +// see bug #1800764 "TOOLS: MinGW tools building broken" +#ifdef main +#undef main +#endif // main + +#include "create_project.h" +#include "codeblocks.h" + +#include "msvc.h" +#include "visualstudio.h" +#include "msbuild.h" + +#include <fstream> +#include <iostream> + +#include <stack> +#include <algorithm> +#include <iomanip> + +#include <cstring> +#include <cstdlib> +#include <ctime> + +#if (defined(_WIN32) || defined(WIN32)) && !defined(__GNUC__) +#define USE_WIN32_API +#endif + +#ifdef USE_WIN32_API +#include <windows.h> +#else +#include <sstream> +#include <sys/param.h> +#include <sys/stat.h> +#include <dirent.h> +#endif + +namespace { +/** + * Converts the given path to only use slashes as + * delimiters. + * This means that for example the path: + * foo/bar\test.txt + * will be converted to: + * foo/bar/test.txt + * + * @param path Path string. + * @return Converted path. + */ +std::string unifyPath(const std::string &path); + +/** + * Returns the last path component. + * + * @param path Path string. + * @return Last path component. + */ +std::string getLastPathComponent(const std::string &path); + +/** + * Display the help text for the program. + * + * @param exe Name of the executable. + */ +void displayHelp(const char *exe); + +/** + * Structure for describing an FSNode. This is a very minimalistic + * description, which includes everything we need. + * It only contains the name of the node and whether it is a directory + * or not. + */ +struct FSNode { + FSNode() : name(), isDirectory(false) {} + FSNode(const std::string &n, bool iD) : name(n), isDirectory(iD) {} + + std::string name; ///< Name of the file system node + bool isDirectory; ///< Whether it is a directory or not +}; + +typedef std::list<FSNode> FileList; +} // End of anonymous namespace + +enum ProjectType { + kProjectNone, + kProjectCodeBlocks, + kProjectMSVC +}; + +int main(int argc, char *argv[]) { +#ifndef USE_WIN32_API + // Initialize random number generator for UUID creation + std::srand(std::time(0)); +#endif + + if (argc < 2) { + displayHelp(argv[0]); + return -1; + } + + const std::string srcDir = argv[1]; + + BuildSetup setup; + setup.srcDir = unifyPath(srcDir); + + if (setup.srcDir.at(setup.srcDir.size() - 1) == '/') + setup.srcDir.erase(setup.srcDir.size() - 1); + + setup.filePrefix = setup.srcDir; + setup.outputDir = '.'; + + setup.engines = parseConfigure(setup.srcDir); + + if (setup.engines.empty()) { + std::cout << "WARNING: No engines found in configure file or configure file missing in \"" << setup.srcDir << "\"\n"; + return 0; + } + + setup.features = getAllFeatures(); + + ProjectType projectType = kProjectNone; + int msvcVersion = 9; + + // Parse command line arguments + using std::cout; + for (int i = 2; i < argc; ++i) { + if (!std::strcmp(argv[i], "--list-engines")) { + cout << " The following enables are available in the ScummVM source distribution\n" + " located at \"" << srcDir << "\":\n"; + + cout << " state | name | description\n\n"; + cout.setf(std::ios_base::left, std::ios_base::adjustfield); + for (EngineDescList::const_iterator j = setup.engines.begin(); j != setup.engines.end(); ++j) + cout << ' ' << (j->enable ? " enabled" : "disabled") << " | " << std::setw((std::streamsize)15) << j->name << std::setw((std::streamsize)0) << " | " << j->desc << "\n"; + cout.setf(std::ios_base::right, std::ios_base::adjustfield); + + return 0; + + } else if (!std::strcmp(argv[i], "--codeblocks")) { + if (projectType != kProjectNone) { + std::cerr << "ERROR: You cannot pass more than one project type!\n"; + return -1; + } + + projectType = kProjectCodeBlocks; + + } else if (!std::strcmp(argv[i], "--msvc")) { + if (projectType != kProjectNone) { + std::cerr << "ERROR: You cannot pass more than one project type!\n"; + return -1; + } + + projectType = kProjectMSVC; + + } else if (!std::strcmp(argv[i], "--msvc-version")) { + if (i + 1 >= argc) { + std::cerr << "ERROR: Missing \"version\" parameter for \"--msvc-version\"!\n"; + return -1; + } + + msvcVersion = atoi(argv[++i]); + + if (msvcVersion != 8 && msvcVersion != 9 && msvcVersion != 10) { + std::cerr << "ERROR: Unsupported version: \"" << msvcVersion << "\" passed to \"--msvc-version\"!\n"; + return -1; + } + } else if (!strncmp(argv[i], "--enable-", 9)) { + const char *name = &argv[i][9]; + if (!*name) { + std::cerr << "ERROR: Invalid command \"" << argv[i] << "\"\n"; + return -1; + } + + if (!std::strcmp(name, "all-engines")) { + for (EngineDescList::iterator j = setup.engines.begin(); j != setup.engines.end(); ++j) + j->enable = true; + } else if (!setEngineBuildState(name, setup.engines, true)) { + // If none found, we'll try the features list + if (!setFeatureBuildState(name, setup.features, true)) { + std::cerr << "ERROR: \"" << name << "\" is neither an engine nor a feature!\n"; + return -1; + } + } + } else if (!strncmp(argv[i], "--disable-", 10)) { + const char *name = &argv[i][10]; + if (!*name) { + std::cerr << "ERROR: Invalid command \"" << argv[i] << "\"\n"; + return -1; + } + + if (!std::strcmp(name, "all-engines")) { + for (EngineDescList::iterator j = setup.engines.begin(); j != setup.engines.end(); ++j) + j->enable = false; + } else if (!setEngineBuildState(name, setup.engines, false)) { + // If none found, we'll try the features list + if (!setFeatureBuildState(name, setup.features, false)) { + std::cerr << "ERROR: \"" << name << "\" is neither an engine nor a feature!\n"; + return -1; + } + } + } else if (!std::strcmp(argv[i], "--file-prefix")) { + if (i + 1 >= argc) { + std::cerr << "ERROR: Missing \"prefix\" parameter for \"--file-prefix\"!\n"; + return -1; + } + + setup.filePrefix = unifyPath(argv[++i]); + if (setup.filePrefix.at(setup.filePrefix.size() - 1) == '/') + setup.filePrefix.erase(setup.filePrefix.size() - 1); + } else if (!std::strcmp(argv[i], "--output-dir")) { + if (i + 1 >= argc) { + std::cerr << "ERROR: Missing \"path\" parameter for \"--output-dirx\"!\n"; + return -1; + } + + setup.outputDir = unifyPath(argv[++i]); + if (setup.outputDir.at(setup.outputDir.size() - 1) == '/') + setup.outputDir.erase(setup.outputDir.size() - 1); + + } else if (!std::strcmp(argv[i], "--build-events")) { + setup.runBuildEvents = true; + } else { + std::cerr << "ERROR: Unknown parameter \"" << argv[i] << "\"\n"; + return -1; + } + } + + // Print status + cout << "Enabled engines:\n\n"; + for (EngineDescList::const_iterator i = setup.engines.begin(); i != setup.engines.end(); ++i) { + if (i->enable) + cout << " " << i->desc << '\n'; + } + + cout << "\nDisabled engines:\n\n"; + for (EngineDescList::const_iterator i = setup.engines.begin(); i != setup.engines.end(); ++i) { + if (!i->enable) + cout << " " << i->desc << '\n'; + } + + cout << "\nEnabled features:\n\n"; + for (FeatureList::const_iterator i = setup.features.begin(); i != setup.features.end(); ++i) { + if (i->enable) + cout << " " << i->description << '\n'; + } + + cout << "\nDisabled features:\n\n"; + for (FeatureList::const_iterator i = setup.features.begin(); i != setup.features.end(); ++i) { + if (!i->enable) + cout << " " << i->description << '\n'; + } + + // Setup defines and libraries + setup.defines = getEngineDefines(setup.engines); + setup.libraries = getFeatureLibraries(setup.features); + + // Add features + StringList featureDefines = getFeatureDefines(setup.features); + setup.defines.splice(setup.defines.begin(), featureDefines); + + // Windows only has support for the SDL backend, so we hardcode it here (along with winmm) + setup.defines.push_back("WIN32"); + setup.defines.push_back("SDL_BACKEND"); + setup.libraries.push_back("sdl"); + setup.libraries.push_back("winmm"); + +// Initialize global & project-specific warnings +#define SET_GLOBAL_WARNINGS(...) \ + { \ + std::string global[PP_NARG(__VA_ARGS__)] = { __VA_ARGS__ }; \ + globalWarnings.assign(global, global + (sizeof(global) / sizeof(global[0]))); \ + } + +#define SET_WARNINGS(name, ...) \ + { \ + std::string project[PP_NARG(__VA_ARGS__)] = { __VA_ARGS__ }; \ + projectWarnings[name].assign(project, project + (sizeof(project) / sizeof(project[0]))); \ + } + + // List of global warnings and map of project-specific warnings + StringList globalWarnings; + std::map<std::string, StringList> projectWarnings; + + CreateProjectTool::ProjectProvider *provider = NULL; + + switch (projectType) { + default: + case kProjectNone: + std::cerr << "ERROR: No project type has been specified!\n"; + return -1; + + case kProjectCodeBlocks: + //////////////////////////////////////////////////////////////////////////// + // Code::Blocks is using GCC behind the scenes, so we need to pass a list + // of options to enable or disable warnings + //////////////////////////////////////////////////////////////////////////// + // + // -Wall + // enable all warnings + // + // -Wno-long-long -Wno-multichar -Wno-unknown-pragmas -Wno-reorder + // disable annoying and not-so-useful warnings + // + // -Wpointer-arith -Wcast-qual -Wcast-align + // -Wshadow -Wimplicit -Wnon-virtual-dtor -Wwrite-strings + // enable even more warnings... + // + // -fno-rtti -fno-exceptions -fcheck-new + // disable RTTI and exceptions, and enable checking of pointers returned + // by "new" + // + //////////////////////////////////////////////////////////////////////////// + + SET_GLOBAL_WARNINGS("-Wall", "-Wno-long-long", "-Wno-multichar", "-Wno-unknown-pragmas", "-Wno-reorder", + "-Wpointer-arith", "-Wcast-qual", "-Wcast-align", "-Wshadow", "-Wimplicit", + "-Wnon-virtual-dtor", "-Wwrite-strings", "-fno-rtti", "-fno-exceptions", "-fcheck-new"); + + provider = new CreateProjectTool::CodeBlocksProvider(globalWarnings, projectWarnings); + + break; + + case kProjectMSVC: + //////////////////////////////////////////////////////////////////////////// + // For Visual Studio, all warnings are on by default in the project files, + // so we pass a list of warnings to disable globally or per-project + // + // Tracker reference: + // https://sourceforge.net/tracker/?func=detail&aid=2909981&group_id=37116&atid=418822 + //////////////////////////////////////////////////////////////////////////// + // + // 4068 (unknown pragma) + // only used in scumm engine to mark code sections + // + // 4100 (unreferenced formal parameter) + // + // 4103 (alignment changed after including header, may be due to missing #pragma pack(pop)) + // used by pack-start / pack-end + // + // 4127 (conditional expression is constant) + // used in a lot of engines + // + // 4244 ('conversion' conversion from 'type1' to 'type2', possible loss of data) + // throws tons and tons of warnings, most of them false positives + // + // 4250 ('class1' : inherits 'class2::member' via dominance) + // two or more members have the same name. Should be harmless + // + // 4310 (cast truncates constant value) + // used in some engines + // + // 4351 (new behavior: elements of array 'array' will be default initialized) + // a change in behavior in Visual Studio 2005. We want the new behavior, so it can be disabled + // + // 4512 ('class' : assignment operator could not be generated) + // some classes use const items and the default assignment operator cannot be generated + // + // 4702 (unreachable code) + // mostly thrown after error() calls (marked as NORETURN) + // + // 4706 (assignment within conditional expression) + // used in a lot of engines + // + // 4800 ('type' : forcing value to bool 'true' or 'false' (performance warning)) + // + // 4996 ('function': was declared deprecated) + // disabling it removes all the non-standard unsafe functions warnings (strcpy_s, etc.) + // + // 6211 (Leaking memory <pointer> due to an exception. Consider using a local catch block to clean up memory) + // we disable exceptions + // + // 6204 (possible buffer overrun in call to <function>: use of unchecked parameter <variable>) + // 6385 (invalid data: accessing <buffer name>, the readable size is <size1> bytes, but <size2> bytes may be read) + // 6386 (buffer overrun: accessing <buffer name>, the writable size is <size1> bytes, but <size2> bytes may be written) + // give way too many false positives + // + //////////////////////////////////////////////////////////////////////////// + // + // 4189 (local variable is initialized but not referenced) + // false positive in lure engine + // + // 4355 ('this' : used in base member initializer list) + // only disabled for specific engines where it is used in a safe way + // + // 4510 ('class' : default constructor could not be generated) + // + // 4511 ('class' : copy constructor could not be generated) + // + // 4610 (object 'class' can never be instantiated - user-defined constructor required) + // "correct" but harmless (as is 4510) + // + //////////////////////////////////////////////////////////////////////////// + + SET_GLOBAL_WARNINGS("4068", "4100", "4103", "4127", "4244", "4250", "4310", "4351", "4512", "4702", "4706", "4800", "4996", "6204", "6211", "6385", "6386"); + SET_WARNINGS("agi", "4510", "4610"); + SET_WARNINGS("agos", "4511"); + SET_WARNINGS("lure", "4189", "4355"); + SET_WARNINGS("kyra", "4355"); + SET_WARNINGS("m4", "4355"); + + if (msvcVersion == 8 || msvcVersion == 9) + provider = new CreateProjectTool::VisualStudioProvider(globalWarnings, projectWarnings, msvcVersion); + else + provider = new CreateProjectTool::MSBuildProvider(globalWarnings, projectWarnings, msvcVersion); + + break; + } + + provider->createProject(setup); + + delete provider; +} + +namespace { +std::string unifyPath(const std::string &path) { + std::string result = path; + std::replace(result.begin(), result.end(), '\\', '/'); + return result; +} + +std::string getLastPathComponent(const std::string &path) { + std::string::size_type pos = path.find_last_of('/'); + if (pos == std::string::npos) + return path; + else + return path.substr(pos + 1); +} + +void displayHelp(const char *exe) { + using std::cout; + + cout << "Usage:\n" + << exe << " path\\to\\source [optional options]\n" + << "\n" + << " Creates project files for the ScummVM source located at \"path\\to\\source\".\n" + " The project files will be created in the directory where tool is run from and\n" + " will include \"path\\to\\source\" for relative file paths, thus be sure that you\n" + " pass a relative file path like \"..\\..\\trunk\".\n" + "\n" + " Additionally there are the following switches for changing various settings:\n" + "\n" + "Project specific settings:\n" + " --codeblock build Code::Blocks project files\n" + " --msvc build Visual Studio project files\n" + " --file-prefix prefix allow overwriting of relative file prefix in the\n" + " MSVC project files. By default the prefix is the\n" + " \"path\\to\\source\" argument\n" + " --output-dir path overwrite path, where the project files are placed\n" + " By default this is \".\", i.e. the current working\n" + " directory\n" + "\n" + "MSVC specific settings:\n" + " --msvc-version version set the targeted MSVC version. Possible values:\n" + " 8 stands for \"Visual Studio 2005\"\n" + " 9 stands for \"Visual Studio 2008\"\n" + " 10 stands for \"Visual Studio 2010\"\n" + " The default is \"9\", thus \"Visual Studio 2008\"\n" + " --build-events Run custom build events as part of the build\n" + " (default: false)\n" + "\n" + "ScummVM engine settings:\n" + " --list-engines list all available engines and their default state\n" + " --enable-engine enable building of the engine with the name \"engine\"\n" + " --disable-engine disable building of the engine with the name \"engine\"\n" + " --enable-all-engines enable building of all engines\n" + " --disable-all-engines disable building of all engines\n" + "\n" + "ScummVM optional feature settings:\n" + " --enable-name enable inclusion of the feature \"name\"\n" + " --disable-name disable inclusion of the feature \"name\"\n" + "\n" + " There are the following features available:\n" + "\n"; + + cout << " state | name | description\n\n"; + const FeatureList features = getAllFeatures(); + cout.setf(std::ios_base::left, std::ios_base::adjustfield); + for (FeatureList::const_iterator i = features.begin(); i != features.end(); ++i) + cout << ' ' << (i->enable ? " enabled" : "disabled") << " | " << std::setw((std::streamsize)15) << i->name << std::setw((std::streamsize)0) << " | " << i->description << '\n'; + cout.setf(std::ios_base::right, std::ios_base::adjustfield); +} + +typedef StringList TokenList; + +/** + * Takes a given input line and creates a list of tokens out of it. + * + * A token in this context is separated by whitespaces. A special case + * are quotation marks though. A string inside quotation marks is treated + * as single token, even when it contains whitespaces. + * + * Thus for example the input: + * foo bar "1 2 3 4" ScummVM + * will create a list with the following entries: + * "foo", "bar", "1 2 3 4", "ScummVM" + * As you can see the quotation marks will get *removed* too. + * + * @param input The text to be tokenized. + * @return A list of tokens. + */ +TokenList tokenize(const std::string &input); + +/** + * Try to parse a given line and create an engine definition + * out of the result. + * + * This may take *any* input line, when the line is not used + * to define an engine the result of the function will be "false". + * + * Note that the contents of "engine" are undefined, when this + * function returns "false". + * + * @param line Text input line. + * @param engine Reference to an object, where the engine information + * is to be stored in. + * @return "true", when parsing succeeded, "false" otherwise. + */ +bool parseEngine(const std::string &line, EngineDesc &engine); +} // End of anonymous namespace + +EngineDescList parseConfigure(const std::string &srcDir) { + std::string configureFile = srcDir + "/configure"; + + std::ifstream configure(configureFile.c_str()); + if (!configure) + return EngineDescList(); + + std::string line; + EngineDescList engines; + + for (;;) { + std::getline(configure, line); + if (configure.eof()) + break; + + if (configure.fail()) + error("Failed while reading from " + configureFile); + + EngineDesc desc; + if (parseEngine(line, desc)) + engines.push_back(desc); + } + + return engines; +} + +bool isSubEngine(const std::string &name, const EngineDescList &engines) { + for (EngineDescList::const_iterator i = engines.begin(); i != engines.end(); ++i) { + if (std::find(i->subEngines.begin(), i->subEngines.end(), name) != i->subEngines.end()) + return true; + } + + return false; +} + +bool setEngineBuildState(const std::string &name, EngineDescList &engines, bool enable) { + if (enable && isSubEngine(name, engines)) { + // When we enable a sub engine, we need to assure that the parent is also enabled, + // thus we enable both sub engine and parent over here. + EngineDescList::iterator engine = std::find(engines.begin(), engines.end(), name); + if (engine != engines.end()) { + engine->enable = enable; + + for (engine = engines.begin(); engine != engines.end(); ++engine) { + if (std::find(engine->subEngines.begin(), engine->subEngines.end(), name) != engine->subEngines.end()) { + engine->enable = true; + break; + } + } + + return true; + } + } else { + EngineDescList::iterator engine = std::find(engines.begin(), engines.end(), name); + if (engine != engines.end()) { + engine->enable = enable; + + // When we disable an einge, we also need to disable all the sub engines. + if (!enable && !engine->subEngines.empty()) { + for (StringList::const_iterator j = engine->subEngines.begin(); j != engine->subEngines.end(); ++j) { + EngineDescList::iterator subEngine = std::find(engines.begin(), engines.end(), *j); + if (subEngine != engines.end()) + subEngine->enable = false; + } + } + + return true; + } + } + + return false; +} + +StringList getEngineDefines(const EngineDescList &engines) { + StringList result; + + for (EngineDescList::const_iterator i = engines.begin(); i != engines.end(); ++i) { + if (i->enable) { + std::string define = "ENABLE_" + i->name; + std::transform(define.begin(), define.end(), define.begin(), toupper); + result.push_back(define); + } + } + + return result; +} + +namespace { +bool parseEngine(const std::string &line, EngineDesc &engine) { + // Format: + // add_engine engine_name "Readable Description" enable_default ["SubEngineList"] + TokenList tokens = tokenize(line); + + if (tokens.size() < 4) + return false; + + TokenList::const_iterator token = tokens.begin(); + + if (*token != "add_engine") + return false; + ++token; + + engine.name = *token; ++token; + engine.desc = *token; ++token; + engine.enable = (*token == "yes"); ++token; + if (token != tokens.end()) + engine.subEngines = tokenize(*token); + + return true; +} + +TokenList tokenize(const std::string &input) { + TokenList result; + + std::string::size_type sIdx = input.find_first_not_of(" \t"); + std::string::size_type nIdx = std::string::npos; + + if (sIdx == std::string::npos) + return result; + + do { + if (input.at(sIdx) == '\"') { + ++sIdx; + nIdx = input.find_first_of('\"', sIdx); + } else { + nIdx = input.find_first_of(' ', sIdx); + } + + if (nIdx != std::string::npos) { + result.push_back(input.substr(sIdx, nIdx - sIdx)); + sIdx = input.find_first_not_of(" \t", nIdx + 1); + } else { + result.push_back(input.substr(sIdx)); + break; + } + } while (sIdx != std::string::npos); + + return result; +} +} // End of anonymous namespace + +namespace { +const Feature s_features[] = { + // Libraries + { "libz", "USE_ZLIB", "zlib", true, "zlib (compression) support" }, + { "mad", "USE_MAD", "libmad", true, "libmad (MP3) support" }, + { "vorbis", "USE_VORBIS", "libvorbisfile_static libvorbis_static libogg_static", true, "Ogg Vorbis support" }, + { "flac", "USE_FLAC", "libFLAC_static", true, "FLAC support" }, + { "png", "USE_PNG", "libpng", true, "libpng support" }, + { "theora", "USE_THEORADEC", "libtheora_static", true, "Theora decoding support" }, + { "mpeg2", "USE_MPEG2", "libmpeg2", false, "mpeg2 codec for cutscenes" }, + + // ScummVM feature flags + { "scalers", "USE_SCALERS", "", true, "Scalers" }, + { "hqscalers", "USE_HQ_SCALERS", "", true, "HQ scalers" }, + { "16bit", "USE_RGB_COLOR", "", true, "16bit color support" }, + { "mt32emu", "USE_MT32EMU", "", true, "integrated MT-32 emulator" }, + { "nasm", "USE_NASM", "", true, "IA-32 assembly support" }, // This feature is special in the regard, that it needs additional handling. + { "opengl", "USE_OPENGL", "opengl32", true, "OpenGL support" }, + { "indeo3", "USE_INDEO3", "", true, "Indeo3 codec support"}, + { "translation", "USE_TRANSLATION", "", true, "Translation support" }, + { "langdetect", "USE_DETECTLANG", "", true, "System language detection support" } // This feature actually depends on "translation", there + // is just no current way of properly detecting this... +}; +} // End of anonymous namespace + +FeatureList getAllFeatures() { + const size_t featureCount = sizeof(s_features) / sizeof(s_features[0]); + + FeatureList features; + for (size_t i = 0; i < featureCount; ++i) + features.push_back(s_features[i]); + + return features; +} + +StringList getFeatureDefines(const FeatureList &features) { + StringList defines; + + for (FeatureList::const_iterator i = features.begin(); i != features.end(); ++i) { + if (i->enable && i->define && i->define[0]) + defines.push_back(i->define); + } + + return defines; +} + +StringList getFeatureLibraries(const FeatureList &features) { + StringList libraries; + + for (FeatureList::const_iterator i = features.begin(); i != features.end(); ++i) { + if (i->enable && i->libraries && i->libraries[0]) { + StringList fLibraries = tokenize(i->libraries); + libraries.splice(libraries.end(), fLibraries); + } + } + + return libraries; +} + +bool setFeatureBuildState(const std::string &name, FeatureList &features, bool enable) { + FeatureList::iterator i = std::find(features.begin(), features.end(), name); + if (i != features.end()) { + i->enable = enable; + return true; + } else { + return false; + } +} + +namespace CreateProjectTool { + +////////////////////////////////////////////////////////////////////////// +// Utilities +////////////////////////////////////////////////////////////////////////// + +std::string convertPathToWin(const std::string &path) { + std::string result = path; + std::replace(result.begin(), result.end(), '/', '\\'); + return result; +} + +std::string getIndent(const int indentation) { + std::string result; + for (int i = 0; i < indentation; ++i) + result += '\t'; + return result; +} + +void splitFilename(const std::string &fileName, std::string &name, std::string &ext) { + const std::string::size_type dot = fileName.find_last_of('.'); + name = (dot == std::string::npos) ? fileName : fileName.substr(0, dot); + ext = (dot == std::string::npos) ? std::string() : fileName.substr(dot + 1); +} + +bool producesObjectFile(const std::string &fileName) { + std::string n, ext; + splitFilename(fileName, n, ext); + + if (ext == "cpp" || ext == "c" || ext == "asm") + return true; + else + return false; +} + +/** + * Checks whether the give file in the specified directory is present in the given + * file list. + * + * This function does as special match against the file list. It will not take file + * extensions into consideration, when the extension of a file in the specified + * directory is one of "h", "cpp", "c" or "asm". + * + * @param dir Parent directory of the file. + * @param fileName File name to match. + * @param fileList List of files to match against. + * @return "true" when the file is in the list, "false" otherwise. + */ +bool isInList(const std::string &dir, const std::string &fileName, const StringList &fileList) { + std::string compareName, extensionName; + splitFilename(fileName, compareName, extensionName); + + if (!extensionName.empty()) + compareName += '.'; + + for (StringList::const_iterator i = fileList.begin(); i != fileList.end(); ++i) { + if (i->compare(0, dir.size(), dir)) + continue; + + // When no comparison name is given, we try to match whether a subset of + // the given directory should be included. To do that we must assure that + // the first character after the substring, having the same size as dir, must + // be a path delimiter. + if (compareName.empty()) { + if (i->size() >= dir.size() + 1 && i->at(dir.size()) == '/') + return true; + else + continue; + } + + const std::string lastPathComponent = getLastPathComponent(*i); + if (!producesObjectFile(fileName) && extensionName != "h") { + if (fileName == lastPathComponent) + return true; + } else { + if (!lastPathComponent.compare(0, compareName.size(), compareName)) + return true; + } + } + + return false; +} + +/** + * A strict weak compare predicate for sorting a list of + * "FileNode *" entries. + * + * It will sort directory nodes before file nodes. + * + * @param l Left-hand operand. + * @param r Right-hand operand. + * @return "true" if and only if l should be sorted before r. + */ +bool compareNodes(const FileNode *l, const FileNode *r) { + if (!l) { + return false; + } else if (!r) { + return true; + } else { + if (l->children.empty() && !r->children.empty()) { + return false; + } else if (!l->children.empty() && r->children.empty()) { + return true; + } else { + return l->name < r->name; + } + } +} + +/** + * Returns a list of all files and directories in the specified + * path. + * + * @param dir Directory which should be listed. + * @return List of all children. + */ +FileList listDirectory(const std::string &dir) { + FileList result; +#ifdef USE_WIN32_API + WIN32_FIND_DATA fileInformation; + HANDLE fileHandle = FindFirstFile((dir + "/*").c_str(), &fileInformation); + + if (fileHandle == INVALID_HANDLE_VALUE) + return result; + + do { + if (fileInformation.cFileName[0] == '.') + continue; + + result.push_back(FSNode(fileInformation.cFileName, (fileInformation.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)); + } while (FindNextFile(fileHandle, &fileInformation) == TRUE); + + FindClose(fileHandle); +#else + DIR *dirp = opendir(dir.c_str()); + struct dirent *dp = NULL; + + if (dirp == NULL) + return result; + + while ((dp = readdir(dirp)) != NULL) { + if (dp->d_name[0] == '.') + continue; + + struct stat st; + if (stat((dir + '/' + dp->d_name).c_str(), &st)) + continue; + + result.push_back(FSNode(dp->d_name, S_ISDIR(st.st_mode))); + } + + closedir(dirp); +#endif + return result; +} + +/** + * Scans the specified directory against files, which should be included + * in the project files. It will not include files present in the exclude list. + * + * @param dir Directory in which to search for files. + * @param includeList Files to include in the project. + * @param excludeList Files to exclude from the project. + * @return Returns a file node for the specific directory. + */ +FileNode *scanFiles(const std::string &dir, const StringList &includeList, const StringList &excludeList) { + FileList files = listDirectory(dir); + + if (files.empty()) + return 0; + + FileNode *result = new FileNode(dir); + assert(result); + + for (FileList::const_iterator i = files.begin(); i != files.end(); ++i) { + if (i->isDirectory) { + const std::string subDirName = dir + '/' + i->name; + if (!isInList(subDirName, std::string(), includeList)) + continue; + + FileNode *subDir = scanFiles(subDirName, includeList, excludeList); + + if (subDir) { + subDir->name = i->name; + result->children.push_back(subDir); + } + continue; + } + + if (isInList(dir, i->name, excludeList)) + continue; + + std::string name, ext; + splitFilename(i->name, name, ext); + + if (ext != "h") { + if (!isInList(dir, i->name, includeList)) + continue; + } + + FileNode *child = new FileNode(i->name); + assert(child); + result->children.push_back(child); + } + + if (result->children.empty()) { + delete result; + return 0; + } else { + result->children.sort(compareNodes); + return result; + } +} + +////////////////////////////////////////////////////////////////////////// +// Project Provider methods +////////////////////////////////////////////////////////////////////////// +ProjectProvider::ProjectProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, const int version) + : _version(version), _globalWarnings(global_warnings), _projectWarnings(project_warnings) { +} + +void ProjectProvider::createProject(const BuildSetup &setup) { + _uuidMap = createUUIDMap(setup); + + // We also need to add the UUID of the main project file. + const std::string svmUUID = _uuidMap["scummvm"] = createUUID(); + + // Create Solution/Workspace file + createWorkspace(setup); + + StringList in, ex; + + // Create engine project files + for (UUIDMap::const_iterator i = _uuidMap.begin(); i != _uuidMap.end(); ++i) { + if (i->first == "scummvm") + continue; + + in.clear(); ex.clear(); + const std::string moduleDir = setup.srcDir + "/engines/" + i->first; + + createModuleList(moduleDir, setup.defines, in, ex); + createProjectFile(i->first, i->second, setup, moduleDir, in, ex); + } + + // Last but not least create the main ScummVM project file. + in.clear(); ex.clear(); + + // File list for the ScummVM project file + createModuleList(setup.srcDir + "/backends", setup.defines, in, ex); + createModuleList(setup.srcDir + "/backends/platform/sdl", setup.defines, in, ex); + createModuleList(setup.srcDir + "/base", setup.defines, in, ex); + createModuleList(setup.srcDir + "/common", setup.defines, in, ex); + createModuleList(setup.srcDir + "/engines", setup.defines, in, ex); + createModuleList(setup.srcDir + "/graphics", setup.defines, in, ex); + createModuleList(setup.srcDir + "/gui", setup.defines, in, ex); + createModuleList(setup.srcDir + "/audio", setup.defines, in, ex); + createModuleList(setup.srcDir + "/audio/softsynth/mt32", setup.defines, in, ex); + createModuleList(setup.srcDir + "/video", setup.defines, in, ex); + + // Resource files + in.push_back(setup.srcDir + "/icons/scummvm.ico"); + in.push_back(setup.srcDir + "/dists/scummvm.rc"); + + // Various text files + in.push_back(setup.srcDir + "/AUTHORS"); + in.push_back(setup.srcDir + "/COPYING"); + in.push_back(setup.srcDir + "/COPYING.LGPL"); + in.push_back(setup.srcDir + "/COPYRIGHT"); + in.push_back(setup.srcDir + "/NEWS"); + in.push_back(setup.srcDir + "/README"); + in.push_back(setup.srcDir + "/TODO"); + + // Create the scummvm project file. + createProjectFile("scummvm", svmUUID, setup, setup.srcDir, in, ex); + + // Create other misc. build files + createOtherBuildFiles(setup); +} + +ProjectProvider::UUIDMap ProjectProvider::createUUIDMap(const BuildSetup &setup) const { + UUIDMap result; + + for (EngineDescList::const_iterator i = setup.engines.begin(); i != setup.engines.end(); ++i) { + if (!i->enable || isSubEngine(i->name, setup.engines)) + continue; + + result[i->name] = createUUID(); + } + + return result; +} + +std::string ProjectProvider::createUUID() const { +#ifdef USE_WIN32_API + UUID uuid; + if (UuidCreate(&uuid) != RPC_S_OK) + error("UuidCreate failed"); + + unsigned char *string = 0; + if (UuidToStringA(&uuid, &string) != RPC_S_OK) + error("UuidToStringA failed"); + + std::string result = std::string((char *)string); + std::transform(result.begin(), result.end(), result.begin(), toupper); + RpcStringFreeA(&string); + return result; +#else + unsigned char uuid[16]; + + for (int i = 0; i < 16; ++i) + uuid[i] = (unsigned char)((std::rand() / (double)(RAND_MAX)) * 0xFF); + + uuid[8] &= 0xBF; uuid[8] |= 0x80; + uuid[6] &= 0x4F; uuid[6] |= 0x40; + + std::stringstream uuidString; + uuidString << std::hex << std::uppercase << std::setfill('0'); + for (int i = 0; i < 16; ++i) { + uuidString << std::setw(2) << (int)uuid[i]; + if (i == 3 || i == 5 || i == 7 || i == 9) { + uuidString << std::setw(0) << '-'; + } + } + + return uuidString.str(); +#endif +} + +void ProjectProvider::addFilesToProject(const std::string &dir, std::ofstream &projectFile, + const StringList &includeList, const StringList &excludeList, + const std::string &filePrefix) { + // Check for duplicate object file names + StringList duplicate; + + for (StringList::const_iterator i = includeList.begin(); i != includeList.end(); ++i) { + const std::string fileName = getLastPathComponent(*i); + + // Leave out non object file names. + if (fileName.size() < 2 || fileName.compare(fileName.size() - 2, 2, ".o")) + continue; + + // Check whether an duplicate has been found yet + if (std::find(duplicate.begin(), duplicate.end(), fileName) != duplicate.end()) + continue; + + // Search for duplicates + StringList::const_iterator j = i; ++j; + for (; j != includeList.end(); ++j) { + if (fileName == getLastPathComponent(*j)) { + duplicate.push_back(fileName); + break; + } + } + } + + FileNode *files = scanFiles(dir, includeList, excludeList); + + writeFileListToProject(*files, projectFile, 0, duplicate, std::string(), filePrefix + '/'); + + delete files; +} + +void ProjectProvider::createModuleList(const std::string &moduleDir, const StringList &defines, StringList &includeList, StringList &excludeList) const { + const std::string moduleMkFile = moduleDir + "/module.mk"; + std::ifstream moduleMk(moduleMkFile.c_str()); + if (!moduleMk) + error(moduleMkFile + " is not present"); + + includeList.push_back(moduleMkFile); + + std::stack<bool> shouldInclude; + shouldInclude.push(true); + + bool hadModule = false; + std::string line; + for (;;) { + std::getline(moduleMk, line); + + if (moduleMk.eof()) + break; + + if (moduleMk.fail()) + error("Failed while reading from " + moduleMkFile); + + TokenList tokens = tokenize(line); + if (tokens.empty()) + continue; + + TokenList::const_iterator i = tokens.begin(); + if (*i == "MODULE") { + if (hadModule) + error("More than one MODULE definition in " + moduleMkFile); + // Format: "MODULE := path/to/module" + if (tokens.size() < 3) + error("Malformed MODULE definition in " + moduleMkFile); + ++i; + if (*i != ":=") + error("Malformed MODULE definition in " + moduleMkFile); + ++i; + + std::string moduleRoot = unifyPath(*i); + if (moduleDir.compare(moduleDir.size() - moduleRoot.size(), moduleRoot.size(), moduleRoot)) + error("MODULE root " + moduleRoot + " does not match base dir " + moduleDir); + + hadModule = true; + } else if (*i == "MODULE_OBJS") { + if (tokens.size() < 3) + error("Malformed MODULE_OBJS definition in " + moduleMkFile); + ++i; + + // This is not exactly correct, for example an ":=" would usually overwrite + // all already added files, but since we do only save the files inside + // includeList or excludeList currently, we couldn't handle such a case easily. + // (includeList and excludeList should always preserve their entries, not added + // by this function, thus we can't just clear them on ":=" or "="). + // But hopefully our module.mk files will never do such things anyway. + if (*i != ":=" && *i != "+=" && *i != "=") + error("Malformed MODULE_OBJS definition in " + moduleMkFile); + + ++i; + + while (i != tokens.end()) { + if (*i == "\\") { + std::getline(moduleMk, line); + tokens = tokenize(line); + i = tokens.begin(); + } else { + if (shouldInclude.top()) + includeList.push_back(moduleDir + "/" + unifyPath(*i)); + else + excludeList.push_back(moduleDir + "/" + unifyPath(*i)); + ++i; + } + } + } else if (*i == "ifdef") { + if (tokens.size() < 2) + error("Malformed ifdef in " + moduleMkFile); + ++i; + + if (std::find(defines.begin(), defines.end(), *i) == defines.end()) + shouldInclude.push(false); + else + shouldInclude.push(true); + } else if (*i == "ifndef") { + if (tokens.size() < 2) + error("Malformed ifndef in " + moduleMkFile); + ++i; + + if (std::find(defines.begin(), defines.end(), *i) == defines.end()) + shouldInclude.push(true); + else + shouldInclude.push(false); + } else if (*i == "else") { + shouldInclude.top() = !shouldInclude.top(); + } else if (*i == "endif") { + if (shouldInclude.size() <= 1) + error("endif without ifdef found in " + moduleMkFile); + shouldInclude.pop(); + } else if (*i == "elif") { + error("Unsupported operation 'elif' in " + moduleMkFile); + } else if (*i == "ifeq") { + //XXX + shouldInclude.push(false); + } + } + + if (shouldInclude.size() != 1) + error("Malformed file " + moduleMkFile); +} + +} // End of anonymous namespace + +void error(const std::string &message) { + std::cerr << "ERROR: " << message << "!" << std::endl; + std::exit(-1); +} diff --git a/devtools/create_project/create_project.h b/devtools/create_project/create_project.h new file mode 100644 index 0000000000..8c4b8c7d23 --- /dev/null +++ b/devtools/create_project/create_project.h @@ -0,0 +1,443 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef TOOLS_CREATE_PROJECT_H +#define TOOLS_CREATE_PROJECT_H + +#include <map> +#include <list> +#include <string> + +#include <cassert> + +// The PP_NARG macro returns the number of arguments that have been passed to it. +#define PP_NARG(...) \ + PP_NARG_(__VA_ARGS__,PP_RSEQ_N()) +#define PP_NARG_(...) \ + PP_ARG_N(__VA_ARGS__) +#define PP_ARG_N( \ + _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ + _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ + _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ + _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ + _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ + _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ + _61,_62,_63,N,...) N +#define PP_RSEQ_N() \ + 63,62,61,60, \ + 59,58,57,56,55,54,53,52,51,50, \ + 49,48,47,46,45,44,43,42,41,40, \ + 39,38,37,36,35,34,33,32,31,30, \ + 29,28,27,26,25,24,23,22,21,20, \ + 19,18,17,16,15,14,13,12,11,10, \ + 9,8,7,6,5,4,3,2,1,0 + +#define SET_VALUES(list, ...) \ + { \ + std::string values[PP_NARG(__VA_ARGS__)] = { __VA_ARGS__ }; \ + list.assign(values, values + (sizeof(values) / sizeof(values[0]))); \ + } + +typedef std::list<std::string> StringList; + +/** + * Structure to describe a game engine to be built into ScummVM. + * + * We do get the game engines available by parsing the "configure" + * script of our source distribution. See "parseConfigure" for more + * information on that. + * @see parseConfigure + */ +struct EngineDesc { + /** + * The name of the engine. We use this to determine the directory + * the engine is in and to create the define, which needs to be + * set to enable the engine. + */ + std::string name; + + /** + * A human readable description of the engine. We will use this + * to display a description of the engine to the user in the list + * of which engines are built and which are disabled. + */ + std::string desc; + + /** + * Whether the engine should be included in the build or not. + */ + bool enable; + + /** + * A list of all available sub engine names. Sub engines are engines + * which are built on top of an existing engines and can be only + * enabled when the parten engine is enabled. + */ + StringList subEngines; + + bool operator==(const std::string &n) const { + return (name == n); + } +}; + +typedef std::list<EngineDesc> EngineDescList; + +/** + * This function parses the ScummVM configure file and creates a list + * of available engines. + * + * It will also automatically setup the default build state (enabled + * or disabled) to the state specified in the "configure" file. + * + * @param srcDir Path to the root of the ScummVM source. + * @return List of available engines. + */ +EngineDescList parseConfigure(const std::string &srcDir); + +/** + * Checks whether the specified engine is a sub engine. To determine this + * there is a fully setup engine list needed. + * + * @param name Name of the engine to check. + * @param engines List of engines. + * @return "true", when the engine is a sub engine, "false" otherwise. + */ +bool isSubEngine(const std::string &name, const EngineDescList &engines); + +/** + * Enables or disables the specified engine in the engines list. + * + * This function also disables all sub engines of an engine, when it is + * to be disabled. + * Also this function does enable the parent of a sub engine, when a + * sub engine is to be enabled. + * + * @param name Name of the engine to be enabled or disabled. + * @param engines The list of engines, which should be operated on. + * @param enable Whether the engine should be enabled or disabled. + * @return "true", when it succeeded, "false" otherwise. + */ +bool setEngineBuildState(const std::string &name, EngineDescList &engines, bool enable); + +/** + * Returns a list of all defines, according to the engine list passed. + * + * @param features The list of engines, which should be operated on. (this may contain engines, which are *not* enabled!) + */ +StringList getEngineDefines(const EngineDescList &engines); + +/** + * Structure to define a given feature, usually an external library, + * used to build ScummVM. + */ +struct Feature { + const char *name; ///< Name of the feature + const char *define; ///< Define of the feature + + const char *libraries; ///< Libraries, which need to be linked, for the feature + + bool enable; ///< Whether the feature is enabled or not + + const char *description; ///< Human readable description of the feature + + bool operator==(const std::string &n) const { + return (name == n); + } +}; +typedef std::list<Feature> FeatureList; + +/** + * Creates a list of all features available for MSVC. + * + * @return A list including all features available. + */ +FeatureList getAllFeatures(); + +/** + * Returns a list of all defines, according to the feature set + * passed. + * + * @param features List of features for the build (this may contain features, which are *not* enabled!) + */ +StringList getFeatureDefines(const FeatureList &features); + +/** + * Returns a list of all external library files, according to the + * feature set passed. + * + * @param features List of features for the build (this may contain features, which are *not* enabled!) + */ +StringList getFeatureLibraries(const FeatureList &features); + +/** + * Sets the state of a given feature. This can be used to + * either include or exclude an feature. + * + * @param name Name of the feature. + * @param features List of features to operate on. + * @param enable Whether the feature should be enabled or disabled. + * @return "true", when it succeeded, "false" otherwise. + */ +bool setFeatureBuildState(const std::string &name, FeatureList &features, bool enable); + +/** + * Structure to describe a build setup. + * + * This includes various information about which engines to + * enable, which features should be built into ScummVM. + * It also contains the path to the ScummVM souce root. + */ +struct BuildSetup { + std::string srcDir; ///< Path to the ScummVM sources. + std::string filePrefix; ///< Prefix for the relative path arguments in the project files. + std::string outputDir; ///< Path where to put the MSVC project files. + + EngineDescList engines; ///< Engine list for the build (this may contain engines, which are *not* enabled!). + FeatureList features; ///< Feature list for the build (this may contain features, which are *not* enabled!). + + StringList defines; ///< List of all defines for the build. + StringList libraries; ///< List of all external libraries required for the build. + + bool runBuildEvents; + + BuildSetup() { + runBuildEvents = false; + } +}; + +/** + * Quits the program with the specified error message. + * + * @param message The error message to print to stderr. + */ +#if defined(__GNUC__) + #define NORETURN_POST __attribute__((__noreturn__)) +#elif defined(_MSC_VER) + #define NORETURN_PRE __declspec(noreturn) +#endif + +#ifndef NORETURN_PRE +#define NORETURN_PRE +#endif + +#ifndef NORETURN_POST +#define NORETURN_POST +#endif +void NORETURN_PRE error(const std::string &message) NORETURN_POST; + +namespace CreateProjectTool { + +/** + * Gets a proper sequence of \t characters for the given + * indentation level. + * + * For example with an indentation level of 2 this will + * produce: + * \t\t + * + * @param indentation The indentation level + * @return Sequence of \t characters. + */ +std::string getIndent(const int indentation); + +/** + * Converts the given path to only use backslashes. + * This means that for example the path: + * foo/bar\test.txt + * will be converted to: + * foo\bar\test.txt + * + * @param path Path string. + * @return Converted path. + */ +std::string convertPathToWin(const std::string &path); + +/** + * Splits a file name into name and extension. + * The file name must be only the filename, no + * additional path name. + * + * @param fileName Filename to split + * @param name Reference to a string, where to store the name. + * @param ext Reference to a string, where to store the extension. + */ +void splitFilename(const std::string &fileName, std::string &name, std::string &ext); + +/** + * Checks whether the given file will produce an object file or not. + * + * @param fileName Name of the file. + * @return "true" when it will produce a file, "false" otherwise. + */ +bool producesObjectFile(const std::string &fileName); + +/** + * Structure representing a file tree. This contains two + * members: name and children. "name" holds the name of + * the node. "children" does contain all the node's children. + * When the list "children" is empty, the node is a file entry, + * otherwise it's a directory. + */ +struct FileNode { + typedef std::list<FileNode *> NodeList; + + explicit FileNode(const std::string &n) : name(n), children() {} + + ~FileNode() { + for (NodeList::iterator i = children.begin(); i != children.end(); ++i) + delete *i; + } + + std::string name; ///< Name of the node + NodeList children; ///< List of children for the node +}; + +class ProjectProvider { +public: + typedef std::map<std::string, std::string> UUIDMap; + + /** + * Instantiate new ProjectProvider class + * + * @param global_warnings List of warnings that apply to all projects + * @param project_warnings List of project-specific warnings + * @param version Target project version. + */ + ProjectProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, const int version = 0); + virtual ~ProjectProvider() {} + + /** + * Creates all build files + * + * @param setup Description of the desired build setup. + */ + void createProject(const BuildSetup &setup); + +protected: + const int _version; ///< Target project version + StringList &_globalWarnings; ///< Global warnings + std::map<std::string, StringList> &_projectWarnings; ///< Per-project warnings + + UUIDMap _uuidMap; ///< List of (project name, UUID) pairs + + /** + * Create workspace/solution file + * + * @param setup Description of the desired build setup. + */ + virtual void createWorkspace(const BuildSetup &setup) = 0; + + /** + * Create other files (such as build properties) + * + * @param setup Description of the desired build setup. + */ + virtual void createOtherBuildFiles(const BuildSetup &setup) = 0; + + /** + * Create a project file for the specified list of files. + * + * @param name Name of the project file. + * @param uuid UUID of the project file. + * @param setup Description of the desired build. + * @param moduleDir Path to the module. + * @param includeList Files to include (must have "moduleDir" as prefix). + * @param excludeList Files to exclude (must have "moduleDir" as prefix). + */ + virtual void createProjectFile(const std::string &name, const std::string &uuid, const BuildSetup &setup, const std::string &moduleDir, + const StringList &includeList, const StringList &excludeList) = 0; + + /** + * Writes file entries for the specified directory node into + * the given project file. It will also take care of duplicate + * object files. + * + * @param dir Directory node. + * @param projectFile File stream to write to. + * @param indentation Indentation level to use. + * @param duplicate List of duplicate object file names. + * @param objPrefix Prefix to use for object files, which would name clash. + * @param filePrefix Generic prefix to all files of the node. + */ + virtual void writeFileListToProject(const FileNode &dir, std::ofstream &projectFile, const int indentation, + const StringList &duplicate, const std::string &objPrefix, const std::string &filePrefix) = 0; + + /** + * Output a list of project references to the file stream + * + * @param output File stream to write to. + */ + virtual void writeReferences(std::ofstream &) {}; + + /** + * Get the file extension for project files + */ + virtual const char *getProjectExtension() { return ""; } + + /** + * Adds files of the specified directory recursively to given project file. + * + * @param dir Path to the directory. + * @param projectFile Output stream object, where all data should be written to. + * @param includeList Files to include (must have a relative directory as prefix). + * @param excludeList Files to exclude (must have a relative directory as prefix). + * @param filePrefix Prefix to use for relative path arguments. + */ + void addFilesToProject(const std::string &dir, std::ofstream &projectFile, + const StringList &includeList, const StringList &excludeList, + const std::string &filePrefix); + + /** + * Creates a list of files of the specified module. This also + * creates a list of files, which should not be included. + * All filenames will have "moduleDir" as prefix. + * + * @param moduleDir Path to the module. + * @param defines List of set defines. + * @param includeList Reference to a list, where included files should be added. + * @param excludeList Reference to a list, where excluded files should be added. + */ + void createModuleList(const std::string &moduleDir, const StringList &defines, StringList &includeList, StringList &excludeList) const; + + /** + * Creates an UUID for every enabled engine of the + * passed build description. + * + * @param setup Description of the desired build. + * @return A map, which includes UUIDs for all enabled engines. + */ + UUIDMap createUUIDMap(const BuildSetup &setup) const; + + /** + * Creates an UUID and returns it in string representation. + * + * @return A new UUID as string. + */ + std::string createUUID() const; +}; + +} // End of CreateProjectTool namespace + +#endif // TOOLS_CREATE_PROJECT_H diff --git a/devtools/create_project/module.mk b/devtools/create_project/module.mk new file mode 100644 index 0000000000..4382fe176c --- /dev/null +++ b/devtools/create_project/module.mk @@ -0,0 +1,20 @@ +# $URL$ +# $Id$ + +MODULE := devtools/create_project + +MODULE_OBJS := \ + create_project.o \ + codeblocks.o \ + msvc.o \ + visualstudio.o \ + msbuild.o + +# Set the name of the executable +TOOL_EXECUTABLE := create_project + +# Include common rules +include $(srcdir)/rules.mk + +# Silence variadic macros warning for C++ (disabled as this is included globally) +#CXXFLAGS := $(CXXFLAGS) -Wno-variadic-macros diff --git a/devtools/create_project/msbuild.cpp b/devtools/create_project/msbuild.cpp new file mode 100644 index 0000000000..73511218b4 --- /dev/null +++ b/devtools/create_project/msbuild.cpp @@ -0,0 +1,516 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#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; +} + +#define OUTPUT_CONFIGURATION_MSBUILD(config, 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") + +#define OUTPUT_CONFIGURATION_TYPE_MSBUILD(config) \ + (project << "\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='" << config << "'\" Label=\"Configuration\">\n" \ + "\t\t<ConfigurationType>" << (name == "scummvm" ? "Application" : "StaticLibrary") << "</ConfigurationType>\n" \ + "\t</PropertyGroup>\n") + +#define OUTPUT_PROPERTIES_MSBUILD(config, 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") + +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"; + + OUTPUT_CONFIGURATION_MSBUILD("Debug", "Win32"); + OUTPUT_CONFIGURATION_MSBUILD("Debug", "x64"); + OUTPUT_CONFIGURATION_MSBUILD("Analysis", "Win32"); + OUTPUT_CONFIGURATION_MSBUILD("Analysis", "x64"); + OUTPUT_CONFIGURATION_MSBUILD("Release", "Win32"); + OUTPUT_CONFIGURATION_MSBUILD("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"; + + OUTPUT_CONFIGURATION_TYPE_MSBUILD("Release|Win32"); + OUTPUT_CONFIGURATION_TYPE_MSBUILD("Analysis|Win32"); + OUTPUT_CONFIGURATION_TYPE_MSBUILD("Debug|Win32"); + OUTPUT_CONFIGURATION_TYPE_MSBUILD("Release|x64"); + OUTPUT_CONFIGURATION_TYPE_MSBUILD("Analysis|x64"); + OUTPUT_CONFIGURATION_TYPE_MSBUILD("Debug|x64"); + + project << "\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n" + "\t<ImportGroup Label=\"ExtensionSettings\">\n" + "\t</ImportGroup>\n"; + + OUTPUT_PROPERTIES_MSBUILD("Release|Win32", "ScummVM_Release.props"); + OUTPUT_PROPERTIES_MSBUILD("Analysis|Win32", "ScummVM_Analysis.props"); + OUTPUT_PROPERTIES_MSBUILD("Debug|Win32", "ScummVM_Debug.props"); + OUTPUT_PROPERTIES_MSBUILD("Release|x64", "ScummVM_Release64.props"); + OUTPUT_PROPERTIES_MSBUILD("Analysis|x64", "ScummVM_Analysis64.props"); + OUTPUT_PROPERTIES_MSBUILD("Debug|x64", "ScummVM_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 scummvm project + if (name == "scummvm") + writeReferences(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); +} + +#define OUTPUT_FILTER_MSBUILD(files, action) \ + if (!files.empty()) { \ + filters << "\t<ItemGroup>\n"; \ + for (std::list<FileEntry>::const_iterator entry = files.begin(); entry != files.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::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 + OUTPUT_FILTER_MSBUILD(_compileFiles, "ClCompile") + OUTPUT_FILTER_MSBUILD(_includeFiles, "ClInclude") + OUTPUT_FILTER_MSBUILD(_otherFiles, "None") + OUTPUT_FILTER_MSBUILD(_resourceFiles, "ResourceCompile") + OUTPUT_FILTER_MSBUILD(_asmFiles, "CustomBuild") + + filters << "</Project>"; +} + +void MSBuildProvider::writeReferences(std::ofstream &output) { + output << "\t<ItemGroup>\n"; + + for (UUIDMap::const_iterator i = _uuidMap.begin(); i != _uuidMap.end(); ++i) { + if (i->first == "scummvm") + 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 (name != "scummvm" && name != "sword25" && name != "tinsel" && 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 (name == "scummvm" || name == "sword25") { + project << "\t\t\t<DisableLanguageExtensions>false</DisableLanguageExtensions>\n"; + } else { + if (name == "tinsel" && !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 scummvm project + if (name == "scummvm") { + 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)scummvm.exe</OutputFile>\n" + "\t\t\t<AdditionalDependencies>" << libraries << "%(AdditionalDependencies)</AdditionalDependencies>\n" + "\t\t</Link>\n"; + + if (setup.runBuildEvents) { + // Only generate revision number in debug builds + if (!isRelease) { + project << "\t\t<PreBuildEvent>\n" + "\t\t\t<Message>Generate internal_version.h</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) << "</Command>\n" + "\t\t</PostBuildEvent>\n"; + } + } + + project << "\t</ItemDefinitionGroup>\n"; +} + +void MSBuildProvider::outputGlobalPropFile(std::ofstream &properties, int bits, const StringList &defines, const std::string &prefix) { + + 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 + ';'; + + 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.30319.1</_ProjectFileVersion>\n" + "\t\t<_PropertySheetDisplayName>ScummVM_Global</_PropertySheetDisplayName>\n" + "\t\t<ExecutablePath>$(SCUMMVM_LIBS)\\bin;$(ExecutablePath)</ExecutablePath>\n" + "\t\t<LibraryPath>$(SCUMMVM_LIBS)\\lib\\" << (bits == 32 ? "x86" : "x64") << ";$(LibraryPath)</LibraryPath>\n" + "\t\t<IncludePath>$(SCUMMVM_LIBS)\\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>$(SCUMMVM_LIBS)\\include;" << prefix << ";" << prefix << "\\engines;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n" + "\t\t\t<PreprocessorDefinitions>" << definesList << "%(PreprocessorDefinitions)</PreprocessorDefinitions>\n" + "\t\t\t<ExceptionHandling></ExceptionHandling>\n" + "\t\t\t<RuntimeTypeInfo>false</RuntimeTypeInfo>\n" + "\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" + "\t\t\t<EntryPointSymbol>WinMainCRTStartup</EntryPointSymbol>\n" + "\t\t</Link>\n" + "\t\t<ResourceCompile>\n" + "\t\t\t<PreprocessorDefinitions>HAS_INCLUDE_SET;%(PreprocessorDefinitions)</PreprocessorDefinitions>\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 + '/' + "ScummVM_" + outputType + (isWin32 ? "" : "64") + getPropertiesExtension()).c_str()); + if (!properties) + error("Could not open \"" + setup.outputDir + '/' + "ScummVM_" + 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=\"ScummVM_Global" << (isWin32 ? "" : "64") << ".props\" />\n" + "\t</ImportGroup>\n" + "\t<PropertyGroup>\n" + "\t\t<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\n" + "\t\t<_PropertySheetDisplayName>ScummVM_" << 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<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(); +} + +#define OUTPUT_NASM_COMMAND_MSBUILD(config) \ + 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" \ + "\t\t\t<Outputs Condition=\"'$(Configuration)|$(Platform)'=='" << config << "|Win32'\">$(IntDir)" << (isDuplicate ? (*entry).prefix : "") << "%(Filename).obj;%(Outputs)</Outputs>\n"; + +#define OUPUT_FILES_MSBUILD(files, action) \ + if (!files.empty()) { \ + projectFile << "\t<ItemGroup>\n"; \ + for (std::list<FileEntry>::const_iterator entry = files.begin(); entry != files.end(); ++entry) { \ + projectFile << "\t\t<" action " Include=\"" << (*entry).path << "\" />\n"; \ + } \ + projectFile << "\t</ItemGroup>\n"; \ + } + +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; + } +} + + +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"; + + if (hasEnding((*entry).path, "base\\version.cpp")) + projectFile << "\t\t\t<PreprocessorDefinitions Condition=\"'$(Configuration)'=='Debug'\">SCUMMVM_REVISION#" $(SCUMMVM_REVISION_STRING)";%(PreprocessorDefinitions)</PreprocessorDefinitions>\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 + OUPUT_FILES_MSBUILD(_includeFiles, "ClInclude") + OUPUT_FILES_MSBUILD(_otherFiles, "None") + OUPUT_FILES_MSBUILD(_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"; + + OUTPUT_NASM_COMMAND_MSBUILD("Debug") + OUTPUT_NASM_COMMAND_MSBUILD("Analysis") + OUTPUT_NASM_COMMAND_MSBUILD("Release") + + projectFile << "\t\t</CustomBuild>\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 diff --git a/devtools/create_project/msbuild.h b/devtools/create_project/msbuild.h new file mode 100644 index 0000000000..fa5311734b --- /dev/null +++ b/devtools/create_project/msbuild.h @@ -0,0 +1,82 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef TOOLS_CREATE_PROJECT_MSBUILD_H +#define TOOLS_CREATE_PROJECT_MSBUILD_H + +#include "msvc.h" + +namespace CreateProjectTool { + +class MSBuildProvider : public MSVCProvider { +public: + MSBuildProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, const int version); + +protected: + void createProjectFile(const std::string &name, const std::string &uuid, const BuildSetup &setup, const std::string &moduleDir, + const StringList &includeList, const StringList &excludeList); + + void outputProjectSettings(std::ofstream &project, const std::string &name, const BuildSetup &setup, bool isRelease, bool isWin32, bool enableAnalysis); + + void writeFileListToProject(const FileNode &dir, std::ofstream &projectFile, const int indentation, + const StringList &duplicate, const std::string &objPrefix, const std::string &filePrefix); + + void writeReferences(std::ofstream &output); + + void outputGlobalPropFile(std::ofstream &properties, int bits, const StringList &defines, const std::string &prefix); + + void createBuildProp(const BuildSetup &setup, bool isRelease, bool isWin32, bool enableAnalysis); + + const char *getProjectExtension(); + const char *getPropertiesExtension(); + int getVisualStudioVersion(); + +private: + struct FileEntry { + std::string name; + std::string path; + std::string filter; + std::string prefix; + + bool operator<(const FileEntry& rhs) const { + return path.compare(rhs.path) == -1; // Not exactly right for alphabetical order, but good enough + } + }; + typedef std::list<FileEntry> FileEntries; + + std::list<std::string> _filters; // list of filters (we need to create a GUID for each filter id) + FileEntries _compileFiles; + FileEntries _includeFiles; + FileEntries _otherFiles; + FileEntries _asmFiles; + FileEntries _resourceFiles; + + void computeFileList(const FileNode &dir, const StringList &duplicate, const std::string &objPrefix, const std::string &filePrefix); + void createFiltersFile(const BuildSetup &setup, const std::string &name); +}; + +} // End of CreateProjectTool namespace + +#endif // TOOLS_CREATE_PROJECT_MSBUILD_H diff --git a/devtools/create_project/msvc.cpp b/devtools/create_project/msvc.cpp new file mode 100644 index 0000000000..e2fff59c46 --- /dev/null +++ b/devtools/create_project/msvc.cpp @@ -0,0 +1,177 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "msvc.h" + +#include <fstream> + +#include <algorithm> + +namespace CreateProjectTool { + +////////////////////////////////////////////////////////////////////////// +// MSVC Provider (Base class) +////////////////////////////////////////////////////////////////////////// +MSVCProvider::MSVCProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, const int version) + : ProjectProvider(global_warnings, project_warnings, version) { +} + +void MSVCProvider::createWorkspace(const BuildSetup &setup) { + UUIDMap::const_iterator svmUUID = _uuidMap.find("scummvm"); + if (svmUUID == _uuidMap.end()) + error("No UUID for \"scummvm\" project created"); + + const std::string svmProjectUUID = svmUUID->second; + assert(!svmProjectUUID.empty()); + + std::string solutionUUID = createUUID(); + + std::ofstream solution((setup.outputDir + '/' + "scummvm.sln").c_str()); + if (!solution) + error("Could not open \"" + setup.outputDir + '/' + "scummvm.sln\" for writing"); + + solution << "Microsoft Visual Studio Solution File, Format Version " << _version + 1 << ".00\n"; + solution << "# Visual Studio " << getVisualStudioVersion() << "\n"; + + solution << "Project(\"{" << solutionUUID << "}\") = \"scummvm\", \"scummvm" << getProjectExtension() << "\", \"{" << svmProjectUUID << "}\"\n"; + + // Project dependencies are moved to vcxproj files in Visual Studio 2010 + if (_version < 10) + writeReferences(solution); + + solution << "EndProject\n"; + + // Note we assume that the UUID map only includes UUIDs for enabled engines! + for (UUIDMap::const_iterator i = _uuidMap.begin(); i != _uuidMap.end(); ++i) { + if (i->first == "scummvm") + continue; + + solution << "Project(\"{" << solutionUUID << "}\") = \"" << i->first << "\", \"" << i->first << getProjectExtension() << "\", \"{" << i->second << "}\"\n" + << "EndProject\n"; + } + + solution << "Global\n" + "\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n" + "\t\tDebug|Win32 = Debug|Win32\n" + "\t\tAnalysis|Win32 = Analysis|Win32\n" + "\t\tRelease|Win32 = Release|Win32\n" + "\t\tDebug|x64 = Debug|x64\n" + "\t\tAnalysis|x64 = Analysis|x64\n" + "\t\tRelease|x64 = Release|x64\n" + "\tEndGlobalSection\n" + "\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n"; + + for (UUIDMap::const_iterator i = _uuidMap.begin(); i != _uuidMap.end(); ++i) { + solution << "\t\t{" << i->second << "}.Debug|Win32.ActiveCfg = Debug|Win32\n" + "\t\t{" << i->second << "}.Debug|Win32.Build.0 = Debug|Win32\n" + "\t\t{" << i->second << "}.Analysis|Win32.ActiveCfg = Analysis|Win32\n" + "\t\t{" << i->second << "}.Analysis|Win32.Build.0 = Analysis|Win32\n" + "\t\t{" << i->second << "}.Release|Win32.ActiveCfg = Release|Win32\n" + "\t\t{" << i->second << "}.Release|Win32.Build.0 = Release|Win32\n" + "\t\t{" << i->second << "}.Debug|x64.ActiveCfg = Debug|x64\n" + "\t\t{" << i->second << "}.Debug|x64.Build.0 = Debug|x64\n" + "\t\t{" << i->second << "}.Analysis|x64.ActiveCfg = Analysis|x64\n" + "\t\t{" << i->second << "}.Analysis|x64.Build.0 = Analysis|x64\n" + "\t\t{" << i->second << "}.Release|x64.ActiveCfg = Release|x64\n" + "\t\t{" << i->second << "}.Release|x64.Build.0 = Release|x64\n"; + } + + solution << "\tEndGlobalSection\n" + "\tGlobalSection(SolutionProperties) = preSolution\n" + "\t\tHideSolutionNode = FALSE\n" + "\tEndGlobalSection\n" + "EndGlobal\n"; +} + +void MSVCProvider::createOtherBuildFiles(const BuildSetup &setup) { + // Create the global property file + createGlobalProp(setup); + + // Create the configuration property files (for Debug and Release with 32 and 64bits versions) + // Note: we use the debug properties for the analysis configuration + createBuildProp(setup, true, false, false); + createBuildProp(setup, true, true, false); + createBuildProp(setup, false, false, false); + createBuildProp(setup, false, false, true); + createBuildProp(setup, false, true, false); + createBuildProp(setup, false, true, true); +} + +void MSVCProvider::createGlobalProp(const BuildSetup &setup) { + std::ofstream properties((setup.outputDir + '/' + "ScummVM_Global" + getPropertiesExtension()).c_str()); + if (!properties) + error("Could not open \"" + setup.outputDir + '/' + "ScummVM_Global" + getPropertiesExtension() + "\" for writing"); + + outputGlobalPropFile(properties, 32, setup.defines, convertPathToWin(setup.filePrefix)); + properties.close(); + + properties.open((setup.outputDir + '/' + "ScummVM_Global64" + getPropertiesExtension()).c_str()); + if (!properties) + error("Could not open \"" + setup.outputDir + '/' + "ScummVM_Global64" + getPropertiesExtension() + "\" for writing"); + + // HACK: We must disable the "nasm" feature for x64. To achieve that we must duplicate the feature list and + // recreate a define list. + FeatureList x64Features = setup.features; + setFeatureBuildState("nasm", x64Features, false); + StringList x64Defines = getFeatureDefines(x64Features); + StringList x64EngineDefines = getEngineDefines(setup.engines); + x64Defines.splice(x64Defines.end(), x64EngineDefines); + + // HACK: This definitly should not be here, but otherwise we would not define SDL_BACKEND for x64. + x64Defines.push_back("WIN32"); + x64Defines.push_back("SDL_BACKEND"); + + outputGlobalPropFile(properties, 64, x64Defines, convertPathToWin(setup.filePrefix)); +} + +std::string MSVCProvider::getPreBuildEvent() const { + std::string cmdLine = ""; + + cmdLine = "@echo off\n" + "echo Executing Pre-Build script...\n" + "echo.\n" + "@call "$(SolutionDir)../../devtools/create_project/scripts/prebuild.cmd" "$(SolutionDir)/../.."\n" + "EXIT /B0"; + + return cmdLine; +} + +std::string MSVCProvider::getPostBuildEvent(bool isWin32) const { + std::string cmdLine = ""; + + cmdLine = "@echo off\n" + "echo Executing Post-Build script...\n" + "echo.\n" + "@call "$(SolutionDir)../../devtools/create_project/scripts/postbuild.cmd" "$(SolutionDir)/../.." "$(OutDir)" "; + + cmdLine += (isWin32) ? "x86" : "x64"; + + cmdLine += "\n" + "EXIT /B0"; + + return cmdLine; +} + +} // End of CreateProjectTool namespace diff --git a/devtools/create_project/msvc.h b/devtools/create_project/msvc.h new file mode 100644 index 0000000000..f41ecc3aba --- /dev/null +++ b/devtools/create_project/msvc.h @@ -0,0 +1,100 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef TOOLS_CREATE_PROJECT_MSVC_H +#define TOOLS_CREATE_PROJECT_MSVC_H + +#include "create_project.h" + +namespace CreateProjectTool { + +class MSVCProvider : public ProjectProvider { +public: + MSVCProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, const int version); + +protected: + + void createWorkspace(const BuildSetup &setup); + + void createOtherBuildFiles(const BuildSetup &setup); + + /** + * Create the global project properties. + * + * @param setup Description of the desired build setup. + */ + void createGlobalProp(const BuildSetup &setup); + + /** + * Outputs a property file based on the input parameters. + * + * It can be easily used to create different global properties files + * for a 64 bit and a 32 bit version. It will also take care that the + * two platform configurations will output their files into different + * directories. + * + * @param properties File stream in which to write the property settings. + * @param bits Number of bits the platform supports. + * @param defines Defines the platform needs to have set. + * @param prefix File prefix, used to add additional include paths. + */ + virtual void outputGlobalPropFile(std::ofstream &properties, int bits, const StringList &defines, const std::string &prefix) = 0; + + /** + * Generates the project properties for debug and release settings. + * + * @param setup Description of the desired build setup. + * @param isRelease Type of property file + * @param isWin32 Bitness of property file + * @param enableAnalysis PREfast support + */ + virtual void createBuildProp(const BuildSetup &setup, bool isRelease, bool isWin32, bool enableAnalysis) = 0; + + /** + * Get the file extension for property files + */ + virtual const char *getPropertiesExtension() = 0; + + /** + * Get the Visual Studio version (used by the VS shell extension to launch the correct VS version) + */ + virtual int getVisualStudioVersion() = 0; + + /** + * Get the command line for the revision tool (shared between all Visual Studio based providers) + */ + std::string getPreBuildEvent() const; + + /** + * Get the command line for copying data files to the build directory + * + * @param isWin32 Bitness of property file + */ + std::string getPostBuildEvent(bool isWin32) const; +}; + +} // End of CreateProjectTool namespace + +#endif // TOOLS_CREATE_PROJECT_MSVC_H diff --git a/devtools/create_project/msvc10/create_project.sln b/devtools/create_project/msvc10/create_project.sln new file mode 100644 index 0000000000..69eeb8ed19 --- /dev/null +++ b/devtools/create_project/msvc10/create_project.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "create_project", "create_project.vcxproj", "{CF177559-077D-4A08-AABE-BE0FD35F6C63}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Debug|Win32.ActiveCfg = Debug|Win32 + {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Debug|Win32.Build.0 = Debug|Win32 + {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Release|Win32.ActiveCfg = Release|Win32 + {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/devtools/create_project/msvc10/create_project.vcxproj b/devtools/create_project/msvc10/create_project.vcxproj new file mode 100644 index 0000000000..532d6dba29 --- /dev/null +++ b/devtools/create_project/msvc10/create_project.vcxproj @@ -0,0 +1,117 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{CF177559-077D-4A08-AABE-BE0FD35F6C63}</ProjectGuid> + <RootNamespace>create_project</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <MinimalRebuild>true</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>EditAndContinue</DebugInformationFormat> + <DisableLanguageExtensions>false</DisableLanguageExtensions> + <DisableSpecificWarnings>4003;4512;4127</DisableSpecificWarnings> + </ClCompile> + <Link> + <AdditionalDependencies>Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies> + <GenerateDebugInformation>true</GenerateDebugInformation> + <TargetMachine>MachineX86</TargetMachine> + </Link> + <PostBuildEvent> + <Command>xcopy /Y $(TargetPath) $(SolutionDir)\..\..\..\dists\msvc10\ +xcopy /Y $(TargetPath) $(SolutionDir)\..\..\..\dists\msvc9\ +xcopy /Y $(TargetPath) $(SolutionDir)\..\..\..\dists\msvc8\ +xcopy /Y $(TargetPath) $(SolutionDir)\..\..\..\dists\codeblocks\</Command> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4003;4512;4127</DisableSpecificWarnings> + </ClCompile> + <Link> + <AdditionalDependencies>Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies> + <GenerateDebugInformation>true</GenerateDebugInformation> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <TargetMachine>MachineX86</TargetMachine> + </Link> + <PostBuildEvent> + <Command>xcopy /Y $(TargetPath) $(SolutionDir)\..\..\..\dists\msvc10\ +xcopy /Y $(TargetPath) $(SolutionDir)\..\..\..\dists\msvc9\ +xcopy /Y $(TargetPath) $(SolutionDir)\..\..\..\dists\msvc8\ +xcopy /Y $(TargetPath) $(SolutionDir)\..\..\..\dists\codeblocks\</Command> + </PostBuildEvent> + <PreBuildEvent> + <Command> + </Command> + </PreBuildEvent> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\codeblocks.cpp" /> + <ClCompile Include="..\create_project.cpp" /> + <ClCompile Include="..\msbuild.cpp" /> + <ClCompile Include="..\msvc.cpp" /> + <ClCompile Include="..\visualstudio.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\codeblocks.h" /> + <ClInclude Include="..\create_project.h" /> + <ClInclude Include="..\msbuild.h" /> + <ClInclude Include="..\msvc.h" /> + <ClInclude Include="..\visualstudio.h" /> + </ItemGroup> + <ItemGroup> + <None Include="..\scripts\postbuild.cmd" /> + <None Include="..\scripts\prebuild.cmd" /> + <None Include="..\scripts\revision.vbs" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/devtools/create_project/msvc10/create_project.vcxproj.filters b/devtools/create_project/msvc10/create_project.vcxproj.filters new file mode 100644 index 0000000000..7922e1e6f7 --- /dev/null +++ b/devtools/create_project/msvc10/create_project.vcxproj.filters @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Header Files"> + <UniqueIdentifier>{2e3580c8-ec3a-4c81-8351-b668c668db2a}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files"> + <UniqueIdentifier>{31aaf58c-d3cb-4ed6-8eca-163b4a9b31a6}</UniqueIdentifier> + </Filter> + <Filter Include="scripts"> + <UniqueIdentifier>{f980f6fb-41b6-4161-b035-58b200c85cad}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\codeblocks.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\create_project.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\msvc.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\msbuild.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\visualstudio.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\codeblocks.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\create_project.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\msvc.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\msbuild.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\visualstudio.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <None Include="..\scripts\prebuild.cmd"> + <Filter>scripts</Filter> + </None> + <None Include="..\scripts\revision.vbs"> + <Filter>scripts</Filter> + </None> + <None Include="..\scripts\postbuild.cmd"> + <Filter>scripts</Filter> + </None> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/devtools/create_project/msvc8/create_project.sln b/devtools/create_project/msvc8/create_project.sln new file mode 100644 index 0000000000..4a0152f33f --- /dev/null +++ b/devtools/create_project/msvc8/create_project.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "create_project", "create_project.vcproj", "{CF177559-077D-4A08-AABE-BE0FD35F6C63}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Debug|Win32.ActiveCfg = Debug|Win32 + {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Debug|Win32.Build.0 = Debug|Win32 + {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Release|Win32.ActiveCfg = Release|Win32 + {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/devtools/create_project/msvc8/create_project.vcproj b/devtools/create_project/msvc8/create_project.vcproj new file mode 100644 index 0000000000..bc3b2437ac --- /dev/null +++ b/devtools/create_project/msvc8/create_project.vcproj @@ -0,0 +1,235 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="create_project" + ProjectGUID="{CF177559-077D-4A08-AABE-BE0FD35F6C63}" + RootNamespace="create_project" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + WarningLevel="4" + DebugInformationFormat="4" + DisableSpecificWarnings="4003;4512;4127" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Rpcrt4.lib" + GenerateDebugInformation="true" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="2" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + EnableIntrinsicFunctions="true" + RuntimeLibrary="2" + EnableFunctionLevelLinking="true" + WarningLevel="3" + DebugInformationFormat="3" + DisableSpecificWarnings="4003;4512;4127" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Rpcrt4.lib" + GenerateDebugInformation="true" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath="..\create_project.cpp" + > + </File> + <File + RelativePath="..\codeblocks.cpp" + > + </File> + <File + RelativePath="..\msvc.cpp" + > + </File> + <File + RelativePath="..\msbuild.cpp" + > + </File> + <File + RelativePath="..\visualstudio.cpp" + > + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + <File + RelativePath="..\create_project.h" + > + </File> + <File + RelativePath="..\codeblocks.h" + > + </File> + <File + RelativePath="..\msvc.h" + > + </File> + <File + RelativePath="..\msbuild.h" + > + </File> + <File + RelativePath="..\visualstudio.h" + > + </File> + </Filter> + <Filter + Name="Scripts" + Filter="vbs;cmd" + UniqueIdentifier="{45B110C8-4C64-4677-8ED6-F9A93C6D55A0}" + > + <File + RelativePath="..\scripts\prebuild.cmd" + > + </File> + <File + RelativePath="..\scripts\postbuild.cmd" + > + </File> + <File + RelativePath="..\scripts\revision.vbs" + > + </File> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/devtools/create_project/msvc9/create_project.sln b/devtools/create_project/msvc9/create_project.sln new file mode 100644 index 0000000000..df754e1d78 --- /dev/null +++ b/devtools/create_project/msvc9/create_project.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "create_project", "create_project.vcproj", "{CF177559-077D-4A08-AABE-BE0FD35F6C63}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Debug|Win32.ActiveCfg = Debug|Win32 + {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Debug|Win32.Build.0 = Debug|Win32 + {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Release|Win32.ActiveCfg = Release|Win32 + {CF177559-077D-4A08-AABE-BE0FD35F6C63}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/devtools/create_project/msvc9/create_project.vcproj b/devtools/create_project/msvc9/create_project.vcproj new file mode 100644 index 0000000000..c89b88a1c9 --- /dev/null +++ b/devtools/create_project/msvc9/create_project.vcproj @@ -0,0 +1,236 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="9.00" + Name="create_project" + ProjectGUID="{CF177559-077D-4A08-AABE-BE0FD35F6C63}" + RootNamespace="create_project" + TargetFrameworkVersion="196613" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + WarningLevel="4" + DebugInformationFormat="4" + DisableSpecificWarnings="4003;4512;4127" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Rpcrt4.lib" + GenerateDebugInformation="true" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="2" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + EnableIntrinsicFunctions="true" + RuntimeLibrary="2" + EnableFunctionLevelLinking="true" + WarningLevel="3" + DebugInformationFormat="3" + DisableSpecificWarnings="4003;4512;4127" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Rpcrt4.lib" + GenerateDebugInformation="true" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath="..\create_project.cpp" + > + </File> + <File + RelativePath="..\codeblocks.cpp" + > + </File> + <File + RelativePath="..\msvc.cpp" + > + </File> + <File + RelativePath="..\msbuild.cpp" + > + </File> + <File + RelativePath="..\visualstudio.cpp" + > + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + <File + RelativePath="..\create_project.h" + > + </File> + <File + RelativePath="..\codeblocks.h" + > + </File> + <File + RelativePath="..\msvc.h" + > + </File> + <File + RelativePath="..\msbuild.h" + > + </File> + <File + RelativePath="..\visualstudio.h" + > + </File> + </Filter> + <Filter + Name="Scripts" + Filter="vbs;cmd" + UniqueIdentifier="{45B110C8-4C64-4677-8ED6-F9A93C6D55A0}" + > + <File + RelativePath="..\scripts\prebuild.cmd" + > + </File> + <File + RelativePath="..\scripts\postbuild.cmd" + > + </File> + <File + RelativePath="..\scripts\revision.vbs" + > + </File> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/devtools/create_project/scripts/postbuild.cmd b/devtools/create_project/scripts/postbuild.cmd new file mode 100644 index 0000000000..5c2bd8a1ad --- /dev/null +++ b/devtools/create_project/scripts/postbuild.cmd @@ -0,0 +1,45 @@ +REM @echo off
+
+REM ---------------------------------------------------------------
+REM -- Post-Build Script
+REM ---------------------------------------------------------------
+REM
+REM Copy engine data, themes, translation and required dlls to the
+REM output folder.
+REM
+REM Expected parameters
+REM Root folder
+REM Output folder
+REM Architecture
+
+if "%~1"=="" goto error_input
+if "%~2"=="" goto error_output
+if "%~3"=="" goto error_arch
+
+echo Copying data files
+echo.
+
+REM Copy files
+xcopy /F /Y "%~1/dists/engine-data/*.dat" %~2 > NUL 2>&1
+xcopy /F /Y "%~1/dists/engine-data/*.tbl" %~2 > NUL 2>&1
+xcopy /F /Y "%~1/dists/engine-data/*.cpt" %~2 > NUL 2>&1
+xcopy /F /Y "%~1/dists/engine-data/README" %~2 > NUL 2>&1
+xcopy /F /Y "%~1/gui/themes/*.zip" %~2 > NUL 2>&1
+xcopy /F /Y "%~1/gui/themes/translations.dat" %~2 > NUL 2>&1
+xcopy /F /Y "%SCUMMVM_LIBS%/lib/%~3/SDL.dll" %~2 > NUL 2>&1
+goto done
+
+:error_output
+echo Invalid root folder (%~1)!
+goto done
+
+:error_output
+echo Invalid output folder (%~2)!
+goto done
+
+:error_arch
+echo Invalid arch parameter (was: %~3, allowed: x86, x64)!
+goto done
+
+:done
+exit /B0
diff --git a/devtools/create_project/scripts/prebuild.cmd b/devtools/create_project/scripts/prebuild.cmd new file mode 100644 index 0000000000..b824f0d5a0 --- /dev/null +++ b/devtools/create_project/scripts/prebuild.cmd @@ -0,0 +1,27 @@ +@echo off
+
+REM ---------------------------------------------------------------
+REM -- Pre-Build Script
+REM ---------------------------------------------------------------
+REM
+REM Generate file with proper revision number
+REM
+REM Expected parameters
+REM Root folder
+
+if "%~1"=="" goto error_input
+
+REM Run the revision script
+@call cscript "%~1/devtools/create_project/scripts/revision.vbs" %~1 1>NUL
+if not %errorlevel% == 0 goto error_script
+goto done
+
+:error_output
+echo Invalid root folder (%~1)!
+goto done
+
+:error_script:
+echo An error occured while running the revision script!
+
+:done
+exit /B0
diff --git a/devtools/create_project/scripts/revision.vbs b/devtools/create_project/scripts/revision.vbs new file mode 100644 index 0000000000..851185371b --- /dev/null +++ b/devtools/create_project/scripts/revision.vbs @@ -0,0 +1,445 @@ +' +' 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, version 2 +' of the License. +' +' 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. +' +' Based off OpenTTD determineversion.vbs (released under GPL version 2) +' +'/ + +Option Explicit + +' Working copy check priority: +' True: TortoiseSVN -> SVN -> Git -> Hg +' False: Git -> Hg -> TortoiseSVN -> SVN +Dim prioritySVN: prioritySVN = False + +Dim FSO : Set FSO = CreateObject("Scripting.FileSystemObject") +Dim WshShell : Set WshShell = CreateObject("WScript.Shell") + +' Folders +Dim rootFolder : rootFolder = "" + +' Info variables +Dim tool : tool = "" +Dim branch : branch = "trunk" +Dim revision : revision = "" +Dim modified : modified = False + +' Parse our command line arguments +If ParseCommandLine() Then + ' Determine the revision and update the props file with the revision numbers + DetermineRevision() +End If + +'//////////////////////////////////////////////////////////////// +'// Revision checking +'//////////////////////////////////////////////////////////////// +Sub DetermineRevision() + Wscript.StdErr.WriteLine "Determining current revision:" + + ' Set the current directory to the root folder + WshShell.CurrentDirectory = rootFolder + + ' Try until we find a proper working copy + If (prioritySVN) Then + If Not DetermineTortoiseSVNVersion() Then + If Not DetermineSVNVersion() Then + If Not DetermineGitVersion() Then + If Not DetermineHgVersion() Then + Wscript.StdErr.WriteLine "Could not determine the current revision, skipping..." + Exit Sub + End If + End If + End If + End If + Else + If Not DetermineGitVersion() Then + If Not DetermineHgVersion() Then + If Not DetermineTortoiseSVNVersion() Then + If Not DetermineSVNVersion() Then + Wscript.StdErr.WriteLine "Could not determine the current revision, skipping..." + Exit Sub + End If + End If + End If + End If + End If + + Wscript.StdErr.WriteLine "Found revision " & revision & " on branch " & branch & vbCrLf + + ' Setup our revision string + Dim revisionString : revisionString = "r" & revision + + If (modified) Then + revisionString = revisionString & " M" + End If + + ' If we are not on trunk, add the branch name to the revision string + If (branch <> "trunk" And branch <> "") Then + revisionString = revisionString & " (" & branch & ")" + End If + + ' Add the DVCS name at the end + revisionString = revisionString & " - " & tool + + ' Setup an environment variable with the revision string + Dim Env: Set Env = WshShell.Environment("User") + Env.item("SCUMMVM_REVISION_STRING") = revisionString +End Sub + +Function DetermineTortoiseSVNVersion() + Err.Clear + On Error Resume Next + DetermineTortoiseSVNVersion = False + Wscript.StdErr.Write " TortoiseSVN... " + tool = "svn" + + ' Get the directory where TortoiseSVN (should) reside(s) + Dim sTortoise + + ' First, try with 32-bit architecture + sTortoise = ReadRegistryKey("HKLM", "SOFTWARE\TortoiseSVN", "Directory", 32) + + If sTortoise = "" Or IsNull(sTortoise) Then + ' No 32-bit version of TortoiseSVN installed, try 64-bit version (doesn't hurt on 32-bit machines, it returns nothing or is ignored) + sTortoise = ReadRegistryKey("HKLM", "SOFTWARE\TortoiseSVN", "Directory", 64) + End If + + ' Check if Tortoise is present + If sTortoise = "" Then + Wscript.StdErr.WriteLine "TortoiseSVN not installed!" + Exit Function + End If + + ' If TortoiseSVN is installed, try to get the revision number + Dim SubWCRev : Set SubWCRev = WScript.CreateObject("SubWCRev.object") + SubWCRev.GetWCInfo rootFolder, 0, 0 + + ' Check if this is a working copy + If Not SubWCRev.IsSvnItem Then + Wscript.StdErr.WriteLine "Not a working copy!" + Exit Function + End If + + revision = SubWCRev.Revision + + ' Check for modifications + If SubWCRev.HasModifications Then modified = True + + If revision = "" Then + Wscript.StdErr.WriteLine "No revision found!" + Exit Function + End If + + DetermineTortoiseSVNVersion = True +End Function + +Function DetermineSVNVersion() + Err.Clear + On Error Resume Next + DetermineSVNVersion = False + Wscript.StdErr.Write " SVN... " + tool = "svn" + + ' Set the environment to English + WshShell.Environment("PROCESS")("LANG") = "en" + + ' Do we have subversion installed? Check immediately whether we've got a modified WC. + Dim oExec: Set oExec = WshShell.Exec("svnversion " & rootFolder) + If Err.Number <> 0 Then + Wscript.StdErr.WriteLine "SVN not installed!" + Exit Function + End If + + ' Wait till the application is finished ... + Do While oExec.Status = 0 + WScript.Sleep 100 + Loop + + Dim line: line = OExec.StdOut.ReadLine() + If line = "exported" Then + Wscript.StdErr.WriteLine "Not a working copy!" + Exit Function + End If + + If InStr(line, "M") Then + modified = True + End If + + ' And use svn info to get the correct revision and branch information. + Set oExec = WshShell.Exec("svn info " & rootFolder) + + If Err.Number <> 0 Then + Wscript.StdErr.WriteLine "No revision found!" + Exit Function + End If + + Do + line = OExec.StdOut.ReadLine() + If InStr(line, "Last Changed Rev") Then + revision = Mid(line, 19) + End If + Loop While Not OExec.StdOut.atEndOfStream + + If revision = 0 Then + Wscript.StdErr.WriteLine "No revision found!" + Exit Function + End If + + DetermineSVNVersion = True +End Function + +Function DetermineGitVersion() + Err.Clear + On Error Resume Next + DetermineGitVersion = False + Wscript.StdErr.Write " Git... " + tool = "git" + + ' First check if we have both a .git & .svn folders (in case hg-git has been set up to have the git folder at the working copy level) + If FSO.FolderExists(rootFolder & "/.git") And FSO.FolderExists(rootFolder & "/.hg") Then + Wscript.StdErr.WriteLine "Mercurial clone with git repository in tree!" + Exit Function + End If + + ' Set the environment to English + WshShell.Environment("PROCESS")("LANG") = "en" + + ' Detect if we are using msysgit that has a cmd script in the path instead of an exe... + Dim gitPath : gitPath = "git " + Dim oExec : Set oExec = WshShell.Exec("git") + If Err.Number <> 0 Then + gitPath = "git.cmd " + End If + + Err.Clear + Set oExec = WshShell.Exec(gitPath & "rev-parse --verify HEAD") + If Err.Number <> 0 Then + Wscript.StdErr.WriteLine "Git not installed!" + Exit Function + End If + + ' Wait till the application is finished ... + Do While oExec.Status = 0 + WScript.Sleep 100 + Loop + + If oExec.ExitCode <> 0 Then + Wscript.StdErr.WriteLine "Error parsing git revision!" + Exit Function + End If + + ' Get the version hash + Dim hash: hash = oExec.StdOut.ReadLine() + + ' Make sure index is in sync with disk + Set oExec = WshShell.Exec(gitPath & "update-index --refresh") + If Err.Number = 0 Then + ' Wait till the application is finished ... + Do While oExec.Status = 0 + WScript.Sleep 100 + Loop + End If + + Set oExec = WshShell.Exec(gitPath & "diff-index --exit-code --quiet HEAD " & rootFolder) + If oExec.ExitCode <> 0 Then + Wscript.StdErr.WriteLine "Error parsing git revision!" + Exit Function + End If + + ' Wait till the application is finished ... + Do While oExec.Status = 0 + WScript.Sleep 100 + Loop + + If oExec.ExitCode = 1 Then + modified = True + End If + + ' Get branch name + Set oExec = WshShell.Exec(gitPath & "symbolic-ref HEAD") + If Err.Number = 0 Then + Dim line: line = oExec.StdOut.ReadLine() + line = Mid(line, InStrRev(line, "/") + 1) + If line <> "master" Then + branch = line + End If + End If + + ' Check for svn clones + Set oExec = WshShell.Exec(gitPath & "log --pretty=format:%s --grep=" & Chr(34) & "^(svn r[0-9]*)" & Chr(34) & " -1 " & rootFolder) + if Err.Number = 0 Then + revision = Mid(oExec.StdOut.ReadLine(), 7) + revision = Mid(revision, 1, InStr(revision, ")") - 1) + tool = "svn-git" + End If + + ' No revision? Maybe it is a custom git-svn clone + If revision = "" Then + Err.Clear + Set oExec = WshShell.Exec(gitPath & "log --pretty=format:%b --grep=" & Chr(34) & "git-svn-id:.*@[0-9]*" & Chr(34) & " -1 " & rootFolder) + If Err.Number = 0 Then + revision = oExec.StdOut.ReadLine() + revision = Mid(revision, InStr(revision, "@") + 1) + revision = Mid(revision, 1, InStr(revision, " ") - 1) + tool = "svn-git" + End If + End If + + ' Fallback to abbreviated revision number + If revision = "" Then + revision = Mid(hash, 1, 8) + End If + + DetermineGitVersion = True +End Function + +Function DetermineHgVersion() + Err.Clear + On Error Resume Next + DetermineHgVersion = False + Wscript.StdErr.Write " Mercurial... " + tool = "hg" + + Err.Clear + Dim oExec: Set oExec = WshShell.Exec("hg parents --template ""{rev}:{node|short}""") + If Err.Number <> 0 Then + Wscript.StdErr.WriteLine "Mercurial not installed!" + Exit Function + End If + + ' Wait till the application is finished ... + Do While oExec.Status = 0 + WScript.Sleep 100 + Loop + + If oExec.ExitCode <> 0 Then + Wscript.StdErr.WriteLine "Error parsing mercurial revision!" + Exit Function + End If + + Dim info : info = Split(OExec.StdOut.ReadLine(), ":") + Dim version : version = info(0) + Dim hash : hash = info(1) + + Set oExec = WshShell.Exec("hg status " & rootFolder) + If Err.Number <> 0 Then + Wscript.StdErr.WriteLine "Error parsing mercurial revision!" + Exit Function + End If + + ' Check for modifications + Do + line = OExec.StdOut.ReadLine() + If Len(line) > 0 And Mid(line, 1, 1) <> "?" Then + modified = True + Exit Do + End If + Loop While Not OExec.StdOut.atEndOfStream + + ' Check for branch + Set oExec = WshShell.Exec("hg branch") + If Err.Number = 0 Then + line = OExec.StdOut.ReadLine() + If line <> "default" Then + branch = line + End If + End If + + ' Check for SVN clone + Set oExec = WshShell.Exec("hg log -f -l 1 --template ""{svnrev}\n"" --cwd " & rootFolder) + If Err.Number = 0 Then + revision = Mid(OExec.StdOut.ReadLine(), 7) + revision = Mid(revision, 1, InStr(revision, ")") - 1) + tool = "svn-hg" + End If + + ' Fallback to abbreviated revision number + If revision = "" Then + revision = version & "(" & hash & ")" + End If + + DetermineHgVersion = True +End Function + +'//////////////////////////////////////////////////////////////// +'// Utilities +'//////////////////////////////////////////////////////////////// +Function ParseCommandLine() + ParseCommandLine = True + + If Wscript.Arguments.Count <> 1 Then + Wscript.StdErr.WriteLine "[Error] Invalid number of arguments (was: " & Wscript.Arguments.Count & ", expected: 1)" + + ParseCommandLine = False + Exit Function + End If + + ' Get our arguments + rootFolder = Wscript.Arguments.Item(0) + + ' Check that the folders are valid + If Not FSO.FolderExists(rootFolder) Then + Wscript.StdErr.WriteLine "[Error] Invalid root folder (" & rootFolder & ")" + + ParseCommandLine = False + Exit Function + End If + + ' Set absolute path + rootFolder = FSO.GetAbsolutePathName(rootFolder) +End Function + +Function ReadRegistryKey(shive, subkey, valuename, architecture) + Dim hiveKey, objCtx, objLocator, objServices, objReg, Inparams, Outparams + + ' First, get the Registry Provider for the requested architecture + Set objCtx = CreateObject("WbemScripting.SWbemNamedValueSet") + objCtx.Add "__ProviderArchitecture", architecture ' Must be 64 of 32 + Set objLocator = CreateObject("Wbemscripting.SWbemLocator") + Set objServices = objLocator.ConnectServer("","root\default","","",,,,objCtx) + Set objReg = objServices.Get("StdRegProv") + + ' Check the hive and give it the right value + Select Case shive + Case "HKCR", "HKEY_CLASSES_ROOT" + hiveKey = &h80000000 + Case "HKCU", "HKEY_CURRENT_USER" + hiveKey = &H80000001 + Case "HKLM", "HKEY_LOCAL_MACHINE" + hiveKey = &h80000002 + Case "HKU", "HKEY_USERS" + hiveKey = &h80000003 + Case "HKCC", "HKEY_CURRENT_CONFIG" + hiveKey = &h80000005 + Case "HKDD", "HKEY_DYN_DATA" ' Only valid for Windows 95/98 + hiveKey = &h80000006 + Case Else + MsgBox "Hive not valid (ReadRegistryKey)" + End Select + + Set Inparams = objReg.Methods_("GetStringValue").Inparameters + Inparams.Hdefkey = hiveKey + Inparams.Ssubkeyname = subkey + Inparams.Svaluename = valuename + Set Outparams = objReg.ExecMethod_("GetStringValue", Inparams,,objCtx) + + ReadRegistryKey = Outparams.SValue +End Function diff --git a/devtools/create_project/visualstudio.cpp b/devtools/create_project/visualstudio.cpp new file mode 100644 index 0000000000..2b7c8908cb --- /dev/null +++ b/devtools/create_project/visualstudio.cpp @@ -0,0 +1,378 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "visualstudio.h" + +#include <fstream> + +#include <algorithm> + +namespace CreateProjectTool { + +////////////////////////////////////////////////////////////////////////// +// Visual Studio Provider (Visual Studio 2005 & 2008) +////////////////////////////////////////////////////////////////////////// + +VisualStudioProvider::VisualStudioProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, const int version) + : MSVCProvider(global_warnings, project_warnings, version) { +} + +const char *VisualStudioProvider::getProjectExtension() { + return ".vcproj"; +} + +const char *VisualStudioProvider::getPropertiesExtension() { + return ".vsprops"; +} + +int VisualStudioProvider::getVisualStudioVersion() { + if (_version == 9) + return 2008; + + if (_version == 8) + return 2005; + + error("Unsupported version passed to createScummVMSolution"); +} + +#define OUTPUT_CONFIGURATION_SCUMMVM(config, platform, props) { \ + project << "\t\t<Configuration Name=\"" << config << "|" << platform << "\" ConfigurationType=\"1\" InheritedPropertySheets=\".\\ScummVM_" << config << props << ".vsprops\">\n" \ + "\t\t\t<Tool\tName=\"VCCLCompilerTool\" DisableLanguageExtensions=\"false\" />\n" \ + "\t\t\t<Tool\tName=\"VCLinkerTool\" OutputFile=\"$(OutDir)/scummvm.exe\"\n" \ + "\t\t\t\tAdditionalDependencies=\"" << libraries << "\"\n" \ + "\t\t\t/>\n" \ + "\t\t</Configuration>\n"; \ +} + +#define OUTPUT_CONFIGURATION_SCUMMVM_DEBUG(config, platform, props, isWin32) { \ + project << "\t\t<Configuration Name=\"" << config << "|" << platform << "\" ConfigurationType=\"1\" InheritedPropertySheets=\".\\ScummVM_" << config << props << ".vsprops\">\n" \ + "\t\t\t<Tool\tName=\"VCCLCompilerTool\" DisableLanguageExtensions=\"false\" />\n" \ + "\t\t\t<Tool\tName=\"VCLinkerTool\" OutputFile=\"$(OutDir)/scummvm.exe\"\n" \ + "\t\t\t\tAdditionalDependencies=\"" << libraries << "\"\n" \ + "\t\t\t/>\n"; \ + if (setup.runBuildEvents) { \ + project << "\t\t\t<Tool\tName=\"VCPreBuildEventTool\"\n" \ + "\t\t\t\tCommandLine=\"" << getPreBuildEvent() << "\"\n" \ + "\t\t\t/>\n" \ + "\t\t\t<Tool\tName=\"VCPostBuildEventTool\"\n" \ + "\t\t\t\tCommandLine=\"" << getPostBuildEvent(isWin32) << "\"\n" \ + "\t\t\t/>\n"; \ + } \ + project << "\t\t</Configuration>\n"; \ +} + +#define OUTPUT_CONFIGURATION(config, platform, props) { \ + project << "\t\t<Configuration Name=\"" << config << "|" << platform << "\" ConfigurationType=\"4\" InheritedPropertySheets=\".\\ScummVM_" << config << props << ".vsprops\">\n" \ + "\t\t\t<Tool Name=\"VCCLCompilerTool\" "<< toolConfig << "/>\n" \ + "\t\t</Configuration>\n"; \ +} + +void VisualStudioProvider::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=\"windows-1252\"?>\n" + "<VisualStudioProject\n" + "\tProjectType=\"Visual C++\"\n" + "\tVersion=\"" << _version << ".00\"\n" + "\tName=\"" << name << "\"\n" + "\tProjectGUID=\"{" << uuid << "}\"\n" + "\tRootNamespace=\"" << name << "\"\n" + "\tKeyword=\"Win32Proj\"\n"; + + if (_version >= 9) + project << "\tTargetFrameworkVersion=\"131072\"\n"; + + project << "\t>\n" + "\t<Platforms>\n" + "\t\t<Platform Name=\"Win32\" />\n" + "\t\t<Platform Name=\"x64\" />\n" + "\t</Platforms>\n" + "\t<Configurations>\n"; + + // Check for project-specific warnings: + std::map< std::string, std::list<std::string> >::iterator warningsIterator = _projectWarnings.find(name); + + if (name == "scummvm") { + std::string libraries; + + for (StringList::const_iterator i = setup.libraries.begin(); i != setup.libraries.end(); ++i) + libraries += ' ' + *i + ".lib"; + + // Win32 + OUTPUT_CONFIGURATION_SCUMMVM_DEBUG("Debug", "Win32", "", true); + OUTPUT_CONFIGURATION_SCUMMVM_DEBUG("Analysis", "Win32", "", true); + OUTPUT_CONFIGURATION_SCUMMVM("Release", "Win32", ""); + + // x64 + // For 'x64' we must disable NASM support. Usually we would need to disable the "nasm" feature for that and + // re-create the library list, BUT since NASM doesn't link any additional libraries, we can just use the + // libraries list created for IA-32. If that changes in the future, we need to adjust this part! + OUTPUT_CONFIGURATION_SCUMMVM_DEBUG("Debug", "x64", "64", true); + OUTPUT_CONFIGURATION_SCUMMVM_DEBUG("Analysis", "x64", "64", true); + OUTPUT_CONFIGURATION_SCUMMVM("Release", "x64", "64"); + + } else { + std::string warnings = ""; + if (warningsIterator != _projectWarnings.end()) + for (StringList::const_iterator i = warningsIterator->second.begin(); i != warningsIterator->second.end(); ++i) + warnings += *i + ';'; + + std::string toolConfig; + toolConfig = (!warnings.empty() ? "DisableSpecificWarnings=\"" + warnings + "\"" : ""); + toolConfig += (name == "tinsel" ? "DebugInformationFormat=\"3\" " : ""); + toolConfig += (name == "sword25" ? "DisableLanguageExtensions=\"false\" " : ""); + + // Win32 + OUTPUT_CONFIGURATION("Debug", "Win32", ""); + OUTPUT_CONFIGURATION("Analysis", "Win32", ""); + OUTPUT_CONFIGURATION("Release", "Win32", ""); + OUTPUT_CONFIGURATION("Debug", "x64", "64"); + OUTPUT_CONFIGURATION("Analysis", "x64", "64"); + OUTPUT_CONFIGURATION("Release", "x64", "64"); + } + + project << "\t</Configurations>\n" + "\t<Files>\n"; + + 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); + + project << "\t</Files>\n" + "</VisualStudioProject>\n"; +} + +void VisualStudioProvider::writeReferences(std::ofstream &output) { + output << "\tProjectSection(ProjectDependencies) = postProject\n"; + + for (UUIDMap::const_iterator i = _uuidMap.begin(); i != _uuidMap.end(); ++i) { + if (i->first == "scummvm") + continue; + + output << "\t\t{" << i->second << "} = {" << i->second << "}\n"; + } + + output << "\tEndProjectSection\n"; +} + +void VisualStudioProvider::outputGlobalPropFile(std::ofstream &properties, int bits, const StringList &defines, const std::string &prefix) { + 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) { + if (i != defines.begin()) + definesList += ';'; + definesList += *i; + } + + properties << "<?xml version=\"1.0\" encoding=\"Windows-1252\"?>\n" + "<VisualStudioPropertySheet\n" + "\tProjectType=\"Visual C++\"\n" + "\tVersion=\"8.00\"\n" + "\tName=\"ScummVM_Global\"\n" + "\tOutputDirectory=\"$(ConfigurationName)" << bits << "\"\n" + "\tIntermediateDirectory=\"$(ConfigurationName)" << bits << "/$(ProjectName)\"\n" + "\t>\n" + "\t<Tool\n" + "\t\tName=\"VCCLCompilerTool\"\n" + "\t\tDisableLanguageExtensions=\"true\"\n" + "\t\tDisableSpecificWarnings=\"" << warnings << "\"\n" + "\t\tAdditionalIncludeDirectories=\"" << prefix << ";" << prefix << "\\engines;$(SCUMMVM_LIBS)\\include\"\n" + "\t\tPreprocessorDefinitions=\"" << definesList << "\"\n" + "\t\tExceptionHandling=\"0\"\n" + "\t\tRuntimeTypeInfo=\"false\"\n" + "\t\tWarningLevel=\"4\"\n" + "\t\tWarnAsError=\"false\"\n" + "\t\tCompileAs=\"0\"\n" + "\t\t/>\n" + "\t<Tool\n" + "\t\tName=\"VCLibrarianTool\"\n" + "\t\tIgnoreDefaultLibraryNames=\"\"\n" + "\t/>\n" + "\t<Tool\n" + "\t\tName=\"VCLinkerTool\"\n" + "\t\tIgnoreDefaultLibraryNames=\"\"\n" + "\t\tSubSystem=\"1\"\n" + "\t\tEntryPointSymbol=\"WinMainCRTStartup\"\n" + "\t\tAdditionalLibraryDirectories=\"$(SCUMMVM_LIBS)\\lib\\" << ((bits == 32) ? "x86" : "x64") << "\"\n" + "\t/>\n" + "\t<Tool\n" + "\t\tName=\"VCResourceCompilerTool\"\n" + "\t\tPreprocessorDefinitions=\"HAS_INCLUDE_SET\"\n" + "\t\tAdditionalIncludeDirectories=\"" << prefix << "\"\n" + "\t/>\n" + "</VisualStudioPropertySheet>\n"; + + properties.flush(); +} + +void VisualStudioProvider::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 + '/' + "ScummVM_" + outputType + (isWin32 ? "" : "64") + getPropertiesExtension()).c_str()); + if (!properties) + error("Could not open \"" + setup.outputDir + '/' + "ScummVM_" + outputType + (isWin32 ? "" : "64") + getPropertiesExtension() + "\" for writing"); + + properties << "<?xml version=\"1.0\" encoding=\"Windows-1252\"?>\n" + "<VisualStudioPropertySheet\n" + "\tProjectType=\"Visual C++\"\n" + "\tVersion=\"8.00\"\n" + "\tName=\"ScummVM_" << outputType << outputBitness << "\"\n" + "\tInheritedPropertySheets=\".\\ScummVM_Global" << (isWin32 ? "" : "64") << ".vsprops\"\n" + "\t>\n" + "\t<Tool\n" + "\t\tName=\"VCCLCompilerTool\"\n"; + + if (isRelease) { + properties << "\t\tEnableIntrinsicFunctions=\"true\"\n" + "\t\tWholeProgramOptimization=\"true\"\n" + "\t\tPreprocessorDefinitions=\"WIN32;RELEASE_BUILD\"\n" + "\t\tStringPooling=\"true\"\n" + "\t\tBufferSecurityCheck=\"false\"\n" + "\t\tDebugInformationFormat=\"0\"\n" + "\t\tAdditionalOption=\"" << (enableAnalysis ? "/analyze" : "") << "\"\n" + "\t/>\n" + "\t<Tool\n" + "\t\tName=\"VCLinkerTool\"\n" + "\t\tLinkIncremental=\"1\"\n" + "\t\tIgnoreDefaultLibraryNames=\"\"\n" + "\t\tSetChecksum=\"true\"\n"; + } else { + properties << "\t\tOptimization=\"0\"\n" + "\t\tPreprocessorDefinitions=\"WIN32\"\n" + "\t\tMinimalRebuild=\"true\"\n" + "\t\tBasicRuntimeChecks=\"3\"\n" + "\t\tRuntimeLibrary=\"1\"\n" + "\t\tEnableFunctionLevelLinking=\"true\"\n" + "\t\tWarnAsError=\"false\"\n" + "\t\tDebugInformationFormat=\"" << (isWin32 ? "4" : "3") << "\"\n" // For x64 format "4" (Edit and continue) is not supported, thus we default to "3" + "\t\tAdditionalOption=\"" << (enableAnalysis ? "/analyze" : "") << "\"\n" + "\t/>\n" + "\t<Tool\n" + "\t\tName=\"VCLinkerTool\"\n" + "\t\tLinkIncremental=\"2\"\n" + "\t\tGenerateDebugInformation=\"true\"\n" + "\t\tIgnoreDefaultLibraryNames=\"libcmt.lib\"\n"; + } + + properties << "\t/>\n" + "</VisualStudioPropertySheet>\n"; + + properties.flush(); + properties.close(); +} + +void VisualStudioProvider::writeFileListToProject(const FileNode &dir, std::ofstream &projectFile, const int indentation, + const StringList &duplicate, const std::string &objPrefix, const std::string &filePrefix) { + const std::string indentString = getIndent(indentation + 2); + + if (indentation) + projectFile << getIndent(indentation + 1) << "<Filter\tName=\"" << dir.name << "\">\n"; + + for (FileNode::NodeList::const_iterator i = dir.children.begin(); i != dir.children.end(); ++i) { + const FileNode *node = *i; + + if (!node->children.empty()) { + writeFileListToProject(*node, projectFile, indentation + 1, duplicate, objPrefix + node->name + '_', filePrefix + node->name + '/'); + } else { + if (producesObjectFile(node->name)) { + std::string name, ext; + splitFilename(node->name, name, ext); + const bool isDuplicate = (std::find(duplicate.begin(), duplicate.end(), name + ".o") != duplicate.end()); + + if (ext == "asm") { + std::string objFileName = "$(IntDir)\\"; + if (isDuplicate) + objFileName += objPrefix; + objFileName += "$(InputName).obj"; + + const std::string toolLine = indentString + "\t\t<Tool Name=\"VCCustomBuildTool\" CommandLine=\"nasm.exe -f win32 -g -o "" + objFileName + "" "$(InputPath)"
\" Outputs=\"" + objFileName + "\" />\n"; + + // NASM is not supported for x64, thus we do not need to add additional entries here :-). + projectFile << indentString << "<File RelativePath=\"" << convertPathToWin(filePrefix + node->name) << "\">\n" + << indentString << "\t<FileConfiguration Name=\"Debug|Win32\">\n" + << toolLine + << indentString << "\t</FileConfiguration>\n" + << indentString << "\t<FileConfiguration Name=\"Analysis|Win32\">\n" + << toolLine + << indentString << "\t</FileConfiguration>\n" + << indentString << "\t<FileConfiguration Name=\"Release|Win32\">\n" + << toolLine + << indentString << "\t</FileConfiguration>\n" + << indentString << "</File>\n"; + } else { + if (isDuplicate) { + const std::string toolLine = indentString + "\t\t<Tool Name=\"VCCLCompilerTool\" ObjectFile=\"$(IntDir)\\" + objPrefix + "$(InputName).obj\" XMLDocumentationFileName=\"$(IntDir)\\" + objPrefix + "$(InputName).xdc\" />\n"; + + projectFile << indentString << "<File RelativePath=\"" << convertPathToWin(filePrefix + node->name) << "\">\n" + << indentString << "\t<FileConfiguration Name=\"Debug|Win32\">\n" + << toolLine + << indentString << "\t</FileConfiguration>\n" + << indentString << "\t<FileConfiguration Name=\"Analysis|Win32\">\n" + << toolLine + << indentString << "\t</FileConfiguration>\n" + << indentString << "\t<FileConfiguration Name=\"Release|Win32\">\n" + << toolLine + << indentString << "\t</FileConfiguration>\n" + << indentString << "\t<FileConfiguration Name=\"Debug|x64\">\n" + << toolLine + << indentString << "\t</FileConfiguration>\n" + << indentString << "\t<FileConfiguration Name=\"Analysis|x64\">\n" + << toolLine + << indentString << "\t</FileConfiguration>\n" + << indentString << "\t<FileConfiguration Name=\"Release|x64\">\n" + << toolLine + << indentString << "\t</FileConfiguration>\n" + << indentString << "</File>\n"; + } else { + projectFile << indentString << "<File RelativePath=\"" << convertPathToWin(filePrefix + node->name) << "\" />\n"; + } + } + } else { + projectFile << indentString << "<File RelativePath=\"" << convertPathToWin(filePrefix + node->name) << "\" />\n"; + } + } + } + + if (indentation) + projectFile << getIndent(indentation + 1) << "</Filter>\n"; +} + +} // End of CreateProjectTool namespace diff --git a/devtools/create_project/visualstudio.h b/devtools/create_project/visualstudio.h new file mode 100644 index 0000000000..0cf572429b --- /dev/null +++ b/devtools/create_project/visualstudio.h @@ -0,0 +1,57 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef TOOLS_CREATE_PROJECT_VISUALSTUDIO_H +#define TOOLS_CREATE_PROJECT_VISUALSTUDIO_H + +#include "msvc.h" + +namespace CreateProjectTool { + +class VisualStudioProvider : public MSVCProvider { +public: + VisualStudioProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, const int version); + +protected: + void createProjectFile(const std::string &name, const std::string &uuid, const BuildSetup &setup, const std::string &moduleDir, + const StringList &includeList, const StringList &excludeList); + + void writeFileListToProject(const FileNode &dir, std::ofstream &projectFile, const int indentation, + const StringList &duplicate, const std::string &objPrefix, const std::string &filePrefix); + + void writeReferences(std::ofstream &output); + + void outputGlobalPropFile(std::ofstream &properties, int bits, const StringList &defines, const std::string &prefix); + + void createBuildProp(const BuildSetup &setup, bool isRelease, bool isWin32, bool enableAnalysis); + + const char *getProjectExtension(); + const char *getPropertiesExtension(); + int getVisualStudioVersion(); +}; + +} // End of CreateProjectTool namespace + +#endif // TOOLS_CREATE_PROJECT_VISUALSTUDIO_H |