Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,459 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include "cmake.h"
#include <algorithm>
#include <cstring>
#include <fstream>
#include <iterator>
namespace CreateProjectTool {
CMakeProvider::CMakeProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, StringList &global_errors)
: ProjectProvider(global_warnings, project_warnings, global_errors) {
}
const CMakeProvider::Library *CMakeProvider::getLibraryFromFeature(const char *feature, SDLVersion useSDL) const {
static const Library s_libraries[] = {
{ "sdl", "sdl", kSDLVersion1, "FindSDL", "SDL", "SDL_INCLUDE_DIR", "SDL_LIBRARY", nullptr, nullptr },
{ "sdl", "sdl2", kSDLVersion2, nullptr, "SDL2", nullptr, "SDL2_LIBRARIES", nullptr, nullptr },
{ "sdl", "sdl3", kSDLVersion3, nullptr, "SDL3", nullptr, "SDL3_LIBRARIES", nullptr, nullptr },
{ "freetype2", "freetype2", kSDLVersionAny, "FindFreetype", "Freetype", "FREETYPE_INCLUDE_DIRS", "FREETYPE_LIBRARIES", nullptr, nullptr },
{ "zlib", "zlib", kSDLVersionAny, "FindZLIB", "ZLIB", "ZLIB_INCLUDE_DIRS", "ZLIB_LIBRARIES", nullptr, nullptr },
{ "png", "libpng", kSDLVersionAny, "FindPNG", "PNG", "PNG_INCLUDE_DIRS", "PNG_LIBRARIES", nullptr, nullptr },
{ "jpeg", "libjpeg", kSDLVersionAny, "FindJPEG", "JPEG", "JPEG_INCLUDE_DIRS", "JPEG_LIBRARIES", nullptr, nullptr },
{ "mpeg2", "libmpeg2", kSDLVersionAny, "FindMPEG2", "MPEG2", "MPEG2_INCLUDE_DIRS", "MPEG2_mpeg2_LIBRARY", nullptr, nullptr },
{ "opengl", nullptr, kSDLVersionAny, "FindOpenGL", "OpenGL", "OPENGL_INCLUDE_DIR", "OPENGL_gl_LIBRARY", nullptr, nullptr },
{ "libcurl", "libcurl", kSDLVersionAny, "FindCURL", "CURL", "CURL_INCLUDE_DIRS", "CURL_LIBRARIES", nullptr, "ws2_32" },
{ "sdlnet", nullptr, kSDLVersion1, "FindSDL_net", "SDL_net", "SDL_NET_INCLUDE_DIRS", "SDL_NET_LIBRARIES", nullptr, nullptr },
LibraryProps("sdlnet", "SDL2_net", kSDLVersion2).Libraries("SDL2_net"),
LibraryProps("sdlnet", "SDL3_net", kSDLVersion3).Libraries("SDL3_net"),
LibraryProps("flac", "flac").Libraries("FLAC"),
LibraryProps("mad", "mad").Libraries("mad"),
LibraryProps("mikmod", "mikmod").Libraries("mikmod"),
LibraryProps("openmpt", "openmpt").Libraries("openmpt"),
LibraryProps("ogg", "ogg").Libraries("ogg"),
LibraryProps("vorbis", "vorbisfile vorbis").Libraries("vorbisfile vorbis"),
LibraryProps("tremor", "vorbisidec").Libraries("vorbisidec"),
LibraryProps("theoradec", "theoradec").Libraries("theoradec"),
LibraryProps("vpx", "vpx").Libraries("vpx"),
LibraryProps("fluidsynth", "fluidsynth").Libraries("fluidsynth"),
LibraryProps("faad", "faad2").Libraries("faad"),
LibraryProps("fribidi", "fribidi").Libraries("fribidi"),
LibraryProps("discord", "discord").Libraries("discord-rpc"),
LibraryProps("tts").WinLibraries("sapi ole32"),
LibraryProps("enet").WinLibraries("winmm ws2_32"),
LibraryProps("retrowave", "retrowave").Libraries("retrowave"),
LibraryProps("a52", "a52").Libraries("a52"),
LibraryProps("mpc", "mpcdec").Libraries("mpcdec")
};
for (unsigned int i = 0; i < sizeof(s_libraries) / sizeof(s_libraries[0]); i++) {
bool matchingSDL = (s_libraries[i].sdlVersion == kSDLVersionAny)
|| (s_libraries[i].sdlVersion == useSDL);
if (std::strcmp(feature, s_libraries[i].feature) == 0 && matchingSDL) {
return &s_libraries[i];
}
}
return nullptr;
}
void CMakeProvider::createWorkspace(const BuildSetup &setup) {
std::string filename = setup.outputDir + "/CMakeLists.txt";
std::ofstream workspace(filename.c_str());
if (!workspace || !workspace.is_open())
error("Could not open \"" + filename + "\" for writing");
workspace << "cmake_minimum_required(VERSION 3.13)\n";
workspace << "project(" << setup.projectDescription << ")\n\n";
workspace << R"EOS(set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_CXX_STANDARD 11) # Globally enable C++11
add_compile_definitions($<$<NOT:$<CONFIG:Debug>>:RELEASE_BUILD>)
add_compile_options($<$<NOT:$<CONFIG:Debug>>:-UNDEBUG>)
# Remove /D NDEBUG to avoid MSVC warnings about conflicting defines.
foreach (flags_var_to_scrub
CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_RELWITHDEBINFO
CMAKE_CXX_FLAGS_MINSIZEREL
CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_RELWITHDEBINFO
CMAKE_C_FLAGS_MINSIZEREL)
string (REGEX REPLACE "(^| )[/-]D *NDEBUG($| )" " "
"${flags_var_to_scrub}" "${${flags_var_to_scrub}}")
endforeach()
find_package(PkgConfig QUIET)
include(CMakeParseArguments)
set(SCUMMVM_LIBS)
macro(find_feature)
set(_OPTIONS_ARGS)
set(_ONE_VALUE_ARGS name findpackage_name include_dirs_var libraries_var)
set(_MULTI_VALUE_ARGS pkgconfig_name libraries win_libraries)
cmake_parse_arguments(_feature "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
if (_feature_pkgconfig_name AND PKG_CONFIG_FOUND)
pkg_check_modules(${_feature_name} REQUIRED ${_feature_pkgconfig_name})
include_directories(${${_feature_name}_INCLUDE_DIRS})
list(APPEND SCUMMVM_LIBS ${${_feature_name}_LIBRARIES})
endif()
if (NOT ${_feature_name}_FOUND)
if (_feature_findpackage_name)
find_package(${_feature_findpackage_name} REQUIRED)
endif()
if (_feature_include_dirs_var)
include_directories(${${_feature_include_dirs_var}} REQUIRED)
endif()
if (_feature_libraries_var)
list(APPEND SCUMMVM_LIBS ${${_feature_libraries_var}})
endif()
if (_feature_libraries)
list(APPEND SCUMMVM_LIBS ${_feature_libraries})
endif()
if (WIN32 AND _feature_win_libraries)
list(APPEND SCUMMVM_LIBS ${_feature_win_libraries})
endif()
endif()
endmacro()
)EOS";
workspace << R"EOS(function(add_engine engine_name)
string(TOUPPER ${engine_name} _engine_var)
set(_enable_engine_var "ENABLE_${_engine_var}")
if(NOT ${_enable_engine_var})
return()
endif()
add_library(${engine_name} ${ARGN})
# Generate definitions for the engine
add_definitions(-D${_enable_engine_var})
foreach(SUB_ENGINE IN LISTS SUB_ENGINES_${_engine_var})
add_definitions(-DENABLE_${SUB_ENGINE})
endforeach(SUB_ENGINE)
file(APPEND "engines/plugins_table.h" "#if PLUGIN_ENABLED_STATIC(${_engine_var})\n")
file(APPEND "engines/plugins_table.h" "LINK_PLUGIN(${_engine_var})\n")
file(APPEND "engines/plugins_table.h" "#endif\n")
# Enable C++11
set_property(TARGET ${engine_name} PROPERTY CXX_STANDARD 11)
set_property(TARGET ${engine_name} PROPERTY CXX_STANDARD_REQUIRED ON)
# Link against the engine
target_link_libraries()EOS" << setup.projectName << R"( ${engine_name})
endfunction()
)";
workspace << "# Define the engines and subengines\n";
writeEngines(setup, workspace);
writeSubEngines(setup, workspace);
workspace << "# Generate options for the engines\n";
writeEngineOptions(workspace);
std::string includeDirsList;
for (const std::string &includeDir : setup.includeDirs)
includeDirsList += includeDir + ' ';
workspace << "include_directories(. ${"
<< setup.projectDescription << "_SOURCE_DIR}/" << setup.filePrefix
<< " ${" << setup.projectDescription << "_SOURCE_DIR}/" << setup.filePrefix << "/engines "
<< includeDirsList << "$ENV{"<<LIBS_DEFINE<<"}/include)\n\n";
workspace << "# Libraries and features\n\n";
writeFeatureLibSearch(setup, workspace, "sdl");
workspace << R"(# Depending on how SDL2 was built, there can be either and imported target or flags variables
# Define the flags variables from the imported target if necessary
if (TARGET SDL2::SDL2)
get_target_property(SDL2_INCLUDE_DIRS SDL2::SDL2 INTERFACE_INCLUDE_DIRECTORIES)
get_target_property(SDL2_LIBRARIES SDL2::SDL2 LOCATION)
endif()
include_directories(${SDL2_INCLUDE_DIRS})
# Explicitly support MacPorts and Homebrew (hopefully harmless on other platforms)
link_directories(/opt/local/lib /opt/homebrew/lib)
)";
for (const Feature &feature : setup.features) {
if (!feature.enable || featureExcluded(feature.name)) continue;
writeFeatureLibSearch(setup, workspace, feature.name);
if (!feature.define || !feature.define[0]) continue;
workspace << "add_definitions(-D" << feature.define << ")\n";
}
workspace << "\n";
writeWarnings(workspace);
writeDefines(setup, workspace);
workspace << R"(# Generate "engines/plugins_table.h"
file(REMOVE "engines/plugins_table.h")
file(APPEND "engines/plugins_table.h" "/* This file is automatically generated by CMake */\n")
)";
}
void CMakeProvider::writeFeatureLibSearch(const BuildSetup &setup, std::ofstream &workspace, const char *feature) const {
const Library *library = getLibraryFromFeature(feature, setup.useSDL);
if (library) {
workspace << "find_feature(";
workspace << "name " << library->feature;
if (library->pkgConfig) {
workspace << " pkgconfig_name ";
workspace << library->pkgConfig;
}
if (library->package) {
workspace << " findpackage_name ";
workspace << library->package;
}
if (library->includesVar) {
workspace << " include_dirs_var ";
workspace << library->includesVar;
}
if (library->librariesVar) {
workspace << " libraries_var ";
workspace << library->librariesVar;
}
if (library->libraries) {
workspace << " libraries ";
workspace << library->libraries;
}
if (library->winLibraries) {
workspace << " win_libraries ";
workspace << library->winLibraries;
}
workspace << ")\n";
}
}
void CMakeProvider::writeEngines(const BuildSetup &setup, std::ofstream &workspace) const {
workspace << "set(ENGINES";
for (const EngineDesc &engine : setup.engines) {
// We ignore all sub engines here because they require special handling.
if (!engine.enable || isSubEngine(engine.name, setup.engines)) {
continue;
}
workspace << " " << toUpper(engine.name);
}
workspace << ")\n";
}
void CMakeProvider::writeSubEngines(const BuildSetup &setup, std::ofstream &workspace) const {
for (const EngineDesc &engine : setup.engines) {
// We ignore all sub engines here because they are handled in the inner loop
if (!engine.enable || isSubEngine(engine.name, setup.engines) || engine.subEngines.empty()) {
continue;
}
workspace << "set(SUB_ENGINES_" << toUpper(engine.name);
for (const std::string &subEngineName : engine.subEngines) {
const EngineDesc &subEngine = findEngineDesc(subEngineName, setup.engines);
if (!subEngine.enable) continue;
workspace << " " << toUpper(subEngineName);
}
workspace << ")\n";
}
workspace << "\n";
}
static std::string filePrefix(const BuildSetup &setup, const std::string &moduleDir) {
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);
}
return modulePath.empty() ? setup.filePrefix : setup.filePrefix + '/' + modulePath;
}
void CMakeProvider::createProjectFile(const std::string &name, const std::string &, const BuildSetup &setup, const std::string &moduleDir,
const StringList &includeList, const StringList &excludeList, const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) {
const std::string projectFile = setup.outputDir + "/CMakeLists.txt";
std::ofstream project(projectFile.c_str(), std::ofstream::out | std::ofstream::app);
if (!project)
error("Could not open \"" + projectFile + "\" for writing");
if (name == setup.projectName) {
project << "add_executable(" << name;
// console subsystem is required for text-console, tools, and tests
if (setup.useWindowsSubsystem && !setup.featureEnabled("text-console") && !setup.devTools && !setup.tests) {
project << " WIN32";
}
project << "\n";
} else if (name == setup.projectName + "-detection") {
project << "list(APPEND SCUMMVM_LIBS " << name << ")\n";
project << "add_library(" << name << "\n";
} else {
enginesStr << "add_engine(" << name << "\n";
addFilesToProject(moduleDir, enginesStr, includeList, excludeList, pchIncludeRoot, pchDirs, pchExclude, filePrefix(setup, moduleDir));
enginesStr << ")\n\n";
return;
}
addFilesToProject(moduleDir, project, includeList, excludeList, pchIncludeRoot, pchDirs, pchExclude, filePrefix(setup, moduleDir));
project << ")\n";
project << "\n";
if (name == setup.projectName) {
project << "# Engines libraries handling\n";
writeEnginesLibrariesHandling(setup, project);
project << "# Libraries\n";
const Library *sdlLibrary = getLibraryFromFeature("sdl", setup.useSDL);
std::string libraryDirsList;
for (const std::string &libraryDir : setup.libraryDirs)
libraryDirsList += libraryDir + ' ';
project << "target_link_libraries(" << name << " " << libraryDirsList << "${" << sdlLibrary->librariesVar << "} ${SCUMMVM_LIBS})\n";
project << "if (WIN32)\n";
project << "\ttarget_sources(" << name << " PUBLIC " << setup.filePrefix << "/dists/" << name << ".rc)\n";
project << "\ttarget_link_libraries(" << name << " winmm)\n";
// Needed for select (used in socket.cpp), when curl is linked dynamically
project << "\tif (libcurl_FOUND)\n";
project << "\t\ttarget_link_libraries(" << name << " ws2_32)\n";
project << "\tendif()\n";
project << "endif()\n";
project << "\n";
project << "set_property(TARGET " << name << " PROPERTY CXX_STANDARD 11)\n";
project << "set_property(TARGET " << name << " PROPERTY CXX_STANDARD_REQUIRED ON)\n";
}
}
void CMakeProvider::writeWarnings(std::ofstream &output) const {
output << "if (MSVC)\n";
// TODO: Support MSVC warnings
output << "else()\n";
output << "\tset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS}";
for (const std::string &warning : _globalWarnings) {
output << ' ' << warning;
}
output << "\")\n";
output << "\tif(CMAKE_CXX_COMPILER_ID STREQUAL \"GNU\")\n";
output << "\t\tif(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 7.1)\n";
output << "\t\t\tset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -Wno-stringop-overflow\")\n";
output << "\t\tendif()\n";
output << "\t\tif(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.1)\n";
output << "\t\t\tset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -Wno-stringop-truncation\")\n";
output << "\t\tendif()\n";
output << "\t\tif(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 12.0)\n";
output << "\t\t\tset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -Wno-address-of-packed-member\")\n";
output << "\t\tendif()\n";
output << "\tendif()\n";
output << "endif()\n";
}
void CMakeProvider::writeDefines(const BuildSetup &setup, std::ofstream &output) const {
output << "if (WIN32)\n";
output << "\tadd_definitions(-DWIN32)\n";
output << "else()\n";
output << "\tadd_definitions(-DPOSIX)\n";
output << "\t# Hope for the best regarding fseeko and 64-bit off_t\n";
output << "\tadd_definitions(-D_FILE_OFFSET_BITS=64)\n";
output << "\tadd_definitions(-DHAS_FSEEKO_OFFT_64)\n";
output << "endif()\n";
output << "add_definitions(-DSDL_BACKEND)\n";
if (setup.useSDL == kSDLVersion2) {
output << "add_definitions(-DUSE_SDL2)\n";
} else if (setup.useSDL == kSDLVersion3) {
output << "add_definitions(-DUSE_SDL3)\n";
}
if (getFeatureBuildState("opengl", setup.features)) {
output << "add_definitions(-DUSE_GLAD)\n";
}
if (setup.useStaticDetection) {
output << "add_definitions(-DDETECTION_STATIC)\n";
}
}
void CMakeProvider::writeFileListToProject(const FileNode &dir, std::ostream &projectFile, const int indentation,
const std::string &objPrefix, const std::string &filePrefix,
const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) {
std::string lastName;
for (const FileNode *node : dir.children) {
if (!node->children.empty()) {
writeFileListToProject(*node, projectFile, indentation + 1, objPrefix + node->name + '_', filePrefix + node->name + '/', pchIncludeRoot, pchDirs, pchExclude);
} else {
std::string name, ext;
splitFilename(node->name, name, ext);
if (name != lastName) {
if (!lastName.empty()) {
projectFile << "\n";
}
projectFile << "\t";
} else {
projectFile << " ";
}
projectFile << filePrefix + node->name;
lastName = name;
}
}
projectFile << "\n";
}
const char *CMakeProvider::getProjectExtension() {
return ".txt";
}
void CMakeProvider::writeEngineOptions(std::ofstream &workspace) const {
workspace << "foreach(ENGINE IN LISTS ENGINES)\n";
workspace << "\toption(ENABLE_${ENGINE} \"Enable ${ENGINE}\" ON)\n";
workspace << "endforeach(ENGINE)\n\n";
}
void CMakeProvider::writeEnginesLibrariesHandling(const BuildSetup &setup, std::ofstream &workspace) const {
workspace << enginesStr.str();
}
bool CMakeProvider::featureExcluded(const char *name) const {
return std::strcmp(name, "nasm") == 0 ||
std::strcmp(name, "updates") == 0 ; // NASM is not supported for now
}
const EngineDesc &CMakeProvider::findEngineDesc(const std::string &name, const EngineDescList &engines) const {
for (const EngineDesc &engine : engines) {
if (engine.name == name)
return engine;
}
error("Unable to find requested engine");
}
} // End of CreateProjectTool namespace

