diff --git a/mob.ini b/mob.ini index d79b962..ccf92a2 100644 --- a/mob.ini +++ b/mob.ini @@ -47,6 +47,7 @@ git_shallow = false [usvfs:task] git_shallow = false +configuration = Release [installer:task] enabled = false @@ -84,40 +85,14 @@ force = false configure = true pull = true -[prebuilt] -boost = true -lz4 = true -openssl = true -pyqt = true -python = true - [versions] vs = 17 vs_year = 2022 vs_toolset = 14.3 sdk = 10.0.26100.0 -sevenz = 24.09 -boost = 1.88.0 -boost_vs = 14.3 -fmt = 11.1.4 -gtest = main -directxtex = main -libloot = 0.26.1 -lz4 = v1.10.0 -nmm = 0.71.2 -openssl = 3.5.0 pyqt = 6.7.1 -pyqt_builder = 1.16.4 -pyqt_sip = 13.8.0 -python = v3.12.10 -pybind11 = v2.12.1 -bzip2 = 1.0.8 -sip = 6.8.6 -spdlog = v1.15.2 qt = 6.7.3 qt_vs = 2022 -zlib = v1.3.1 -libbsarch = 0.0.12 usvfs = master explorerpp = 1.4.0 ss_paper_lad_6788 = 7.2 @@ -130,16 +105,10 @@ ss_starfield_trosski = V1.11 ss_fallout3_trosski = v1.11 ss_fallout4_trosski = v1.11 -[build-types] -libbsarch = release -pyqt = release -python = release - [paths] third_party = prefix = cache = -patches = licenses = build = install = @@ -148,11 +117,9 @@ install_installer = install_libs = install_pdbs = install_dlls = -install_loot = install_plugins = install_stylesheets = install_licenses = -install_pythoncore = install_translations = vs = vcpkg = diff --git a/patches/pyqt/builder.py.manual_patch b/patches/pyqt/builder.py.manual_patch deleted file mode 100644 index e2f536a..0000000 --- a/patches/pyqt/builder.py.manual_patch +++ /dev/null @@ -1,36 +0,0 @@ ---- builder.py (date 1575938575861) -+++ builder.py (date 1575938575861) -@@ -402,17 +402,29 @@ - 'QMAKE_LFLAGS += -Wl,--version-script={}.exp'.format( - buildable.target)) - -- pro_lines.append( -+ if project.py_platform == 'win32': -+ for include_dir in project.py_include_dir.split(';'): -+ pro_lines.append( -+ 'INCLUDEPATH += {}'.format( -+ self.qmake_quote(include_dir))) -+ else: -+ pro_lines.append( - 'INCLUDEPATH += {}'.format( -- self.qmake_quote(project.py_include_dir))) -+ self.qmake_quote(project.py_include_dir))) - -+ if project.py_pylib_shlib != "": -+ pro_lines.append( -+ 'DEFINES += {}'.format( -+ self.qmake_quote("PYTHON_LIB=\"{}\"".format( -+ project.py_pylib_shlib)))) -+ - # Python.h on Windows seems to embed the need for pythonXY.lib, so tell - # it where it is. - # TODO: is this still necessary for Python v3.8? - if not buildable.static: - pro_lines.extend(['win32 {', -- ' LIBS += -L{}'.format( -- self.qmake_quote(project.py_pylib_dir)), -+ ' LIBS += -L{}{}'.format( -+ self.qmake_quote(project.py_pylib_dir), '' if project.py_pylib_lib == '' else ' -l' + project.py_pylib_lib), - '}']) - - # Add any installables from the buildable diff --git a/patches/python/sources/openssl.props.patch b/patches/python/sources/openssl.props.patch deleted file mode 100644 index d60f6cb..0000000 --- a/patches/python/sources/openssl.props.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- PCbuild/openssl.props (revision 5c02a39a0b31a330e06b4d6f44835afb205dc7cc) -+++ PCbuild/openssl.props (date 1575994670797) -@@ -13,6 +13,7 @@ - <_DLLSuffix>-3 - <_DLLSuffix Condition="$(Platform) == 'ARM'">$(_DLLSuffix)-arm - <_DLLSuffix Condition="$(Platform) == 'ARM64'">$(_DLLSuffix)-arm64 -+ <_DLLSuffix Condition="$(Platform) == 'x64'">$(_DLLSuffix)-x64 - $(_DLLSuffix) - - diff --git a/src/cmd/cmake.cpp b/src/cmd/cmake.cpp deleted file mode 100644 index f6ef356..0000000 --- a/src/cmd/cmake.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "pch.h" -#include "../tasks/tasks.h" -#include "commands.h" - -namespace mob { - - cmake_command::cmake_command() : command(requires_options) {} - - command::meta_t cmake_command::meta() const - { - return {"cmake", "runs cmake in a directory"}; - } - - clipp::group cmake_command::do_group() - { - return clipp::group( - clipp::command("cmake").set(picked_), - - (clipp::option("-h", "--help") >> help_) % "shows this message", - - (clipp::option("-G", "--generator") & clipp::value("GEN") >> gen_) % - ("sets the -G option for cmake [default: VS]"), - - (clipp::option("-c", "--cmd") & clipp::value("CMD") >> cmd_) % - "overrides the cmake command line [default: \"..\"]", - - (clipp::option("--x64").set(x64_, true) | - clipp::option("--x86").set(x64_, false)) % - "whether to use the x64 or x86 vcvars; if -G is not set, " - "whether to pass \"-A Win32\" or \"-A x64\" for the default " - "VS generator [default: x64]", - - (clipp::option("--install-prefix") & clipp::value("PATH") >> prefix_) % - "sets CMAKE_INSTALL_PREFIX [default: empty]", - - (clipp::option("-d", "--debug").set(debug_, true)) % - "whether to configure for debug mode [default: false]", - - (clipp::value("PATH") >> path_) % "path from which to run `cmake`"); - } - - int cmake_command::do_run() - { - auto t = tasks::modorganizer::create_cmake_tool( - fs::path(utf8_to_utf16(path_)), mob::cmake::generate, - debug_ ? config::debug : config::relwithdebinfo); - - t.generator(gen_); - t.cmd(cmd_); - t.prefix(prefix_); - t.output(path_); - - if (!x64_) - t.architecture(arch::x86); - - // copy the global context, the tool will modify it - context cxcopy(gcx()); - - t.run(cxcopy); - - return 0; - } - - std::string cmake_command::do_doc() - { - return "Runs `cmake ..` in the given directory with the same command line\n" - "as the one used for modorganizer projects."; - } - -} // namespace mob diff --git a/src/cmd/cmake_config.cpp b/src/cmd/cmake_config.cpp new file mode 100644 index 0000000..ccd7589 --- /dev/null +++ b/src/cmd/cmake_config.cpp @@ -0,0 +1,43 @@ +#include "pch.h" + +#include "../core/conf.h" +#include "../tasks/tasks.h" + +#include "commands.h" + +namespace mob { + + cmake_config_command::cmake_config_command() : command(requires_options) {} + + command::meta_t cmake_config_command::meta() const + { + return {"cmake-config", "print CMake configuration variables"}; + } + + clipp::group cmake_config_command::do_group() + { + return clipp::group( + clipp::command("cmake-config").set(picked_), + (clipp::option("-h", "--help") >> help_) % ("shows this message"), + clipp::command("prefix-path").set(var_, variable::prefix_path) | + clipp::command("install-prefix").set(var_, variable::install_prefix)); + } + + std::string cmake_config_command::do_doc() + { + return "Print CMake variables to be used when configuring projects.\n"; + } + + int cmake_config_command::do_run() + { + switch (var_) { + case variable::prefix_path: + u8cout << tasks::modorganizer::cmake_prefix_path(); + break; + case variable::install_prefix: + u8cout << conf().path().install().string(); + break; + } + return 0; + } +} // namespace mob diff --git a/src/cmd/commands.h b/src/cmd/commands.h index 267a133..801dec0 100644 --- a/src/cmd/commands.h +++ b/src/cmd/commands.h @@ -281,7 +281,6 @@ namespace mob { void make_bin(); void make_pdbs(); void make_src(); - void make_uibase(); void make_installer(); protected: @@ -297,7 +296,6 @@ namespace mob { bool bin_ = true; bool src_ = true; bool pdbs_ = true; - bool uibase_ = true; bool installer_ = false; std::string utf8out_; fs::path out_; @@ -367,27 +365,6 @@ namespace mob { std::vector get_repos() const; }; - // runs cmake in a directory with the same parameters as `build` would - // - class cmake_command : public command { - public: - cmake_command(); - meta_t meta() const override; - - protected: - clipp::group do_group() override; - int do_run() override; - std::string do_doc() override; - - private: - std::string gen_; - std::string cmd_; - bool x64_ = true; - bool debug_ = false; - std::string prefix_; - std::string path_; - }; - // lists the inis found by mob // class inis_command : public command { @@ -427,4 +404,20 @@ namespace mob { void do_build(); }; + // print CMake configuration variables + // + class cmake_config_command : public command { + public: + cmake_config_command(); + meta_t meta() const override; + + protected: + clipp::group do_group() override; + int do_run() override; + std::string do_doc() override; + + enum class variable { prefix_path, install_prefix }; + variable var_; + }; + } // namespace mob diff --git a/src/cmd/release.cpp b/src/cmd/release.cpp index 31691b4..8ae786f 100644 --- a/src/cmd/release.cpp +++ b/src/cmd/release.cpp @@ -44,9 +44,19 @@ namespace mob { u8cout << "making src archive " << path_to_utf8(out) << "\n"; const std::vector ignore = {"\\..+", // dot files - ".*\\.log", ".*\\.tlog", ".*\\.dll", - ".*\\.exe", ".*\\.lib", ".*\\.obj", - ".*\\.ts", ".*\\.aps", "vsbuild"}; + "explorer\\+\\+", + "stylesheets", + "transifex-translations" + ".*\\.log", + ".*\\.tlog", + ".*\\.dll", + ".*\\.exe", + ".*\\.lib", + ".*\\.obj", + ".*\\.ts", + ".*\\.aps", + "(bin|lib)", + "vsbuild(32|64)?"}; const std::vector ignore_re(ignore.begin(), ignore.end()); @@ -77,25 +87,6 @@ namespace mob { op::archive_from_files(gcx(), files, tasks::modorganizer::super_path(), out); } - void release_command::make_uibase() - { - const auto out = out_ / make_filename("uibase"); - u8cout << "making uibase archive " << path_to_utf8(out) << "\n"; - - std::vector files; - - if (!fs::exists(tasks::modorganizer::super_path())) { - gcx().bail_out(context::generic, "modorganizer super path not found: {}", - tasks::modorganizer::super_path()); - } - - op::archive_from_glob( - gcx(), tasks::modorganizer::super_path() / "uibase" / "src" / "*.h", out, - {}); - op::archive_from_files(gcx(), {conf().path().install_libs() / "uibase.lib"}, - conf().path().install_libs(), out); - } - void release_command::make_installer() { const auto file = "Mod.Organizer-" + version_ + ".exe"; @@ -178,11 +169,6 @@ namespace mob { clipp::option("--no-src").set(src_, false)) % "sets whether the source archive is created [default: yes]", - //( - // clipp::option("--uibase").set(uibase_, true) | - // clipp::option("--no-uibase").set(uibase_, false) - //) % "sets whether the uibase archive is created [default: yes]", - (clipp::option("--inst").set(installer_, true) | clipp::option("--no-inst").set(installer_, false)) % "sets whether the installer is copied [default: no]", @@ -271,9 +257,6 @@ namespace mob { if (src_) make_src(); - if (uibase_) - make_uibase(); - if (installer_) make_installer(); @@ -299,7 +282,6 @@ namespace mob { make_bin(); make_pdbs(); make_src(); - make_uibase(); make_installer(); return 0; diff --git a/src/core/conf.cpp b/src/core/conf.cpp index 82b38f1..b4b8583 100644 --- a/src/core/conf.cpp +++ b/src/core/conf.cpp @@ -512,7 +512,6 @@ namespace mob { set_path_if_empty("vcpkg", find_vcpkg); // set after vs as it will use the VS set_path_if_empty("qt_install", find_qt); set_path_if_empty("temp_dir", find_temp_dir); - set_path_if_empty("patches", find_in_root("patches")); set_path_if_empty("licenses", find_in_root("licenses")); set_path_if_empty("qt_bin", qt::installation_path() / "bin"); set_path_if_empty("qt_translations", qt::installation_path() / "translations"); @@ -534,10 +533,8 @@ namespace mob { resolve_path("install_libs", p.install(), "lib"); resolve_path("install_pdbs", p.install(), "pdb"); resolve_path("install_dlls", p.install_bin(), "dlls"); - resolve_path("install_loot", p.install_bin(), "loot"); resolve_path("install_plugins", p.install_bin(), "plugins"); resolve_path("install_licenses", p.install_bin(), "licenses"); - resolve_path("install_pythoncore", p.install_bin(), "pythoncore"); resolve_path("install_stylesheets", p.install_bin(), "stylesheets"); resolve_path("install_translations", p.install_bin(), "translations"); @@ -685,11 +682,6 @@ namespace mob { return {}; } - conf_prebuilt conf::prebuilt() - { - return {}; - } - conf_versions conf::version() { return {}; diff --git a/src/core/conf.h b/src/core/conf.h index c1cbcbe..4e147a3 100644 --- a/src/core/conf.h +++ b/src/core/conf.h @@ -245,7 +245,6 @@ namespace mob { VALUE(third_party); VALUE(prefix); VALUE(cache); - VALUE(patches); VALUE(licenses); VALUE(build); @@ -256,11 +255,9 @@ namespace mob { VALUE(install_pdbs); VALUE(install_dlls); - VALUE(install_loot); VALUE(install_plugins); VALUE(install_stylesheets); VALUE(install_licenses); - VALUE(install_pythoncore); VALUE(install_translations); VALUE(vs); diff --git a/src/main.cpp b/src/main.cpp index c912402..7119c6e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,36 +24,6 @@ namespace mob { // mob doesn't have a concept of task dependencies, just task ordering, so // if a task depends on another, it has to be earlier in the order - // third-party tasks - - add_task() - .add_task() - .add_task() - .add_task() - .add_task() - .add_task() - .add_task() - .add_task() - .add_task(); - - add_task() - .add_task() - .add_task() - .add_task(); - - add_task() - .add_task() - .add_task() - .add_task(); - - add_task() - .add_task() - .add_task() - .add_task() - .add_task() - .add_task() - .add_task(); - // super tasks using mo = modorganizer; @@ -61,9 +31,9 @@ namespace mob { // most of the alternate names below are from the transifex slugs, which // are sometimes different from the project names, for whatever reason - add_task() - .add_task("cmake_common") - .add_task("modorganizer-uibase"); + add_task().add_task().add_task("cmake_common"); + + add_task("modorganizer-uibase"); add_task() .add_task("modorganizer-archive") @@ -72,35 +42,13 @@ namespace mob { .add_task("modorganizer-bsatk") .add_task("modorganizer-nxmhandler") .add_task("modorganizer-helper") - .add_task("githubpp") - .add_task("modorganizer-game_gamebryo") + .add_task("modorganizer-game_bethesda"); + + add_task() .add_task({"modorganizer-bsapacker", "bsa_packer"}) - .add_task("modorganizer-preview_bsa"); - - // the gamebryo flag must be set for all game plugins that inherit from - // the gamebryo classes; this will merge the .ts file from gamebryo with - // the one from the specific plugin - add_task() - .add_task("modorganizer-game_oblivion", mo::gamebryo) - .add_task("modorganizer-game_nehrim", mo::gamebryo) - .add_task("modorganizer-game_fallout3", mo::gamebryo) - .add_task("modorganizer-game_fallout4", mo::gamebryo) - .add_task("modorganizer-game_fallout4vr", mo::gamebryo) - .add_task("modorganizer-game_fallout76", mo::gamebryo) - .add_task("modorganizer-game_fallout4london", mo::gamebryo) - .add_task("modorganizer-game_falloutnv", mo::gamebryo) - .add_task("modorganizer-game_morrowind", mo::gamebryo) - .add_task("modorganizer-game_skyrim", mo::gamebryo) - .add_task("modorganizer-game_skyrimse", mo::gamebryo) - .add_task("modorganizer-game_skyrimvr", mo::gamebryo) - .add_task("modorganizer-game_starfield", mo::gamebryo) - .add_task("modorganizer-game_ttw", mo::gamebryo) - .add_task("modorganizer-game_enderal", mo::gamebryo) - .add_task("modorganizer-game_enderalse", mo::gamebryo); - - add_task() .add_task({"modorganizer-tool_inieditor", "inieditor"}) .add_task({"modorganizer-tool_inibakery", "inibakery"}) + .add_task("modorganizer-preview_bsa") .add_task("modorganizer-preview_base") .add_task("modorganizer-diagnose_basic") .add_task("modorganizer-check_fnis") @@ -110,12 +58,15 @@ namespace mob { .add_task("modorganizer-installer_quick") .add_task("modorganizer-installer_fomod") .add_task("modorganizer-installer_fomod_csharp") - .add_task("modorganizer-installer_omod", mo::nuget) + .add_task("modorganizer-installer_omod") .add_task("modorganizer-installer_wizard") .add_task("modorganizer-bsa_extractor") .add_task("modorganizer-plugin_python"); add_task() + .add_task() + .add_task() + .add_task() .add_task({"modorganizer-tool_configurator", "pycfg"}) .add_task("modorganizer-fnistool") .add_task("modorganizer-basic_games") @@ -126,7 +77,6 @@ namespace mob { .add_task({"modorganizer", "organizer"}); // other tasks - add_task(); add_task(); } @@ -148,9 +98,9 @@ namespace mob { std::make_unique(), std::make_unique(), std::make_unique(), - std::make_unique(), std::make_unique(), - std::make_unique()}; + std::make_unique(), + std::make_unique()}; // commands are shown in the help help->set_commands(commands); diff --git a/src/tasks/boost.cpp b/src/tasks/boost.cpp deleted file mode 100644 index 3289d22..0000000 --- a/src/tasks/boost.cpp +++ /dev/null @@ -1,336 +0,0 @@ -#include "pch.h" -#include "../core/process.h" -#include "tasks.h" - -namespace mob::tasks { - - namespace { - std::string boost_version_no_tags() - { - const auto v = boost::parsed_version(); - - // 1.72[.1] - std::string s = v.major + "." + v.minor; - - if (v.patch != "") - s += "." + v.patch; - - return s; - } - - std::string boost_version_dash() - { - const auto v = boost::parsed_version(); - - // boost_1_72[_0[_b1_rc1]] - std::string s = "Boost-" + v.major + "." + v.minor; - - if (v.patch != "") - s += "." + v.patch; - - return s; - } - - std::string boost_version_no_tags_underscores() - { - return replace_all(boost_version_no_tags(), ".", "_"); - } - - std::string boost_version_all_underscores() - { - const auto v = boost::parsed_version(); - - // boost_1_72[_0[_b1_rc1]] - std::string s = "boost_" + v.major + "_" + v.minor; - - if (v.patch != "") - s += "_" + v.patch; - - if (v.rest != "") - s += "_" + replace_all(v.rest, "-", "_"); - - return s; - } - - std::string address_model_for_arch(arch a) - { - switch (a) { - case arch::x86: - return "32"; - - case arch::x64: - case arch::dont_care: - return "64"; - - default: - gcx().bail_out(context::generic, "boost: bad arch"); - } - } - - fs::path config_jam_file() - { - return boost::source_path() / "user-config-64.jam"; - } - - url prebuilt_url() - { - const auto underscores = replace_all(boost::version(), ".", "_"); - return make_prebuilt_url("boost_prebuilt_" + underscores + ".7z"); - } - - url source_url() - { - return "https://archives.boost.io/release/" + boost_version_no_tags() + - "/source/" + boost_version_all_underscores() + ".7z"; - } - - fs::path b2_exe() - { - return boost::source_path() / "b2.exe"; - } - - } // namespace - - boost::boost() : basic_task("boost") {} - - std::string boost::version() - { - return conf().version().get("boost"); - } - - std::string boost::version_vs() - { - return conf().version().get("boost_vs"); - } - - bool boost::prebuilt() - { - return conf().prebuilt().get("boost"); - } - - fs::path boost::source_path() - { - // ex: build/boost_1_74_0 - return conf().path().build() / ("boost_" + boost_version_no_tags_underscores()); - } - - fs::path boost::cmake_path(arch a) - { - return lib_path(a) / "cmake" / boost_version_dash(); - } - - fs::path boost::lib_path(arch a) - { - // ex: build/boost_1_74_0/lib64-msvc-14.2/lib - return root_lib_path(a) / "lib"; - } - - fs::path boost::root_lib_path(arch a) - { - // ex: build/boost_1_74_0/lib64-msvc-14.2 - - const std::string lib = - "lib" + address_model_for_arch(a) + "-msvc-" + version_vs(); - - return source_path() / lib; - } - - void boost::do_clean(clean c) - { - if (is_set(c, clean::redownload)) { - // delete downloaded file - - if (prebuilt()) - run_tool(downloader(prebuilt_url(), downloader::clean)); - else - run_tool(downloader(source_url(), downloader::clean)); - } - - if (is_set(c, clean::reextract)) { - // delete the whole thing - cx().trace(context::reextract, "deleting {}", source_path()); - op::delete_directory(cx(), source_path(), op::optional); - - // no need for the rest - return; - } - - // those don't make sense for prebults - if (!prebuilt()) { - if (is_set(c, clean::reconfigure)) { - // delete bin and b2.exe to make sure bootstrap runs again - op::delete_directory(cx(), source_path() / "bin.v2", op::optional); - op::delete_file(cx(), b2_exe(), op::optional); - - // delete jam files - op::delete_file(cx(), config_jam_file(), op::optional); - op::delete_file(cx(), source_path() / "project-config.jam", - op::optional); - } - - if (is_set(c, clean::rebuild)) { - // delete libs - op::delete_directory(cx(), root_lib_path(arch::x86), op::optional); - op::delete_directory(cx(), root_lib_path(arch::x64), op::optional); - } - } - } - - void boost::do_fetch() - { - if (prebuilt()) - fetch_prebuilt(); - else - fetch_from_source(); - } - - void boost::do_build_and_install() - { - if (prebuilt()) - build_and_install_prebuilt(); - else - build_and_install_from_source(); - } - - void boost::fetch_prebuilt() - { - cx().trace(context::generic, "using prebuilt boost"); - - const auto file = run_tool(downloader(prebuilt_url())); - - run_tool(extractor().file(file).output(source_path())); - } - - void boost::build_and_install_prebuilt() {} - - void boost::fetch_from_source() - { - const auto file = run_tool(downloader(source_url())); - - run_tool(extractor().file(file).output(source_path())); - } - - void boost::bootstrap() - { - // bootstrap b2 - - write_config_jam(); - - const auto bootstrap = source_path() / "bootstrap.bat"; - - run_tool(process_runner(process() - .binary(bootstrap) - .external_error_log(source_path() / "bootstrap.log") - .cwd(source_path()))); - } - - void boost::build_and_install_from_source() - { - // bypass boostrap - if (fs::exists(b2_exe())) { - cx().trace(context::bypass, "{} exists, boost already bootstrapped", - b2_exe()); - } - else { - bootstrap(); - } - - // we do not need all variants of all components but since people should - // usually be using the pre-built, we can build everything without losing too - // much time and it is much easier to deal when mixing - // - // note: filesystem is only required by USVFS I think, so maybe think about - // removing it if we switch to std::filesystem in USVFS - // - clipp::arg_list components{"thread", "date_time", "filesystem", "locale", - "program_options"}; - - // static link, static runtime, x64 - do_b2(components, "static", "static", arch::x64); - - // static link, static/shared runtime, x86, required by usvfs 32-bit - do_b2(components, "static", "static", arch::x86); - do_b2(components, "static", "shared", arch::x86); - - // static link, shared runtime, x64 - do_b2(components, "static", "shared", arch::x64); - - // shared link, shared runtime, x64 - do_b2(components, "shared", "shared", arch::x64); - } - - void boost::do_b2(const std::vector& components, - const std::string& link, const std::string& runtime_link, arch a) - { - // will transform all components to --with-X - - run_tool(process_runner(process() - .binary(b2_exe()) - .arg("address-model=", address_model_for_arch(a)) - .arg("link=", link) - .arg("runtime-link=", runtime_link) - .arg("toolset=", "msvc-" + vs::toolset()) - .arg("--user-config=", config_jam_file()) - .arg("--stagedir=", root_lib_path(a)) - .arg("--libdir=", root_lib_path(a)) - .args(map(components, - [](auto&& c) { - return "--with-" + c; - })) - .env(env::vs(a)) - .cwd(source_path()))); - } - - void boost::write_config_jam() - { - // b2 requires forward slashes - auto forward_slashes = [](auto&& p) { - std::string s = path_to_utf8(p); - return replace_all(s, "\\", "/"); - }; - - // this currently writes an empty configuration file, at some point it was used - // to configure the Boost.Python built - // - // kept here in case we need a custom user-configuration in the future - // - std::ostringstream oss; - - // logging - { - cx().trace(context::generic, - "writing config file at {}:", config_jam_file()); - - for_each_line(oss.str(), [&](auto&& line) { - cx().trace(context::generic, " {}", line); - }); - } - - // writing - op::write_text_file(cx(), encodings::utf8, config_jam_file(), oss.str()); - } - - boost::version_info boost::parsed_version() - { - // 1.72.0-b1-rc1 - // everything but 1.72 is optional - std::regex re("(\\d+)\\." // 1. - "(\\d+)" // 72 - "(?:" - "\\.(\\d+)" // .0 - "(?:" // - "-(.+)" // -b1-rc1 - ")?" - ")?"); - - std::smatch m; - - const auto s = version(); - - if (!std::regex_match(s, m, re)) - gcx().bail_out(context::generic, "bad boost version '{}'", s); - - return {m[1], m[2], m[3], m[4]}; - } - -} // namespace mob::tasks diff --git a/src/tasks/boost_di.cpp b/src/tasks/boost_di.cpp deleted file mode 100644 index fddbaad..0000000 --- a/src/tasks/boost_di.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "pch.h" -#include "tasks.h" - -namespace mob::tasks { - - // boost-di is needed by bsapacker - - boost_di::boost_di() : basic_task("boost-di", "boostdi", "boost_di") {} - - std::string boost_di::version() - { - return {}; - } - - bool boost_di::prebuilt() - { - // prebuilts don't exist for this, it's headers only - return false; - } - - fs::path boost_di::source_path() - { - return conf().path().build() / "di"; - } - - void boost_di::do_clean(clean c) - { - // delete the whole thing - if (is_set(c, clean::reclone)) - git_wrap::delete_directory(cx(), source_path()); - } - - void boost_di::do_fetch() - { - run_tool(make_git() - .url(make_git_url("boost-experimental", "di")) - .branch("cpp14") - .root(source_path())); - } - -} // namespace mob::tasks diff --git a/src/tasks/bzip2.cpp b/src/tasks/bzip2.cpp deleted file mode 100644 index 253ed4c..0000000 --- a/src/tasks/bzip2.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "pch.h" -#include "tasks.h" - -namespace mob::tasks { - - // required by python - - namespace { - - url source_url() - { - return "https://sourceware.org/pub/bzip2/" - "bzip2-" + - bzip2::version() + ".tar.gz"; - } - - } // namespace - - bzip2::bzip2() : basic_task("bzip2") {} - - std::string bzip2::version() - { - return conf().version().get("bzip2"); - } - - bool bzip2::prebuilt() - { - // no prebuilts, just the source, required by python, which uses the - // source files directly - return false; - } - - fs::path bzip2::source_path() - { - return conf().path().build() / ("bzip2-" + version()); - } - - void bzip2::do_clean(clean c) - { - // delete download - if (is_set(c, clean::redownload)) - run_tool(downloader(source_url(), downloader::clean)); - - // delete the whole directory - if (is_set(c, clean::reextract)) { - cx().trace(context::reextract, "deleting {}", source_path()); - op::delete_directory(cx(), source_path(), op::optional); - } - } - - void bzip2::do_fetch() - { - const auto file = run_tool(downloader(source_url())); - - run_tool(extractor().file(file).output(source_path())); - } - -} // namespace mob::tasks diff --git a/src/tasks/directxtex.cpp b/src/tasks/directxtex.cpp deleted file mode 100644 index b7d79f2..0000000 --- a/src/tasks/directxtex.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include "pch.h" -#include "tasks.h" - -namespace mob::tasks { - - namespace { - - msbuild create_msbuild_tool(arch a, config config, - msbuild::ops o = msbuild::build) - { - return std::move(msbuild(o).architecture(a).configuration(config).solution( - directxtex::source_path() / "DirectXTex" / - "DirectXTex_Desktop_2022.vcxproj")); - } - - } // namespace - - directxtex::directxtex() : basic_task("directxtex") {} - - std::string directxtex::version() - { - return conf().version().get("directxtex"); - } - - bool directxtex::prebuilt() - { - return false; - } - - fs::path directxtex::source_path() - { - return conf().path().build() / "DirectXTex"; - } - - void directxtex::do_clean(clean c) - { - if (is_set(c, clean::reclone)) { - git_wrap::delete_directory(cx(), source_path()); - return; - } - - if (is_set(c, clean::rebuild)) { - run_tool(create_msbuild_tool(arch::x64, config::release, msbuild::clean)); - run_tool(create_msbuild_tool(arch::x64, config::debug, msbuild::clean)); - } - } - - void directxtex::do_fetch() - { - run_tool(make_git() - .url(make_git_url("microsoft", "DirectXTex")) - .branch(version()) - .root(source_path())); - } - - void directxtex::do_build_and_install() - { - op::create_directories(cx(), directxtex::source_path() / "Include"); - op::create_directories(cx(), directxtex::source_path() / "Lib" / "Debug"); - op::create_directories(cx(), directxtex::source_path() / "Lib" / "Release"); - - // DO NOT run these in parallel because both generate files that are shared - // between release and debug - run_tool(create_msbuild_tool(arch::x64, config::release)); - run_tool(create_msbuild_tool(arch::x64, config::debug)); - - const auto binary_path = - source_path() / "DirectXTex" / "Bin" / "Desktop_2022" / "x64"; - - for (const auto& header : {"DDS.h", "DirectXTex.h", "DirectXTex.inl "}) { - op::copy_file_to_dir_if_better(cx(), source_path() / "DirectXTex" / header, - source_path() / "Include"); - } - op::copy_file_to_dir_if_better(cx(), binary_path / "Debug" / "DirectXTex.lib", - source_path() / "Lib" / "Debug"); - op::copy_file_to_dir_if_better(cx(), binary_path / "Release" / "DirectXTex.lib", - source_path() / "Lib" / "Release"); - } - -} // namespace mob::tasks diff --git a/src/tasks/gtest.cpp b/src/tasks/gtest.cpp deleted file mode 100644 index 359a433..0000000 --- a/src/tasks/gtest.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include "pch.h" -#include "tasks.h" - -namespace mob::tasks { - - namespace { - - cmake create_cmake_tool(arch a, config config, cmake::ops o = cmake::generate) - { - return std::move(cmake(o) - .generator(cmake::vs) - .architecture(a) - .arg("-Wno-deprecated") - .arg("-Dgtest_force_shared_crt=ON") - .prefix(gtest::build_path(a, config)) - .root(gtest::source_path())); - } - - msbuild create_msbuild_tool(arch a, config config, - msbuild::ops o = msbuild::build) - { - const fs::path build_path = create_cmake_tool(a, config).build_path(); - - return std::move(msbuild(o).architecture(a).configuration(config).solution( - build_path / "INSTALL.vcxproj")); - } - - } // namespace - - gtest::gtest() : basic_task("gtest", "googletest") {} - - std::string gtest::version() - { - return conf().version().get("gtest"); - } - - bool gtest::prebuilt() - { - return false; - } - - fs::path gtest::source_path() - { - return conf().path().build() / "googletest"; - } - - fs::path gtest::build_path(arch a, config c) - { - return source_path() / "build" / (a == arch::x64 ? "x64" : "Win32") / - msbuild::configuration_name(c); - } - - void gtest::do_clean(clean c) - { - if (is_set(c, clean::reclone)) { - git_wrap::delete_directory(cx(), source_path()); - return; - } - - if (is_set(c, clean::reconfigure)) { - run_tool(create_cmake_tool(arch::x86, config::release, cmake::clean)); - run_tool(create_cmake_tool(arch::x64, config::release, cmake::clean)); - } - - if (is_set(c, clean::rebuild)) { - run_tool(create_msbuild_tool(arch::x86, config::release, msbuild::clean)); - run_tool(create_msbuild_tool(arch::x86, config::debug, msbuild::clean)); - run_tool(create_msbuild_tool(arch::x64, config::release, msbuild::clean)); - run_tool(create_msbuild_tool(arch::x64, config::debug, msbuild::clean)); - } - } - - void gtest::do_fetch() - { - run_tool(make_git() - .url(make_git_url("google", "googletest")) - .branch(version()) - .root(source_path())); - } - - void gtest::do_build_and_install() - { - op::create_directories(cx(), gtest::build_path(arch::x64).parent_path()); - op::create_directories(cx(), gtest::build_path(arch::x86).parent_path()); - - parallel({{"gtest64", - [&] { - run_tool(create_cmake_tool(arch::x64, config::release)); - run_tool(create_msbuild_tool(arch::x64, config::release)); - - run_tool(create_cmake_tool(arch::x64, config::debug)); - run_tool(create_msbuild_tool(arch::x64, config::debug)); - }}, - - {"gtest32", [&] { - run_tool(create_cmake_tool(arch::x86, config::release)); - run_tool(create_msbuild_tool(arch::x86, config::release)); - - run_tool(create_cmake_tool(arch::x86, config::debug)); - run_tool(create_msbuild_tool(arch::x86, config::debug)); - }}}); - } - -} // namespace mob::tasks diff --git a/src/tasks/installer.cpp b/src/tasks/installer.cpp index f90db80..8feb3c6 100644 --- a/src/tasks/installer.cpp +++ b/src/tasks/installer.cpp @@ -36,9 +36,21 @@ namespace mob::tasks { { const std::string repo = "modorganizer-Installer"; + // find the best suitable branch + const auto fallback = task_conf().mo_fallback_branch(); + auto branch = task_conf().mo_branch(); + if (!fallback.empty() && + !git_wrap::remote_branch_exists(make_git_url(task_conf().mo_org(), repo), + branch)) { + cx().warning(context::generic, + "{} has no remote {} branch, switching to {}", repo, branch, + fallback); + branch = fallback; + } + run_tool(make_git() .url(make_git_url(task_conf().mo_org(), repo)) - .branch(task_conf().mo_branch()) + .branch(branch) .root(source_path())); } diff --git a/src/tasks/libbsarch.cpp b/src/tasks/libbsarch.cpp deleted file mode 100644 index de41c56..0000000 --- a/src/tasks/libbsarch.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "pch.h" -#include "tasks.h" - -namespace mob::tasks { - - namespace { - - std::string dir_name() - { - return "libbsarch-" + libbsarch::version() + "-" + - (libbsarch::build_type() == config::debug ? "debug" : "release") + - "-x64"; - } - - url source_url() - { - return "https://github.com/ModOrganizer2/libbsarch/releases/download/" + - libbsarch::version() + "/" + dir_name() + ".7z"; - } - - } // namespace - - libbsarch::libbsarch() : basic_task("libbsarch") {} - - std::string libbsarch::version() - { - return conf().version().get("libbsarch"); - } - - config libbsarch::build_type() - { - return conf().build_types().get("libbsarch"); - } - - bool libbsarch::prebuilt() - { - return false; - } - - fs::path libbsarch::source_path() - { - return conf().path().build() / dir_name(); - } - - void libbsarch::do_clean(clean c) - { - // delete the download - if (is_set(c, clean::redownload)) - run_tool(downloader(source_url(), downloader::clean)); - - // delete the whole directory - if (is_set(c, clean::reextract)) { - cx().trace(context::reextract, "deleting {}", source_path()); - op::delete_directory(cx(), source_path(), op::optional); - } - } - - void libbsarch::do_fetch() - { - const auto file = run_tool(downloader(source_url())); - - run_tool(extractor().file(file).output(source_path())); - } - - void libbsarch::do_build_and_install() - { - // copy dll - op::copy_file_to_dir_if_better(cx(), source_path() / "libbsarch.dll", - conf().path().install_dlls()); - } - -} // namespace mob::tasks diff --git a/src/tasks/libloot.cpp b/src/tasks/libloot.cpp deleted file mode 100644 index 0715848..0000000 --- a/src/tasks/libloot.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "pch.h" -#include "tasks.h" - -namespace mob::tasks { - - namespace { - - std::string release_name() - { - // the naming convention is `libloot-version-win64.7z`, - // such as libloot-0.19.3-win64.7z. - return "libloot-" + libloot::version() + "-" + "win64"; - } - - url source_url() - { - return "https://github.com/loot/libloot/releases/download/" + - libloot::version() + "/" + release_name() + ".7z"; - } - - } // namespace - - libloot::libloot() : basic_task("libloot") {} - - std::string libloot::version() - { - return conf().version().get("libloot"); - } - - bool libloot::prebuilt() - { - return false; - } - - fs::path libloot::source_path() - { - return conf().path().build() / release_name(); - } - - void libloot::do_clean(clean c) - { - // delete download - if (is_set(c, clean::redownload)) - run_tool(downloader(source_url(), downloader::clean)); - - // delete the whole directory - if (is_set(c, clean::reextract)) { - cx().trace(context::reextract, "deleting {}", source_path()); - op::delete_directory(cx(), source_path(), op::optional); - } - } - - void libloot::do_fetch() - { - const auto file = run_tool(downloader(source_url())); - - run_tool(extractor().file(file).output(source_path())); - } - - void libloot::do_build_and_install() - { - // copy dll - op::copy_file_to_dir_if_better(cx(), source_path() / "bin" / "loot.dll", - conf().path().install_loot()); - } - -} // namespace mob::tasks diff --git a/src/tasks/lz4.cpp b/src/tasks/lz4.cpp deleted file mode 100644 index 281ca7d..0000000 --- a/src/tasks/lz4.cpp +++ /dev/null @@ -1,142 +0,0 @@ -#include "pch.h" -#include "tasks.h" - -namespace mob::tasks { - - namespace { - - fs::path solution_dir() - { - return lz4::source_path() / "build" / "VS2022"; - } - - fs::path solution_file() - { - return solution_dir() / "lz4.sln"; - } - - fs::path out_dir() - { - return solution_dir() / "bin" / "x64_Release"; - } - - url prebuilt_url() - { - return make_prebuilt_url("lz4_prebuilt_" + lz4::version() + ".7z"); - } - - } // namespace - - lz4::lz4() : basic_task("lz4") {} - - std::string lz4::version() - { - return conf().version().get("lz4"); - } - - bool lz4::prebuilt() - { - return conf().prebuilt().get("lz4"); - } - - fs::path lz4::source_path() - { - return conf().path().build() / ("lz4-" + version()); - } - - void lz4::do_clean(clean c) - { - if (prebuilt()) { - // delete download - if (is_set(c, clean::redownload)) - run_tool(downloader(prebuilt_url(), downloader::clean)); - - // delete the whole directory - if (is_set(c, clean::reextract)) { - cx().trace(context::reextract, "deleting {}", source_path()); - op::delete_directory(cx(), source_path(), op::optional); - } - } - else { - // delete the whole directory - if (is_set(c, clean::reclone)) { - git_wrap::delete_directory(cx(), source_path()); - - // no point in doing anything more - return; - } - - // msbuild clean - if (is_set(c, clean::rebuild)) - run_tool(create_msbuild_tool(msbuild::clean)); - } - } - - void lz4::do_fetch() - { - if (prebuilt()) - fetch_prebuilt(); - else - fetch_from_source(); - } - - void lz4::do_build_and_install() - { - if (prebuilt()) - build_and_install_prebuilt(); - else - build_and_install_from_source(); - } - - void lz4::fetch_prebuilt() - { - cx().trace(context::generic, "using prebuilt lz4"); - - const auto file = run_tool(downloader(prebuilt_url())); - - run_tool(extractor().file(file).output(source_path())); - } - - void lz4::build_and_install_prebuilt() - { - // copy pdb and dll - - op::copy_file_to_dir_if_better(cx(), source_path() / "bin" / "liblz4.pdb", - conf().path().install_pdbs()); - - op::copy_file_to_dir_if_better(cx(), source_path() / "bin" / "liblz4.dll", - conf().path().install_dlls()); - } - - void lz4::fetch_from_source() - { - // clone - run_tool(make_git() - .url(make_git_url("lz4", "lz4")) - .branch(version()) - .root(source_path())); - } - - void lz4::build_and_install_from_source() - { - run_tool(create_msbuild_tool()); - - // cmake_common looks for the lib files in the bin/ directory, which is - // correct for prebuilts, but not from source, so copy the files in there - op::copy_glob_to_dir_if_better(cx(), out_dir() / "*", source_path() / "bin", - op::copy_files); - - // copy dll and pdb - op::copy_file_to_dir_if_better(cx(), source_path() / "bin" / "liblz4.dll", - conf().path().install_dlls()); - - op::copy_file_to_dir_if_better(cx(), source_path() / "bin" / "liblz4.pdb", - conf().path().install_pdbs()); - } - - msbuild lz4::create_msbuild_tool(msbuild::ops o) - { - return std::move(msbuild(o).solution(solution_file()).targets({"liblz4-dll"})); - } - -} // namespace mob::tasks diff --git a/src/tasks/modorganizer.cpp b/src/tasks/modorganizer.cpp index c7947c7..139027d 100644 --- a/src/tasks/modorganizer.cpp +++ b/src/tasks/modorganizer.cpp @@ -59,18 +59,18 @@ namespace mob::tasks { g.init_repo(); } - modorganizer::modorganizer(std::string long_name, flags f) - : modorganizer(std::vector{long_name}, f) + modorganizer::modorganizer(std::string long_name) + : modorganizer(std::vector{long_name}) { } - modorganizer::modorganizer(std::vector names, flags f) - : modorganizer(std::vector(names.begin(), names.end()), f) + modorganizer::modorganizer(std::vector names) + : modorganizer(std::vector(names.begin(), names.end())) { } - modorganizer::modorganizer(std::vector names, flags f) - : task(make_names(names)), repo_(names[0]), flags_(f) + modorganizer::modorganizer(std::vector names) + : task(make_names(names)), repo_(names[0]) { if (names.size() > 1) { project_ = names[1]; @@ -80,14 +80,11 @@ namespace mob::tasks { } } - bool modorganizer::is_gamebryo_plugin() const + std::string modorganizer::cmake_prefix_path() { - return is_set(flags_, gamebryo); - } - - bool modorganizer::is_nuget_plugin() const - { - return is_set(flags_, nuget); + return conf().path().qt_install().string() + ";" + + (modorganizer::super_path() / "cmake_common").string() + ";" + + (conf().path().install() / "lib" / "cmake").string(); } fs::path modorganizer::source_path() const @@ -96,18 +93,9 @@ namespace mob::tasks { return super_path() / name(); } - fs::path modorganizer::project_file_path() const - { - // ask cmake for the build path it would use - const auto build_path = create_cmake_tool(source_path()).build_path(); - - // use the INSTALL project - return build_path / (project_ + ".sln"); - } - fs::path modorganizer::super_path() { - return conf().path().build() / "modorganizer_super"; + return conf().path().build(); } url modorganizer::git_url() const @@ -137,11 +125,7 @@ namespace mob::tasks { // cmake clean if (is_set(c, clean::reconfigure)) - run_tool(create_cmake_tool(cmake::clean)); - - // msbuild clean - if (is_set(c, clean::rebuild)) - run_tool(create_msbuild_tool(msbuild::clean)); + run_tool(cmake(cmake::clean).root(source_path())); } void modorganizer::do_fetch() @@ -165,7 +149,7 @@ namespace mob::tasks { void modorganizer::do_build_and_install() { - // adds a git submodule in modorganizer_super for this project; note that + // adds a git submodule in build for this project; note that // git_submodule_adder runs a thread because adding submodules is slow, but // can happen while stuff is building git_submodule_adder::instance().queue( @@ -177,66 +161,44 @@ namespace mob::tasks { // not all modorganizer projects need to actually be built, such as // cmake_common, so don't try if there's no cmake file - if (!fs::exists(source_path() / "CMakeLists.txt")) { + if (!exists(source_path() / "CMakeLists.txt")) { cx().trace(context::generic, "{} has no CMakeLists.txt, not building", repo_); return; } + // if there is a CMakeLists.txt, there must be a CMakePresets.json otherwise + // we cannot build + if (!exists(source_path() / "CMakePresets.json")) { + gcx().bail_out(context::generic, + "{} has no CMakePresets.txt, aborting build", repo_); + } + // run cmake - run_tool(create_cmake_tool()); + run_tool(cmake(cmake::generate) + .generator(cmake::vs) + .def("CMAKE_INSTALL_PREFIX:PATH", conf().path().install()) + .def("CMAKE_PREFIX_PATH", cmake_prefix_path()) + .configuration_types({task_conf().configuration()}) + .preset("vs2022-windows") + .root(source_path())); - // run restore for nuget - // - // until https://gitlab.kitware.com/cmake/cmake/-/issues/20646 is resolved, - // we need a manual way of running the msbuild -t:restore - if (is_nuget_plugin()) - run_tool(create_msbuild_tool().targets({"restore"})); + // run cmake --build with default target + // TODO: handle rebuild by adding `--clean-first` + // TODO: have a way to specify the `--parallel` value - 16 is useful to build + // game_bethesda that has 15 games, so 15 projects + run_tool(cmake(cmake::build) + .root(source_path()) + .arg("--parallel") + .arg("16") + .configuration(task_conf().configuration())); - // run msbuild - run_tool(create_msbuild_tool()); - } - - cmake modorganizer::create_cmake_tool(cmake::ops o) - { - return create_cmake_tool(source_path(), o, task_conf().configuration()); - } - - cmake modorganizer::create_cmake_tool(const fs::path& root, cmake::ops o, config c) - { - return std::move( - cmake(o) - .generator(cmake::vs) - .def("CMAKE_INSTALL_PREFIX:PATH", conf().path().install()) - .def("DEPENDENCIES_DIR", conf().path().build()) - .def("BOOST_ROOT", boost::source_path()) - .def("BOOST_LIBRARYDIR", boost::lib_path(arch::x64)) - .def("Boost_DIR", boost::cmake_path(arch::x64)) - .def("SPDLOG_ROOT", spdlog::source_path()) - .def("LOOT_PATH", libloot::source_path()) - .def("LZ4_ROOT", lz4::source_path()) - .def("QT_ROOT", qt::installation_path()) - .def("ZLIB_ROOT", zlib::source_path()) - .def("PYTHON_ROOT", python::source_path()) - .def("SEVENZ_ROOT", sevenz::source_path()) - .def("LIBBSARCH_ROOT", libbsarch::source_path()) - .def("BOOST_DI_ROOT", boost_di::source_path()) - // gtest has no RelWithDebInfo, so simply use Debug/Release - .def("GTEST_ROOT", - gtest::build_path(arch::x64, c == config::debug ? config::debug - : config::release)) - .def("OPENSSL_ROOT_DIR", openssl::source_path()) - .def("DIRECTXTEX_ROOT", directxtex::source_path()) - .root(root)); - } - - msbuild modorganizer::create_msbuild_tool(msbuild::ops o) - { - return std::move(msbuild(o) - .solution(project_file_path()) - .configuration(task_conf().configuration()) - .architecture(arch::x64)); + // run cmake --install + run_tool(cmake(cmake::build) + .root(source_path()) + .targets("INSTALL") + .configuration(task_conf().configuration())); } } // namespace mob::tasks diff --git a/src/tasks/openssl.cpp b/src/tasks/openssl.cpp deleted file mode 100644 index 5b1f502..0000000 --- a/src/tasks/openssl.cpp +++ /dev/null @@ -1,235 +0,0 @@ -#include "pch.h" -#include "../core/process.h" -#include "tasks.h" - -namespace mob::tasks { - - namespace { - - url source_url() - { - return "https://www.openssl.org/source/" - "openssl-" + - openssl::version() + ".tar.gz"; - } - - url prebuilt_url() - { - return make_prebuilt_url("openssl-prebuilt-" + openssl::version() + ".7z"); - } - - std::string version_no_patch_underscores(bool primaryOnly = true) - { - auto v = openssl::parsed_version(); - - std::string s = v.major; - - if (v.minor != "" && !primaryOnly) - s += "_" + v.minor; - - return s; - } - - // the filenames of the dlls, but without extension, because this is used for - // both dlls and pdbs - // - std::vector output_names() - { - return {"libcrypto-" + version_no_patch_underscores() + "-x64", - "libssl-" + version_no_patch_underscores() + "-x64"}; - } - - } // namespace - - openssl::openssl() : basic_task("openssl") {} - - std::string openssl::version() - { - return conf().version().get("openssl"); - } - - bool openssl::prebuilt() - { - return conf().prebuilt().get("openssl"); - } - - fs::path openssl::source_path() - { - return conf().path().build() / ("openssl-" + version()); - } - - fs::path openssl::build_path() - { - return source_path() / "build"; - } - - fs::path openssl::bin_path() - { - return build_path() / "bin"; - } - - void openssl::do_clean(clean c) - { - if (prebuilt()) { - // delete prebuilt download - if (is_set(c, clean::redownload)) - run_tool(downloader(prebuilt_url(), downloader::clean)); - } - else { - // delete source download - if (is_set(c, clean::redownload)) - run_tool(downloader(source_url(), downloader::clean)); - } - - // there's no easy way to clean anything for openssl, it puts files all - // over the place, just delete the whole thing - if (is_any_set(c, clean::reextract | clean::reconfigure | clean::rebuild)) { - cx().trace(context::reextract, "deleting {}", source_path()); - op::delete_directory(cx(), source_path(), op::optional); - } - } - - void openssl::do_fetch() - { - if (prebuilt()) - fetch_prebuilt(); - else - fetch_from_source(); - } - - void openssl::do_build_and_install() - { - if (prebuilt()) - build_and_install_prebuilt(); - else - build_and_install_from_source(); - } - - void openssl::fetch_prebuilt() - { - cx().trace(context::generic, "using prebuilt openssl"); - - const auto file = run_tool(downloader(prebuilt_url())); - - run_tool(extractor().file(file).output(source_path())); - } - - void openssl::fetch_from_source() - { - const auto file = run_tool(downloader(source_url())); - - run_tool(extractor().file(file).output(source_path())); - } - - void openssl::build_and_install_prebuilt() - { - // nothing to built for prebuilt, just copy - copy_files(); - } - - void openssl::build_and_install_from_source() - { - // running the Configure perl script generates a file `makefile`; since - // Configuring takes forever and will fully run every time, don't run it if - // the makefile already exists - if (fs::exists(source_path() / "makefile")) - cx().trace(context::bypass, "openssl already configured"); - else - configure(); - - // run the install_engines target in the makefile, this builds everything - // required - install_engines(); - - // applink.c is required when building python from source, the .vcxproj - // assumes it's in the include path for whatever reason, so copy it there - op::copy_file_to_dir_if_better(cx(), source_path() / "ms" / "applink.c", - include_path()); - - copy_files(); - } - - void openssl::configure() - { - run_tool(process_runner(process() - .binary(perl::binary()) - .arg("Configure") - .arg("VC-WIN64A") - .arg("--openssldir=", build_path()) - .arg("--prefix=", build_path()) - .arg("-FS") - .arg("-MP1") - .arg("-wd4566") - .cwd(source_path()) - .env(env::vs(arch::x64)))); - } - - void openssl::install_engines() - { - build_loop(cx(), [&](bool mp) { - // jom defaults to multiprocess, give allow_failure for multiprocess - // builds and force single_job for the last single process build - - const int exit_code = - run_tool(jom() - .path(source_path()) - .target("install_engines") - .flag(mp ? jom::allow_failure : jom::single_job)); - - return (exit_code == 0); - }); - } - - void openssl::copy_files() - { - // duplicate the dlls to both bin/ and bin/dlls, they're needed by both - // MO and Qt - copy_dlls_to(conf().path().install_bin()); - copy_dlls_to(conf().path().install_dlls()); - - // pdbs - copy_pdbs_to(conf().path().install_pdbs()); - } - - void openssl::copy_dlls_to(const fs::path& dir) - { - for (auto&& name : output_names()) { - op::copy_file_to_dir_if_better(cx(), bin_path() / (name + ".dll"), dir); - } - } - - void openssl::copy_pdbs_to(const fs::path& dir) - { - for (auto&& name : output_names()) { - op::copy_file_to_dir_if_better(cx(), bin_path() / (name + ".pdb"), dir); - } - } - - fs::path openssl::include_path() - { - return openssl::source_path() / "include"; - } - - openssl::version_info openssl::parsed_version() - { - // 1.2.3d - // everything but 1 is optional - std::regex re("(\\d+)" // 1 - "(?:" // - "\\.(\\d+)" // .2 - "(?:" // - "\\.(\\d+)([a-zA-Z]+)?" // .3d - ")?" // - ")?"); - - std::smatch m; - - const auto s = version(); - - if (!std::regex_match(s, m, re)) - gcx().bail_out(context::generic, "bad openssl version '{}'", s); - - return {m[1], m[2], m[3]}; - } - -} // namespace mob::tasks diff --git a/src/tasks/pybind11.cpp b/src/tasks/pybind11.cpp deleted file mode 100644 index 82edd10..0000000 --- a/src/tasks/pybind11.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "pch.h" -#include "../core/process.h" -#include "tasks.h" - -// see the top of pyqt.cpp for some stuff about python/sip/pyqt - -namespace mob::tasks { - - pybind11::pybind11() : basic_task("pybind11") {} - - bool pybind11::prebuilt() - { - // header only available - return true; - } - - std::string pybind11::version() - { - return conf().version().get("pybind11"); - } - - fs::path pybind11::source_path() - { - return conf().path().build() / "pybind11"; - } - - void pybind11::do_clean(clean c) - { - if (is_set(c, clean::reclone)) { - git_wrap::delete_directory(cx(), source_path()); - return; - } - } - - void pybind11::do_fetch() - { - run_tool(make_git() - .url(make_git_url("pybind", "pybind11")) - .branch(version()) - .root(source_path())); - } - - void pybind11::do_build_and_install() {} -} // namespace mob::tasks diff --git a/src/tasks/pyqt.cpp b/src/tasks/pyqt.cpp deleted file mode 100644 index fd62421..0000000 --- a/src/tasks/pyqt.cpp +++ /dev/null @@ -1,331 +0,0 @@ -#include "pch.h" -#include "../core/process.h" -#include "tasks.h" - -// build process for python, sip and pyqt; if one is built from source, all -// three need to be built from source, plus openssl because python needs it -// -// 1) build openssl -// -// 2) build python, needs openssl -// -// 3) build sip, needs python: -// - download and extract source archive -// - run `python setup.py install` in sip's directory, this generates -// sip-install.exe and sip-module.exe in python-XX/Scripts (among others) -// - run `sip-module.exe --sip-h` to generate a sip.h file in sip's source -// directory -// - that header file is copied into python/include and is included by -// by plugin_python in sipapiaccess.h -// -// 4) build pyqt, needs sip -// - download and extract source archive -// - use `pip install` to install PyQt-builder -// - run `sip-install.exe` with the list of required modules, creating a -// folder for each module in PyQt6-XX/build/ with `.pyd` files -// - run `sip-module.exe --sdist`, which creates -// downloads/PyQt6_sip-XXX.tar.gz -// - run `pip install` with that file, which creates -// `python-XX/Lib/site-packages/PyQt6/sip.cp32-win_amd64.pyd` -// - for installation, a bunch of files from site-packages/PyQt6/ are -// copied into install/bin/plugins/data/PyQt6, including a .pyi file from -// sip - -namespace mob::tasks { - - namespace { - - url source_url() - { - const auto version = pyqt::version(); - std::string base = "https://pypi.io/packages/source/p/pyqt6/"; - if (version.find("dev") != std::string::npos) { - base = "https://riverbankcomputing.com/pypi/packages/PyQt6/"; - } - return base + "pyqt6-" + pyqt::version() + ".tar.gz"; - } - - url prebuilt_url() - { - return make_prebuilt_url( - "PyQt6_gpl-prebuilt-" + pyqt::version() + - (pyqt::build_type() == config::debug ? "-debug" : "") + ".7z"); - } - - // file created by sip-module.exe - // - fs::path sip_install_file() - { - return "PyQt6_sip-" + sip::version_for_pyqt() + ".tar.gz"; - } - - } // namespace - - pyqt::pyqt() : basic_task("pyqt") {} - - std::string pyqt::version() - { - return conf().version().get("pyqt"); - } - - std::string pyqt::builder_version() - { - return conf().version().get("pyqt_builder"); - } - - bool pyqt::prebuilt() - { - return conf().prebuilt().get("pyqt"); - } - - fs::path pyqt::source_path() - { - return conf().path().build() / ("pyqt6-" + version()); - } - - fs::path pyqt::build_path() - { - return source_path() / "build"; - } - - config pyqt::build_type() - { - return conf().build_types().get("pyqt"); - } - - std::string pyqt::pyqt_sip_module_name() - { - return "PyQt6.sip"; - } - - void pyqt::do_clean(clean c) - { - if (prebuilt()) { - // delete prebuilt download - if (is_set(c, clean::redownload)) - run_tool(downloader(prebuilt_url(), downloader::clean)); - } - else { - // delete source download - if (is_set(c, clean::redownload)) - run_tool(downloader(source_url(), downloader::clean)); - } - - // delete whole directory - if (is_set(c, clean::reextract)) { - cx().trace(context::reextract, "deleting {}", source_path()); - op::delete_directory(cx(), source_path(), op::optional); - - // no need to do anything else - return; - } - - if (!prebuilt()) { - // delete the pyqt-sip file that's created when building from source - if (is_set(c, clean::rebuild)) { - op::delete_file(cx(), conf().path().cache() / sip_install_file(), - op::optional); - } - } - } - - void pyqt::do_fetch() - { - if (prebuilt()) - fetch_prebuilt(); - else - fetch_from_source(); - } - - void pyqt::do_build_and_install() - { - if (prebuilt()) - build_and_install_prebuilt(); - else - build_and_install_from_source(); - } - - void pyqt::fetch_prebuilt() - { - const auto file = run_tool(downloader(prebuilt_url())); - - run_tool(extractor().file(file).output(source_path())); - } - - void pyqt::build_and_install_prebuilt() - { - // copy the prebuilt files directly into the python directory, they're - // required by sip, which is always built from source - op::copy_glob_to_dir_if_better(cx(), source_path() / "*", python::source_path(), - op::copy_files | op::copy_dirs); - - // copy files to build/install for MO - copy_files(); - } - - void pyqt::fetch_from_source() - { - const auto file = run_tool(downloader(source_url())); - - run_tool(extractor().file(file).output(source_path())); - } - - void pyqt::build_and_install_from_source() - { - // use pip to install the pyqt builder - if (python::build_type() == config::debug) { - // PyQt-builder has sip as a dependency, so installing it directly will - // replace the sip we have installed manually, but the installed sip will - // not work (see comment in sip::build() for details) - // - // the workaround is to install the dependencies manually (only packaging), - // and then use a --no-dependencies install with pip - // - run_tool(pip(pip::install).package("packaging")); - run_tool(pip(pip::install) - .package("PyQt-builder") - .no_dependencies() - .version(builder_version())); - } - else { - run_tool( - pip(pip::install).package("PyQt-builder").version(builder_version())); - } - - // patch for builder.py - run_tool(patcher() - .task(name()) - .file("builder.py.manual_patch") - .root(python::site_packages_path() / "pyqtbuild")); - - // build modules and generate the PyQt6_sip-XX.tar.gz file - sip_build(); - - // run pip install for the PyQt6_sip-XX.tar.gz file - install_sip_file(); - - // copy files to build/install for MO - copy_files(); - } - - void pyqt::sip_build() - { - // put qt and python in the path, set CL and LIB, which are used by the - // visual c++ compiler that's eventually spawned, and set PYTHONHOME - auto pyqt_env = - env::vs_x64() - .append_path({qt::bin_path(), python::build_path(), - python::source_path(), python::scripts_path()}) - .set("CL", " /MP") - .set("LIB", ";" + path_to_utf8(conf().path().install_libs()), - env::append) - .set("PYTHONHOME", path_to_utf8(python::source_path())); - - // create a bypass file, because pyqt always tries to build stuff and it - // takes forever - bypass_file built_bypass(cx(), source_path(), "built"); - - if (built_bypass.exists()) { - cx().trace(context::bypass, "pyqt already built"); - } - else { - // sip-install.exe has trouble with deleting the build/ directory and - // trying to recreate it too fast, giving an access denied error; do it - // here instead - op::delete_directory(cx(), source_path() / "build", op::optional); - - // build modules - run_tool(process_runner(process() - .binary(sip::sip_install_exe()) - .arg("--confirm-license") - .arg("--verbose", process::log_trace) - .arg("--pep484-pyi") - .arg("--link-full-dll") - .arg("--build-dir", build_path()) - // .arg("--enable", - //"pylupdate") // these are not in modules so - // they .arg("--enable", "pyrcc") // don't - // get copied below - // .args(zip(repeat("--enable"), modules())) - .cwd(source_path()) - .env(pyqt_env))); - - // done, create the bypass file - built_bypass.create(); - } - - // generate the PyQt6_sip-XX.tar.gz file - run_tool(process_runner(process() - .binary(sip::sip_module_exe()) - .arg("--sdist") - .arg(pyqt_sip_module_name()) - .cwd(conf().path().cache()) - .env(pyqt_env))); - } - - void pyqt::install_sip_file() - { - // create a bypass file, because pyqt always tries to install stuff and it - // takes forever - bypass_file installed_bypass(cx(), source_path(), "installed"); - - if (installed_bypass.exists()) { - cx().trace(context::bypass, "pyqt already installed"); - } - else { - if (python::build_type() == config::debug) { - - const auto pyqt_sip_folder = source_path() / "PyQt6_sip" / - ("pyqt6_sip-" + sip::version_for_pyqt()); - - // in debug, we need to do stuff manually because pip does not work - // as expected - run_tool(extractor() - .file(conf().path().cache() / sip_install_file()) - .output(pyqt_sip_folder.parent_path())); - - run_tool(mob::python() - .root(pyqt_sip_folder) - .arg("setup.py") - .arg("build") - .arg("--debug")); - - run_tool(pip(pip::install).file(pyqt_sip_folder)); - } - else { - // run `pip install` on the generated PyQt6_sip-XX.tar.gz file - run_tool( - pip(pip::install).file(conf().path().cache() / sip_install_file())); - } - - // done, create the bypass file - installed_bypass.create(); - } - } - - void pyqt::copy_files() - { - // pyqt puts its files in python-XX/Lib/site-packages/PyQt6 - const fs::path site_packages_pyqt = python::site_packages_path() / "PyQt6"; - - // copying some dlls from Qt's installation directory into - // python-XX/PCBuild/amd64, those are needed by PyQt6 when building several - // projects - - const std::vector dlls{"Qt6Core", "Qt6Xml"}; - - for (auto dll : dlls) { - if (build_type() == config::debug) { - dll += "d"; - } - dll += ".dll"; - op::copy_file_to_dir_if_better( - cx(), qt::bin_path() / dll, python::build_path(), - op::unsafe); // source file is outside prefix - } - - // installation of PyQt6 python files (.pyd, etc.) is done - // by the python plugin directly - } - -} // namespace mob::tasks diff --git a/src/tasks/python.cpp b/src/tasks/python.cpp deleted file mode 100644 index b70d804..0000000 --- a/src/tasks/python.cpp +++ /dev/null @@ -1,276 +0,0 @@ -#include "pch.h" -#include "../core/process.h" -#include "tasks.h" - -// see the top of pyqt.cpp for some stuff about python/sip/pyqt - -namespace mob::tasks { - - namespace { - - std::string version_without_v() - { - const auto v = python::parsed_version(); - - // 3.8.1 - std::string s = v.major + "." + v.minor; - if (v.patch != "") - s += "." + v.patch; - - return s; - } - - std::string version_for_dll() - { - const auto v = python::parsed_version(); - - // 38 - return v.major + v.minor; - } - - url prebuilt_url() - { - return make_prebuilt_url( - "python-prebuilt-" + version_without_v() + - (python::build_type() == config::debug ? "-debug" : "") + ".7z"); - } - - fs::path solution_file() - { - return python::source_path() / "PCBuild" / "pcbuild.sln"; - } - - fs::path python_core_zip_file() - { - return python::build_path() / "pythoncore" / - ("python" + version_for_dll() + ".zip"); - } - - } // namespace - - python::python() : basic_task("python") {} - - std::string python::version() - { - return conf().version().get("python"); - } - - bool python::prebuilt() - { - return conf().prebuilt().get("python"); - } - - python::version_info python::parsed_version() - { - // v3.8.1 - // v and .1 are optional - std::regex re(R"(v?(\d+)\.(\d+)(?:\.(\d+))?)"); - std::smatch m; - - const auto s = version(); - - if (!std::regex_match(s, m, re)) - gcx().bail_out(context::generic, "bad python version '{}'", s); - - version_info v; - - v.major = m[1]; - v.minor = m[2]; - v.patch = m[3]; - - return v; - } - - fs::path python::source_path() - { - return conf().path().build() / ("python-" + version_without_v()); - } - - fs::path python::build_path() - { - return source_path() / "PCBuild" / "amd64"; - } - - config python::build_type() - { - return conf().build_types().get("python"); - } - - void python::do_clean(clean c) - { - if (prebuilt()) { - // delete download - if (is_set(c, clean::redownload)) - run_tool(downloader(prebuilt_url(), downloader::clean)); - - // delete the whole directory - if (is_set(c, clean::reextract)) { - cx().trace(context::reextract, "deleting {}", source_path()); - op::delete_directory(cx(), source_path(), op::optional); - } - } - else { - // delete the whole directory - if (is_set(c, clean::reclone)) { - git_wrap::delete_directory(cx(), source_path()); - - // no need to do anything else - return; - } - - // msbuild clean - if (is_set(c, clean::rebuild)) - run_tool(create_msbuild_tool(msbuild::clean)); - } - } - - void python::do_fetch() - { - if (prebuilt()) - fetch_prebuilt(); - else - fetch_from_source(); - } - - void python::do_build_and_install() - { - if (prebuilt()) - build_and_install_prebuilt(); - else - build_and_install_from_source(); - } - - void python::fetch_prebuilt() - { - const auto file = run_tool(downloader(prebuilt_url())); - - run_tool(extractor().file(file).output(source_path())); - } - - void python::build_and_install_prebuilt() - { - install_pip(); - copy_files(); - } - - void python::fetch_from_source() - { - run_tool(make_git() - .url(make_git_url("python", "cpython")) - .branch(version()) - .root(source_path())); - } - - void python::build_and_install_from_source() - { - // download externals - prepare_dependencies(); - - // build - run_tool(create_msbuild_tool()); - - // package stuff into pythoncore.zip - package(); - - // install pip for other tasks that need it - install_pip(); - - // boost.python expects pyconfig.h to be in the include path - op::copy_file_to_dir_if_better(cx(), source_path() / "PC" / "pyconfig.h", - include_path()); - - copy_files(); - } - - void python::prepare_dependencies() - { - const auto bat = source_path() / "PCBuild" / "get_externals.bat"; - run_tool(process_runner(process().binary(bat).cwd(source_path()))); - } - - void python::package() - { - if (fs::exists(python_core_zip_file())) { - cx().trace(context::bypass, "python already packaged"); - return; - } - - const auto bat = source_path() / "python.bat"; - - auto p = process() - .binary(bat) - .arg(fs::path("PC/layout")) - .arg("--source", source_path()) - .arg("--build", build_path()) - .arg("--temp", (build_path() / "pythoncore_temp")) - .arg("--copy", (build_path() / "pythoncore")) - .arg("--preset-embed") - .cwd(source_path()); - - if (build_type() == config::debug) { - p = p.arg("--debug"); - } - - // package libs into pythonXX.zip - run_tool(process_runner(p)); - } - - void python::copy_files() - { - // libs - op::copy_glob_to_dir_if_better(cx(), build_path() / "*.lib", - conf().path().install_libs(), op::copy_files); - - // pdbs - op::copy_file_to_dir_if_better( - cx(), - build_path() / ("python" + version_for_dll() + - (build_type() == config::debug ? "_d" : "") + ".pdb"), - conf().path().install_pdbs()); - - // dlls and python libraries are installed by the python plugin - } - - void python::install_pip() - { - cx().trace(context::generic, "installing pip"); - run_tool(pip(pip::ensure)); - } - - msbuild python::create_msbuild_tool(msbuild::ops o) - { - return std::move( - msbuild(o) - .solution(solution_file()) - .targets({"python", "pythonw", "python3dll", "select", "pyexpat", - "unicodedata", "_queue", "_bz2", "_ssl", "_overlapped"}) - .configuration(build_type()) - .properties( - {"bz2Dir=" + path_to_utf8(bzip2::source_path()), - "zlibDir=" + path_to_utf8(zlib::source_path()), - "opensslIncludeDir=" + path_to_utf8(openssl::include_path()), - "opensslOutDir=" + path_to_utf8(openssl::source_path())})); - } - - fs::path python::python_exe() - { - return build_path() / - (build_type() == config::debug ? "python_d.exe" : "python.exe"); - } - - fs::path python::include_path() - { - return source_path() / "Include"; - } - - fs::path python::scripts_path() - { - return source_path() / "Scripts"; - } - - fs::path python::site_packages_path() - { - return source_path() / "Lib" / "site-packages"; - } - -} // namespace mob::tasks diff --git a/src/tasks/sevenz.cpp b/src/tasks/sevenz.cpp deleted file mode 100644 index f552508..0000000 --- a/src/tasks/sevenz.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "pch.h" -#include "tasks.h" - -namespace mob::tasks { - - namespace { - - std::string version_for_url() - { - return replace_all(sevenz::version(), ".", ""); - } - - url source_url() - { - return "https://www.7-zip.org/a/7z" + version_for_url() + "-src.7z"; - } - - // 7z has a bunch of modules, like the gui, etc., just build the dll - // - fs::path module_to_build() - { - return sevenz::source_path() / "CPP" / "7zip" / "Bundles" / "Format7zF"; - } - - } // namespace - - sevenz::sevenz() : basic_task("7z", "sevenz") {} - - std::string sevenz::version() - { - return conf().version().get("sevenz"); - } - - bool sevenz::prebuilt() - { - return false; - } - - fs::path sevenz::source_path() - { - return conf().path().build() / ("7zip-" + version()); - } - - void sevenz::do_clean(clean c) - { - // delete download - if (is_set(c, clean::redownload)) - run_tool(downloader(source_url(), downloader::clean)); - - // delete whole directory - if (is_set(c, clean::reextract)) { - cx().trace(context::reextract, "deleting {}", source_path()); - op::delete_directory(cx(), source_path(), op::optional); - - // no need to do anything else - return; - } - - // delete whole output directory - if (is_set(c, clean::rebuild)) - op::delete_directory(cx(), module_to_build() / "x64", op::optional); - } - - void sevenz::do_fetch() - { - const auto file = run_tool(downloader(source_url())); - - run_tool(extractor().file(file).output(source_path())); - } - - void sevenz::do_build_and_install() - { - build(); - - // copy 7z.dll to install/bin/dlls - op::copy_file_to_dir_if_better(cx(), module_to_build() / "x64/7z.dll", - conf().path().install_dlls()); - } - - void sevenz::build() - { - build_loop(cx(), [&](bool mp) { - const int exit_code = run_tool(nmake() - .path(module_to_build()) - .def("CPU=x64") - .def("NEW_COMPILER=1") - .def("MY_STATIC_LINK=1") - .def("NO_BUFFEROVERFLOWU=1")); - - return (exit_code == 0); - }); - } - -} // namespace mob::tasks diff --git a/src/tasks/sip.cpp b/src/tasks/sip.cpp deleted file mode 100644 index aed6e34..0000000 --- a/src/tasks/sip.cpp +++ /dev/null @@ -1,206 +0,0 @@ -#include "pch.h" -#include "../core/process.h" -#include "tasks.h" - -// see the top of pyqt.cpp for some stuff about python/sip/pyqt - -namespace mob::tasks { - - namespace { - - fs::path download_file() - { - return conf().path().cache() / ("sip-" + sip::version() + ".tar.gz"); - } - - std::string version_for_module_source() - { - // 12.7.2 - // .2 is optional - std::regex re(R"((\d+)\.(\d+)(?:\.(\d+))?)"); - std::smatch m; - - const auto s = sip::version_for_pyqt(); - - if (!std::regex_match(s, m, re)) - gcx().bail_out(context::generic, "bad pyqt sip version {}", s); - - // 12.7 - return m[1].str(); // + "." + m[2].str(); - } - - // header file generated by `sip-module.exe` at the end of the build process, - // used as a bypass file and also copied into python's include directory, - // plugin_python needs it - // - fs::path sip_header_file() - { - return sip::source_path() / "sip.h"; - } - - } // namespace - - sip::sip() : basic_task("sip") {} - - std::string sip::version() - { - return conf().version().get("sip"); - } - - std::string sip::version_for_pyqt() - { - return conf().version().get("pyqt_sip"); - } - - bool sip::prebuilt() - { - return false; - } - - fs::path sip::source_path() - { - return conf().path().build() / ("sip-" + version()); - } - - fs::path sip::sip_module_exe() - { - return python::scripts_path() / "sip-module.exe"; - } - - fs::path sip::sip_install_exe() - { - return python::scripts_path() / "sip-install.exe"; - } - - fs::path sip::module_source_path() - { - // 12.7 - const auto dir = version_for_module_source(); - - return source_path() / "sipbuild" / "module" / "source" / dir; - } - - void sip::do_clean(clean c) - { - // delete file downloaded by pip - if (is_set(c, clean::redownload)) { - if (fs::exists(download_file())) { - cx().trace(context::redownload, "deleting {}", download_file()); - op::delete_file(cx(), download_file(), op::optional); - } - } - - // delete the whole thing - if (is_set(c, clean::reextract)) { - cx().trace(context::reextract, "deleting {}", source_path()); - op::delete_directory(cx(), source_path(), op::optional); - } - - // delete the whole build directory - if (is_set(c, clean::rebuild)) { - op::delete_directory(cx(), source_path() / "build", op::optional); - - if (fs::exists(sip_header_file())) - op::delete_file(cx(), sip_header_file(), op::optional); - } - - // note that there's a bunch of files still left python-XX/Scripts that - // can't be easily deleted except by deleting something like "sip-*", but - // there might be other stuff in there - } - - void sip::do_fetch() - { - if (fs::exists(download_file())) { - cx().trace(context::bypass, "sip: {} already exists", download_file()); - } - else { - // download - run_tool(pip(pip::download).package("sip").version(version())); - } - - // extract - run_tool(extractor().file(download_file()).output(source_path())); - } - - void sip::do_build_and_install() - { - if (fs::exists(sip_header_file())) { - cx().trace(context::bypass, "{} already exists", sip_header_file()); - } - else { - build(); - generate_header(); - } - - // sip.h is included by sipapiaccess.h in plugin_python and it assumes it's - // in the include path - op::copy_file_to_dir_if_better(cx(), sip_header_file(), python::include_path()); - } - - void sip::build() - { - if (python::build_type() == config::debug) { - // if Python is build in debug mode, fall back to old setup.py because pip - // install seems to generated broken script wrapper that point to a - // non-existing python.exe instead of python_d.exe - run_tool(pip(pip::install).package("setuptools")); - run_tool(mob::python().root(source_path()).arg("setup.py").arg("install")); - } - else { - run_tool(pip(pip::install).file(source_path())); - } - } - - void sip::convert_script_file_to_acp(const std::string& filename) - { - // all the various .py files that were installed in python-XX/Scripts/ - // by build() above have a shebang that has the absolute path to the python - // executable - // - // these .py files are used by their corresponding .exe file, like - // `sip-module.exe` calls into `sip-module.py` - // - // the files are encoded in utf-8, but the .exe's will fail to execute them - // if they have non-ascii characters in the python path - // - // this converts the files into ACP, hoping that the characters actually - // exist in the codepage, so that the .exe can run - // - // if the path contains utf-8 characters that don't exist in the ACP, - // conversion will fail and U+FFFD will be written, but it would have failed - // anyway - - const fs::path src = python::scripts_path() / filename; - const fs::path backup = python::scripts_path() / (filename + ".bak"); - const fs::path dest = python::scripts_path() / (filename + ".acp"); - - if (!fs::exists(backup)) { - cx().debug(context::generic, "converting {} to acp", src); - - // read the utf8 file - const std::string utf8 = op::read_text_file(cx(), encodings::utf8, src); - - // convert to acp and write to filename.acp - op::write_text_file(cx(), encodings::acp, dest, utf8); - - // rename the source to .bak and rename filename.acp to the original - op::replace_file(cx(), src, dest, backup); - } - } - - void sip::generate_header() - { - // generate sip.h, will be copied to python's include directory, used - // by plugin_python - run_tool(process_runner(process() - .binary(sip_module_exe()) - .chcp(65001) - .stdout_encoding(encodings::acp) - .stderr_encoding(encodings::acp) - .arg("--sip-h") - .arg(pyqt::pyqt_sip_module_name()) - .cwd(source_path()))); - } - -} // namespace mob::tasks diff --git a/src/tasks/spdlog.cpp b/src/tasks/spdlog.cpp deleted file mode 100644 index 913c438..0000000 --- a/src/tasks/spdlog.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "pch.h" -#include "tasks.h" - -namespace mob::tasks { - - spdlog::spdlog() : basic_task("spdlog") {} - - std::string spdlog::version() - { - return conf().version().get("spdlog"); - } - - bool spdlog::prebuilt() - { - return false; - } - - fs::path spdlog::source_path() - { - return conf().path().build() / ("spdlog-" + version()); - } - - void spdlog::do_clean(clean c) - { - // delete the whole directory - if (is_set(c, clean::reclone)) - git_wrap::delete_directory(cx(), source_path()); - } - - void spdlog::do_fetch() - { - run_tool(make_git() - .url(make_git_url("gabime", "spdlog")) - .branch(version()) - .root(source_path())); - } - -} // namespace mob::tasks diff --git a/src/tasks/stylesheets.cpp b/src/tasks/stylesheets.cpp index 0cc7691..a9df301 100644 --- a/src/tasks/stylesheets.cpp +++ b/src/tasks/stylesheets.cpp @@ -77,7 +77,7 @@ namespace mob::tasks { fs::path stylesheets::release_build_path(const release& r) const { // something like build/paper-mono-v2.1 - return conf().path().build() / (r.repo + "-" + r.version); + return conf().path().build() / "stylesheets" / (r.repo + "-" + r.version); } downloader stylesheets::make_downloader_tool(const release& r, diff --git a/src/tasks/task.cpp b/src/tasks/task.cpp index 451366b..f8bd06c 100644 --- a/src/tasks/task.cpp +++ b/src/tasks/task.cpp @@ -391,13 +391,6 @@ namespace mob { do_fetch(); check_interrupted(); - - // auto patching if the task has a source path - if (!get_source_path().empty()) { - cx().debug(context::generic, "patching"); - - run_tool(patcher().task(name(), get_prebuilt()).root(get_source_path())); - } } void task::build_and_install() @@ -413,6 +406,7 @@ namespace mob { cx().info(context::generic, "build and install"); do_build_and_install(); + cx().info(context::generic, "done"); } void task::check_bailed() diff --git a/src/tasks/tasks.h b/src/tasks/tasks.h index 54afb97..bf76107 100644 --- a/src/tasks/tasks.h +++ b/src/tasks/tasks.h @@ -11,87 +11,6 @@ namespace mob::tasks { // single header for all the tasks, not worth having a header per task - class boost : public basic_task { - public: - struct version_info { - std::string major, minor, patch, rest; - }; - - boost(); - - static version_info parsed_version(); - static std::string version(); - static std::string version_vs(); - static bool prebuilt(); - - static fs::path source_path(); - static fs::path cmake_path(arch a); - static fs::path lib_path(arch a); - static fs::path root_lib_path(arch a); - - protected: - void do_clean(clean c) override; - void do_fetch() override; - void do_build_and_install() override; - - private: - void fetch_prebuilt(); - void build_and_install_prebuilt(); - - void fetch_from_source(); - void build_and_install_from_source(); - void write_config_jam(); - - void bootstrap(); - - void do_b2(const std::vector& components, const std::string& link, - const std::string& runtime_link, arch a); - }; - - // needed by bsapacker - // - class boost_di : public basic_task { - public: - boost_di(); - - static std::string version(); - static bool prebuilt(); - static fs::path source_path(); - - protected: - void do_clean(clean c) override; - void do_fetch() override; - }; - - // needed by python - // - class bzip2 : public basic_task { - public: - bzip2(); - - static std::string version(); - static bool prebuilt(); - static fs::path source_path(); - - protected: - void do_clean(clean c) override; - void do_fetch() override; - }; - - class directxtex : public basic_task { - public: - directxtex(); - - static std::string version(); - static bool prebuilt(); - static fs::path source_path(); - - protected: - void do_clean(clean c) override; - void do_fetch() override; - void do_build_and_install() override; - }; - class explorerpp : public basic_task { public: explorerpp(); @@ -105,21 +24,6 @@ namespace mob::tasks { void do_fetch() override; }; - class gtest : public basic_task { - public: - gtest(); - - static std::string version(); - static bool prebuilt(); - static fs::path source_path(); - static fs::path build_path(arch = arch::x64, config = config::release); - - protected: - void do_clean(clean c) override; - void do_fetch() override; - void do_build_and_install() override; - }; - class installer : public basic_task { public: installer(); @@ -134,38 +38,6 @@ namespace mob::tasks { void do_build_and_install() override; }; - class libbsarch : public basic_task { - public: - libbsarch(); - - static std::string version(); - static config build_type(); - static bool prebuilt(); - static fs::path source_path(); - - protected: - void do_clean(clean c) override; - void do_fetch() override; - void do_build_and_install() override; - }; - - class libloot : public basic_task { - public: - libloot(); - - static std::string version(); - static std::string hash(); - static std::string branch(); - - static bool prebuilt(); - static fs::path source_path(); - - protected: - void do_clean(clean c) override; - void do_fetch() override; - void do_build_and_install() override; - }; - class licenses : public task { public: licenses(); @@ -174,29 +46,6 @@ namespace mob::tasks { void do_build_and_install() override; }; - class lz4 : public basic_task { - public: - lz4(); - - static std::string version(); - static bool prebuilt(); - static fs::path source_path(); - - protected: - void do_clean(clean c) override; - void do_fetch() override; - void do_build_and_install() override; - - private: - void fetch_prebuilt(); - void build_and_install_prebuilt(); - - void fetch_from_source(); - void build_and_install_from_source(); - - msbuild create_msbuild_tool(msbuild::ops o = msbuild::build); - }; - // a task for all modorganizer projects except for the installer, which is // technically an MO project but is built differently // @@ -206,6 +55,10 @@ namespace mob::tasks { // class modorganizer : public task { public: + // build CMAKE_PREFIX_PATH for MO2 tasks + // + static std::string cmake_prefix_path(); + // path of the root modorganizer_super directory // static fs::path super_path(); @@ -217,34 +70,13 @@ namespace mob::tasks { cmake::ops o = cmake::generate, config config = config::relwithdebinfo); - // flags for some MO projects - enum flags { - noflags = 0x00, - - // gamebryo project, used by the translations task because these - // projects have multiple .ts files that have to be merged - gamebryo = 0x01, - - // project that uses nuget, cmake doesn't support those right now, so - // `msbuild -t:restore` has to be run manually - nuget = 0x02, - }; - // some mo tasks have more than one name, mostly because the transifex slugs // are different than the names on github; the std::string and const char* // overloads are because they're constructed from initializer lists and it's // more convenient that way - modorganizer(std::string name, flags f = noflags); - modorganizer(std::vector names, flags f = noflags); - modorganizer(std::vector names, flags f = noflags); - - // whether this project has the gamebryo flag on - // - bool is_gamebryo_plugin() const; - - // whether this project has the nuget flag on - // - bool is_nuget_plugin() const; + modorganizer(std::string name); + modorganizer(std::vector names); + modorganizer(std::vector names); // url to the git repo // @@ -272,261 +104,6 @@ namespace mob::tasks { private: std::string repo_; std::string project_; - flags flags_; - - // creates the cmake tool for this MO project - // - cmake create_cmake_tool(cmake::ops o = cmake::generate); - - // creates the msbuild tool for this MO project - // - msbuild create_msbuild_tool(msbuild::ops o = msbuild::build); - - // this is the file targeted by the msbuild tool - // - // it's not actually the .sln file because the cmake files have historically - // been inconsistent in what the main project in the solution is and whether - // the INSTALL project was enabled or not, so just building the .sln itself - // might not actually build everything - // - // by targeting the INSTALL project directly, everything will always be - // built correctly, regardless of how the solution file is generated - // - fs::path project_file_path() const; - }; - - class ncc : public basic_task { - public: - ncc(); - - static std::string version(); - static bool prebuilt(); - static fs::path source_path(); - - protected: - void do_clean(clean c) override; - void do_fetch() override; - void do_build_and_install() override; - - private: - msbuild create_msbuild_tool(msbuild::ops o); - }; - - class nmm : public basic_task { - public: - nmm(); - - static std::string version(); - static bool prebuilt(); - static fs::path source_path(); - - protected: - void do_clean(clean c) override; - void do_fetch() override; - void do_build_and_install() override; - - private: - msbuild create_msbuild_tool(msbuild::ops o = msbuild::build, - msbuild::flags_t f = msbuild::noflags); - }; - - class openssl : public basic_task { - public: - struct version_info { - std::string major, minor, patch; - }; - - openssl(); - - static version_info parsed_version(); - static std::string version(); - static bool prebuilt(); - - static fs::path source_path(); - static fs::path include_path(); - static fs::path build_path(); - static fs::path bin_path(); - - protected: - void do_clean(clean c) override; - void do_fetch() override; - void do_build_and_install() override; - - private: - void fetch_prebuilt(); - void fetch_from_source(); - void build_and_install_prebuilt(); - void build_and_install_from_source(); - - void configure(); - void install_engines(); - void copy_files(); - void copy_dlls_to(const fs::path& dir); - void copy_pdbs_to(const fs::path& dir); - }; - - // when building from source, builds both pyqt5 and pyqt5-sip; when using the - // prebuilt, the downloaded zip contains both - // - class pyqt : public basic_task { - public: - pyqt(); - - static std::string version(); - static std::string builder_version(); - static bool prebuilt(); - - static fs::path source_path(); - static fs::path build_path(); - static config build_type(); - - // "PyQt5.sip", used both in pyqt and sip - // - static std::string pyqt_sip_module_name(); - - protected: - void do_clean(clean c) override; - void do_fetch() override; - void do_build_and_install() override; - - private: - void fetch_prebuilt(); - void fetch_from_source(); - void build_and_install_prebuilt(); - void build_and_install_from_source(); - - void sip_build(); - void install_sip_file(); - void copy_files(); - }; - - class python : public basic_task { - public: - struct version_info { - std::string major; - std::string minor; - std::string patch; - }; - - python(); - - static std::string version(); - static bool prebuilt(); - static version_info parsed_version(); - - // build/python-XX - // - static fs::path source_path(); - - // build/python-XX/PCBuild/amd64 - // - static fs::path build_path(); - - // build/python-XX/PCBuild/amd64/python.exe - // - static fs::path python_exe(); - - // build/python-XX/Include - // - static fs::path include_path(); - - // build/python-XX/Scripts - // - static fs::path scripts_path(); - - // build/python-XX/Lib/site-packages - // - static fs::path site_packages_path(); - - // configuration to build - // - static config build_type(); - - protected: - void do_clean(clean c) override; - void do_fetch() override; - void do_build_and_install() override; - - private: - void fetch_prebuilt(); - void fetch_from_source(); - void build_and_install_prebuilt(); - void build_and_install_from_source(); - - void prepare_dependencies(); - void package(); - void install_pip(); - void copy_files(); - - msbuild create_msbuild_tool(msbuild::ops o = msbuild::build); - }; - - class pybind11 : public basic_task { - public: - pybind11(); - - static bool prebuilt(); - static std::string version(); - static fs::path source_path(); - - protected: - void do_clean(clean c) override; - void do_fetch() override; - void do_build_and_install() override; - }; - - class sevenz : public basic_task { - public: - sevenz(); - - static std::string version(); - static bool prebuilt(); - static fs::path source_path(); - - protected: - void do_clean(clean c) override; - void do_fetch() override; - void do_build_and_install() override; - - private: - void build(); - }; - - class sip : public basic_task { - public: - sip(); - - static std::string version(); - static std::string version_for_pyqt(); - static bool prebuilt(); - - static fs::path source_path(); - static fs::path sip_module_exe(); - static fs::path sip_install_exe(); - static fs::path module_source_path(); - - protected: - void do_clean(clean c) override; - void do_fetch() override; - void do_build_and_install() override; - - private: - void build(); - void generate_header(); - void convert_script_file_to_acp(const std::string& filename); - }; - - class spdlog : public basic_task { - public: - spdlog(); - - static std::string version(); - static bool prebuilt(); - static fs::path source_path(); - - protected: - void do_clean(clean c) override; - void do_fetch() override; }; class stylesheets : public task { @@ -624,11 +201,6 @@ namespace mob::tasks { // duplicate warnings std::set warned_; - // whether the given project name is a gamebryo task, `dir` is just for - // logging - // - bool is_gamebryo_plugin(const std::string& dir, const std::string& project); - // parses the directory name, walks all the .ts files, returns a project // object for them // @@ -637,7 +209,7 @@ namespace mob::tasks { // returns a lang object that contains at least the given main_ts_file, // but might contain more if it's a gamebryo plugin // - lang create_lang(bool gamebryo, const std::string& project_name, + lang create_lang(const std::string& project_name, const fs::path& main_ts_file); }; @@ -677,22 +249,4 @@ namespace mob::tasks { config = config::release) const; }; - class zlib : public basic_task { - public: - zlib(); - - static std::string version(); - static bool prebuilt(); - static fs::path source_path(); - - protected: - void do_clean(clean c) override; - void do_fetch() override; - void do_build_and_install() override; - - private: - cmake create_cmake_tool(cmake::ops o = cmake::generate); - msbuild create_msbuild_tool(msbuild::ops o = msbuild::build); - }; - } // namespace mob::tasks diff --git a/src/tasks/translations.cpp b/src/tasks/translations.cpp index bc29c50..6910b19 100644 --- a/src/tasks/translations.cpp +++ b/src/tasks/translations.cpp @@ -125,9 +125,6 @@ namespace mob::tasks { // walks all the .ts files in the project, creates a `lang` object for // each // - // each project directory is named "mod-organizer-2.project_name", so this - // splits on the dot to get the project name, checks if it's a gamebryo - // plugin, and adds the gamebryo .ts file as well if necessary // splitting const auto dir_name = path_to_utf8(dir.filename()); @@ -150,7 +147,6 @@ namespace mob::tasks { // project project p(project_name); - const bool gamebryo = is_gamebryo_plugin(dir_name, project_name); // for each file for (auto f : fs::directory_iterator(dir)) { @@ -168,14 +164,14 @@ namespace mob::tasks { } // add a new `lang` object for it - p.langs.push_back(create_lang(gamebryo, project_name, f.path())); + p.langs.push_back(create_lang(project_name, f.path())); } return p; } translations::projects::lang - translations::projects::create_lang(bool gamebryo, const std::string& project_name, + translations::projects::create_lang(const std::string& project_name, const fs::path& main_ts_file) { lang lg(path_to_utf8(main_ts_file.stem())); @@ -183,64 +179,9 @@ namespace mob::tasks { // every lang has the .ts file from the project, gamebryo plugins have more lg.ts_files.push_back(main_ts_file); - if (gamebryo) { - // this is a gamebryo plugin, so it needs the gamebryo .ts file as well, - // find it - - // the .ts files for gamebryo are in mod-organizer-2.game_gamebryo/ - const fs::path gamebryo_dir = - conf().transifex().get("project") + "." + "game_gamebryo"; - - // the .ts file has the same name, it's just "lang.ts" - const auto gamebryo_ts = root_ / gamebryo_dir / main_ts_file.filename(); - - if (fs::exists(gamebryo_ts)) { - // found, add it - lg.ts_files.push_back(gamebryo_ts); - } - else { - // not found, that means the plugin was translated into a language, - // but the gamebryo project wasn't; warn once - if (!warned_.contains(gamebryo_ts)) { - warned_.insert(gamebryo_ts); - - warnings_.push_back(::std::format( - "{} is a gamebryo plugin but there is no '{}'; the " - ".qm file will be missing some translations (will " - "only warn once)", - project_name, path_to_utf8(gamebryo_ts))); - } - } - } - return lg; } - bool translations::projects::is_gamebryo_plugin(const std::string& dir, - const std::string& project) - { - const auto* t = task_manager::instance().find_one(project); - - if (!t) { - warnings_.push_back( - ::std::format("directory '{}' was parsed as project '{}', but there's " - "no task with this name", - dir, project)); - - return false; - } - - // gamebryo plugins are all `modorganizer` tasks - const auto* mo_task = static_cast(t); - if (!mo_task) { - // not an mo task, can't be a gamebryo plugin - return false; - } - - // check the flag - return mo_task->is_gamebryo_plugin(); - } - translations::translations() : task("translations") {} fs::path translations::source_path() diff --git a/src/tasks/usvfs.cpp b/src/tasks/usvfs.cpp index e2bfe3d..2c3e7e9 100644 --- a/src/tasks/usvfs.cpp +++ b/src/tasks/usvfs.cpp @@ -76,8 +76,10 @@ namespace mob::tasks { { run_tool(create_cmake_tool(arch::x64)); run_tool(create_cmake_tool(arch::x86)); - run_tool(create_msbuild_tool(arch::x64)); - run_tool(create_msbuild_tool(arch::x86)); + run_tool(create_msbuild_tool(arch::x64, msbuild::build, + task_conf().configuration())); + run_tool(create_msbuild_tool(arch::x86, msbuild::build, + task_conf().configuration())); } cmake usvfs::create_cmake_tool(arch a, cmake::ops o) const diff --git a/src/tasks/zlib.cpp b/src/tasks/zlib.cpp deleted file mode 100644 index 1eeb8e4..0000000 --- a/src/tasks/zlib.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "pch.h" -#include "tasks.h" - -namespace mob::tasks { - - zlib::zlib() : basic_task("zlib") {} - - std::string zlib::version() - { - return conf().version().get("zlib"); - } - - bool zlib::prebuilt() - { - return false; - } - - fs::path zlib::source_path() - { - return conf().path().build() / ("zlib-" + version()); - } - - void zlib::do_clean(clean c) - { - // delete the whole directory - if (is_set(c, clean::reclone)) { - git_wrap::delete_directory(cx(), source_path()); - - // no point in doing anything more - return; - } - - // cmake clean - if (is_set(c, clean::reconfigure)) - run_tool(create_cmake_tool(cmake::clean)); - - // msbuild clean - if (is_set(c, clean::rebuild)) - run_tool(create_msbuild_tool(msbuild::clean)); - } - - void zlib::do_fetch() - { - run_tool(make_git() - .url(make_git_url("madler", "zlib")) - .branch(version()) - .root(source_path())); - } - - void zlib::do_build_and_install() - { - const fs::path build_path = run_tool(create_cmake_tool()); - - run_tool(create_msbuild_tool()); - - // zconf.h needs to be copied to the root directory, it's where python - // looks for it - op::copy_file_to_dir_if_better(cx(), build_path / "zconf.h", source_path()); - } - - cmake zlib::create_cmake_tool(cmake::ops o) - { - return std::move(cmake(o) - .generator(cmake::vs) - .root(source_path()) - .arg("-Wno-deprecated") - .prefix(source_path())); - } - - msbuild zlib::create_msbuild_tool(msbuild::ops o) - { - const fs::path build_path = create_cmake_tool().build_path(); - return std::move(msbuild(o).solution(build_path / "INSTALL.vcxproj")); - } - -} // namespace mob::tasks diff --git a/src/tools/cmake.cpp b/src/tools/cmake.cpp index 3d8e629..3a89ff2 100644 --- a/src/tools/cmake.cpp +++ b/src/tools/cmake.cpp @@ -114,6 +114,12 @@ namespace mob { return *this; } + cmake& cmake::configuration_types(const std::vector& configs) + { + config_types_ = configs; + return *this; + } + cmake& cmake::cmd(const std::string& s) { cmd_ = s; @@ -181,6 +187,16 @@ namespace mob { p = p.arg("--preset").arg(preset_); } + if (!config_types_.empty()) { + std::string types; + for (const auto& c : config_types_) { + if (!types.empty()) + types += ";"; + types += config_to_string(c); + } + p = p.arg("-DCMAKE_CONFIGURATION_TYPES=" + types); + } + p = p.arg("-DCMAKE_INSTALL_MESSAGE=" + conf_cmake::to_string(conf().cmake().install_message())) .arg("--log-level=ERROR") diff --git a/src/tools/cmake.h b/src/tools/cmake.h index 9420fc5..11a289a 100644 --- a/src/tools/cmake.h +++ b/src/tools/cmake.h @@ -69,6 +69,9 @@ namespace mob { // cmake& configuration(mob::config config); + // set the configuration types available when generating + cmake& configuration_types(const std::vector& configs); + // overrides the directory in which cmake will write build files // // by default, this is a directory inside what was given in root() with a @@ -184,6 +187,9 @@ namespace mob { // configuration mob::config config_{mob::config::relwithdebinfo}; + // configuration types + std::vector config_types_; + // passed verbatim std::vector args_; diff --git a/src/tools/jom.cpp b/src/tools/jom.cpp deleted file mode 100644 index 66e6bc8..0000000 --- a/src/tools/jom.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include "pch.h" -#include "../core/conf.h" -#include "../core/process.h" -#include "tools.h" - -namespace mob { - - jom::jom() : basic_process_runner("jom"), arch_(arch::def) {} - - fs::path jom::binary() - { - return conf().tool().get("jom"); - } - - jom& jom::path(const fs::path& p) - { - cwd_ = p; - return *this; - } - - jom& jom::target(const std::string& s) - { - target_ = s; - return *this; - } - - jom& jom::def(const std::string& s) - { - def_.push_back(s); - return *this; - } - - jom& jom::flag(flags_t f) - { - flags_ = f; - return *this; - } - - jom& jom::architecture(arch a) - { - arch_ = a; - return *this; - } - - int jom::result() const - { - return exit_code(); - } - - void jom::do_run() - { - process p; - - // jom doesn't handle sigint well, it just continues, so kill it on - // interruption - auto pflags = process::terminate_on_interrupt; - - if (flags_ & allow_failure) { - // tasks will set allow_failure for the first couple of runs of jom, - // which often fails because of the /J multi-process flag, so don't log - // errors in that case - p.stderr_level(context::level::trace); - pflags |= process::allow_failure; - } - - p.binary(binary()) - .cwd(cwd_) - .stderr_filter([](process::filter& f) { - // initial log line, can't get rid of it, /L or /NOLOGO don't seem - // to work - if (f.line.find("empower your cores") != std::string::npos) - f.lv = context::level::trace; - }) - .arg("/C", process::log_quiet) // silent - .arg("/S", process::log_quiet) // silent - .arg("/L", process::log_quiet) // silent, jom likes to spew crap - .arg("/D", process::log_dump) // verbose stuff - .arg("/P", process::log_dump) // verbose stuff - .arg("/W", process::log_dump) // verbose stuff - .arg("/K"); // don't stop on errors - - if (flags_ & single_job) - p.arg("/J", "1"); // single-process - - for (auto&& def : def_) - p.arg(def); - - p.arg(target_).flags(pflags).env(env::vs(arch_)); - - execute_and_join(p); - } - -} // namespace mob diff --git a/src/tools/nmake.cpp b/src/tools/nmake.cpp deleted file mode 100644 index abd011e..0000000 --- a/src/tools/nmake.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "pch.h" -#include "../core/conf.h" -#include "../core/process.h" -#include "tools.h" - -namespace mob { - - nmake::nmake() : basic_process_runner("nmake"), arch_(arch::def) {} - - fs::path nmake::binary() - { - return conf().tool().get("nmake"); - } - - nmake& nmake::path(const fs::path& p) - { - cwd_ = p; - return *this; - } - - nmake& nmake::target(const std::string& s) - { - target_ = s; - return *this; - } - - nmake& nmake::def(const std::string& s) - { - def_.push_back(s); - return *this; - } - - nmake& nmake::architecture(arch a) - { - arch_ = a; - return *this; - } - - int nmake::result() const - { - return exit_code(); - } - - void nmake::do_run() - { - process p; - - p.binary(binary()) - .cwd(cwd_) - .stderr_filter([](process::filter& f) { - // initial log line, can't get rid of it, /L or /NOLOGO don't seem - // to work - if (f.line.find("Microsoft (R) Macro Assembler (x64)") != - std::string::npos) - f.lv = context::level::trace; - if (f.line.find("Copyright (C) Microsoft Corporation.") != - std::string::npos) - f.lv = context::level::trace; - if (f.line.find("Microsoft (R) Program Maintenance Utility") != - std::string::npos) - f.lv = context::level::trace; - }) - .arg("/C", process::log_quiet) // silent - .arg("/S", process::log_quiet) // silent - .arg("/L", process::log_quiet) // silent, nmake likes to spew crap - .arg("/D", process::log_dump) // verbose stuff - .arg("/P", process::log_dump) // verbose stuff - .arg("/W", process::log_dump) // verbose stuff - .arg("/K"); // don't stop on errors - - for (auto&& def : def_) - p.arg(def); - - p.arg(target_).env(env::vs(arch_)); - - execute_and_join(p); - } - -} // namespace mob diff --git a/src/tools/patcher.cpp b/src/tools/patcher.cpp deleted file mode 100644 index 7966297..0000000 --- a/src/tools/patcher.cpp +++ /dev/null @@ -1,156 +0,0 @@ -#include "pch.h" -#include "../core/conf.h" -#include "../core/process.h" -#include "tools.h" - -namespace mob { - - patcher::patcher() : basic_process_runner("patch"), prebuilt_(false) {} - - fs::path patcher::binary() - { - return conf().tool().get("patch"); - } - - patcher& patcher::task(const std::string& name, bool prebuilt) - { - task_ = name; - prebuilt_ = prebuilt; - return *this; - } - - patcher& patcher::file(const fs::path& p) - { - file_ = p; - return *this; - } - - patcher& patcher::root(const fs::path& dir) - { - root_ = dir; - return *this; - } - - void patcher::do_run() - { - // patches should be in mob/patches/task-name, but not all tasks need - // patches - const fs::path root = conf().path().patches() / task_; - - if (!fs::exists(root)) { - cx().trace(context::generic, - "patch directory {} doesn't exist, assuming no patches", root); - - return; - } - - if (!file_.empty()) { - // patcher tool is being run for a manual patch - cx().trace(context::generic, "doing manual patch from {}", file_); - do_patch(root / file_); - return; - } - - // patcher tool is being by the task for auto patching, figure out the - // directory to use depending on whether it's a prebuilt - const fs::path patches = root / (prebuilt_ ? "prebuilt" : "sources"); - cx().trace(context::generic, "looking for patches in {}", patches); - - if (!fs::exists(patches)) { - cx().trace(context::generic, - "patch directory {} doesn't exist, assuming no patches", - patches); - - return; - } - - // for each path file - for (auto e : fs::directory_iterator(patches)) { - if (!e.is_regular_file()) { - cx().trace(context::generic, "skipping {}, not a file", e.path()); - continue; - } - - const auto p = e.path(); - - if (p.extension() == ".manual_patch") { - cx().trace(context::generic, "skipping manual patch {}", e.path()); - continue; - } - else if (p.extension() != ".patch") { - cx().warning(context::generic, "file with unknown extension {}", p); - continue; - } - - do_patch(p); - } - } - - void patcher::do_patch(const fs::path& patch) - { - // there's no way to figure out if patch failure is because 1) the patch - // file is incorrect, or 2) the patch has already been applied - // - // an incorrect patch file would probably mean that the source has changed - // and the patch must be updated or removed if it's not required anymore - // - // so patching is a two step process: check if the patch has already been - // applied, and apply it if it hasn't - - // use by both the check and apply processes - const auto base = process() - .binary(binary()) - .arg("--read-only", "ignore") - .arg("--strip", "0") - .arg("--directory", root_) - .arg("--quiet", process::log_quiet); - - // process to reverse the path: the only way to check if a patch has been - // applied is actually to try to reverse it and check if there was an error - // - // this uses --dry-run because if the file was already patched, it shouldn't - // actually be reversed - auto check = process(base) - .flags(process::allow_failure) - .arg("--dry-run") - .arg("--force") // no prompts - .arg("--reverse") // swaps old and new files - .arg("--input", patch); - - // process to apply the patch - auto apply = - process(base) - .arg("--forward") // don't try to reverse the patch if it fails - .arg("--batch") // no prompts - .arg("--input", patch); - - cx().trace(context::generic, "trying to patch using {}", patch); - - { - // check, returns 0 when the patch would have been reversed correctly, - // 1 if not, anything else on error - cx().trace(context::generic, "checking if already patched"); - const auto ret = execute_and_join(check); - - if (ret == 0) { - // reversing the patch would succeed, so the patch has already been - // applied - cx().trace(context::generic, "patch {} already applied", patch); - return; - } - - // anything other than 0 or 1 is a hard error - if (ret != 1) - cx().bail_out(context::generic, "patch returned {}", ret); - - cx().trace(context::generic, "looks like the patch is needed"); - } - - { - // apply - cx().trace(context::generic, "applying patch {}", patch); - execute_and_join(apply); - } - } - -} // namespace mob diff --git a/src/tools/python.cpp b/src/tools/python.cpp deleted file mode 100644 index 46c79bc..0000000 --- a/src/tools/python.cpp +++ /dev/null @@ -1,187 +0,0 @@ -#include "pch.h" -#include "../core/process.h" -#include "../tasks/tasks.h" -#include "tools.h" - -namespace mob { - - python::python() : basic_process_runner("python") {} - - python& python::root(const fs::path& p) - { - root_ = p; - return *this; - } - - python& python::arg(const std::string& s) - { - args_.push_back(s); - return *this; - } - - void python::do_run() - { - // python is a bit finicky for utf8, so: - // 1) chcp changes the codepage to utf8 - // 2) `-X utf8` and the PYTHONUTF8 environment variable are set, which - // is probably redundant - - auto p = process() - .binary(tasks::python::python_exe()) - .chcp(65001) - .stdout_encoding(encodings::utf8) - .stderr_encoding(encodings::utf8) - .stderr_filter([&](process::filter& f) { - // filter out crap from setuptools - if (f.line.find("zip_safe flag not set") != std::string::npos) - f.lv = context::level::trace; - else if (f.line.find("module references __file__") != - std::string::npos) - f.lv = context::level::trace; - }) - .arg("-X", "utf8"); // forces utf8 - - for (auto&& a : args_) - p.arg(a); - - p.cwd(root_).env(this_env::get().set("PYTHONUTF8", "1")); // forces utf8 - - execute_and_join(p); - } - - pip::pip(ops op) : basic_process_runner("pip"), op_(op), no_deps_{false} {} - - pip& pip::package(const std::string& s) - { - package_ = s; - return *this; - } - - pip& pip::version(const std::string& s) - { - version_ = s; - return *this; - } - - pip& pip::file(const fs::path& p) - { - file_ = p; - return *this; - } - - pip& pip::no_dependencies() - { - no_deps_ = true; - return *this; - } - - void pip::do_run() - { - switch (op_) { - case ensure: - do_ensure(); - break; - - case install: - do_install(); - break; - - case download: - do_download(); - break; - - default: - cx().bail_out(context::generic, "pip unknown op {}", op_); - } - } - - void pip::do_ensure() - { - // ensure - execute_and_join( - process() - .stderr_filter([](auto&& f) { - // this spits out two warnings about not being on PATH and suggests - // to add --no-warn-script-location, but that's not actually a valid - // parameter for `ensurepip` and it fails, unlike the `install` - // commands below - // - // so just filter it out - - if (f.line.find("which is not on PATH") != std::string::npos) - f.lv = context::level::debug; - else if (f.line.find("Consider adding this") != std::string::npos) - f.lv = context::level::debug; - }) - .binary(tasks::python::python_exe()) - .arg("-m", "ensurepip")); - - // upgrade - execute_and_join(process() - .binary(tasks::python::python_exe()) - .arg("-m pip") - .arg("install") - .arg("--no-warn-script-location") - .arg("--upgrade pip")); - - // ssl errors while downloading through python without certifi - execute_and_join(process() - .binary(tasks::python::python_exe()) - .arg("-m pip") - .arg("install") - .arg("--no-warn-script-location") - .arg("certifi")); - } - - void pip::do_install() - { - auto p = process() - .binary(tasks::python::python_exe()) - .chcp(65001) - .stdout_encoding(encodings::utf8) - .stderr_encoding(encodings::utf8) - .arg("-X", "utf8") - .arg("-m", "pip") - .arg("install") - .arg("--force") - .arg("--no-warn-script-location") - .arg("--disable-pip-version-check"); - - if (!package_.empty()) { - if (version_.empty()) { - p.arg(package_); - } - else { - p.arg(package_ + "==" + version_); - } - } - else if (!file_.empty()) - p.arg(file_); - - if (no_deps_) { - p.arg("--no-dependencies"); - } - - p.env(this_env::get().set("PYTHONUTF8", "1")); - - execute_and_join(p); - } - - void pip::do_download() - { - execute_and_join(process() - .binary(tasks::python::python_exe()) - .chcp(65001) - .stdout_encoding(encodings::utf8) - .stderr_encoding(encodings::utf8) - .arg("-X", "utf8") - .arg("-m", "pip") - .arg("download") - .arg("--no-binary=:all:") - .arg("--no-deps") - .arg("-d", conf().path().cache()) - .arg(package_ + "==" + version_) - .env(this_env::get().set("PYTHONUTF8", "1"))); - } - -} // namespace mob diff --git a/src/tools/tools.cpp b/src/tools/tools.cpp index 28549d0..a0779fe 100644 --- a/src/tools/tools.cpp +++ b/src/tools/tools.cpp @@ -73,16 +73,6 @@ namespace mob { return gcx(); } - fs::path perl::binary() - { - return conf().tool().get("perl"); - } - - fs::path nasm::binary() - { - return conf().tool().get("nasm"); - } - fs::path qt::installation_path() { return conf().path().qt_install(); @@ -201,19 +191,6 @@ namespace mob { return trim_copy(p.stdout_string()); } - nuget::nuget(fs::path sln) : basic_process_runner("nuget"), sln_(std::move(sln)) {} - - fs::path nuget::binary() - { - return conf().tool().get("nuget"); - } - - void nuget::do_run() - { - execute_and_join(process().binary(binary()).arg("restore").arg(sln_).cwd( - sln_.parent_path())); - } - transifex::transifex(ops o) : basic_process_runner("transifex"), op_(o), stdout_(context::level::trace), min_(100), force_(false) diff --git a/src/tools/tools.h b/src/tools/tools.h index 3d16fef..47d85eb 100644 --- a/src/tools/tools.h +++ b/src/tools/tools.h @@ -95,23 +95,6 @@ namespace mob { // these are not strictly tools, but they're a centralized place for perl, // nasm, qt and vswhere stuff - // only used when building openssl from source - // - struct perl { - // path to perl binary - // - static fs::path binary(); - }; - - // only used when building openssl from source, bundled with mob in - // third-party/bin - // - struct nasm { - // path to nasm binary - // - static fs::path binary(); - }; - struct qt { // path to qt's root directory, the one that contains bin, include, etc. // @@ -365,199 +348,6 @@ namespace mob { const fs::path& files_root); }; - // tool to apply patches available for a third-party task; patches live in - // mob/patches, in one directory per task - // - // patch.exe is bundled with mob in third-party/bin - // - // there are two ways of patching a task: - // - // 1) auto patching: each task runs the patcher tool as a step in - // task::fetch(), just after calling do_fetch(), which checks for a - // directory `patches/task-name/sources` or `patches/task-name/prebuilt` - // depending on whether this is a prebuilt or not - // - // any file ending with `.patch` will be applied, rooted in the path - // given to root() (defaults to the task's source directory) - // - // 2) manual patching: a task can run the patcher with a specific patch file - // given in file() at any time, which is useful for tasks that need to - // patch files generated later in the building process, such as pyqt - // - // manual patch files can be anywhere, but they're in patches/task-name with - // a `.manual_patch` by convention - // - class patcher : public basic_process_runner { - public: - // path to the patch binary - // - static fs::path binary(); - - patcher(); - - // sets the task name and whether it's a prebuilt, used in task::fetch() for - // auto patching - // - patcher& task(const std::string& name, bool prebuilt = false); - - // sets the patch's filename; if this is not set, uses the task name and - // prebuilt flag from task() - // - patcher& file(const fs::path& p); - - // directory in which the patches are applied; the filenames in the patch - // files must be relative to this directory - // - patcher& root(const fs::path& dir); - - protected: - // applies the patch file from the task directory or the patch file given - // in file() - // - void do_run() override; - - private: - // task name and prebuilt flag, used to generate the auto patching directory - std::string task_; - bool prebuilt_; - - // root directory, used to resolve the relative file names in the patch - // files - fs::path root_; - - // patch file, empty for auto patching - fs::path file_; - - // applies one patch file - // - void do_patch(const fs::path& patch_file); - }; - - // tool that runs `nmake` - // - class nmake : public basic_process_runner { - public: - // path to the job binary - // - static fs::path binary(); - - nmake(); - - // path in which to invoke nmake - // - nmake& path(const fs::path& p); - - // makefile target - // - nmake& target(const std::string& s); - - // adds a macro definition as "NAME=value" - // - nmake& def(const std::string& s); - - // sets the architecture used to run nmake, used to get the appropriate - // VS environment variables, defaults to arch::def - // - nmake& architecture(arch a); - - // nmake's exit code - // - int result() const; - - protected: - // runs nmake - // - void do_run() override; - - private: - // set in path() - fs::path cwd_; - - // set in def(), just plain arguments - std::vector def_; - - // set in target(), another plain argument - std::string target_; - - // set in architecture() - arch arch_; - }; - - // tool that runs `jom`, an alternative to `nmake` that supports parallel - // builds, bundled with mob in third-party/bin - // - // note that although jom reduces build times considerably, some third parties - // don't handle it very well, giving a bunch of errors about files in use, etc. - // - // so most tools that use jom use a loop that runs jom several times, allowing - // failure, and then run jom one last time in single_job mode to finish the - // build, which should be guaranteed to work - // - class jom : public basic_process_runner { - public: - // path to the job binary - // - static fs::path binary(); - - enum flags_t { - noflags = 0x00, - - // disables multi-process build - single_job = 0x01, - - // don't bail out on failure - allow_failure = 0x02 - }; - - jom(); - - // path in which to invoke jom - // - jom& path(const fs::path& p); - - // makefile target - // - jom& target(const std::string& s); - - // adds a macro definition as "NAME=value" - // - jom& def(const std::string& s); - - // sets flags - // - jom& flag(flags_t f); - - // sets the architecture used to run jom, used to get the appropriate - // VS environment variables, defaults to arch::def - // - jom& architecture(arch a); - - // jom's exit code - // - int result() const; - - protected: - // runs jom - // - void do_run() override; - - private: - // set in path() - fs::path cwd_; - - // set in def(), just plain arguments - std::vector def_; - - // set in target(), another plain argument - std::string target_; - - // set in flag() - flags_t flags_; - - // set in architecture() - arch arch_; - }; - // tool that runs devenv.exe, only invoked to upgrade projects for now // class vs : public basic_process_runner { @@ -619,125 +409,6 @@ namespace mob { void do_upgrade(); }; - // tool that runs `nuget restore` for the given solution, bundled with mob in - // third-party/bin - // - class nuget : public basic_process_runner { - public: - // nuget tool for the given solution - // - nuget(fs::path sln); - - // path to the nuget binary - // - static fs::path binary(); - - protected: - // runs nuget - void do_run() override; - - private: - // solution file set in constructor - fs::path sln_; - }; - - // tool that runs python - // - class python : public basic_process_runner { - public: - python(); - - // working directory - // - python& root(const fs::path& p); - - // arbitrary arguments given to python - // - python& arg(const std::string& s); - - protected: - // runs python - // - void do_run() override; - - private: - // working directory - fs::path root_; - - // arguments - std::vector args_; - }; - - // tool that runs pip for one of the operations in the enum - // - class pip : public basic_process_runner { - public: - // what run() should do - // - enum ops { - // installs pip if needed and updates it - ensure = 1, - - // runs `-m pip install` for the given package/version or file - // - install, - - // runs `-m pip download` for the given package and version, does not - // use file() - download - }; - - // a pip tool for the given operation - // - pip(ops o); - - // `pip install` can work with either a "package==version" string, which - // downloads the file if needed, or a local file - // - // so for the `install` operation, either package/version or file can be - // given, but the `download` operation requires the package/version only - // and puts the downloaded file in the "cache" path (defaults to the - // downloads/ directory) - // - pip& package(const std::string& s); - pip& version(const std::string& s); - pip& file(const fs::path& p); - - // do not install dependencies for the package - // - pip& no_dependencies(); - - protected: - // runs pip - // - void do_run() override; - - private: - // what pip command to run - ops op_; - - // set in package(), version() and file() - std::string package_; - std::string version_; - fs::path file_; - - // no depndencies - bool no_deps_; - - // runs `-m ensurepip`, then upgrades pip - // - void do_ensure(); - - // runs `-m pip install` with the given package/version or file - // - void do_install(); - - // runs `-m pip download` with the given package/version, saves the file - // in the cache directory - // - void do_download(); - }; - // tool that runs transifex, used for pulling translations before release, // bundled with mob in third-party/bin // diff --git a/src/utility.h b/src/utility.h index a0becf4..3b833e3 100644 --- a/src/utility.h +++ b/src/utility.h @@ -50,16 +50,6 @@ namespace mob { class url; - // returns a url for a prebuilt binary having the given filename; prebuilts are - // hosted on github, in the umbrella repo - // - url make_prebuilt_url(const std::string& filename); - - // returns a url for an appveyor artifact; this is used by usvfs for prebuilts - // - url make_appveyor_artifact_url(arch a, const std::string& project, - const std::string& filename); - // returns "mob x.y" // std::string mob_version();