aboutsummaryrefslogtreecommitdiff
path: root/tools/create_project/create_project.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/create_project/create_project.cpp')
-rw-r--r--tools/create_project/create_project.cpp1230
1 files changed, 0 insertions, 1230 deletions
diff --git a/tools/create_project/create_project.cpp b/tools/create_project/create_project.cpp
deleted file mode 100644
index b896e85131..0000000000
--- a/tools/create_project/create_project.cpp
+++ /dev/null
@@ -1,1230 +0,0 @@
-/* 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);
-}