View File

@@ -0,0 +1,97 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TOOLS_CREATE_PROJECT_CMAKE_H
#define TOOLS_CREATE_PROJECT_CMAKE_H
#include "create_project.h"
#include <sstream>
namespace CreateProjectTool {
/**
* A ProjectProvider used to generate CMake project descriptions
*
* Generated CMake projects are minimal, and will only work with GCC.
*/
class CMakeProvider final : public ProjectProvider {
public:
CMakeProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, StringList &global_errors);
protected:
void createWorkspace(const BuildSetup &setup) final;
void createOtherBuildFiles(const BuildSetup &) final {}
void addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList) final {}
void 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 &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) final;
void writeFileListToProject(const FileNode &dir, std::ostream &projectFile, const int indentation,
const std::string &objPrefix, const std::string &filePrefix,
const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) final;
const char *getProjectExtension() final;
private:
std::stringstream enginesStr;
/**
* CMake properties for a library required by a feature
*/
struct Library {
const char *feature;
const char *pkgConfig;
SDLVersion sdlVersion;
const char *module;
const char *package;
const char *includesVar;
const char *librariesVar;
const char *libraries;
const char *winLibraries;
};
struct LibraryProps : Library {
LibraryProps(const char *_feature, const char *_pkgConfig = nullptr, SDLVersion _sdlVersion = kSDLVersionAny) :
Library({_feature, _pkgConfig, _sdlVersion, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}) {}
LibraryProps &LibrariesVar(const char *var) { librariesVar = var; return *this; }
LibraryProps &Libraries(const char *libs) { libraries = libs; return *this; }
LibraryProps &WinLibraries(const char *libs) { winLibraries = libs; return *this; }
};
const Library *getLibraryFromFeature(const char *feature, SDLVersion useSDL) const;
void writeWarnings(std::ofstream &output) const;
void writeDefines(const BuildSetup &setup, std::ofstream &output) const;
void writeEngines(const BuildSetup &setup, std::ofstream &workspace) const;
void writeSubEngines(const BuildSetup &setup, std::ofstream &workspace) const;
void writeEngineOptions(std::ofstream &workspace) const;
void writeEnginesLibrariesHandling(const BuildSetup &setup, std::ofstream &workspace) const;
void writeFeatureLibSearch(const BuildSetup &setup, std::ofstream &workspace, const char *feature) const;
bool featureExcluded(const char *name) const;
const EngineDesc &findEngineDesc(const std::string &name, const EngineDescList &engines) const;
};
} // End of CreateProjectTool namespace
#endif // TOOLS_CREATE_PROJECT_CMAKE_H

View File

@@ -0,0 +1,3 @@
/Makefile
/build
/create_project*

View File

@@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.13)
project(create_project)
set(SOURCE_FILES
../cmake.cpp
../cmake.h
../codeblocks.cpp
../codeblocks.h
../create_project.cpp
../create_project.h
../msbuild.cpp
../msbuild.h
../msvc.cpp
../msvc.h
../xcode.cpp
../xcode.h
)
add_executable(create_project ${SOURCE_FILES})
if (WIN32)
target_link_libraries(create_project rpcrt4 advapi32)
endif ()
set_property(TARGET create_project PROPERTY CXX_STANDARD 11)
set_property(TARGET create_project PROPERTY CXX_STANDARD_REQUIRED ON)

View File

@@ -0,0 +1,288 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include "codeblocks.h"
#include <fstream>
#include <cstring>
namespace CreateProjectTool {
CodeBlocksProvider::CodeBlocksProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, StringList &global_errors)
: ProjectProvider(global_warnings, project_warnings, global_errors) {
}
void CodeBlocksProvider::createWorkspace(const BuildSetup &setup) {
std::ofstream workspace((setup.outputDir + '/' + setup.projectName + ".workspace").c_str());
if (!workspace)
error("Could not open \"" + setup.outputDir + '/' + setup.projectName + ".workspace\" for writing");
workspace << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n"
"<CodeBlocks_workspace_file>\n";
workspace << "\t<Workspace title=\"" << setup.projectDescription << "\">\n";
writeReferences(setup, workspace);
// Note we assume that the UUID map only includes UUIDs for enabled engines!
for (UUIDMap::const_iterator i = _engineUuidMap.begin(); i != _engineUuidMap.end(); ++i) {
workspace << "\t\t<Project filename=\"" << i->first << ".cbp\" />\n";
}
workspace << "\t</Workspace>\n"
"</CodeBlocks_workspace_file>";
}
StringList getFeatureLibraries(const BuildSetup &setup) {
StringList libraries;
std::string libSDL = "lib";
libSDL += setup.getSDLName();
libraries.push_back(libSDL);
for (FeatureList::const_iterator i = setup.features.begin(); i != setup.features.end(); ++i) {
if (i->enable && i->library) {
std::string libname;
if (!std::strcmp(i->name, "libcurl")) {
libname = i->name;
} else if (!std::strcmp(i->name, "zlib")) {
libname = "libz";
} else if (!std::strcmp(i->name, "vorbis")) {
libname = "libvorbis";
libraries.push_back("libvorbisfile");
} else if (!std::strcmp(i->name, "png")) {
libname = "libpng16";
} else if (!std::strcmp(i->name, "sdlnet")) {
libname = libSDL + "_net";
libraries.push_back("iphlpapi");
} else {
libname = "lib";
libname += i->name;
}
libraries.push_back(libname);
}
}
// Win32 libraries
libraries.push_back("ole32");
libraries.push_back("uuid");
libraries.push_back("winmm");
return libraries;
}
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 &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) {
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 == setup.projectName) {
StringList libraries = getFeatureLibraries(setup);
std::string deps;
for (StringList::const_iterator i = libraries.begin(); i != libraries.end(); ++i)
deps += (*i) + ".a;";
project << "\t\t\t<Target title=\"default\">\n"
"\t\t\t\t<Option output=\"" << setup.projectName << "\\" << setup.projectName << "\" prefix_auto=\"1\" extension_auto=\"1\" />\n"
"\t\t\t\t<Option object_output=\"" << setup.projectName << "\" />\n"
"\t\t\t\t<Option external_deps=\"" << deps /* + list of engines 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);
for (StringList::const_iterator i = setup.includeDirs.begin(); i != setup.includeDirs.end(); ++i)
project << "\t\t\t\t\t<Add directory=\"" << convertPathToWin(*i) << "\" />\n";
project << "\t\t\t\t\t<Add directory=\"$(" << LIBS_DEFINE << ")include\" />\n"
"\t\t\t\t\t<Add directory=\"$(" << LIBS_DEFINE << ")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\t<Add directory=\".\\\" />\n"
"\t\t\t\t</Compiler>\n";
//////////////////////////////////////////////////////////////////////////
// Linker
project << "\t\t\t\t<Linker>\n";
for (StringList::const_iterator i = libraries.begin(); i != libraries.end(); ++i)
project << "\t\t\t\t\t<Add library=\"" << (*i) << "\" />\n";
for (UUIDMap::const_iterator i = _engineUuidMap.begin(); i != _engineUuidMap.end(); ++i) {
project << "\t\t\t\t\t<Add library=\"" << setup.projectName << "\\engines\\" << i->first << "\\lib" << i->first << ".a\" />\n";
}
for (StringList::const_iterator i = setup.libraryDirs.begin(); i != setup.libraryDirs.end(); ++i)
project << "\t\t\t\t\t<Add directory=\"" << convertPathToWin(*i) << "\" />\n";
project << "\t\t\t\t\t<Add directory=\"$(" << LIBS_DEFINE << ")lib\\mingw\" />\n"
"\t\t\t\t\t<Add directory=\"$(" << LIBS_DEFINE << ")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=\"..\\..\\..\\" << setup.projectName << "\" />\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=\"" << setup.projectName << "\\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=\"" << setup.projectName << "\" />\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=\"..\\..\\..\\" << setup.projectName << "\" />\n";
// Sword2.5 engine needs theora and vorbis includes
if (name == "sword25")
project << "\t\t\t\t\t<Add directory=\"$(" << LIBS_DEFINE << ")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.empty())
addFilesToProject(moduleDir, project, includeList, excludeList, pchIncludeRoot, pchDirs, pchExclude, setup.filePrefix + '/' + modulePath);
else
addFilesToProject(moduleDir, project, includeList, excludeList, pchIncludeRoot, pchDirs, pchExclude, 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::addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList) {
includeList.push_back(setup.srcDir + "/icons/" + setup.projectName + ".ico");
includeList.push_back(setup.srcDir + "/dists/" + setup.projectName + ".rc");
}
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::ostream &projectFile, const int indentation,
const std::string &objPrefix, const std::string &filePrefix,
const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) {
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, objPrefix + node->name + '_', filePrefix + node->name + '/', pchIncludeRoot, pchDirs, pchExclude);
} 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=\"$(" << LIBS_DEFINE << ")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(const BuildSetup &setup, std::ofstream &output) {
output << "\t\t<Project filename=\"" << setup.projectName << ".cbp\" active=\"1\">\n";
for (UUIDMap::const_iterator i = _engineUuidMap.begin(); i != _engineUuidMap.end(); ++i) {
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

View File

@@ -0,0 +1,59 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TOOLS_CREATE_PROJECT_CODEBLOCKS_H
#define TOOLS_CREATE_PROJECT_CODEBLOCKS_H
#include "create_project.h"
namespace CreateProjectTool {
class CodeBlocksProvider final : public ProjectProvider {
public:
CodeBlocksProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, StringList &global_errors);
protected:
void createWorkspace(const BuildSetup &setup) final;
void createOtherBuildFiles(const BuildSetup &) final {}
void addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList) final;
void 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 &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) final;
void writeFileListToProject(const FileNode &dir, std::ostream &projectFile, const int indentation,
const std::string &objPrefix, const std::string &filePrefix,
const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) final;
void writeReferences(const BuildSetup &setup, std::ofstream &output) final;
const char *getProjectExtension() final;
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

View File

@@ -0,0 +1,59 @@
<?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="..\config.h" />
<Unit filename="..\cmake.cpp" />
<Unit filename="..\cmake.h" />
<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="..\xcode.cpp" />
<Unit filename="..\xcode.h" />
<Extensions>
<code_completion />
<envvars />
<debugger />
<lib_finder disable_auto="1" />
</Extensions>
</Project>
</CodeBlocks_project_file>

View File

@@ -0,0 +1,36 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TOOLS_CREATE_PROJECT_CONFIG_H
#define TOOLS_CREATE_PROJECT_CONFIG_H
#define PROJECT_DESCRIPTION "ScummVM" // Used in console output and build configuration
#define PROJECT_NAME "scummvm" // Used for folders, icons, resources and project/solution name
#define LIBS_DEFINE "SCUMMVM_LIBS" // Name of the include environment variable
#define REVISION_DEFINE "SCUMMVM_INTERNAL_REVISION"
#define FIRST_ENGINE "scumm" // Name of the engine which should be sorted as first element
#define ENABLE_LANGUAGE_EXTENSIONS "" // Comma separated list of projects that need language extensions
#define DISABLE_EDIT_AND_CONTINUE "tinsel,tony,scummvm" // Comma separated list of projects that need Edit&Continue to be disabled for co-routine support (the main project is automatically added)
#define NEEDS_RTTI 1 // Enable RTTI globally
#endif // TOOLS_CREATE_PROJECT_CONFIG_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,753 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TOOLS_CREATE_PROJECT_H
#define TOOLS_CREATE_PROJECT_H
#ifndef __has_feature // Optional of course.
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
#if defined(_MSC_VER) && _MSC_VER < 1900
#error MSVC support requires MSVC 2015 or newer
#endif
#include <list>
#include <map>
#include <string>
#include <vector>
#include <cassert>
typedef std::list<std::string> StringList;
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.
*
* You can also use this with non-whitespace by passing another separator
* character (e.g. ',').
*
* @param input The text to be tokenized.
* @param separator The token separator.
* @return A list of tokens.
*/
TokenList tokenize(const std::string &input, char separator = ' ');
/**
* 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 = false;
/**
* Features required for this engine.
*/
StringList requiredFeatures;
/**
* Components wished for this engine.
*/
StringList wishedComponents;
/**
* 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 project directory 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 individual configure.engine
* files.
*
* @param srcDir Path to the root of the project source.
* @return List of available engines.
*/
EngineDescList parseEngines(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
bool library; ///< Whether this feature needs to be linked to a library
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;
struct Component {
std::string name; ///< Name of the component
std::string define; ///< Define of the component
Feature &feature; ///< Associated feature
std::string description; ///< Human readable description of the component
bool needed;
bool operator==(const std::string &n) const {
return (name == n);
}
};
typedef std::list<Component> ComponentList;
struct Tool {
const char *name; ///< Name of the tools
bool enable; ///< Whether the tools is enabled or not
};
typedef std::list<Tool> ToolList;
/**
* Creates a list of all features available for MSVC.
*
* @return A list including all features available.
*/
FeatureList getAllFeatures();
/**
* Creates a list of all components.
*
* @param srcDir The source directory containing the configure script
* @param features The features list used to link the component to its feature
*
* @return A list including all components available linked to its features.
*/
ComponentList getAllComponents(const std::string &srcDir, FeatureList &features);
/**
* Disable the features for the unused components.
*
* @param components List of components for the build
*/
void disableComponents(const ComponentList &components);
/**
* 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);
/**
* Sets the state of a given feature. This can be used to
* either include or exclude a 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);
/**
* Gets the state of a given feature.
*
* @param name Name of the feature.
* @param features List of features to operate on.
* @return "true", when the feature is enabled, "false" otherwise.
*/
bool getFeatureBuildState(const std::string &name, const FeatureList &features);
/**
* Specifies the required SDL version of a feature.
*/
enum SDLVersion {
kSDLVersionAny = 0,
kSDLVersion1, ///< SDL 1.2
kSDLVersion2, ///< SDL 2
kSDLVersion3 ///< SDL 3
};
/**
* Structure to describe a build setup.
*
* This includes various information about which engines to
* enable, which features should be built into the main executable.
* It also contains the path to the project source root.
*/
struct BuildSetup {
std::string projectName; ///< Project name
std::string projectDescription; ///< Project description
std::string srcDir; ///< Path to the 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.
std::string libsDir; ///< Path to libraries for MSVC builds. If absent, use LIBS_DEFINE environment var instead.
StringList includeDirs; ///< List of additional include paths
StringList libraryDirs; ///< List of additional library paths
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!).
ComponentList components;
StringList defines; ///< List of all defines for the build.
StringList testDirs; ///< List of all folders containing tests
bool devTools = false; ///< Generate project files for the tools
bool tests = false; ///< Generate project files for the tests
bool runBuildEvents = false; ///< Run build events as part of the build (generate revision number and copy engine/theme data & needed files to the build folder
bool createInstaller = false; ///< Create installer after the build
SDLVersion useSDL = kSDLVersion2; ///< Which version of SDL to use.
bool useStaticDetection = true; ///< Whether to link detection features inside the executable or not.
bool useWindowsUnicode = true; ///< Whether to use Windows Unicode APIs or ANSI APIs.
bool useWindowsSubsystem = false; ///< Whether to use Windows subsystem or Console subsystem (default: Console)
bool appleEmbedded = false; ///< Whether the build will target iOS or tvOS instead of macOS.
bool useXCFramework = false; ///< Whether to use Apple XCFrameworks instead of static libraries
bool useVcpkg = false; ///< Whether to load libraries from vcpkg or SCUMMVM_LIBS
bool useSlnx = false; ///< Whether to use old .sln or new .slnx format
bool win32 = false; ///< Target is Windows
bool featureEnabled(const std::string &feature) const;
Feature getFeature(const std::string &feature) const;
const char *getSDLName() const;
};
/**
* 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;
/**
* Structure to describe a Visual Studio version specification.
*
* This includes various generation details for MSVC projects,
* as well as describe the versions supported.
*/
struct MSVCVersion {
int version; ///< Version number passed as parameter.
const char *name; ///< Full program name.
const char *solutionFormat; ///< Format used for solution files.
const char *solutionVersion; ///< Version number used in solution files.
const char *project; ///< Version number used in project files.
const char *toolsetMSVC; ///< Toolset version for MSVC compiler.
const char *toolsetLLVM; ///< Toolset version for Clang/LLVM compiler.
};
typedef std::list<MSVCVersion> MSVCList;
enum MSVC_Architecture {
ARCH_ARM64,
ARCH_X86,
ARCH_AMD64
};
std::string getMSVCArchName(MSVC_Architecture arch);
std::string getMSVCConfigName(MSVC_Architecture arch);
enum EngineDataGroup {
kEngineDataGroupNormal,
kEngineDataGroupCore,
kEngineDataGroupBig,
kEngineDataGroupCount,
};
struct EngineDataGroupResolution {
EngineDataGroup engineDataGroup;
const char *mkFilePath;
const char *winHeaderPath;
};
/**
* Creates a list of all supported versions of Visual Studio.
*
* @return A list including all versions available.
*/
MSVCList getAllMSVCVersions();
/**
* Returns the definitions for a specific Visual Studio version.
*
* @param version The requested version.
* @return The version information, or NULL if the version isn't supported.
*/
const MSVCVersion *getMSVCVersion(int version);
/**
* Auto-detects the latest version of Visual Studio installed.
*
* @return Version number, or 0 if no installations were found.
*/
int getInstalledMSVC();
/**
* Removes given feature from setup.
*
* @param setup The setup to be processed.
* @param feature The feature to be removed
* @return A copy of setup less feature.
*/
BuildSetup removeFeatureFromSetup(BuildSetup setup, const std::string &feature);
namespace CreateProjectTool {
/**
* 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;
/**
* 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);
/**
* Splits a full path into directory and filename.
* This assumes the last part is the filename, even if it
* has no extension.
*
* @param path Path to split
* @param name Reference to a string, where to store the directory part.
* @param ext Reference to a string, where to store the filename part.
*/
void splitPath(const std::string &path, std::string &dir, std::string &file);
/**
* Calculates the include path and PCH file path (without the base directory).
*
* @param filePath Path to the source file.
* @param pchIncludeRoot Path to the PCH inclusion root directory (ending with separator).
* @param pchDirs List of PCH directories.
* @param pchExclude List of PCH exclusions.
* @param separator Path separator
* @param outPchIncludePath Output path to be used by #include directives.
* @param outPchFilePath Output file path.
* @param outPchFileName Output file name.
* @return True if the file path uses PCH, false if not.
*/
bool calculatePchPaths(const std::string &sourceFilePath, const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude, char separator, std::string &outPchIncludePath, std::string &outPchFilePath, std::string &outPchFileName);
/**
* Returns the basename of a path.
* examples:
* a/b/c/d.ext -> d.ext
* d.ext -> d.ext
*
* @param fileName Filename
* @return The basename
*/
std::string basename(const std::string &fileName);
/**
* 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);
/**
* Convert an integer to string
*
* @param num the integer to convert
* @return string representation of the number
*/
std::string toString(int num);
/**
* Convert a string to uppercase
*
* @param str the source string
* @return The string transformed to uppercase
*/
std::string toUpper(const std::string &str);
/**
* 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);
/**
* Create a directory at the given path.
*
* @param dir The path to create.
*/
void createDirectory(const std::string &dir);
/**
* 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:
struct EngineDataGroupDef {
StringList dataFiles;
std::string winHeaderPath;
};
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, StringList &global_errors);
virtual ~ProjectProvider() {}
/**
* Creates all build files
*
* @param setup Description of the desired build setup.
*/
void createProject(BuildSetup &setup);
/**
* Returns the last path component.
*
* @param path Path string.
* @return Last path component.
*/
static std::string getLastPathComponent(const std::string &path);
protected:
StringList &_globalWarnings; ///< Global (ignored) warnings
StringList &_globalErrors; ///< Global errors (promoted from warnings)
std::map<std::string, StringList> &_projectWarnings; ///< Per-project warnings
UUIDMap _engineUuidMap; ///< List of (project name, UUID) pairs
UUIDMap _allProjUuidMap;
EngineDataGroupDef _engineDataGroupDefs[kEngineDataGroupCount];
/**
* 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;
/**
* Add resources to the project
*
* @param setup Description of the desired build setup.
*/
virtual void addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList) = 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, const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) = 0;
/**
* Writes file entries for the specified directory node into
* the given project file.
*
* @param dir Directory node.
* @param projectFile File stream to write to.
* @param indentation Indentation level to use.
* @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::ostream &projectFile, const int indentation,
const std::string &objPrefix, const std::string &filePrefix,
const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) = 0;
/**
* Output a list of project references to the file stream
*
* @param output File stream to write to.
*/
virtual void writeReferences(const BuildSetup &, 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::ostream &projectFile,
const StringList &includeList, const StringList &excludeList,
const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude,
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 testDirs List of folders containing tests.
* @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 &testDirs, StringList &includeList, StringList &excludeList, StringList &pchDirs, StringList &pchExclude, bool forDetection = false) const;
/**
* Creates a list of data files from a specified .mk file
*
* @param makeFilePath Path to the engine data makefile.
* @param defines List of set defines.
* @param outDataFiles Output list of data files.
* @param outWinHeaderPath Output Windows resource header path.
*/
void createDataFilesList(EngineDataGroup engineDataGroup, const std::string &baseDir, const StringList &defines, StringList &outDataFiles, std::string &outWinHeaderPath) 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 for every enabled tool of the
* passed build description.
*
* @return A map, which includes UUIDs for all enabled tools.
*/
UUIDMap createToolsUUIDMap() const;
/**
* Creates an UUID and returns it in string representation.
*
* @return A new UUID as string.
*/
std::string createUUID() const;
/**
* Creates a name-based UUID and returns it in string representation.
*
* @param name Unique name to hash.
* @return A new UUID as string.
*/
std::string createUUID(const std::string &name) const;
private:
/**
* Returns the string representation of an existing UUID.
*
* @param uuid 128-bit array.
* @return Existing UUID as string.
*/
std::string UUIDToString(unsigned char *uuid) const;
/**
* This creates the engines/plugins_table.h file required for building
* ScummVM.
*
* @param setup Description of the desired build.
*/
void createEnginePluginsTable(const BuildSetup &setup);
/**
* Creates resource embed files
*/
void createResourceEmbeds(const BuildSetup &setup) const;
};
} // namespace CreateProjectTool
#endif // TOOLS_CREATE_PROJECT_H

View File

@@ -0,0 +1,24 @@
MODULE := devtools/create_project
MODULE_OBJS := \
cmake.o \
create_project.o \
codeblocks.o \
msvc.o \
msbuild.o \
xcode.o
# Set the name of the executable
TOOL_EXECUTABLE := create_project
# Set custom build flags for create_project.o: It uses C++ iostreams,
# which make use of global constructors. So we don't want warnings for
# that.
$(srcdir)/devtools/create_project/create_project.o: CXXFLAGS:=$(filter-out -Wglobal-constructors,$(CXXFLAGS))
# Include common rules
include $(srcdir)/rules.mk
# Silence variadic macros warning for C++ (disabled as this is included globally)
#CXXFLAGS := $(CXXFLAGS) -Wno-variadic-macros

View File

@@ -0,0 +1,821 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "msbuild.h"
#include "config.h"
#include <algorithm>
#include <fstream>
namespace CreateProjectTool {
//////////////////////////////////////////////////////////////////////////
// MSBuild Provider (Visual Studio 2010 and later)
//////////////////////////////////////////////////////////////////////////
MSBuildProvider::MSBuildProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, StringList &global_errors, const int version, const MSVCVersion &msvc)
: MSVCProvider(global_warnings, project_warnings, global_errors, version, msvc) {
_archs.push_back(ARCH_X86);
_archs.push_back(ARCH_AMD64);
_archs.push_back(ARCH_ARM64);
}
const char *MSBuildProvider::getProjectExtension() {
return ".vcxproj";
}
const char *MSBuildProvider::getPropertiesExtension() {
return ".props";
}
namespace {
inline void outputConfiguration(std::ostream &project, const std::string &config, MSVC_Architecture arch) {
project << "\t\t<ProjectConfiguration Include=\"" << config << "|" << getMSVCConfigName(arch) << "\">\n"
<< "\t\t\t<Configuration>" << config << "</Configuration>\n"
<< "\t\t\t<Platform>" << getMSVCConfigName(arch) << "</Platform>\n"
<< "\t\t</ProjectConfiguration>\n";
}
inline void outputConfigurationType(const BuildSetup &setup, std::ostream &project, const std::string &name, const std::string &config, MSVC_Architecture arch, const MSVCVersion &msvc) {
project << "\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='" << config << "|" << getMSVCConfigName(arch) << "'\" Label=\"Configuration\">\n";
if (name == setup.projectName || setup.devTools || setup.tests) {
project << "\t\t<ConfigurationType>Application</ConfigurationType>\n";
} else {
project << "\t\t<ConfigurationType>StaticLibrary</ConfigurationType>\n";
}
project << "\t\t<PlatformToolset>" << (config == "LLVM" ? msvc.toolsetLLVM : msvc.toolsetMSVC ) << "</PlatformToolset>\n";
project << "\t\t<CharacterSet>" << (setup.useWindowsUnicode ? "Unicode" : "NotSet") << "</CharacterSet>\n";
if (msvc.version >= 16 && config == "ASan") {
project << "\t\t<EnableASAN>true</EnableASAN>\n";
}
project << "\t</PropertyGroup>\n";
}
inline void outputProperties(const BuildSetup &setup, std::ostream &project, const std::string &config, MSVC_Architecture arch) {
project << "\t<ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='" << config << "|" << getMSVCConfigName(arch) << "'\" 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=\"" << setup.projectDescription + '_' << config << getMSVCArchName(arch) << ".props" << "\" />\n"
<< "\t</ImportGroup>\n";
}
} // End of anonymous namespace
void MSBuildProvider::createProjectFile(const std::string &name, const std::string &uuid, const BuildSetup &setup, const std::string &moduleDir,
const StringList &includeList, const StringList &excludeList, const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) {
const std::string projectFile = setup.outputDir + '/' + name + getProjectExtension();
std::ofstream project(projectFile.c_str());
if (!project || !project.is_open()) {
error("Could not open \"" + projectFile + "\" for writing");
return;
}
project << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
<< "<Project DefaultTargets=\"Build\" ToolsVersion=\"" << _msvcVersion.project << "\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n"
<< "\t<ItemGroup Label=\"ProjectConfigurations\">\n";
for (std::list<MSVC_Architecture>::const_iterator arch = _archs.begin(); arch != _archs.end(); ++arch) {
outputConfiguration(project, "Debug", *arch);
outputConfiguration(project, "ASan", *arch);
outputConfiguration(project, "LLVM", *arch);
outputConfiguration(project, "Release", *arch);
}
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\t<VCTargetsPath Condition=\"'$(VCTargetsPath" << _version << ")' != '' and '$(VSVersion)' == '' and $(VisualStudioVersion) == ''\">$(VCTargetsPath" << _version << ")</VCTargetsPath>\n"
<< "\t</PropertyGroup>\n";
// Shared configuration
project << "\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n";
for (std::list<MSVC_Architecture>::const_iterator arch = _archs.begin(); arch != _archs.end(); ++arch) {
outputConfigurationType(setup, project, name, "Release", *arch, _msvcVersion);
outputConfigurationType(setup, project, name, "ASan", *arch, _msvcVersion);
outputConfigurationType(setup, project, name, "LLVM", *arch, _msvcVersion);
outputConfigurationType(setup, project, name, "Debug", *arch, _msvcVersion);
}
project << "\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n"
<< "\t<ImportGroup Label=\"ExtensionSettings\">\n"
<< "\t</ImportGroup>\n";
for (std::list<MSVC_Architecture>::const_iterator arch = _archs.begin(); arch != _archs.end(); ++arch) {
outputProperties(setup, project, "Release", *arch);
outputProperties(setup, project, "ASan", *arch);
outputProperties(setup, project, "LLVM", *arch);
outputProperties(setup, project, "Debug", *arch);
}
project << "\t<PropertyGroup Label=\"UserMacros\" />\n";
// Project-specific settings (asan uses debug properties)
for (std::list<MSVC_Architecture>::const_iterator arch = _archs.begin(); arch != _archs.end(); ++arch) {
BuildSetup archsetup = setup;
std::map<MSVC_Architecture, StringList>::const_iterator disabled_features_it = _arch_disabled_features.find(*arch);
if (disabled_features_it != _arch_disabled_features.end()) {
for (StringList::const_iterator j = disabled_features_it->second.begin(); j != disabled_features_it->second.end(); ++j) {
archsetup = removeFeatureFromSetup(archsetup, *j);
}
}
outputProjectSettings(project, name, archsetup, false, *arch, "Debug");
outputProjectSettings(project, name, archsetup, false, *arch, "ASan");
outputProjectSettings(project, name, archsetup, false, *arch, "LLVM");
outputProjectSettings(project, name, archsetup, true, *arch, "Release");
}
// 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.empty())
addFilesToProject(moduleDir, project, includeList, excludeList, pchIncludeRoot, pchDirs, pchExclude, setup.filePrefix + '/' + modulePath);
else
addFilesToProject(moduleDir, project, includeList, excludeList, pchIncludeRoot, pchDirs, pchExclude, setup.filePrefix);
// Output references for the main project
if (name == setup.projectName)
writeReferences(setup, project);
// Output auto-generated test runner
if (setup.tests) {
project << "\t<ItemGroup>\n";
project << "\t\t<ClCompile Include=\"test/runner/test_runner.cpp\" />\n";
project << "\t\t<ClCompile Include=\"" << setup.srcDir << "/test/system/null_osystem.cpp\" />\n";
project << "\t\t<ClCompile Remove=\"" << setup.srcDir << "/backends/base-backend.cpp\" />\n"; // symbols are already defined in null_osystem.cpp
project << "\t</ItemGroup>\n";
}
// Visual Studio 2015 and up automatically import natvis files that are part of the project
if (name == PROJECT_NAME && _version >= 14) {
project << "\t<ItemGroup>\n";
project << "\t\t<None Include=\"" << setup.srcDir << "/devtools/create_project/scripts/scummvm.natvis\" />\n";
project << "\t</ItemGroup>\n";
}
project << "\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n"
"\t<ImportGroup Label=\"ExtensionTargets\">\n"
"\t</ImportGroup>\n";
if (setup.tests) {
// We override the normal target to ignore the exit code (this allows us to have a clean output and not message about the command exit code)
project << "\t\t<Target Name=\"PostBuildEvent\">\n"
<< "\t\t\t<Message Text=\"Description: Run tests\" />\n"
<< "\t\t\t<Copy SourceFiles=\"" + setup.filePrefix + "/dists/engine-data/encoding.dat\" DestinationFolder=\"$(ProjectDir)test/engine-data\" SkipUnchangedFiles=\"true\" />\n"
<< "\t\t\t<Exec Command=\"$(TargetPath)\" IgnoreExitCode=\"true\" />\n"
<< "\t\t</Target>\n";
}
project << "</Project>\n";
// Output filter file if necessary
createFiltersFile(setup, name);
}
void MSBuildProvider::createFiltersFile(const BuildSetup &setup, const std::string &name) {
// No filters => no need to create a filter file
if (_filters.empty())
return;
// Sort all list alphabetically
_filters.sort();
_compileFiles.sort();
_includeFiles.sort();
_otherFiles.sort();
_resourceFiles.sort();
_asmFiles.sort();
const std::string filtersFile = setup.outputDir + '/' + name + getProjectExtension() + ".filters";
std::ofstream filters(filtersFile.c_str());
if (!filters || !filters.is_open()) {
error("Could not open \"" + filtersFile + "\" for writing");
return;
}
filters << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
<< "<Project ToolsVersion=\"" << _msvcVersion.project << "\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n";
// Output the list of filters
filters << "\t<ItemGroup>\n";
for (std::list<std::string>::iterator filter = _filters.begin(); filter != _filters.end(); ++filter) {
filters << "\t\t<Filter Include=\"" << *filter << "\">\n"
<< "\t\t\t<UniqueIdentifier>" << createUUID() << "</UniqueIdentifier>\n"
<< "\t\t</Filter>\n";
}
filters << "\t</ItemGroup>\n";
// Output files
outputFilter(filters, _compileFiles, "ClCompile");
outputFilter(filters, _includeFiles, "ClInclude");
outputFilter(filters, _otherFiles, "None");
outputFilter(filters, _resourceFiles, "ResourceCompile");
outputFilter(filters, _asmFiles, "CustomBuild");
filters << "</Project>";
}
void MSBuildProvider::outputFilter(std::ostream &filters, const FileEntries &files, const std::string &action) {
if (!files.empty()) {
filters << "\t<ItemGroup>\n";
for (FileEntries::const_iterator entry = files.begin(), end = files.end(); entry != end; ++entry) {
if ((*entry).filter != "") {
filters << "\t\t<" << action << " Include=\"" << (*entry).path << "\">\n"
<< "\t\t\t<Filter>" << (*entry).filter << "</Filter>\n"
<< "\t\t</" << action << ">\n";
} else {
filters << "\t\t<" << action << " Include=\"" << (*entry).path << "\" />\n";
}
}
filters << "\t</ItemGroup>\n";
}
}
void MSBuildProvider::writeReferences(const BuildSetup &setup, std::ofstream &output) {
output << "\t<ItemGroup>\n";
for (UUIDMap::const_iterator i = _engineUuidMap.begin(); i != _engineUuidMap.end(); ++i) {
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, MSVC_Architecture arch, const std::string &configuration) {
// Check for project-specific warnings:
std::map<std::string, StringList>::iterator warningsIterator = _projectWarnings.find(name);
bool enableLanguageExtensions = find(_enableLanguageExtensions.begin(), _enableLanguageExtensions.end(), name) != _enableLanguageExtensions.end();
bool disableEditAndContinue = find(_disableEditAndContinue.begin(), _disableEditAndContinue.end(), name) != _disableEditAndContinue.end();
// Nothing to add here, move along!
if (!setup.devTools && !setup.tests && name != setup.projectName && !enableLanguageExtensions && !disableEditAndContinue && 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 << "|" << getMSVCConfigName(arch) << "'\">\n"
<< "\t\t<ClCompile>\n";
// Language Extensions
if (setup.devTools || setup.tests || name == setup.projectName || enableLanguageExtensions) {
project << "\t\t\t<DisableLanguageExtensions>false</DisableLanguageExtensions>\n";
project << "\t\t\t<ConformanceMode>false</ConformanceMode>\n"; // Required for Windows SDK 8.1
}
// Edit and Continue
if ((name == setup.projectName || disableEditAndContinue) && !isRelease)
project << "\t\t\t<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n";
// Warnings
if (warningsIterator != _projectWarnings.end())
project << "\t\t\t<DisableSpecificWarnings>" << warnings << ";%(DisableSpecificWarnings)</DisableSpecificWarnings>\n";
project << "\t\t</ClCompile>\n";
// Link configuration for main project
if (name == setup.projectName || setup.devTools || setup.tests) {
std::string libraries = outputLibraryDependencies(setup, isRelease);
// MSBuild uses ; for separators instead of spaces
for (std::string::iterator i = libraries.begin(); i != libraries.end(); ++i) {
if (*i == ' ') {
*i = ';';
}
}
project << "\t\t<Link>\n"
<< "\t\t\t<OutputFile>$(OutDir)" << ((setup.devTools || setup.tests) ? name : setup.projectName) << ".exe</OutputFile>\n"
<< "\t\t\t<AdditionalDependencies>" << libraries << "%(AdditionalDependencies)</AdditionalDependencies>\n"
<< "\t\t</Link>\n";
if (!setup.devTools && !setup.tests && setup.runBuildEvents) {
project << "\t\t<PreBuildEvent>\n"
<< "\t\t\t<Message>Generate revision</Message>\n"
<< "\t\t\t<Command>" << getPreBuildEvent(setup) << "</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(arch, setup, isRelease) << "</Command>\n"
<< "\t\t</PostBuildEvent>\n";
} else if (setup.tests) {
project << "\t\t<PreBuildEvent>\n"
<< "\t\t\t<Message>Generate runner.cpp</Message>\n"
<< "\t\t\t<Command>" << getTestPreBuildEvent(setup) << "</Command>\n"
<< "\t\t</PreBuildEvent>\n";
}
}
project << "\t</ItemDefinitionGroup>\n";
}
void MSBuildProvider::outputGlobalPropFile(const BuildSetup &setup, std::ofstream &properties, MSVC_Architecture arch, 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 warningsAsErrors;
for (StringList::const_iterator i = _globalErrors.begin(); i != _globalErrors.end(); ++i)
warningsAsErrors += "/we\"" + (*i) + "\" ";
std::string definesList;
for (StringList::const_iterator i = defines.begin(); i != defines.end(); ++i)
definesList += *i + ';';
// Add define to include revision header
if (setup.runBuildEvents)
definesList += REVISION_DEFINE ";";
std::string includeSDL = setup.getSDLName();
properties << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
<< "<Project DefaultTargets=\"Build\" ToolsVersion=\"" << _msvcVersion.project << "\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n"
<< "\t<PropertyGroup>\n"
<< "\t\t<_PropertySheetDisplayName>" << setup.projectDescription << "_Global</_PropertySheetDisplayName>\n"
<< "\t\t<OutDir>$(Configuration)" << getMSVCArchName(arch) << "\\</OutDir>\n"
<< "\t\t<IntDir>$(Configuration)" << getMSVCArchName(arch) << "\\$(ProjectName)\\</IntDir>\n";
if (_msvcVersion.version >= 17 && setup.useVcpkg)
properties << "\t\t<VcpkgEnableManifest>true</VcpkgEnableManifest>\n";
properties << "\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>.;" << prefix << ";" << prefix << "\\engines;";
if (setup.tests) {
properties << prefix << "\\test\\cxxtest;";
}
// HACK to workaround SDL/SDL.h includes
if (setup.useVcpkg) {
properties << "$(_ZVcpkgCurrentInstalledDir)include\\" << includeSDL;
}
properties << "%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n"
<< "\t\t\t<PreprocessorDefinitions>" << definesList << "%(PreprocessorDefinitions)</PreprocessorDefinitions>\n"
<< "\t\t\t<ExceptionHandling>" << ((setup.devTools || setup.tests) ? "Sync" : "") << "</ExceptionHandling>\n";
#if NEEDS_RTTI
properties << "\t\t\t<RuntimeTypeInfo>true</RuntimeTypeInfo>\n";
#else
properties << "\t\t\t<RuntimeTypeInfo>false</RuntimeTypeInfo>\n";
#endif
// Print a bit more context for warnings, like modern GCC/Clang do
if (_msvcVersion.version >= 15)
properties << "\t\t\t<DiagnosticsFormat>Caret</DiagnosticsFormat>\n";
properties << "\t\t\t<WarningLevel>Level4</WarningLevel>\n"
<< "\t\t\t<TreatWarningAsError>false</TreatWarningAsError>\n"
<< "\t\t\t<CompileAs>Default</CompileAs>\n"
<< "\t\t\t<MultiProcessorCompilation>true</MultiProcessorCompilation>\n"
<< "\t\t\t<ConformanceMode>true</ConformanceMode>\n"
<< "\t\t\t<ObjectFileName>$(IntDir)dists\\msvc\\%(RelativeDir)</ObjectFileName>\n"
<< "\t\t\t<AdditionalOptions>/utf-8 " << (_msvcVersion.version >= 15 ? "/Zc:__cplusplus " : "") << warningsAsErrors << "%(AdditionalOptions)</AdditionalOptions>\n"
<< "\t\t</ClCompile>\n"
<< "\t\t<Link>\n"
<< "\t\t\t<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\n";
// console subsystem is required for text-console, tools, and tests
if (!setup.useWindowsSubsystem || setup.featureEnabled("text-console") || setup.devTools || setup.tests) {
properties << "\t\t\t<SubSystem>Console</SubSystem>\n";
} else {
properties << "\t\t\t<SubSystem>Windows</SubSystem>\n";
}
if (!setup.devTools && !setup.tests)
properties << "\t\t\t<EntryPointSymbol>WinMainCRTStartup</EntryPointSymbol>\n";
properties << "\t\t</Link>\n"
<< "\t\t<ResourceCompile>\n"
<< "\t\t\t<AdditionalIncludeDirectories>.;" << prefix << ";%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n"
<< "\t\t\t<PreprocessorDefinitions>" << definesList << "%(PreprocessorDefinitions)</PreprocessorDefinitions>\n"
<< "\t\t</ResourceCompile>\n"
<< "\t</ItemDefinitionGroup>\n"
<< "</Project>\n";
properties.flush();
}
void MSBuildProvider::createBuildProp(const BuildSetup &setup, bool isRelease, MSVC_Architecture arch, const std::string &configuration) {
std::ofstream properties((setup.outputDir + '/' + setup.projectDescription + "_" + configuration + getMSVCArchName(arch) + getPropertiesExtension()).c_str());
if (!properties || !properties.is_open()) {
error("Could not open \"" + setup.outputDir + '/' + setup.projectDescription + "_" + configuration + getMSVCArchName(arch) + getPropertiesExtension() + "\" for writing");
return;
}
std::string includeDirsList;
for (StringList::const_iterator i = setup.includeDirs.begin(); i != setup.includeDirs.end(); ++i)
includeDirsList += convertPathToWin(*i) + ';';
std::string includeSDL = setup.getSDLName();
std::string libraryDirsList;
for (StringList::const_iterator i = setup.libraryDirs.begin(); i != setup.libraryDirs.end(); ++i)
libraryDirsList += convertPathToWin(*i) + ';';
std::string libsPath;
if (setup.libsDir.empty())
libsPath = "$(" LIBS_DEFINE ")";
else
libsPath = convertPathToWin(setup.libsDir);
std::string cfgPath = (isRelease ? "Release" : "Debug");
properties << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
<< "<Project DefaultTargets=\"Build\" ToolsVersion=\"" << _msvcVersion.project << "\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n"
<< "\t<ImportGroup Label=\"PropertySheets\">\n"
<< "\t\t<Import Project=\"" << setup.projectDescription << "_Global" << getMSVCArchName(arch) << ".props\" />\n"
<< "\t</ImportGroup>\n"
<< "\t<PropertyGroup>\n"
<< "\t\t<_PropertySheetDisplayName>" << setup.projectDescription << "_" << configuration << getMSVCArchName(arch) << "</_PropertySheetDisplayName>\n"
<< "\t\t<LinkIncremental>" << ((isRelease || configuration == "ASan") ? "false" : "true") << "</LinkIncremental>\n"
<< "\t\t<GenerateManifest>false</GenerateManifest>\n";
if (!setup.useVcpkg) {
properties << "\t\t<ExecutablePath>" << libsPath << "\\bin;" << libsPath << "\\bin\\" << getMSVCArchName(arch) << ";" << libsPath << "\\" << cfgPath << "\\bin;$(ExecutablePath)</ExecutablePath>\n"
<< "\t\t<LibraryPath>" << libraryDirsList << libsPath << "\\lib\\" << getMSVCArchName(arch) << ";" << libsPath << "\\lib\\" << getMSVCArchName(arch) << "\\" << cfgPath << ";" << libsPath << "\\lib;" << libsPath << "\\" << cfgPath << "\\lib;$(LibraryPath)</LibraryPath>\n"
<< "\t\t<IncludePath>" << includeDirsList << libsPath << "\\include;" << libsPath << "\\include\\" << includeSDL << ";$(IncludePath)</IncludePath>\n";
} else {
properties << "\t\t<VcpkgTriplet>" << getMSVCArchName(arch) << "-windows</VcpkgTriplet>\n";
properties << "\t\t<VcpkgConfiguration>" << cfgPath << "</VcpkgConfiguration>\n";
}
properties << "\t</PropertyGroup>\n"
<< "\t<ItemDefinitionGroup>\n"
<< "\t\t<ClCompile>\n";
if (isRelease) {
properties << "\t\t\t<IntrinsicFunctions>true</IntrinsicFunctions>\n"
<< "\t\t\t<WholeProgramOptimization>true</WholeProgramOptimization>\n"
<< "\t\t\t<PreprocessorDefinitions>WIN32;RELEASE_BUILD;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n"
<< "\t\t\t<StringPooling>true</StringPooling>\n"
<< "\t\t\t<BufferSecurityCheck>false</BufferSecurityCheck>\n"
<< "\t\t\t<DebugInformationFormat></DebugInformationFormat>\n"
<< "\t\t\t<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n"
<< "\t\t\t<EnablePREfast>false</EnablePREfast>\n"
<< "\t\t</ClCompile>\n"
<< "\t\t<Lib>\n"
<< "\t\t\t<LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>\n"
<< "\t\t</Lib>\n"
<< "\t\t<Link>\n"
<< "\t\t\t<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>\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;" << (configuration == "LLVM" ? "_CRT_SECURE_NO_WARNINGS;" : "") << "%(PreprocessorDefinitions)</PreprocessorDefinitions>\n"
<< "\t\t\t<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\n"
<< "\t\t\t<FunctionLevelLinking>true</FunctionLevelLinking>\n"
<< "\t\t\t<TreatWarningAsError>false</TreatWarningAsError>\n";
if (configuration != "ASan") {
properties << "\t\t\t<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n";
}
// Since MSVC 2015 Edit and Continue is supported for x86 and x86-64, but not for ARM.
if (configuration != "ASan" && (arch == ARCH_X86 || (arch == ARCH_AMD64 && _version >= 14))) {
properties << "\t\t\t<DebugInformationFormat>EditAndContinue</DebugInformationFormat>\n";
} else {
properties << "\t\t\t<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n";
}
if (configuration == "LLVM") {
properties << "\t\t\t<AdditionalOptions>-Wno-microsoft -Wno-long-long -Wno-multichar -Wno-unknown-pragmas -Wno-reorder -Wpointer-arith -Wcast-qual -Wshadow -Wnon-virtual-dtor -Wwrite-strings -Wno-conversion -Wno-shorten-64-to-32 -Wno-sign-compare -Wno-four-char-constants -Wno-nested-anon-types -Qunused-arguments %(AdditionalOptions)</AdditionalOptions>\n";
}
properties << "\t\t</ClCompile>\n"
<< "\t\t<Link>\n"
<< "\t\t\t<GenerateDebugInformation>true</GenerateDebugInformation>\n"
<< "\t\t\t<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>\n";
}
properties << "\t\t</Link>\n"
<< "\t</ItemDefinitionGroup>\n"
<< "</Project>\n";
properties.flush();
properties.close();
}
bool hasEnding(std::string const &fullString, std::string const &ending) {
if (fullString.length() > ending.length()) {
return (0 == fullString.compare(fullString.length() - ending.length(), ending.length(), ending));
} else {
return false;
}
}
void MSBuildProvider::outputNasmCommand(std::ostream &projectFile, const std::string &config, const std::string &prefix) {
projectFile << "\t\t\t<Command Condition=\"'$(Configuration)|$(Platform)'=='" << config << "|Win32'\">nasm.exe -f win32 -g -o \"$(IntDir)" << prefix << "%(Filename).obj\" \"%(FullPath)\"</Command>\n"
<< "\t\t\t<Outputs Condition=\"'$(Configuration)|$(Platform)'=='" << config << "|Win32'\">$(IntDir)" << prefix << "%(Filename).obj;%(Outputs)</Outputs>\n";
if (_version >= 15) {
projectFile << "\t\t\t<OutputItemType Condition=\"'$(Configuration)|$(Platform)'=='" << config << "|Win32'\">Object</OutputItemType>\n"
<< "\t\t\t<BuildInParallel Condition=\"'$(Configuration)|$(Platform)'=='" << config << "|Win32'\">true</BuildInParallel>\n";
}
}
void MSBuildProvider::insertPathIntoDirectory(FileNode &dir, const std::string &path) {
size_t separatorLoc = path.find('\\');
if (separatorLoc != std::string::npos) {
// Inside of a subdirectory
std::string subdirName = path.substr(0, separatorLoc);
FileNode::NodeList::iterator dirIt = dir.children.begin();
FileNode::NodeList::iterator dirItEnd = dir.children.end();
while (dirIt != dirItEnd) {
if ((*dirIt)->name == subdirName)
break;
++dirIt;
}
FileNode *dirNode = nullptr;
if (dirIt == dirItEnd) {
dirNode = new FileNode(subdirName);
dir.children.push_back(dirNode);
} else {
dirNode = *dirIt;
}
insertPathIntoDirectory(*dirNode, path.substr(separatorLoc + 1));
} else {
FileNode *fileNode = new FileNode(path);
dir.children.push_back(fileNode);
}
}
void MSBuildProvider::createFileNodesFromPCHList(FileNode &dir, const std::string &pathBase, const StringList &pchCompileFiles) {
for (StringList::const_iterator it = pchCompileFiles.begin(), itEnd = pchCompileFiles.end(); it != itEnd; ++it) {
const std::string &pchPath = *it;
if (pchPath.size() > pathBase.size() && pchPath.substr(0, pathBase.size()) == pathBase) {
std::string internalPath = pchPath.substr(pathBase.size());
insertPathIntoDirectory(dir, internalPath);
}
}
}
void MSBuildProvider::writeFileListToProject(const FileNode &dir, std::ostream &projectFile, const int,
const std::string &objPrefix, const std::string &filePrefix,
const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) {
// 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, objPrefix, filePrefix);
_filters.pop_back(); // remove last empty filter
StringList pchCompileFiles;
// Output compile, include, other and resource files
outputCompileFiles(projectFile, pchIncludeRoot, pchDirs, pchExclude, pchCompileFiles);
outputFiles(projectFile, _includeFiles, "ClInclude");
outputFiles(projectFile, _otherFiles, "None");
outputFiles(projectFile, _resourceFiles, "ResourceCompile");
if (pchCompileFiles.size() > 0) {
// Generate filters and additional compile files for PCH files
FileNode pchDir(dir.name);
createFileNodesFromPCHList(pchDir, convertPathToWin(dir.name) + '\\', pchCompileFiles);
StringList backupFilters = _filters;
_filters.clear();
_filters.push_back(""); // init filters
computeFileList(pchDir, objPrefix, filePrefix);
_filters.pop_back(); // remove last empty filter
// Combine lists, removing duplicates
for (StringList::const_iterator it = backupFilters.begin(), itEnd = backupFilters.end(); it != itEnd; ++it) {
if (std::find(_filters.begin(), _filters.end(), *it) != _filters.end())
_filters.push_back(*it);
}
}
// Output asm files
if (!_asmFiles.empty()) {
projectFile << "\t<ItemGroup>\n";
for (std::list<FileEntry>::const_iterator entry = _asmFiles.begin(); entry != _asmFiles.end(); ++entry) {
projectFile << "\t\t<CustomBuild Include=\"" << (*entry).path << "\">\n"
<< "\t\t\t<FileType>Document</FileType>\n";
outputNasmCommand(projectFile, "Debug", (*entry).prefix);
outputNasmCommand(projectFile, "ASan", (*entry).prefix);
outputNasmCommand(projectFile, "Release", (*entry).prefix);
outputNasmCommand(projectFile, "LLVM", (*entry).prefix);
projectFile << "\t\t</CustomBuild>\n";
}
projectFile << "\t</ItemGroup>\n";
}
}
void MSBuildProvider::outputFiles(std::ostream &projectFile, const FileEntries &files, const std::string &action) {
if (!files.empty()) {
projectFile << "\t<ItemGroup>\n";
for (FileEntries::const_iterator entry = files.begin(), end = files.end(); entry != end; ++entry) {
projectFile << "\t\t<" << action << " Include=\"" << (*entry).path << "\" />\n";
}
projectFile << "\t</ItemGroup>\n";
}
}
void MSBuildProvider::outputCompileFiles(std::ostream &projectFile, const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude, StringList &outPCHFiles) {
const FileEntries &files = _compileFiles;
const bool hasPCH = (pchDirs.size() > 0);
std::string pchIncludeRootWin;
StringList pchDirsWin;
StringList pchExcludeWin;
if (hasPCH) {
pchIncludeRootWin = convertPathToWin(pchIncludeRoot);
// Convert PCH paths to Win
for (StringList::const_iterator entry = pchDirs.begin(), end = pchDirs.end(); entry != end; ++entry) {
std::string convertedPath = convertPathToWin(*entry);
if (convertedPath.size() < pchIncludeRootWin.size() || convertedPath.substr(0, pchIncludeRootWin.size()) != pchIncludeRootWin) {
error("PCH path '" + convertedPath + "' wasn't located under PCH include root '" + pchIncludeRootWin + "'");
}
pchDirsWin.push_back(convertPathToWin(*entry));
}
for (StringList::const_iterator entry = pchExclude.begin(), end = pchExclude.end(); entry != end; ++entry) {
const std::string path = *entry;
if (path.size() >= 2 && path[path.size() - 1] == 'o' && path[path.size() - 2] == '.')
pchExcludeWin.push_back(convertPathToWin(path.substr(0, path.size() - 2)));
}
}
std::map<std::string, PCHInfo> pchMap;
if (!files.empty()) {
projectFile << "\t<ItemGroup>\n";
for (FileEntries::const_iterator entry = files.begin(), end = files.end(); entry != end; ++entry) {
std::string pchIncludePath, pchFilePath, pchFileName;
bool fileHasPCH = false;
if (hasPCH)
fileHasPCH = calculatePchPaths(entry->path, pchIncludeRootWin, pchDirsWin, pchExcludeWin, '\\', pchIncludePath, pchFilePath, pchFileName);
if (fileHasPCH) {
std::string pchOutputFileName = "$(IntDir)dists\\msvc\\%(RelativeDir)" + pchFileName.substr(0, pchFileName.size() - 2) + ".pch";
PCHInfo &pchInfo = pchMap[pchFilePath];
pchInfo.file = pchIncludePath;
pchInfo.outputFile = pchOutputFileName;
projectFile << "\t\t<ClCompile Include=\"" << (*entry).path << "\">\n";
projectFile << "\t\t\t<PrecompiledHeader>Use</PrecompiledHeader>\n";
projectFile << "\t\t\t<PrecompiledHeaderFile>" << pchIncludePath << "</PrecompiledHeaderFile>\n";
projectFile << "\t\t\t<PrecompiledHeaderOutputFile>" << pchOutputFileName << "</PrecompiledHeaderOutputFile>\n";
projectFile << "\t\t</ClCompile>\n";
} else {
projectFile << "\t\t<ClCompile Include=\"" << (*entry).path << "\" />\n";
}
}
// Flush PCH files
for (std::map<std::string, PCHInfo>::const_iterator pchIt = pchMap.begin(), pchItEnd = pchMap.end(); pchIt != pchItEnd; ++pchIt) {
const PCHInfo &pchInfo = pchIt->second;
const std::string &filePath = pchIt->first;
assert(filePath.size() >= 2 && filePath.substr(filePath.size() - 2) == ".h");
std::string cppFilePath = filePath.substr(0, filePath.size() - 2) + ".cpp";
std::string expectedContents = "/* This file is automatically generated by create_project */\n"
"/* DO NOT EDIT MANUALLY */\n"
"#include \"" + pchInfo.file + "\"\n";
// Try to avoid touching the generated .cpp if it's identical to the expected output.
// If we touch the file, then every file that includes PCH needs to be recompiled.
std::ifstream pchInputFile(cppFilePath.c_str());
bool needToEmit = true;
if (pchInputFile && pchInputFile.is_open()) {
std::string fileContents;
for (;;) {
char buffer[1024];
size_t numRead = sizeof(buffer) - 1;
pchInputFile.read(buffer, numRead);
buffer[pchInputFile.gcount()] = '\0';
fileContents += buffer;
if (pchInputFile.eof() || pchInputFile.fail())
break;
if (fileContents.size() > expectedContents.size())
break;
}
needToEmit = (fileContents != expectedContents);
pchInputFile.close();
}
if (needToEmit) {
std::ofstream pchOutputFile(cppFilePath.c_str());
if (!pchOutputFile || !pchOutputFile.is_open()) {
error("Could not open \"" + cppFilePath + "\" for writing");
return;
}
pchOutputFile << expectedContents;
pchOutputFile.close();
}
projectFile << "\t\t<ClCompile Include=\"" << cppFilePath << "\">\n";
projectFile << "\t\t\t<PrecompiledHeader>Create</PrecompiledHeader>\n";
projectFile << "\t\t\t<PrecompiledHeaderFile>" << pchInfo.file << "</PrecompiledHeaderFile>\n";
projectFile << "\t\t\t<PrecompiledHeaderOutputFile>" << pchInfo.outputFile << "</PrecompiledHeaderOutputFile>\n";
projectFile << "\t\t</ClCompile>\n";
outPCHFiles.push_back(cppFilePath);
}
projectFile << "\t</ItemGroup>\n";
}
}
void MSBuildProvider::computeFileList(const FileNode &dir, 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, 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);
}
}
}
} // namespace CreateProjectTool

View File

@@ -0,0 +1,92 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TOOLS_CREATE_PROJECT_MSBUILD_H
#define TOOLS_CREATE_PROJECT_MSBUILD_H
#include "msvc.h"
namespace CreateProjectTool {
class MSBuildProvider final : public MSVCProvider {
public:
MSBuildProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, StringList &global_errors, const int version, const MSVCVersion &msvc);
protected:
void 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 &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) override;
void outputProjectSettings(std::ofstream &project, const std::string &name, const BuildSetup &setup, bool isRelease, MSVC_Architecture arch, const std::string &configuration);
void writeFileListToProject(const FileNode &dir, std::ostream &projectFile, const int indentation,
const std::string &objPrefix, const std::string &filePrefix,
const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) override;
void writeReferences(const BuildSetup &setup, std::ofstream &output) override;
void outputGlobalPropFile(const BuildSetup &setup, std::ofstream &properties, MSVC_Architecture arch, const StringList &defines, const std::string &prefix) override;
void createBuildProp(const BuildSetup &setup, bool isRelease, MSVC_Architecture arch, const std::string &configuration) override;
const char *getProjectExtension() override;
const char *getPropertiesExtension() override;
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;
struct PCHInfo {
std::string file;
std::string outputFile;
};
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 std::string &objPrefix, const std::string &filePrefix);
void createFiltersFile(const BuildSetup &setup, const std::string &name);
void outputFilter(std::ostream &filters, const FileEntries &files, const std::string &action);
void outputFiles(std::ostream &projectFile, const FileEntries &files, const std::string &action);
void outputCompileFiles(std::ostream &projectFile, const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude, StringList &outPCHFiles);
void outputNasmCommand(std::ostream &projectFile, const std::string &config, const std::string &prefix);
static void createFileNodesFromPCHList(FileNode &dir, const std::string &pathBase, const StringList &pchCompileFiles);
static void insertPathIntoDirectory(FileNode &dir, const std::string &path);
};
} // namespace CreateProjectTool
#endif // TOOLS_CREATE_PROJECT_MSBUILD_H

View File

@@ -0,0 +1,368 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "msvc.h"
#include "config.h"
#include <algorithm>
#include <cstring>
#include <fstream>
namespace CreateProjectTool {
//////////////////////////////////////////////////////////////////////////
// MSVC Provider (Base class)
//////////////////////////////////////////////////////////////////////////
MSVCProvider::MSVCProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, StringList &global_errors, const int version, const MSVCVersion &msvc)
: ProjectProvider(global_warnings, project_warnings, global_errors), _version(version), _msvcVersion(msvc) {
_enableLanguageExtensions = tokenize(ENABLE_LANGUAGE_EXTENSIONS, ',');
_disableEditAndContinue = tokenize(DISABLE_EDIT_AND_CONTINUE, ',');
// NASM not supported for Windows on AMD64 target
StringList amd64_disabled_features;
amd64_disabled_features.push_back("nasm");
_arch_disabled_features[ARCH_AMD64] = amd64_disabled_features;
// NASM not supported for WoA target
StringList arm64_disabled_features;
arm64_disabled_features.push_back("nasm");
_arch_disabled_features[ARCH_ARM64] = arm64_disabled_features;
}
std::string MSVCProvider::getLibraryFromFeature(const char *feature, const BuildSetup &setup, bool isRelease) const {
static const MSVCLibrary s_libraries[] = {
// Libraries
{ "sdl", "SDL.lib", "SDLd.lib", kSDLVersion1, "winmm.lib imm32.lib version.lib setupapi.lib" },
{ "sdl", "SDL2.lib", "SDL2d.lib", kSDLVersion2, "winmm.lib imm32.lib version.lib setupapi.lib" },
{ "sdl", "SDL3.lib", "SDL3d.lib", kSDLVersion3, "winmm.lib imm32.lib version.lib setupapi.lib" },
{ "zlib", "zlib.lib", "zlibd.lib", kSDLVersionAny, nullptr },
{ "mad", "mad.lib", nullptr, kSDLVersionAny, nullptr },
{ "fribidi", "fribidi.lib", nullptr, kSDLVersionAny, nullptr },
{ "ogg", "ogg.lib", nullptr, kSDLVersionAny, nullptr },
{ "vorbis", "vorbis.lib vorbisfile.lib", nullptr, kSDLVersionAny, nullptr },
{ "tremor", "vorbisidec.lib", nullptr, kSDLVersionAny, nullptr },
{ "flac", "FLAC.lib", nullptr, kSDLVersionAny, nullptr },
{ "png", "libpng16.lib", "libpng16d.lib", kSDLVersionAny, nullptr },
{ "gif", "gif.lib", nullptr, kSDLVersionAny, nullptr },
{ "faad", "faad.lib", nullptr, kSDLVersionAny, nullptr },
{ "mikmod", "mikmod.lib", nullptr, kSDLVersionAny, nullptr },
{ "openmpt", "openmpt.lib", nullptr, kSDLVersionAny, nullptr },
{ "mpeg2", "mpeg2.lib", nullptr, kSDLVersionAny, nullptr },
{ "theoradec", "theora.lib", nullptr, kSDLVersionAny, nullptr },
{ "vpx", "vpx.lib", nullptr, kSDLVersionAny, nullptr },
{ "freetype2", "freetype.lib", "freetyped.lib", kSDLVersionAny, nullptr },
{ "jpeg", "jpeg.lib", nullptr, kSDLVersionAny, nullptr },
{"fluidsynth", "fluidsynth.lib", nullptr, kSDLVersionAny, nullptr },
{ "fluidlite", "fluidlite.lib", nullptr, kSDLVersionAny, nullptr },
{ "libcurl", "libcurl.lib", "libcurl-d.lib", kSDLVersionAny, "ws2_32.lib wldap32.lib crypt32.lib normaliz.lib" },
{ "sdlnet", "SDL_net.lib", nullptr, kSDLVersion1, "iphlpapi.lib" },
{ "sdlnet", "SDL2_net.lib", "SDL2_netd.lib", kSDLVersion2, "iphlpapi.lib" },
{ "sdlnet", "SDL3_net.lib", "SDL3_netd.lib", kSDLVersion3, "iphlpapi.lib" },
{ "discord", "discord-rpc.lib", nullptr, kSDLVersionAny, nullptr },
{ "retrowave", "RetroWave.lib", nullptr, kSDLVersionAny, nullptr },
{ "a52", "a52.lib", nullptr, kSDLVersionAny, nullptr },
{ "mpc", "libmpcdec.lib", "libmpcdec_d.lib", kSDLVersionAny, nullptr },
// Feature flags with library dependencies
{ "updates", "WinSparkle.lib", nullptr, kSDLVersionAny, nullptr },
{ "tts", nullptr, nullptr, kSDLVersionAny, "sapi.lib" },
{ "opengl", nullptr, nullptr, kSDLVersionAny, nullptr },
{ "enet", nullptr, nullptr, kSDLVersionAny, "winmm.lib ws2_32.lib" }
};
const MSVCLibrary *library = nullptr;
for (unsigned int i = 0; i < sizeof(s_libraries) / sizeof(s_libraries[0]); i++) {
if (std::strcmp(feature, s_libraries[i].feature) == 0 &&
((s_libraries[i].sdl == kSDLVersionAny) ||
(s_libraries[i].sdl == setup.useSDL))) {
library = &s_libraries[i];
break;
}
}
std::string libs;
if (library) {
// Dependencies come first
if (library->depends) {
libs += library->depends;
libs += " ";
}
// Vcpkg already adds the libs
if (!setup.useVcpkg) {
const char *basename = library->release;
// Debug name takes priority
if (!isRelease && library->debug) {
basename = library->debug;
}
if (basename) {
libs += basename;
}
}
}
return libs;
}
std::string MSVCProvider::outputLibraryDependencies(const BuildSetup &setup, bool isRelease) const {
std::string libs;
// SDL is always enabled
libs += getLibraryFromFeature("sdl", setup, isRelease);
libs += " ";
for (FeatureList::const_iterator i = setup.features.begin(); i != setup.features.end(); ++i) {
if (i->enable) {
std::string lib = getLibraryFromFeature(i->name, setup, isRelease);
if (!lib.empty())
libs += lib + " ";
}
}
return libs;
}
void MSVCProvider::createWorkspace(const BuildSetup &setup) {
if (setup.useSlnx)
createWorkspaceXml(setup);
else
createWorkspaceClassic(setup);
}
void MSVCProvider::createWorkspaceClassic(const BuildSetup &setup) {
UUIDMap::const_iterator svmUUID = _allProjUuidMap.find(setup.projectName);
if (svmUUID == _allProjUuidMap.end())
error("No UUID for \"" + setup.projectName + "\" project created");
const std::string svmProjectUUID = svmUUID->second;
assert(!svmProjectUUID.empty());
std::string solutionUUID = createUUID(setup.projectName + ".sln");
std::ofstream solution((setup.outputDir + '/' + setup.projectName + ".sln").c_str());
if (!solution || !solution.is_open()) {
error("Could not open \"" + setup.outputDir + '/' + setup.projectName + ".sln\" for writing");
return;
}
solution << "Microsoft Visual Studio Solution File, Format Version " << _msvcVersion.solutionFormat << "\n";
solution << "# Visual Studio " << _msvcVersion.solutionVersion << "\n";
if (_version >= 12) {
solution << "VisualStudioVersion = " << _msvcVersion.project << ".0.0\n";
solution << "MinimumVisualStudioVersion = 10.0.40219.1\n";
}
// Write main project
if (!setup.devTools) {
solution << "Project(\"{" << solutionUUID << "}\") = \"" << setup.projectName << "\", \"" << setup.projectName << getProjectExtension() << "\", \"{" << svmProjectUUID << "}\"\n";
// Project dependencies are moved to vcxproj files in Visual Studio 2010
if (_version < 10)
writeReferences(setup, solution);
solution << "EndProject\n";
}
// Note we assume that the UUID map only includes UUIDs for enabled engines!
for (UUIDMap::const_iterator i = _engineUuidMap.begin(); i != _engineUuidMap.end(); ++i) {
solution << "Project(\"{" << solutionUUID << "}\") = \"" << i->first << "\", \"" << i->first << getProjectExtension() << "\", \"{" << i->second << "}\"\n"
<< "EndProject\n";
}
solution << "Global\n"
"\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n";
for (std::list<MSVC_Architecture>::const_iterator arch = _archs.begin(); arch != _archs.end(); ++arch) {
solution << "\t\tDebug|" << getMSVCConfigName(*arch) << " = Debug|" << getMSVCConfigName(*arch) << "\n"
<< "\t\tASan|" << getMSVCConfigName(*arch) << " = ASan|" << getMSVCConfigName(*arch) << "\n"
<< "\t\tLLVM|" << getMSVCConfigName(*arch) << " = LLVM|" << getMSVCConfigName(*arch) << "\n"
<< "\t\tRelease|" << getMSVCConfigName(*arch) << " = Release|" << getMSVCConfigName(*arch) << "\n";
}
solution << "\tEndGlobalSection\n"
"\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n";
for (UUIDMap::const_iterator i = _allProjUuidMap.begin(); i != _allProjUuidMap.end(); ++i) {
for (std::list<MSVC_Architecture>::const_iterator arch = _archs.begin(); arch != _archs.end(); ++arch) {
solution << "\t\t{" << i->second << "}.Debug|" << getMSVCConfigName(*arch) << ".ActiveCfg = Debug|" << getMSVCConfigName(*arch) << "\n"
<< "\t\t{" << i->second << "}.Debug|" << getMSVCConfigName(*arch) << ".Build.0 = Debug|" << getMSVCConfigName(*arch) << "\n"
<< "\t\t{" << i->second << "}.ASan|" << getMSVCConfigName(*arch) << ".ActiveCfg = ASan|" << getMSVCConfigName(*arch) << "\n"
<< "\t\t{" << i->second << "}.ASan|" << getMSVCConfigName(*arch) << ".Build.0 = ASan|" << getMSVCConfigName(*arch) << "\n"
<< "\t\t{" << i->second << "}.LLVM|" << getMSVCConfigName(*arch) << ".ActiveCfg = LLVM|" << getMSVCConfigName(*arch) << "\n"
<< "\t\t{" << i->second << "}.LLVM|" << getMSVCConfigName(*arch) << ".Build.0 = LLVM|" << getMSVCConfigName(*arch) << "\n"
<< "\t\t{" << i->second << "}.Release|" << getMSVCConfigName(*arch) << ".ActiveCfg = Release|" << getMSVCConfigName(*arch) << "\n"
<< "\t\t{" << i->second << "}.Release|" << getMSVCConfigName(*arch) << ".Build.0 = Release|" << getMSVCConfigName(*arch) << "\n";
}
}
solution << "\tEndGlobalSection\n"
<< "\tGlobalSection(SolutionProperties) = preSolution\n"
<< "\t\tHideSolutionNode = FALSE\n"
<< "\tEndGlobalSection\n"
<< "EndGlobal\n";
}
void MSVCProvider::createWorkspaceXml(const BuildSetup &setup) {
const auto svmUUID = _allProjUuidMap.find(setup.projectName);
if (svmUUID == _allProjUuidMap.end())
error("No UUID for \"" + setup.projectName + "\" project created");
const std::string &svmProjectUUID = svmUUID->second;
assert(!svmProjectUUID.empty());
std::ofstream solution((setup.outputDir + '/' + setup.projectName + ".slnx").c_str());
if (!solution || !solution.is_open()) {
error("Could not open \"" + setup.outputDir + '/' + setup.projectName + ".slnx\" for writing");
return;
}
solution << "<Solution>\n";
solution << "\t<Configurations>\n";
solution << "\t\t<BuildType Name=\"ASan\" />\n";
solution << "\t\t<BuildType Name=\"Debug\" />\n";
solution << "\t\t<BuildType Name=\"LLVM\" />\n";
solution << "\t\t<BuildType Name=\"Release\" />\n";
for (const auto &arch : _archs) {
solution << "\t\t<Platform Name=\"" << getMSVCConfigName(arch) << "\" />\n";
}
solution << "\t</Configurations>\n";
// Write main project
if (!setup.devTools) {
solution << "\t<Project Path=\"" << setup.projectName << getProjectExtension()
<< "\" Id=\"" << svmProjectUUID << "\" "
<< " DefaultStartup=\"true\"" /* DefaultStartup has no effect in VS2022, needs VS2026+ */
<< " />\n";
}
for (const auto &engineUuid : _engineUuidMap) {
solution << "\t<Project Path=\"" << engineUuid.first << getProjectExtension()
<< "\" Id=\"" << engineUuid.second
<< "\" />\n";
}
solution << "</Solution>\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 asan configuration
for (std::list<MSVC_Architecture>::const_iterator arch = _archs.begin(); arch != _archs.end(); ++arch) {
createBuildProp(setup, true, *arch, "Release");
createBuildProp(setup, false, *arch, "Debug");
createBuildProp(setup, false, *arch, "ASan");
createBuildProp(setup, false, *arch, "LLVM");
}
}
void MSVCProvider::addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList) {
includeList.push_back(setup.srcDir + "/icons/" + setup.projectName + ".ico");
includeList.push_back(setup.srcDir + "/dists/" + setup.projectName + ".rc");
}
void MSVCProvider::createGlobalProp(const BuildSetup &setup) {
for (std::list<MSVC_Architecture>::const_iterator arch = _archs.begin(); arch != _archs.end(); ++arch) {
std::ofstream properties((setup.outputDir + '/' + setup.projectDescription + "_Global" + getMSVCArchName(*arch) + getPropertiesExtension()).c_str());
if (!properties)
error("Could not open \"" + setup.outputDir + '/' + setup.projectDescription + "_Global" + getMSVCArchName(*arch) + getPropertiesExtension() + "\" for writing");
BuildSetup archSetup = setup;
std::map<MSVC_Architecture, StringList>::const_iterator arch_disabled_features_it = _arch_disabled_features.find(*arch);
if (arch_disabled_features_it != _arch_disabled_features.end()) {
for (StringList::const_iterator feature = arch_disabled_features_it->second.begin(); feature != arch_disabled_features_it->second.end(); ++feature) {
archSetup = removeFeatureFromSetup(archSetup, *feature);
}
}
outputGlobalPropFile(archSetup, properties, *arch, archSetup.defines, convertPathToWin(archSetup.filePrefix));
properties.close();
}
}
std::string MSVCProvider::getPreBuildEvent(const BuildSetup &setup) const {
std::string cmdLine = "";
cmdLine = "@echo off\n"
"echo Executing Pre-Build script...\n"
"echo.\n"
"@call &quot;$(SolutionDir)" + setup.filePrefix + "/devtools/create_project/scripts/prebuild.cmd&quot; &quot;$(SolutionDir)/" + setup.filePrefix + "&quot; &quot;$(SolutionDir)&quot;\n"
"EXIT /B0";
return cmdLine;
}
std::string MSVCProvider::getTestPreBuildEvent(const BuildSetup &setup) const {
// Build list of folders containing tests
std::string target = "";
for (StringList::const_iterator it = setup.testDirs.begin(); it != setup.testDirs.end(); ++it)
target += " $(SolutionDir)" + *it + "*.h";
std::string cmdLine = "";
cmdLine = "if not exist \"$(SolutionDir)test\\runner\" mkdir \"$(SolutionDir)test\\runner\"\n"
"python3 &quot;$(SolutionDir)" + setup.filePrefix + "/test/cxxtest/cxxtestgen.py&quot; --runner=ParenPrinter --no-std --no-eh -o &quot;$(SolutionDir)test/runner/test_runner.cpp&quot;" + target;
return cmdLine;
}
std::string MSVCProvider::getPostBuildEvent(MSVC_Architecture arch, const BuildSetup &setup, bool isRelease) const {
std::string cmdLine = "";
cmdLine = "@echo off\n"
"echo Executing Post-Build script...\n"
"echo.\n"
"@call &quot;$(SolutionDir)" + setup.filePrefix + "/devtools/create_project/scripts/postbuild.cmd&quot; &quot;$(SolutionDir)" + setup.filePrefix + "&quot; &quot;$(OutDir)&quot; ";
cmdLine += setup.getSDLName();
if (setup.useVcpkg) {
cmdLine += " &quot;$(_ZVcpkgCurrentInstalledDir)";
if (!isRelease) {
cmdLine += "debug/";
}
cmdLine += "bin/&quot; ";
} else {
std::string libsPath;
if (setup.libsDir.empty())
libsPath = "%" LIBS_DEFINE "%";
else
libsPath = convertPathToWin(setup.libsDir);
cmdLine += " &quot;";
cmdLine += libsPath;
cmdLine += "/lib/";
cmdLine += getMSVCArchName(arch);
cmdLine += "/$(Configuration)&quot; ";
}
// Specify if installer needs to be built or not
cmdLine += (setup.createInstaller ? "1" : "0");
cmdLine += "\n"
"EXIT /B0";
return cmdLine;
}
} // namespace CreateProjectTool

View File

@@ -0,0 +1,129 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#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, StringList &global_errors, const int version, const MSVCVersion &msvcVersion);
protected:
const int _version;
const MSVCVersion _msvcVersion;
StringList _enableLanguageExtensions;
StringList _disableEditAndContinue;
std::list<MSVC_Architecture> _archs;
std::map<MSVC_Architecture, StringList> _arch_disabled_features;
/**
* MSVC properties for a library required by a feature
*/
struct MSVCLibrary {
const char *feature; ///< Feature ID.
const char *release; ///< Filename of the Release build of the library.
const char *debug; ///< Filename of the Debug build of the library.
SDLVersion sdl; ///< Required SDL version.
const char *depends; ///< Win32 libs this library must be linked against.
};
std::string getLibraryFromFeature(const char *feature, const BuildSetup &setup, bool isRelease) const;
std::string outputLibraryDependencies(const BuildSetup &setup, bool isRelease) const;
void createWorkspace(const BuildSetup &setup) override;
void createWorkspaceClassic(const BuildSetup &setup);
void createWorkspaceXml(const BuildSetup &setup);
void createOtherBuildFiles(const BuildSetup &setup) override;
void addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList) override;
/**
* 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 setup Description of the desired build setup.
* @param properties File stream in which to write the property settings.
* @param arch Target architecture
* @param defines Defines the platform needs to have set.
* @param prefix File prefix, used to add additional include paths.
*/
virtual void outputGlobalPropFile(const BuildSetup &setup, std::ofstream &properties, MSVC_Architecture arch, 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 arch Target architecture
* @param configuration Name of property file
*/
virtual void createBuildProp(const BuildSetup &setup, bool isRelease, MSVC_Architecture arch, const std::string &configuration) = 0;
/**
* Get the file extension for property files
*/
virtual const char *getPropertiesExtension() = 0;
/**
* Get the command line for the revision tool (shared between all Visual Studio based providers)
*/
std::string getPreBuildEvent(const BuildSetup &setup) const;
/**
* Get the command line for the test generator
*
* @param setup Description of the desired build setup.
*/
std::string getTestPreBuildEvent(const BuildSetup &setup) const;
/**
* Get the command line for copying data files to the build directory.
*
* @param arch Target architecture
* @param setup Description of the desired build setup.
* @param isRelease Type of build file
*
* @return The post build event.
*/
std::string getPostBuildEvent(MSVC_Architecture arch, const BuildSetup &setup, bool isRelease) const;
};
} // namespace CreateProjectTool
#endif // TOOLS_CREATE_PROJECT_MSVC_H

View File

@@ -0,0 +1,182 @@
'
' 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.
'
'/
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' This script calls the iscc tool to generate a Inno Setup Windows installer for ScummVM
'
' It tries to read the Inno Setup installation folder from the registry and then calls the
' command line script compiler to create the installer.
'
' This is called from the postbuild.cmd batch file
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'================================================================
' TODO: Reduce duplication with revision.vbs script
' (ReadRegistryKey and ParseCommandLine are identical)
'================================================================
Option Explicit
Dim FSO : Set FSO = CreateObject("Scripting.FileSystemObject")
Dim WshShell : Set WshShell = CreateObject("WScript.Shell")
' Folders
Dim rootFolder : rootFolder = ""
Dim targetFolder : targetFolder = ""
' Parse our command line arguments
If ParseCommandLine() Then
CreateInstaller()
End If
'////////////////////////////////////////////////////////////////
'// Installer creation
'////////////////////////////////////////////////////////////////
Sub CreateInstaller()
' Get inno installation folder
Dim innoPath : innoPath = GetInnoPath()
If (innoPath = "") Then
Exit Sub
End If
' Build command line
Dim commandLine : commandLine = """" & innoPath & "\iscc.exe"" /Qp" & _
" /O""" & targetFolder & """" & _
" """ & rootFolder & "\dists\win32\scummvm.iss"""
Dim oExec: Set oExec = WshShell.Exec(commandline)
If Err.Number <> 0 Then
Wscript.StdErr.WriteLine "Error running iscc.exe!"
Exit Sub
End If
' Wait till the application is finished ...
Dim ostdOut : Set oStdOut = oExec.StdOut
Do While oExec.Status = 0
If Not ostdOut.AtEndOfStream Then
Wscript.StdErr.WriteLine ostdOut.ReadAll
End If
WScript.Sleep 100
Loop
If oExec.ExitCode <> 0 Then
Wscript.StdErr.WriteLine "Error while creating installer!"
Exit Sub
End If
End Sub
Function GetInnoPath()
' Get the directory where Inno Setup (should) reside(s)
Dim sInno
' First, try with 32-bit architecture
sInno = ReadRegistryKey("HKLM", "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Inno Setup 5_is1", "InstallLocation", 32)
If sInno = "" Or IsNull(sInno) Then
' No 32-bit version of Inno Setup installed, try 64-bit version (doesn't hurt on 32-bit machines, it returns nothing or is ignored)
sInno = ReadRegistryKey("HKLM", "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Inno Setup 5_is1", "InstallLocation", 64)
End If
' Check if Inno Setup is present
If sInno = "" Then
Wscript.StdErr.WriteLine "Inno Setup not installed!"
Exit Function
End If
GetInnoPath = sInno
End Function
'////////////////////////////////////////////////////////////////
'// Utilities
'////////////////////////////////////////////////////////////////
Function ParseCommandLine()
ParseCommandLine = True
If Wscript.Arguments.Count <> 2 Then
Wscript.StdErr.WriteLine "[Error] Invalid number of arguments (was: " & Wscript.Arguments.Count & ", expected: 2)"
ParseCommandLine = False
Exit Function
End If
' Get our arguments
rootFolder = Wscript.Arguments.Item(0)
targetFolder = Wscript.Arguments.Item(1)
' 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
If Not FSO.FolderExists(targetFolder) Then
Wscript.StdErr.WriteLine "[Error] Invalid target folder (" & targetFolder & ")"
ParseCommandLine = False
Exit Function
End If
' Set absolute paths
rootFolder = FSO.GetAbsolutePathName(rootFolder)
targetFolder = FSO.GetAbsolutePathName(targetFolder)
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

View File

@@ -0,0 +1,65 @@
@echo off
REM ---------------------------------------------------------------
REM -- Post-Build Script
REM ---------------------------------------------------------------
REM
REM Copy engine data and required dlls to the
REM output folder and optionally create an installer
REM
REM Expected parameters
REM Root folder
REM Output folder
REM SDL version
REM Libs folder
REM Installer ("1" to build, "0" to skip)
if "%~1"=="" goto error_root
if "%~2"=="" goto error_output
if "%~3"=="" goto error_sdl
if "%~4"=="" goto error_libs
if "%~5"=="" goto error_installer
echo Copying data files
echo.
xcopy /F /Y "%~4/%~3.dll" "%~2" 1>NUL 2>&1
xcopy /F /Y "%~4/WinSparkle.dll" "%~2" 1>NUL 2>&1
xcopy /F /Y "%~1/backends/vkeybd/packs/vkeybd_default.zip" "%~2" 1>NUL 2>&1
xcopy /F /Y "%~1/backends/vkeybd/packs/vkeybd_small.zip" "%~2" 1>NUL 2>&1
if "%~5"=="0" goto done
echo Running installer script
echo.
@call cscript "%~1/devtools/create_project/scripts/installer.vbs" "%~1" "%~2" 1>NUL
if not %errorlevel% == 0 goto error_script
goto done
:error_root
echo Invalid root folder (%~1)!
goto done
:error_output
echo Invalid output folder (%~2)!
goto done
:error_sdl
echo Invalid SDL parameter (was: %~3, allowed: SDL, SDL2)!
goto done
:error_libs
echo Invalid libs folder (%~4)!
goto done
:error_installer
echo Invalid installer parameter. Should be "0" or "1" (was %~5)!
goto done
:error_script:
echo An error occurred while running the installer script!
goto done
:done
exit /B0

View File

@@ -0,0 +1,33 @@
@echo off
REM ---------------------------------------------------------------
REM -- Pre-Build Script
REM ---------------------------------------------------------------
REM
REM Generate file with revision number
REM
REM Expected parameters
REM Root folder (the source root folder)
REM Target folder (the build output folder, will be used to copy internal_revision.h)
if "%~1"=="" goto error_root
if "%~2"=="" goto error_target
REM Run the revision script
@call cscript "%~1/devtools/create_project/scripts/revision.vbs" "%~1" "%~2" 1>NUL
if not %errorlevel% == 0 goto error_script
goto done
:error_root
echo Invalid root folder (%~1)!
goto done
:error_target
echo Invalid target folder (%~2)!
goto done
:error_script:
echo An error occurred while running the revision script!
:done
exit /B0

View File

@@ -0,0 +1,505 @@
'
' 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)
'
'/
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' This script tries to determine a revision number based on the current working tree
' by trying revision control tools in the following order:
' - git (with hg-git detection)
' - mercurial
' - TortoiseSVN
' - SVN
'
' It then writes a new header file to be included during build, with the revision
' information, the current branch, the revision control system (when not git) and
' a flag when the tree is dirty.
'
' This is called from the prebuild.cmd batch file
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
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 = ""
Dim targetFolder : targetFolder = ""
' 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..."
OutputRevisionHeader ""
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..."
OutputRevisionHeader ""
Exit Sub
End If
End If
End If
End If
End If
Dim outputInfo : outputInfo = "Found revision " & revision & " on branch " & branch
' Setup our revision string
Dim revisionString : revisionString = revision
If (modified) Then
revisionString = revisionString & "-dirty"
outputInfo = outputInfo & " (dirty)"
End If
' If we are not on trunk, add the branch name to the revision string
If (branch <> "trunk" And branch <> "master" And branch <> "") Then
revisionString = revisionString & "(" & branch & ")"
End If
' Add the DVCS name at the end (when not git)
If (tool <> "git") Then
revisionString = revisionString & "-" & tool
outputInfo = outputInfo & " using " & tool
End If
Wscript.StdErr.WriteLine outputInfo & vbCrLf
OutputRevisionHeader revisionString
End Sub
' Output revision header file
Sub OutputRevisionHeader(str)
FSO.CopyFile rootFolder & "\\base\\internal_revision.h.in", targetFolder & "\\internal_revision.h.tmp"
FindReplaceInFile targetFolder & "\\internal_revision.h.tmp", "@REVISION@", str
CompareFileAndReplace targetFolder & "\\internal_revision.h.tmp", targetFolder & "\\internal_revision.h"
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
Dim line
Wscript.StdErr.Write " Git... "
tool = "git"
' First check if we have both a .git & .hg 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 --unmerged")
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 --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
line = oExec.StdOut.ReadLine()
line = Mid(line, InStrRev(line, "/") + 1)
If line <> "master" Then
branch = line
End If
End If
' Get revision description
Set oExec = WshShell.Exec(gitPath & "describe --match desc/*")
If Err.Number = 0 Then
line = oExec.StdOut.ReadLine()
line = Mid(line, InStr(line, "-") + 1)
If line <> "" Then
revision = line
End If
End If
' Fallback to abbreviated revision number if needed
If revision = "" Then
revision = Mid(hash, 1, 7)
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 <> 2 Then
Wscript.StdErr.WriteLine "[Error] Invalid number of arguments (was: " & Wscript.Arguments.Count & ", expected: 2)"
ParseCommandLine = False
Exit Function
End If
' Get our arguments
rootFolder = Wscript.Arguments.Item(0)
targetFolder = Wscript.Arguments.Item(1)
' 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
If Not FSO.FolderExists(targetFolder) Then
Wscript.StdErr.WriteLine "[Error] Invalid target folder (" & targetFolder & ")"
ParseCommandLine = False
Exit Function
End If
' Set absolute paths
rootFolder = FSO.GetAbsolutePathName(rootFolder)
targetFolder = FSO.GetAbsolutePathName(targetFolder)
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
Sub FindReplaceInFile(filename, to_find, replacement)
Dim file, data
Set file = FSO.OpenTextFile(filename, 1, 0, 0)
data = file.ReadAll
file.Close
data = Replace(data, to_find, replacement)
Set file = FSO.CreateTextFile(filename, -1, 0)
file.Write data
file.Close
End Sub
Sub CompareFileAndReplace(src_filename, dst_filename)
Dim file, src_data, dst_data
Set file = FSO.OpenTextFile(src_filename, 1, 0, 0)
src_data = file.ReadAll
file.Close
If Not FSO.FileExists(dst_filename) Then
FSO.CopyFile src_filename, dst_filename, True
Else
Set file = FSO.OpenTextFile(dst_filename, 1, 0, 0)
dst_data = file.ReadAll
file.Close
If StrComp(src_data, dst_data, vbBinaryCompare) <> 0 Then
' Files are different, overwrite the destination
FSO.CopyFile src_filename, dst_filename, True
End If
End If
' Remove temporary source
FSO.DeleteFile src_filename
End Sub

View File

@@ -0,0 +1,150 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Debug visualizers for a few common ScummVM types for Visual Studio 2012 and up.
To use, copy this file into Documents\Visual Studio 20xx\Visualizers.
-->
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<UIVisualizer ServiceId="{A452AFEA-3DF6-46BB-9177-C0B08F318025}" Id="1" MenuName="Add to Image Watch"/>
<Type Name="Graphics::Surface">
<UIVisualizer ServiceId="{A452AFEA-3DF6-46BB-9177-C0B08F318025}" Id="1" />
</Type>
<Type Name="Graphics::Surface">
<Expand>
<Synthetic Name="[type]">
<DisplayString>UINT8</DisplayString>
</Synthetic>
<Item Name="[channels]" Condition="format.bytesPerPixel==1">1</Item>
<Item Name="[channels]" Condition="format.bytesPerPixel==2">2</Item>
<Synthetic Name="[channels]" Condition="format.bytesPerPixel==3">
<DisplayString>RGB</DisplayString>
</Synthetic>
<Synthetic Name="[channels]" Condition="format.bytesPerPixel==4">
<DisplayString>RGBA</DisplayString>
</Synthetic>
<Item Name="[width]">w</Item>
<Item Name="[height]">h</Item>
<Item Name="[stride]">pitch</Item>
<Item Name="[data]">pixels</Item>
</Expand>
</Type>
<Type Name="Common::Array&lt;*&gt;">
<DisplayString>{{ size={_size} }}</DisplayString>
<Expand>
<Item Name="[size]">_size</Item>
<Item Name="[capacity]">_capacity</Item>
<ArrayItems>
<Size>_size</Size>
<ValuePointer>_storage</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="Common::HashMap&lt;*,*,*,*&gt;">
<DisplayString>{{ size={_size} }}</DisplayString>
<Expand>
<Item Name="[size]">_size</Item>
<Item Name="[capacity]">_mask + 1</Item>
<Item Name="[deleted]">_deleted</Item>
<CustomListItems MaxItemsPerView="5000" ExcludeView="Test">
<Variable Name="ctr" InitialValue="0" />
<Size>_size</Size>
<Loop>
<Break Condition="ctr &gt; _mask" />
<Item Condition="_storage[ctr] &gt; 1" Name="[{_storage[ctr]->_key}]">*_storage[ctr],view(MapHelper)</Item>
<Exec>ctr++</Exec>
</Loop>
</CustomListItems>
</Expand>
</Type>
<Type Name="Common::HashMap&lt;*,*,*,*&gt;::Node" IncludeView="MapHelper">
<DisplayString>{_value}</DisplayString>
</Type>
<Type Name="Common::HashMap&lt;*,*,*,*&gt;::IteratorImpl&lt;*&gt;">
<DisplayString>{_hashmap->_storage[_idx],na}</DisplayString>
<Expand>
<Item Name="[ptr]">_hashmap->_storage[_idx]</Item>
</Expand>
</Type>
<Type Name="Common::List&lt;*&gt;">
<DisplayString Condition="&amp;_anchor == _anchor._next">{{ empty }}</DisplayString>
<DisplayString Condition="&amp;_anchor != _anchor._next">{{ non-empty }}</DisplayString>
<Expand>
<CustomListItems Condition="&amp;_anchor != _anchor._next">
<Variable Name="head" InitialValue="&amp;_anchor"/>
<Variable Name="iter" InitialValue="_anchor._next"/>
<Loop>
<Break Condition="iter == head"/>
<Item>((Common::ListInternal::Node&lt;$T1&gt;*)iter)->_data</Item>
<Exec>iter = iter->_next</Exec>
</Loop>
</CustomListItems>
</Expand>
</Type>
<Type Name="Common::ListInternal::Node&lt;*&gt;">
<DisplayString>{_data}</DisplayString>
</Type>
<Type Name="Common::ListInternal::Iterator&lt;*&gt;">
<AlternativeType Name="Common::ListInternal::ConstIterator&lt;*&gt;" />
<DisplayString>{((Common::ListInternal::Node&lt;$T1&gt;*)_node)->_data}</DisplayString>
<Expand>
<Item Name="[ptr]">((Common::ListInternal::Node&lt;$T1&gt;*)_node)->_data</Item>
</Expand>
</Type>
<Type Name="Common::String">
<DisplayString>{_str,na}</DisplayString>
<StringView>_str,na</StringView>
<Expand>
<Item Name="[size]">_size</Item>
<Item Condition="_str != _storage" Name="[capacity]">_extern._capacity</Item>
<Item Condition="_str != _storage &amp;&amp; _extern._refCount != 0" Name="[refCount]">*_extern._refCount</Item>
<ArrayItems>
<Size>_size</Size>
<ValuePointer>_str</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="Common::U32String">
<DisplayString>{_str,s32}</DisplayString>
<StringView>_str,s32</StringView>
<Expand>
<Item Name="[size]">_size</Item>
<Item Condition="_str != _storage" Name="[capacity]">_extern._capacity</Item>
<Item Condition="_str != _storage &amp;&amp; _extern._refCount != 0" Name="[refCount]">*_extern._refCount</Item>
<ArrayItems>
<Size>_size</Size>
<ValuePointer>_str</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="Common::WeakPtr&lt;*&gt;">
<DisplayString Condition="_pointer == 0">nullptr</DisplayString>
<DisplayString Condition="_pointer != 0">{*_pointer}</DisplayString>
<Expand>
<Item Condition="_pointer != 0" Name="[ptr]">_pointer</Item>
<Item Condition="_tracker != 0" Name="[refCount]">_tracker->_strongRefCount</Item>
</Expand>
</Type>
<Type Name="Common::SharedPtr&lt;*&gt;">
<DisplayString Condition="_pointer == 0">nullptr</DisplayString>
<DisplayString Condition="_pointer != 0">{*_pointer}</DisplayString>
<Expand>
<Item Condition="_pointer != 0" Name="[ptr]">_pointer</Item>
<Item Condition="_tracker != 0" Name="[refCount]">_tracker->_strongRefCount</Item>
</Expand>
</Type>
</AutoVisualizer>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,356 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TOOLS_CREATE_PROJECT_XCODE_H
#define TOOLS_CREATE_PROJECT_XCODE_H
#include "create_project.h"
#include <algorithm>
#include <vector>
namespace CreateProjectTool {
class XcodeProvider final : public ProjectProvider {
public:
XcodeProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, StringList &global_errors);
protected:
void createWorkspace(const BuildSetup &setup) final;
void createOtherBuildFiles(const BuildSetup &setup) final;
void addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList) final;
void 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 &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) final;
void writeFileListToProject(const FileNode &dir, std::ostream &projectFile, const int indentation,
const std::string &objPrefix, const std::string &filePrefix,
const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) final;
private:
enum {
kSettingsAsList = 0x01,
kSettingsSingleItem = 0x02,
kSettingsNoQuote = 0x04,
kSettingsQuoteVariable = 0x08,
kSettingsNoValue = 0x10
};
// File properties
struct FileProperty {
std::string _fileEncoding;
std::string _lastKnownFileType;
std::string _fileName;
std::string _filePath;
std::string _sourceTree;
FileProperty(const std::string &fileType = "", const std::string &name = "", const std::string &path = "", const std::string &source = "")
: _fileEncoding(""), _lastKnownFileType(fileType), _fileName(name), _filePath(path), _sourceTree(source) {
}
};
//////////////////////////////////////////////////////////////////////////
// XCObject and children
typedef std::vector<std::string> ValueList;
struct Entry {
std::string _value;
std::string _comment;
Entry(std::string val, std::string cmt) : _value(val), _comment(cmt) {}
};
typedef std::vector<Entry> EntryList;
struct Setting {
EntryList _entries;
int _flags;
int _indent;
int _order;
Setting(std::string value = "", std::string comment = "", int flgs = 0, int idt = 0, int ord = -1) : _flags(flgs), _indent(idt), _order(ord) {
_entries.push_back(Entry(value, comment));
}
Setting(ValueList values, int flgs = 0, int idt = 0, int ord = -1) : _flags(flgs), _indent(idt), _order(ord) {
for (unsigned int i = 0; i < values.size(); i++)
_entries.push_back(Entry(values[i], ""));
}
Setting(EntryList ents, int flgs = 0, int idt = 0, int ord = -1) : _entries(ents), _flags(flgs), _indent(idt), _order(ord) {}
void addEntry(std::string value, std::string comment = "") {
_entries.push_back(Entry(value, comment));
}
};
typedef std::map<std::string, Setting> SettingList;
typedef std::pair<std::string, Setting> SettingPair;
typedef std::vector<SettingPair> OrderedSettingList;
static bool OrderSortPredicate(const SettingPair &s1, const SettingPair &s2) {
return s1.second._order < s2.second._order;
}
struct Property {
public:
SettingList _settings;
int _flags;
bool _hasOrder;
Property() : _flags(0), _hasOrder(false) {}
// Constructs a simple Property
Property(std::string name, std::string value = "", std::string comment = "", int flgs = 0, int indent = 0, bool order = false) : _flags(flgs), _hasOrder(order) {
_settings[name] = Setting(value, comment, _flags, indent);
}
Property(std::string name, ValueList values, int flgs = 0, int indent = 0, bool order = false) : _flags(flgs), _hasOrder(order) {
_settings[name] = Setting(values, _flags, indent);
}
OrderedSettingList getOrderedSettingList() {
OrderedSettingList list;
// Prepare vector to sort
for (SettingList::const_iterator setting = _settings.begin(); setting != _settings.end(); ++setting)
list.push_back(SettingPair(setting->first, setting->second));
// Sort vector using setting order
if (_hasOrder)
std::sort(list.begin(), list.end(), OrderSortPredicate);
return list;
}
};
typedef std::map<std::string, Property> PropertyList;
// Main object struct
// This is all a big hack unfortunately, but making everything all properly abstracted would
// be overkill since we only have to generate a single project
struct Object {
public:
std::string _id; // Unique identifier for this object
std::string _name; // Name (may not be unique - for ex. configuration entries)
std::string _refType; // Type of object this references (if any)
std::string _comment; // Main comment (empty for no comment)
PropertyList _properties; // List of object properties, including output configuration
// Constructs an object and add a default type property
Object(XcodeProvider *objectParent, std::string objectId, std::string objectName, std::string objectType, std::string objectRefType = "", std::string objectComment = "")
: _id(objectId), _name(objectName), _refType(objectRefType), _comment(objectComment), _parent(objectParent) {
assert(objectParent);
assert(!objectId.empty());
assert(!objectName.empty());
assert(!objectType.empty());
addProperty("isa", objectType, "", kSettingsNoQuote | kSettingsNoValue);
}
virtual ~Object() {}
// Add a simple Property with just a name and a value
void addProperty(std::string propName, std::string propValue, std::string propComment = "", int propFlags = 0, int propIndent = 0) {
_properties[propName] = Property(propValue, "", propComment, propFlags, propIndent);
}
std::string toString(int flags = 0) {
std::string output;
output = "\t\t" + _parent->getHash(_id) + (_comment.empty() ? "" : " /* " + _comment + " */") + " = {";
if (flags & kSettingsAsList)
output += "\n";
// Special case: always output the isa property first
output += _parent->writeProperty("isa", _properties["isa"], flags);
// Write each property
for (PropertyList::iterator property = _properties.begin(); property != _properties.end(); ++property) {
if (property->first == "isa")
continue;
output += _parent->writeProperty(property->first, property->second, flags);
}
if (flags & kSettingsAsList)
output += "\t\t";
output += "};\n";
return output;
}
// Slight hack, to allow Group access to parent.
protected:
XcodeProvider *_parent;
private:
// Returns the type property (should always be the first in the properties map)
std::string getType() {
assert(!_properties.empty());
assert(!_properties["isa"]._settings.empty());
SettingList::iterator it = _properties["isa"]._settings.begin();
return it->first;
}
};
struct ObjectList {
private:
std::map<std::string, bool> _objectMap;
public:
std::vector<Object *> _objects;
std::string _comment;
int _flags = 0;
~ObjectList() {
for (Object *obj : _objects) {
delete obj;
}
}
void add(Object *obj) {
std::map<std::string, bool>::iterator it = _objectMap.find(obj->_id);
if (it != _objectMap.end() && it->second == true) {
delete obj;
return;
}
_objects.push_back(obj);
_objectMap[obj->_id] = true;
}
Object *find(std::string id) {
for (std::vector<Object *>::iterator it = _objects.begin(); it != _objects.end(); ++it) {
if ((*it)->_id == id) {
return *it;
}
}
return NULL;
}
std::string toString() {
std::string output;
if (!_comment.empty())
output = "\n/* Begin " + _comment + " section */\n";
for (std::vector<Object *>::iterator object = _objects.begin(); object != _objects.end(); ++object)
output += (*object)->toString(_flags);
if (!_comment.empty())
output += "/* End " + _comment + " section */\n";
return output;
}
};
// A class to maintain a folder-reference group-hierarchy, which together with the functionality below
// allows for breaking up sub-paths into a chain of groups. This helps with merging engines into the
// overall group-layout.
class Group : public Object {
int _childOrder;
std::map<std::string, Group *> _childGroups;
std::string _treeName;
void addChildInternal(const std::string &id, const std::string &comment);
public:
Group(XcodeProvider *objectParent, const std::string &groupName, const std::string &uniqueName, const std::string &path);
void addChildFile(const std::string &name);
void addChildByHash(const std::string &hash, const std::string &name);
// Should be passed the hash for the entry
void addChildGroup(const Group *group);
void ensureChildExists(const std::string &name);
Group *getChildGroup(const std::string &name);
std::string getHashRef() const { return _parent->getHash(_id); }
};
// The path used by the root-source group
std::string _projectRoot;
// The base source group, currently also re-purposed for containing the various support-groups.
Group *_rootSourceGroup;
// Helper function to create the chain of groups for the various subfolders. Necessary as
// create_project likes to start in engines/
Group *touchGroupsForPath(const std::string &path);
// Functionality for adding file-refs and build-files, as Group-objects need to be able to do this.
void addFileReference(const std::string &id, const std::string &name, FileProperty properties);
void addProductFileReference(const std::string &id, const std::string &name);
void addBuildFile(const std::string &id, const std::string &name, const std::string &fileRefId, const std::string &comment);
// All objects
std::map<std::string, std::string> _hashDictionnary;
ValueList _defines;
// Targets
ValueList _targets;
// Lists of objects
ObjectList _buildFile;
ObjectList _copyFilesBuildPhase;
ObjectList _fileReference;
ObjectList _frameworksBuildPhase;
ObjectList _groups;
ObjectList _nativeTarget;
ObjectList _project;
ObjectList _resourcesBuildPhase;
ObjectList _sourcesBuildPhase;
ObjectList _buildConfiguration;
ObjectList _configurationList;
void outputMainProjectFile(const BuildSetup &setup);
// Setup objects
void setupCopyFilesBuildPhase();
void setupFrameworksBuildPhase(const BuildSetup &setup);
void setupNativeTarget();
void setupProject();
void setupResourcesBuildPhase(const BuildSetup &setup);
void setupSourcesBuildPhase();
void setupBuildConfiguration(const BuildSetup &setup);
void setupImageAssetCatalog(const BuildSetup &setup);
void setupAdditionalSources(std::string targetName, Property &files, int &order);
// Misc
void setupDefines(const BuildSetup &setup); // Setup the list of defines to be used on build configurations
// Retrieve information
ValueList& getResourceFiles(const BuildSetup &setup) const;
std::string getLibString(std::string libName, bool xcframework) const;
// Hash generation
std::string getHash(std::string key);
#ifdef MACOSX
std::string md5(std::string key);
#endif
std::string newHash() const;
// Output
std::string writeProperty(const std::string &variable, Property &property, int flags = 0) const;
std::string writeSetting(const std::string &variable, std::string name, std::string comment = "", int flags = 0, int indent = 0) const;
std::string writeSetting(const std::string &variable, const Setting &setting) const;
};
} // End of CreateProjectTool namespace
#endif // TOOLS_CREATE_PROJECT_XCODE_H

View File

@@ -0,0 +1,275 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
076583601D660492006CBB9B /* cmake.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0765835E1D660492006CBB9B /* cmake.cpp */; };
F9A66C691396D4DF00CEE494 /* codeblocks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9A66C5F1396D4DF00CEE494 /* codeblocks.cpp */; };
F9A66C6A1396D4DF00CEE494 /* create_project.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9A66C621396D4DF00CEE494 /* create_project.cpp */; };
F9A66C6B1396D4DF00CEE494 /* msbuild.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9A66C651396D4DF00CEE494 /* msbuild.cpp */; };
F9A66C6C1396D4DF00CEE494 /* msvc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9A66C671396D4DF00CEE494 /* msvc.cpp */; };
F9A66C871396E2F500CEE494 /* xcode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9A66C861396E2F500CEE494 /* xcode.cpp */; };
F9A66C91139704A400CEE494 /* create_project in CopyFiles */ = {isa = PBXBuildFile; fileRef = F9A66C271396D36100CEE494 /* create_project */; };
F9BA99141398064E00C276C2 /* create_project in CopyFiles */ = {isa = PBXBuildFile; fileRef = F9A66C271396D36100CEE494 /* create_project */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
F9A66C251396D36100CEE494 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 12;
dstPath = ../../../../../dists/ios7;
dstSubfolderSpec = 16;
files = (
F9A66C91139704A400CEE494 /* create_project in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F9BA99131398063A00C276C2 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = ../../../../../dists/macosx;
dstSubfolderSpec = 16;
files = (
F9BA99141398064E00C276C2 /* create_project in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
0765835E1D660492006CBB9B /* cmake.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cmake.cpp; path = ../cmake.cpp; sourceTree = "<group>"; };
0765835F1D660492006CBB9B /* cmake.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cmake.h; path = ../cmake.h; sourceTree = "<group>"; };
F9A66C271396D36100CEE494 /* create_project */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = create_project; sourceTree = BUILT_PRODUCTS_DIR; };
F9A66C491396D47500CEE494 /* installer.vbs */ = {isa = PBXFileReference; lastKnownFileType = text; name = installer.vbs; path = ../scripts/installer.vbs; sourceTree = "<group>"; };
F9A66C4A1396D47500CEE494 /* postbuild.cmd */ = {isa = PBXFileReference; lastKnownFileType = text; name = postbuild.cmd; path = ../scripts/postbuild.cmd; sourceTree = "<group>"; };
F9A66C4B1396D47500CEE494 /* prebuild.cmd */ = {isa = PBXFileReference; lastKnownFileType = text; name = prebuild.cmd; path = ../scripts/prebuild.cmd; sourceTree = "<group>"; };
F9A66C4C1396D47500CEE494 /* revision.vbs */ = {isa = PBXFileReference; lastKnownFileType = text; name = revision.vbs; path = ../scripts/revision.vbs; sourceTree = "<group>"; };
F9A66C5F1396D4DF00CEE494 /* codeblocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = codeblocks.cpp; path = ../codeblocks.cpp; sourceTree = "<group>"; };
F9A66C601396D4DF00CEE494 /* codeblocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = codeblocks.h; path = ../codeblocks.h; sourceTree = "<group>"; };
F9A66C611396D4DF00CEE494 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = config.h; path = ../config.h; sourceTree = "<group>"; };
F9A66C621396D4DF00CEE494 /* create_project.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = create_project.cpp; path = ../create_project.cpp; sourceTree = "<group>"; };
F9A66C631396D4DF00CEE494 /* create_project.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = create_project.h; path = ../create_project.h; sourceTree = "<group>"; };
F9A66C641396D4DF00CEE494 /* module.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = module.mk; path = ../module.mk; sourceTree = "<group>"; };
F9A66C651396D4DF00CEE494 /* msbuild.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = msbuild.cpp; path = ../msbuild.cpp; sourceTree = "<group>"; };
F9A66C661396D4DF00CEE494 /* msbuild.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = msbuild.h; path = ../msbuild.h; sourceTree = "<group>"; };
F9A66C671396D4DF00CEE494 /* msvc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = msvc.cpp; path = ../msvc.cpp; sourceTree = "<group>"; };
F9A66C681396D4DF00CEE494 /* msvc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = msvc.h; path = ../msvc.h; sourceTree = "<group>"; };
F9A66C841396E2D800CEE494 /* xcode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = xcode.h; path = ../xcode.h; sourceTree = "<group>"; };
F9A66C861396E2F500CEE494 /* xcode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = xcode.cpp; path = ../xcode.cpp; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
F9A66C241396D36100CEE494 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
F9A66C1C1396D36100CEE494 = {
isa = PBXGroup;
children = (
0765835E1D660492006CBB9B /* cmake.cpp */,
0765835F1D660492006CBB9B /* cmake.h */,
F9A66C861396E2F500CEE494 /* xcode.cpp */,
F9A66C841396E2D800CEE494 /* xcode.h */,
F9A66C5F1396D4DF00CEE494 /* codeblocks.cpp */,
F9A66C601396D4DF00CEE494 /* codeblocks.h */,
F9A66C611396D4DF00CEE494 /* config.h */,
F9A66C621396D4DF00CEE494 /* create_project.cpp */,
F9A66C631396D4DF00CEE494 /* create_project.h */,
F9A66C641396D4DF00CEE494 /* module.mk */,
F9A66C651396D4DF00CEE494 /* msbuild.cpp */,
F9A66C661396D4DF00CEE494 /* msbuild.h */,
F9A66C671396D4DF00CEE494 /* msvc.cpp */,
F9A66C681396D4DF00CEE494 /* msvc.h */,
F9A66C481396D45D00CEE494 /* Scripts */,
F9A66C281396D36100CEE494 /* Products */,
);
sourceTree = "<group>";
};
F9A66C281396D36100CEE494 /* Products */ = {
isa = PBXGroup;
children = (
F9A66C271396D36100CEE494 /* create_project */,
);
name = Products;
sourceTree = "<group>";
};
F9A66C481396D45D00CEE494 /* Scripts */ = {
isa = PBXGroup;
children = (
F9A66C491396D47500CEE494 /* installer.vbs */,
F9A66C4A1396D47500CEE494 /* postbuild.cmd */,
F9A66C4B1396D47500CEE494 /* prebuild.cmd */,
F9A66C4C1396D47500CEE494 /* revision.vbs */,
);
name = Scripts;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
F9A66C261396D36100CEE494 /* create_project */ = {
isa = PBXNativeTarget;
buildConfigurationList = F9A66C301396D36100CEE494 /* Build configuration list for PBXNativeTarget "create_project" */;
buildPhases = (
F9A66C231396D36100CEE494 /* Sources */,
F9A66C241396D36100CEE494 /* Frameworks */,
F9A66C251396D36100CEE494 /* CopyFiles */,
F9BA99131398063A00C276C2 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = create_project;
productName = create_project;
productReference = F9A66C271396D36100CEE494 /* create_project */;
productType = "com.apple.product-type.tool";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
F9A66C1E1396D36100CEE494 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0720;
};
buildConfigurationList = F9A66C211396D36100CEE494 /* Build configuration list for PBXProject "create_project" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = F9A66C1C1396D36100CEE494;
productRefGroup = F9A66C281396D36100CEE494 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
F9A66C261396D36100CEE494 /* create_project */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
F9A66C231396D36100CEE494 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F9A66C691396D4DF00CEE494 /* codeblocks.cpp in Sources */,
F9A66C6A1396D4DF00CEE494 /* create_project.cpp in Sources */,
F9A66C6B1396D4DF00CEE494 /* msbuild.cpp in Sources */,
F9A66C6C1396D4DF00CEE494 /* msvc.cpp in Sources */,
076583601D660492006CBB9B /* cmake.cpp in Sources */,
F9A66C871396E2F500CEE494 /* xcode.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
F9A66C2E1396D36100CEE494 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD="c++11";
CLANG_CXX_LIBRARY = "libc++";
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
POSIX,
MACOSX,
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.5;
ONLY_ACTIVE_ARCH = YES;
OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
SDKROOT = macosx;
};
name = Debug;
};
F9A66C2F1396D36100CEE494 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD="c++11";
CLANG_CXX_LIBRARY = "libc++";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_PREPROCESSOR_DEFINITIONS = (
POSIX,
MACOSX,
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.5;
OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
SDKROOT = macosx;
};
name = Release;
};
F9A66C311396D36100CEE494 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
DEBUG,
);
MACOSX_DEPLOYMENT_TARGET = 10.8;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
F9A66C321396D36100CEE494 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
MACOSX_DEPLOYMENT_TARGET = 10.8;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
F9A66C211396D36100CEE494 /* Build configuration list for PBXProject "create_project" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F9A66C2E1396D36100CEE494 /* Debug */,
F9A66C2F1396D36100CEE494 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F9A66C301396D36100CEE494 /* Build configuration list for PBXNativeTarget "create_project" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F9A66C311396D36100CEE494 /* Debug */,
F9A66C321396D36100CEE494 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = F9A66C1E1396D36100CEE494 /* Project object */;
}