mirror of
https://github.com/ModOrganizer2/mob.git
synced 2026-07-27 14:07:05 -07:00
Move to VCPKG.
* Use CMake with presets to generate USVFS solution. * Use preset when building super repository. * Allow overriding VCPKG_ROOT with [paths] entry. * Remove gamebryo and nuget specific stuff. * Remove cmake command. Add done log. * Use VCPKG from VS if no VCPKG_ROOT or path setting.
This commit is contained in:
@@ -21,6 +21,10 @@ host =
|
||||
super = cmake_common modorganizer* githubpp
|
||||
plugins = check_fnis bsapacker bsa_extractor diagnose_basic installer_* plugin_python preview_base preview_bsa tool_* game_*
|
||||
|
||||
[translations]
|
||||
mo2-translations = organizer
|
||||
mo2-game-bethesda = game_creation game_enderal game_enderalse game_fallout3 game_fallout4 game_fallout4vr game_falloutNV game_gamebryo game_morrowind game_nehrim game_oblivion game_skyrim game_skyrimse game_skyrimvr game_ttw
|
||||
|
||||
[task]
|
||||
enabled = true
|
||||
mo_org = ModOrganizer2
|
||||
@@ -150,11 +154,12 @@ install_pdbs =
|
||||
install_dlls =
|
||||
install_loot =
|
||||
install_plugins =
|
||||
install_extensions =
|
||||
install_stylesheets =
|
||||
install_licenses =
|
||||
install_pythoncore =
|
||||
install_translations =
|
||||
vs =
|
||||
vcpkg =
|
||||
qt_install =
|
||||
qt_bin =
|
||||
qt_translations =
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ file(GLOB_RECURSE source_files *.cpp)
|
||||
file(GLOB_RECURSE header_files *.h)
|
||||
|
||||
add_executable(mob ${source_files} ${header_files})
|
||||
set_target_properties(mob PROPERTIES CXX_STANDARD 20)
|
||||
set_target_properties(mob PROPERTIES CXX_STANDARD 23)
|
||||
|
||||
target_compile_definitions(mob PUBLIC NOMINMAX)
|
||||
target_compile_options(mob PUBLIC "/MT")
|
||||
|
||||
@@ -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
|
||||
@@ -367,27 +367,6 @@ namespace mob {
|
||||
std::vector<fs::path> 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 {
|
||||
|
||||
+29
-15
@@ -51,24 +51,32 @@ namespace mob::details {
|
||||
|
||||
// returns a string from conf, bails out if it doesn't exist
|
||||
//
|
||||
std::string get_string(std::string_view section, std::string_view key)
|
||||
std::string get_string(std::string_view section, std::string_view key,
|
||||
std::optional<std::string> default_)
|
||||
{
|
||||
auto sitor = g_conf.find(section);
|
||||
if (sitor == g_conf.end())
|
||||
gcx().bail_out(context::conf, "[{}] doesn't exist", section);
|
||||
|
||||
auto kitor = sitor->second.find(key);
|
||||
if (kitor == sitor->second.end())
|
||||
gcx().bail_out(context::conf, "no key '{}' in [{}]", key, section);
|
||||
if (kitor == sitor->second.end()) {
|
||||
if (!default_.has_value()) {
|
||||
gcx().bail_out(context::conf, "no key '{}' in [{}]", key, section);
|
||||
}
|
||||
return *default_;
|
||||
}
|
||||
|
||||
return kitor->second;
|
||||
}
|
||||
|
||||
// calls get_string(), converts to int
|
||||
//
|
||||
int get_int(std::string_view section, std::string_view key)
|
||||
int get_int(std::string_view section, std::string_view key,
|
||||
std::optional<int> default_)
|
||||
{
|
||||
const auto s = get_string(section, key);
|
||||
const auto s = get_string(section, key, default_.transform([](auto v) {
|
||||
return std::to_string(v);
|
||||
}));
|
||||
|
||||
try {
|
||||
return std::stoi(s);
|
||||
@@ -80,9 +88,12 @@ namespace mob::details {
|
||||
|
||||
// calls get_string(), converts to bool
|
||||
//
|
||||
bool get_bool(std::string_view section, std::string_view key)
|
||||
bool get_bool(std::string_view section, std::string_view key,
|
||||
std::optional<bool> default_)
|
||||
{
|
||||
const auto s = get_string(section, key);
|
||||
const auto s = get_string(section, key, default_.transform([](auto v) {
|
||||
return v ? "true" : "false";
|
||||
}));
|
||||
return bool_from_string(s);
|
||||
}
|
||||
|
||||
@@ -428,13 +439,8 @@ namespace mob {
|
||||
|
||||
MOB_ASSERT(!tasks.empty());
|
||||
|
||||
for (auto& t : tasks) {
|
||||
if (t->name() != task &&
|
||||
details::find_string_for_task(t->name(), key)) {
|
||||
continue;
|
||||
}
|
||||
for (auto& t : tasks)
|
||||
details::set_string_for_task(t->name(), key, value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// global task option
|
||||
@@ -509,6 +515,7 @@ namespace mob {
|
||||
set_path_if_empty("pf_x86", find_program_files_x86);
|
||||
set_path_if_empty("pf_x64", find_program_files_x64);
|
||||
set_path_if_empty("vs", find_vs);
|
||||
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"));
|
||||
@@ -530,7 +537,7 @@ namespace mob {
|
||||
resolve_path("install", p.prefix(), "install");
|
||||
resolve_path("install_installer", p.install(), "installer");
|
||||
resolve_path("install_bin", p.install(), "bin");
|
||||
resolve_path("install_libs", p.install(), "libs");
|
||||
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");
|
||||
@@ -538,7 +545,7 @@ namespace mob {
|
||||
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");
|
||||
resolve_path("install_extensions", p.install_bin(), "extensions");
|
||||
|
||||
// finally, resolve the tools that are unlikely to be in PATH; all the
|
||||
// other tools (7z, jom, patch, etc.) are assumed to be in PATH (which
|
||||
@@ -684,6 +691,11 @@ namespace mob {
|
||||
return {};
|
||||
}
|
||||
|
||||
conf_translations conf::translation()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
conf_prebuilt conf::prebuilt()
|
||||
{
|
||||
return {};
|
||||
@@ -777,6 +789,8 @@ namespace mob {
|
||||
|
||||
conf_build_types::conf_build_types() : conf_section("build-types") {}
|
||||
|
||||
conf_translations::conf_translations() : conf_section("translations") {}
|
||||
|
||||
conf_prebuilt::conf_prebuilt() : conf_section("prebuilt") {}
|
||||
|
||||
conf_paths::conf_paths() : conf_section("paths") {}
|
||||
|
||||
+31
-12
@@ -9,7 +9,8 @@ namespace mob::details {
|
||||
|
||||
// returns an option named `key` from the given `section`
|
||||
//
|
||||
std::string get_string(std::string_view section, std::string_view key);
|
||||
std::string get_string(std::string_view section, std::string_view key,
|
||||
std::optional<std::string> default_ = {});
|
||||
|
||||
// convert a string to the given type
|
||||
template <class T>
|
||||
@@ -25,11 +26,13 @@ namespace mob::details {
|
||||
|
||||
// calls get_string(), converts to bool
|
||||
//
|
||||
bool get_bool(std::string_view section, std::string_view key);
|
||||
bool get_bool(std::string_view section, std::string_view key,
|
||||
std::optional<bool> default_ = {});
|
||||
|
||||
// calls get_string(), converts to in
|
||||
//
|
||||
int get_int(std::string_view section, std::string_view key);
|
||||
int get_int(std::string_view section, std::string_view key,
|
||||
std::optional<int> default_ = {});
|
||||
|
||||
// sets the given option, bails out if the option doesn't exist
|
||||
//
|
||||
@@ -60,9 +63,17 @@ namespace mob {
|
||||
template <class DefaultType>
|
||||
class conf_section {
|
||||
public:
|
||||
DefaultType get(std::string_view key) const
|
||||
DefaultType get(std::string_view key,
|
||||
std::optional<DefaultType> default_ = {}) const
|
||||
{
|
||||
const auto value = details::get_string(name_, key);
|
||||
const auto value = [=] {
|
||||
if constexpr (std::is_same_v<DefaultType, std::string>) {
|
||||
return details::get_string(name_, key, default_);
|
||||
}
|
||||
else {
|
||||
return details::get_string(name_, key);
|
||||
}
|
||||
}();
|
||||
|
||||
if constexpr (std::is_convertible_v<std::string, DefaultType>) {
|
||||
return value;
|
||||
@@ -74,18 +85,18 @@ namespace mob {
|
||||
|
||||
// undefined
|
||||
template <class T>
|
||||
T get(std::string_view key) const;
|
||||
T get(std::string_view key, std::optional<T> default_ = {}) const;
|
||||
|
||||
template <>
|
||||
bool get<bool>(std::string_view key) const
|
||||
bool get<bool>(std::string_view key, std::optional<bool> default_) const
|
||||
{
|
||||
return details::get_bool(name_, key);
|
||||
return details::get_bool(name_, key, default_);
|
||||
}
|
||||
|
||||
template <>
|
||||
int get<int>(std::string_view key) const
|
||||
int get<int>(std::string_view key, std::optional<int> default_) const
|
||||
{
|
||||
return details::get_int(name_, key);
|
||||
return details::get_int(name_, key, default_);
|
||||
}
|
||||
|
||||
void set(std::string_view key, std::string_view value)
|
||||
@@ -223,6 +234,13 @@ namespace mob {
|
||||
conf_build_types();
|
||||
};
|
||||
|
||||
// options in [translations]
|
||||
//
|
||||
class conf_translations : public conf_section<std::string> {
|
||||
public:
|
||||
conf_translations();
|
||||
};
|
||||
|
||||
// options in [prebuilt]
|
||||
//
|
||||
class conf_prebuilt : public conf_section<std::string> {
|
||||
@@ -257,13 +275,13 @@ namespace mob {
|
||||
|
||||
VALUE(install_dlls);
|
||||
VALUE(install_loot);
|
||||
VALUE(install_plugins);
|
||||
VALUE(install_extensions);
|
||||
VALUE(install_stylesheets);
|
||||
VALUE(install_licenses);
|
||||
VALUE(install_pythoncore);
|
||||
VALUE(install_translations);
|
||||
|
||||
VALUE(vs);
|
||||
VALUE(vcpkg);
|
||||
VALUE(qt_install);
|
||||
VALUE(qt_bin);
|
||||
VALUE(qt_translations);
|
||||
@@ -285,6 +303,7 @@ namespace mob {
|
||||
conf_cmake cmake();
|
||||
conf_tools tool();
|
||||
conf_transifex transifex();
|
||||
conf_translations translation();
|
||||
conf_prebuilt prebuilt();
|
||||
conf_versions version();
|
||||
conf_build_types build_types();
|
||||
|
||||
@@ -116,6 +116,30 @@ namespace mob::op {
|
||||
}
|
||||
}
|
||||
|
||||
void delete_file_glob_recurse(const context& cx, const fs::path& directory,
|
||||
const fs::path& glob, flags f)
|
||||
{
|
||||
cx.trace(context::fs, "deleting glob {}", glob);
|
||||
|
||||
const auto native = glob.native();
|
||||
|
||||
if (!fs::exists(directory))
|
||||
return;
|
||||
|
||||
for (auto&& e : fs::recursive_directory_iterator(directory)) {
|
||||
const auto p = e.path();
|
||||
const auto name = p.filename().native();
|
||||
|
||||
if (!PathMatchSpecW(name.c_str(), native.c_str())) {
|
||||
cx.trace(context::fs, "{} did not match {}; skipping", name, glob);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
delete_file(cx, p, f);
|
||||
}
|
||||
}
|
||||
|
||||
void remove_readonly(const context& cx, const fs::path& dir, flags f)
|
||||
{
|
||||
cx.trace(context::fs, "removing read-only from {}", dir);
|
||||
|
||||
@@ -65,6 +65,11 @@ namespace mob::op {
|
||||
//
|
||||
void delete_file_glob(const context& cx, const fs::path& glob, flags f = noflags);
|
||||
|
||||
// deletes all files matching the glob in the given directory and its subdirectories
|
||||
//
|
||||
void delete_file_glob_recurse(const context& cx, const fs::path& directory,
|
||||
const fs::path& glob, flags f = noflags);
|
||||
|
||||
// removes the readonly flag for all files in `dir`, recursive
|
||||
//
|
||||
void remove_readonly(const context& cx, const fs::path& dir, flags f = noflags);
|
||||
|
||||
@@ -254,6 +254,24 @@ namespace mob {
|
||||
}
|
||||
}
|
||||
|
||||
fs::path find_vcpkg()
|
||||
{
|
||||
const auto env_path = this_env::get().get("VCPKG_ROOT");
|
||||
|
||||
if (!env_path.empty()) {
|
||||
return fs::absolute(env_path);
|
||||
}
|
||||
|
||||
const auto vs_path = conf().path().vs();
|
||||
const auto vcpkg_vs_path = vs_path / "VC" / "vcpkg";
|
||||
if (!exists(vcpkg_vs_path)) {
|
||||
gcx().bail_out(context::conf, "vcpkg is not part of VS installation at {}",
|
||||
vs_path);
|
||||
}
|
||||
|
||||
return vcpkg_vs_path;
|
||||
}
|
||||
|
||||
fs::path find_qt()
|
||||
{
|
||||
// check from the ini first
|
||||
|
||||
@@ -33,6 +33,11 @@ namespace mob {
|
||||
//
|
||||
fs::path find_vs();
|
||||
|
||||
// returns the absolute path to VCPKG root directory to be used as VCPKG_ROOT when
|
||||
// building
|
||||
//
|
||||
fs::path find_vcpkg();
|
||||
|
||||
// returns the absolute path to Qt's root directory, the one that contains
|
||||
// bin, include, etc.; bails if not found
|
||||
//
|
||||
|
||||
+30
-53
@@ -26,33 +26,33 @@ namespace mob {
|
||||
|
||||
// third-party tasks
|
||||
|
||||
add_task<parallel_tasks>()
|
||||
.add_task<sevenz>()
|
||||
.add_task<zlib>()
|
||||
.add_task<gtest>()
|
||||
.add_task<libbsarch>()
|
||||
.add_task<libloot>()
|
||||
.add_task<openssl>()
|
||||
.add_task<bzip2>()
|
||||
.add_task<directxtex>();
|
||||
// add_task<parallel_tasks>()
|
||||
// .add_task<sevenz>()
|
||||
// .add_task<zlib>()
|
||||
// .add_task<gtest>()
|
||||
// .add_task<libbsarch>()
|
||||
// .add_task<libloot>()
|
||||
// .add_task<openssl>()
|
||||
// .add_task<bzip2>()
|
||||
// .add_task<directxtex>();
|
||||
|
||||
add_task<parallel_tasks>()
|
||||
.add_task<tasks::python>()
|
||||
.add_task<lz4>()
|
||||
.add_task<spdlog>();
|
||||
// add_task<parallel_tasks>()
|
||||
// .add_task<tasks::python>()
|
||||
// .add_task<lz4>()
|
||||
// .add_task<spdlog>();
|
||||
|
||||
add_task<parallel_tasks>()
|
||||
.add_task<boost>()
|
||||
.add_task<boost_di>()
|
||||
.add_task<sip>();
|
||||
// add_task<parallel_tasks>()
|
||||
// .add_task<boost>()
|
||||
// .add_task<boost_di>()
|
||||
// .add_task<sip>();
|
||||
|
||||
add_task<parallel_tasks>()
|
||||
.add_task<pyqt>()
|
||||
.add_task<pybind11>()
|
||||
.add_task<usvfs>()
|
||||
.add_task<stylesheets>()
|
||||
.add_task<licenses>()
|
||||
.add_task<explorerpp>();
|
||||
// add_task<parallel_tasks>()
|
||||
// .add_task<pyqt>()
|
||||
// .add_task<pybind11>()
|
||||
// .add_task<usvfs>()
|
||||
// .add_task<stylesheets>()
|
||||
// .add_task<licenses>()
|
||||
// .add_task<explorerpp>();
|
||||
|
||||
// super tasks
|
||||
|
||||
@@ -61,9 +61,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<parallel_tasks>()
|
||||
.add_task<mo>("cmake_common")
|
||||
.add_task<mo>("modorganizer-uibase");
|
||||
add_task<parallel_tasks>().add_task<usvfs>().add_task<mo>("cmake_common");
|
||||
|
||||
add_task<mo>("modorganizer-uibase");
|
||||
|
||||
add_task<parallel_tasks>()
|
||||
.add_task<mo>("modorganizer-archive")
|
||||
@@ -72,34 +72,12 @@ namespace mob {
|
||||
.add_task<mo>("modorganizer-bsatk")
|
||||
.add_task<mo>("modorganizer-nxmhandler")
|
||||
.add_task<mo>("modorganizer-helper")
|
||||
.add_task<mo>("githubpp")
|
||||
.add_task<mo>("modorganizer-game_gamebryo")
|
||||
.add_task<mo>({"modorganizer-bsapacker", "bsa_packer"})
|
||||
.add_task<mo>("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<parallel_tasks>()
|
||||
.add_task<mo>("modorganizer-game_oblivion", mo::gamebryo)
|
||||
.add_task<mo>("modorganizer-game_nehrim", mo::gamebryo)
|
||||
.add_task<mo>("modorganizer-game_fallout3", mo::gamebryo)
|
||||
.add_task<mo>("modorganizer-game_fallout4", mo::gamebryo)
|
||||
.add_task<mo>("modorganizer-game_fallout4vr", mo::gamebryo)
|
||||
.add_task<mo>("modorganizer-game_fallout76", mo::gamebryo)
|
||||
.add_task<mo>("modorganizer-game_falloutnv", mo::gamebryo)
|
||||
.add_task<mo>("modorganizer-game_morrowind", mo::gamebryo)
|
||||
.add_task<mo>("modorganizer-game_skyrim", mo::gamebryo)
|
||||
.add_task<mo>("modorganizer-game_skyrimse", mo::gamebryo)
|
||||
.add_task<mo>("modorganizer-game_skyrimvr", mo::gamebryo)
|
||||
.add_task<mo>("modorganizer-game_starfield", mo::gamebryo)
|
||||
.add_task<mo>("modorganizer-game_ttw", mo::gamebryo)
|
||||
.add_task<mo>("modorganizer-game_enderal", mo::gamebryo)
|
||||
.add_task<mo>("modorganizer-game_enderalse", mo::gamebryo);
|
||||
.add_task<mo>("modorganizer-preview_bsa")
|
||||
.add_task<mo>("modorganizer-game_bethesda");
|
||||
|
||||
add_task<parallel_tasks>()
|
||||
.add_task<mo>({"modorganizer-tool_inieditor", "inieditor"})
|
||||
.add_task<mo>({"modorganizer-tool_inibakery", "inibakery"})
|
||||
.add_task<mo>("modorganizer-preview_base")
|
||||
.add_task<mo>("modorganizer-diagnose_basic")
|
||||
.add_task<mo>("modorganizer-check_fnis")
|
||||
@@ -109,7 +87,7 @@ namespace mob {
|
||||
.add_task<mo>("modorganizer-installer_quick")
|
||||
.add_task<mo>("modorganizer-installer_fomod")
|
||||
.add_task<mo>("modorganizer-installer_fomod_csharp")
|
||||
.add_task<mo>("modorganizer-installer_omod", mo::nuget)
|
||||
.add_task<mo>("modorganizer-installer_omod")
|
||||
.add_task<mo>("modorganizer-installer_wizard")
|
||||
.add_task<mo>("modorganizer-bsa_extractor")
|
||||
.add_task<mo>("modorganizer-plugin_python");
|
||||
@@ -147,7 +125,6 @@ namespace mob {
|
||||
std::make_unique<list_command>(),
|
||||
std::make_unique<release_command>(),
|
||||
std::make_unique<git_command>(),
|
||||
std::make_unique<cmake_command>(),
|
||||
std::make_unique<inis_command>(),
|
||||
std::make_unique<tx_command>()};
|
||||
|
||||
|
||||
+45
-82
@@ -3,6 +3,15 @@
|
||||
|
||||
namespace mob::tasks {
|
||||
|
||||
// build CMAKE_PREFIX_PATH for MO2 tasks
|
||||
//
|
||||
std::string cmake_prefix_path()
|
||||
{
|
||||
return conf().path().qt_install().string() + ";" +
|
||||
(modorganizer::super_path() / "cmake_common").string() + ";" +
|
||||
(conf().path().install() / "lib" / "cmake").string();
|
||||
}
|
||||
|
||||
// given a vector of names (some projects have more than one, see add_tasks() in
|
||||
// main.cpp), this prepends the simplified name to the vector and returns it
|
||||
//
|
||||
@@ -59,18 +68,18 @@ namespace mob::tasks {
|
||||
g.init_repo();
|
||||
}
|
||||
|
||||
modorganizer::modorganizer(std::string long_name, flags f)
|
||||
: modorganizer(std::vector<std::string>{long_name}, f)
|
||||
modorganizer::modorganizer(std::string long_name)
|
||||
: modorganizer(std::vector<std::string>{long_name})
|
||||
{
|
||||
}
|
||||
|
||||
modorganizer::modorganizer(std::vector<const char*> names, flags f)
|
||||
: modorganizer(std::vector<std::string>(names.begin(), names.end()), f)
|
||||
modorganizer::modorganizer(std::vector<const char*> names)
|
||||
: modorganizer(std::vector<std::string>(names.begin(), names.end()))
|
||||
{
|
||||
}
|
||||
|
||||
modorganizer::modorganizer(std::vector<std::string> names, flags f)
|
||||
: task(make_names(names)), repo_(names[0]), flags_(f)
|
||||
modorganizer::modorganizer(std::vector<std::string> names)
|
||||
: task(make_names(names)), repo_(names[0])
|
||||
{
|
||||
if (names.size() > 1) {
|
||||
project_ = names[1];
|
||||
@@ -80,34 +89,15 @@ namespace mob::tasks {
|
||||
}
|
||||
}
|
||||
|
||||
bool modorganizer::is_gamebryo_plugin() const
|
||||
{
|
||||
return is_set(flags_, gamebryo);
|
||||
}
|
||||
|
||||
bool modorganizer::is_nuget_plugin() const
|
||||
{
|
||||
return is_set(flags_, nuget);
|
||||
}
|
||||
|
||||
fs::path modorganizer::source_path() const
|
||||
{
|
||||
// something like build/modorganizer_super/uibase
|
||||
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 +127,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 +151,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,65 +163,42 @@ 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())
|
||||
.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(mob::config::relwithdebinfo));
|
||||
|
||||
// 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("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::install)
|
||||
.root(source_path())
|
||||
.configuration(mob::config::relwithdebinfo));
|
||||
}
|
||||
|
||||
} // namespace mob::tasks
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace mob::tasks {
|
||||
|
||||
void sevenz::build()
|
||||
{
|
||||
build_loop(cx(), [&](bool mp) {
|
||||
build_loop(cx(), [&]([[maybe_unused]] bool mp) {
|
||||
const int exit_code = run_tool(nmake()
|
||||
.path(module_to_build())
|
||||
.def("CPU=x64")
|
||||
|
||||
@@ -413,6 +413,7 @@ namespace mob {
|
||||
|
||||
cx().info(context::generic, "build and install");
|
||||
do_build_and_install();
|
||||
cx().info(context::generic, "done");
|
||||
}
|
||||
|
||||
void task::check_bailed()
|
||||
|
||||
+5
-51
@@ -216,34 +216,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<std::string> names, flags f = noflags);
|
||||
modorganizer(std::vector<const char*> 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<std::string> names);
|
||||
modorganizer(std::vector<const char*> names);
|
||||
|
||||
// url to the git repo
|
||||
//
|
||||
@@ -271,27 +250,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<ncc> {
|
||||
@@ -623,11 +581,6 @@ namespace mob::tasks {
|
||||
// duplicate warnings
|
||||
std::set<fs::path> 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
|
||||
//
|
||||
@@ -636,7 +589,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);
|
||||
};
|
||||
|
||||
@@ -671,6 +624,7 @@ namespace mob::tasks {
|
||||
void fetch_from_source();
|
||||
void build_and_install_from_source();
|
||||
|
||||
cmake create_cmake_tool(arch, cmake::ops = cmake::generate) const;
|
||||
msbuild create_msbuild_tool(arch, msbuild::ops = msbuild::build,
|
||||
config = config::release) const;
|
||||
};
|
||||
|
||||
+97
-75
@@ -1,6 +1,8 @@
|
||||
#include "pch.h"
|
||||
#include "../core/env.h"
|
||||
#include "../utility/string.h"
|
||||
#include "../utility/threading.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "task_manager.h"
|
||||
#include "tasks.h"
|
||||
|
||||
@@ -125,9 +127,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 +149,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 +166,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 +181,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<const modorganizer*>(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()
|
||||
@@ -256,8 +199,8 @@ namespace mob::tasks {
|
||||
|
||||
// remove the .qm files in the translations/ directory
|
||||
if (is_set(c, clean::rebuild)) {
|
||||
op::delete_file_glob(cx(), conf().path().install_translations() / "*.qm",
|
||||
op::optional);
|
||||
op::delete_file_glob_recurse(cx(), conf().path().install_extensions(),
|
||||
"*.qm", op::optional);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,44 +253,122 @@ namespace mob::tasks {
|
||||
}
|
||||
}
|
||||
|
||||
void generate_translations_metadata(
|
||||
std::filesystem::path const& path,
|
||||
std::vector<mob::tasks::translations::projects::lang> const& languages)
|
||||
{
|
||||
using json = nlohmann::ordered_json;
|
||||
|
||||
json metadata;
|
||||
{
|
||||
std::ifstream ifs(path);
|
||||
metadata = json::parse(ifs);
|
||||
}
|
||||
|
||||
// fix version
|
||||
json translations;
|
||||
for (auto&& lang : languages) {
|
||||
std::vector<std::string> files;
|
||||
files.push_back("translations/" + lang.name + "/*.qm");
|
||||
json jsonlang;
|
||||
jsonlang["files"] = files;
|
||||
translations[lang.name] = jsonlang;
|
||||
}
|
||||
metadata["content"]["translations"] = translations;
|
||||
|
||||
std::ofstream ofs(path);
|
||||
ofs << metadata.dump(2);
|
||||
}
|
||||
|
||||
void translations::do_build_and_install()
|
||||
{
|
||||
// 1) build the list of projects, languages and .ts files
|
||||
// 2) run `lrelease` for every language in every project
|
||||
// 3) copy builtin qt translations
|
||||
|
||||
const auto root = source_path() / "translations";
|
||||
const auto dest = conf().path().install_translations();
|
||||
const auto root = source_path() / "translations";
|
||||
const auto extensions = conf().path().install_extensions();
|
||||
const projects ps(root);
|
||||
|
||||
op::create_directories(cx(), dest);
|
||||
op::create_directories(cx(), extensions / "mo2-translations");
|
||||
|
||||
// log all the warnings added while walking the projects
|
||||
for (auto&& w : ps.warnings())
|
||||
cx().warning(context::generic, "{}", w);
|
||||
|
||||
std::map<std::string, fs::path::string_type> project_to_extension;
|
||||
|
||||
// go through the list of extensions and find the matching projects
|
||||
for (auto& p : fs::directory_iterator(extensions)) {
|
||||
if (!fs::is_directory(p))
|
||||
continue;
|
||||
|
||||
const auto name =
|
||||
mob::replace_all(p.path().filename().string(), "mo2-", "");
|
||||
|
||||
project_to_extension[name] = p.path().filename();
|
||||
project_to_extension[mob::replace_all(name, "-", "_")] =
|
||||
p.path().filename();
|
||||
|
||||
const auto s_projects =
|
||||
conf().translation().get(p.path().filename().string(), "");
|
||||
if (!s_projects.empty()) {
|
||||
const auto extension_projects = mob::split(s_projects, " ");
|
||||
for (const auto& project : extension_projects) {
|
||||
project_to_extension[project] = p.path().filename();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// run `lrelease` in a thread pool
|
||||
parallel_functions v;
|
||||
|
||||
// for each project
|
||||
for (auto& p : ps.get()) {
|
||||
if (!project_to_extension.contains(p.name)) {
|
||||
cx().warning(context::generic,
|
||||
"found project {} but no matching extension", p.name);
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto base = extensions / project_to_extension[p.name];
|
||||
|
||||
if (!fs::exists(base)) {
|
||||
cx().warning(context::generic,
|
||||
"found project {} for extension {} extension is not built",
|
||||
p.name, project_to_extension[p.name]);
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto dest = base / "translations";
|
||||
op::create_directories(cx(), dest);
|
||||
|
||||
// for each language
|
||||
for (auto& lg : p.langs) {
|
||||
op::create_directories(cx(), dest / lg.name);
|
||||
// add a functor that will run lrelease
|
||||
v.push_back(
|
||||
{lg.name + "." + p.name, [&] {
|
||||
// run release for the given project name and list of .ts files
|
||||
run_tool(
|
||||
lrelease().project(p.name).sources(lg.ts_files).out(dest));
|
||||
}});
|
||||
v.push_back({lg.name + "." + p.name, [=] {
|
||||
// run release for the given project name and list of
|
||||
// .ts files
|
||||
run_tool(lrelease()
|
||||
.project(p.name)
|
||||
.sources(lg.ts_files)
|
||||
.out(dest / lg.name));
|
||||
}});
|
||||
}
|
||||
}
|
||||
|
||||
// run all the functors in parallel
|
||||
parallel(v);
|
||||
|
||||
if (auto p = ps.find("organizer"))
|
||||
copy_builtin_qt_translations(*p, dest);
|
||||
if (auto p = ps.find("organizer")) {
|
||||
// the empty metadata for mo2-translations is copied from modorganizer and
|
||||
// then filled here
|
||||
generate_translations_metadata(
|
||||
extensions / "mo2-translations" / "metadata.json", p->langs);
|
||||
copy_builtin_qt_translations(*p, extensions / "mo2-translations" /
|
||||
"translations");
|
||||
}
|
||||
else
|
||||
cx().bail_out(context::generic, "organizer project not found");
|
||||
}
|
||||
@@ -366,7 +387,8 @@ namespace mob::tasks {
|
||||
if (!fs::exists(src))
|
||||
return false;
|
||||
|
||||
op::copy_file_to_dir_if_better(cx(), src, dest, op::unsafe);
|
||||
op::create_directories(cx(), dest / lang);
|
||||
op::copy_file_to_dir_if_better(cx(), src, dest / lang, op::unsafe);
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
+22
-24
@@ -40,6 +40,11 @@ namespace mob::tasks {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_set(c, clean::reconfigure)) {
|
||||
run_tool(create_cmake_tool(arch::x64));
|
||||
run_tool(create_cmake_tool(arch::x86));
|
||||
}
|
||||
|
||||
if (is_set(c, clean::rebuild)) {
|
||||
// msbuild clean
|
||||
run_tool(create_msbuild_tool(arch::x86, msbuild::clean,
|
||||
@@ -69,35 +74,28 @@ namespace mob::tasks {
|
||||
|
||||
void usvfs::build_and_install_from_source()
|
||||
{
|
||||
run_tool(create_msbuild_tool(arch::x86));
|
||||
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));
|
||||
}
|
||||
|
||||
cmake usvfs::create_cmake_tool(arch a, cmake::ops o) const
|
||||
{
|
||||
return std::move(
|
||||
cmake(o)
|
||||
.root(source_path())
|
||||
.def("CMAKE_INSTALL_PREFIX:PATH", conf().path().install())
|
||||
.generator(cmake::vs)
|
||||
.preset(a == arch::x64 ? "vs2022-windows-x64" : "vs2022-windows-x86")
|
||||
.arg("-DBUILD_TESTING=OFF"));
|
||||
}
|
||||
|
||||
msbuild usvfs::create_msbuild_tool(arch a, msbuild::ops o, config c) const
|
||||
{
|
||||
// usvfs doesn't use "Win32" for 32-bit, it uses "x86"
|
||||
//
|
||||
// note that usvfs_proxy has a custom build step in Release that runs
|
||||
// usvfs/vsbuild/stage_helper.cmd, which copies everything into
|
||||
// install/
|
||||
|
||||
const std::string plat = (a == arch::x64 ? "x64" : "x86");
|
||||
|
||||
// udis requires python in its custom build step, so make sure it's on the
|
||||
// path
|
||||
//
|
||||
// BOOST_PATH is in the env because external_dependencies.props will
|
||||
// use it if it exists or reverts to a hardcoded path which might not be using
|
||||
// the same version as mob if it wasn't updated
|
||||
return std::move(
|
||||
msbuild(o)
|
||||
.platform(plat)
|
||||
.configuration(c)
|
||||
.targets({"usvfs_proxy"})
|
||||
.solution(source_path() / "vsbuild" / "usvfs.sln")
|
||||
.env(env::vs(a)
|
||||
.prepend_path(python::build_path())
|
||||
.set("BOOST_PATH", path_to_utf8(boost::source_path()))));
|
||||
const std::string vsbuild = (a == arch::x64 ? "vsbuild64" : "vsbuild32");
|
||||
return std::move(msbuild(o).architecture(a).configuration(c).solution(
|
||||
source_path() / vsbuild / "usvfs.sln"));
|
||||
}
|
||||
|
||||
} // namespace mob::tasks
|
||||
|
||||
+113
-24
@@ -4,8 +4,23 @@
|
||||
|
||||
namespace mob {
|
||||
|
||||
namespace {
|
||||
std::string config_to_string(config c)
|
||||
{
|
||||
switch (c) {
|
||||
case config::debug:
|
||||
return "Debug";
|
||||
case config::release:
|
||||
return "Release";
|
||||
case config::relwithdebinfo:
|
||||
return "RelWithDebInfo";
|
||||
}
|
||||
gcx().bail_out(context::generic, "unknow configuration type {}", c);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
cmake::cmake(ops o)
|
||||
: basic_process_runner("cmake"), op_(o), gen_(jom), arch_(arch::def)
|
||||
: basic_process_runner("cmake"), op_(o), gen_(vs), arch_(arch::def)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -62,6 +77,12 @@ namespace mob {
|
||||
return *this;
|
||||
}
|
||||
|
||||
cmake& cmake::preset(const std::string& s)
|
||||
{
|
||||
preset_ = s;
|
||||
return *this;
|
||||
}
|
||||
|
||||
cmake& cmake::arg(std::string s)
|
||||
{
|
||||
std::replace(s.begin(), s.end(), '\\', '/');
|
||||
@@ -75,6 +96,24 @@ namespace mob {
|
||||
return *this;
|
||||
}
|
||||
|
||||
cmake& cmake::targets(const std::string& target)
|
||||
{
|
||||
targets_ = {target};
|
||||
return *this;
|
||||
}
|
||||
|
||||
cmake& cmake::targets(const std::vector<std::string>& targets)
|
||||
{
|
||||
targets_ = targets;
|
||||
return *this;
|
||||
}
|
||||
|
||||
cmake& cmake::configuration(mob::config config)
|
||||
{
|
||||
config_ = config;
|
||||
return *this;
|
||||
}
|
||||
|
||||
cmake& cmake::cmd(const std::string& s)
|
||||
{
|
||||
cmd_ = s;
|
||||
@@ -110,6 +149,16 @@ namespace mob {
|
||||
break;
|
||||
}
|
||||
|
||||
case build: {
|
||||
do_build();
|
||||
break;
|
||||
}
|
||||
|
||||
case install: {
|
||||
do_install();
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
cx().bail_out(context::generic, "bad cmake op {}", op_);
|
||||
}
|
||||
@@ -126,43 +175,83 @@ namespace mob {
|
||||
auto p = process()
|
||||
.stdout_encoding(encodings::utf8)
|
||||
.stderr_encoding(encodings::utf8)
|
||||
.binary(binary())
|
||||
.arg("-DCMAKE_BUILD_TYPE=Release")
|
||||
.arg("-DCMAKE_INSTALL_MESSAGE=" +
|
||||
conf_cmake::to_string(conf().cmake().install_message()))
|
||||
.arg("--log-level=ERROR")
|
||||
.arg("--no-warn-unused-cli");
|
||||
.binary(binary());
|
||||
|
||||
if (genstring_.empty()) {
|
||||
// there's always a generator name, but some generators don't need
|
||||
// an architecture flag, like jom, so get_arch() might return an empty
|
||||
// string
|
||||
p.arg("-G", "\"" + g.name + "\"")
|
||||
.arg(g.get_arch(arch_))
|
||||
.arg(g.get_host(conf().cmake().host()));
|
||||
}
|
||||
else {
|
||||
// verbatim generator string
|
||||
p.arg("-G", "\"" + genstring_ + "\"");
|
||||
if (!preset_.empty()) {
|
||||
p = p.arg("--preset").arg(preset_);
|
||||
}
|
||||
|
||||
p = p.arg("-DCMAKE_INSTALL_MESSAGE=" +
|
||||
conf_cmake::to_string(conf().cmake().install_message()))
|
||||
.arg("--log-level=ERROR")
|
||||
.arg("--no-warn-unused-cli");
|
||||
|
||||
// prefix
|
||||
if (!prefix_.empty())
|
||||
p.arg("-DCMAKE_INSTALL_PREFIX=", prefix_);
|
||||
|
||||
p.args(args_);
|
||||
|
||||
// `..` by default, overriden by cmd()
|
||||
if (cmd_.empty())
|
||||
p.arg("..");
|
||||
else
|
||||
p.arg(cmd_);
|
||||
if (preset_.empty()) {
|
||||
|
||||
p.env(env::vs(arch_).set("CXXFLAGS", "/wd4566")).cwd(build_path());
|
||||
if (genstring_.empty()) {
|
||||
// there's always a generator name, but some generators don't need
|
||||
// an architecture flag, like jom, so get_arch() might return an empty
|
||||
// string
|
||||
p.arg("-G", "\"" + g.name + "\"")
|
||||
.arg(g.get_arch(arch_))
|
||||
.arg(g.get_host(conf().cmake().host()));
|
||||
}
|
||||
else {
|
||||
// verbatim generator string
|
||||
p.arg("-G", "\"" + genstring_ + "\"");
|
||||
}
|
||||
|
||||
// `..` by default, overriden by cmd()
|
||||
if (cmd_.empty())
|
||||
p.arg("..");
|
||||
else
|
||||
p.arg(cmd_);
|
||||
}
|
||||
|
||||
p.env(env::vs(arch_)
|
||||
.set("CXXFLAGS", "/wd4566")
|
||||
.set("VCPKG_ROOT", absolute(conf().path().vcpkg()).string()))
|
||||
.cwd(preset_.empty() ? build_path() : root_);
|
||||
|
||||
execute_and_join(p);
|
||||
}
|
||||
|
||||
void cmake::do_build()
|
||||
{
|
||||
auto p = process()
|
||||
.stdout_encoding(encodings::utf8)
|
||||
.stderr_encoding(encodings::utf8)
|
||||
.binary(binary())
|
||||
.arg("--build")
|
||||
.arg(build_path())
|
||||
.arg("--config")
|
||||
.arg(config_to_string(config_));
|
||||
|
||||
for (auto& target : targets_) {
|
||||
p = p.arg("--target").arg(target);
|
||||
}
|
||||
|
||||
execute_and_join(p);
|
||||
}
|
||||
|
||||
void cmake::do_install()
|
||||
{
|
||||
execute_and_join(process()
|
||||
.stdout_encoding(encodings::utf8)
|
||||
.stderr_encoding(encodings::utf8)
|
||||
.binary(binary())
|
||||
.arg("--install")
|
||||
.arg(build_path())
|
||||
.arg("--config")
|
||||
.arg(config_to_string(config_)));
|
||||
}
|
||||
|
||||
void cmake::do_clean()
|
||||
{
|
||||
cx().trace(context::rebuild, "deleting all generator directories");
|
||||
|
||||
@@ -29,6 +29,12 @@ namespace mob {
|
||||
// generates the build files
|
||||
generate = 1,
|
||||
|
||||
// build
|
||||
build,
|
||||
|
||||
// install
|
||||
install,
|
||||
|
||||
// cleans the build files so they're regenerated from scratch
|
||||
clean
|
||||
};
|
||||
@@ -54,6 +60,15 @@ namespace mob {
|
||||
//
|
||||
cmake& root(const fs::path& p);
|
||||
|
||||
// set the targets for build
|
||||
//
|
||||
cmake& targets(const std::string& target);
|
||||
cmake& targets(const std::vector<std::string>& target);
|
||||
|
||||
// set the configuration to build or install
|
||||
//
|
||||
cmake& configuration(mob::config config);
|
||||
|
||||
// overrides the directory in which cmake will write build files
|
||||
//
|
||||
// by default, this is a directory inside what was given in root() with a
|
||||
@@ -75,6 +90,10 @@ namespace mob {
|
||||
cmake& def(const std::string& name, const fs::path& p);
|
||||
cmake& def(const std::string& name, const char* s);
|
||||
|
||||
// set a preset to run with cmake --preset
|
||||
//
|
||||
cmake& preset(const std::string& s);
|
||||
|
||||
// adds an arbitrary argument, passed verbatim
|
||||
//
|
||||
cmake& arg(std::string s);
|
||||
@@ -146,6 +165,9 @@ namespace mob {
|
||||
// what run() does
|
||||
ops op_;
|
||||
|
||||
// preset to run
|
||||
std::string preset_;
|
||||
|
||||
// directory where CMakeLists.txt is
|
||||
fs::path root_;
|
||||
|
||||
@@ -156,6 +178,12 @@ namespace mob {
|
||||
// passed as -DCMAKE_INSTALL_PREFIX
|
||||
fs::path prefix_;
|
||||
|
||||
// targets
|
||||
std::vector<std::string> targets_;
|
||||
|
||||
// configuration
|
||||
mob::config config_{mob::config::relwithdebinfo};
|
||||
|
||||
// passed verbatim
|
||||
std::vector<std::string> args_;
|
||||
|
||||
@@ -175,6 +203,8 @@ namespace mob {
|
||||
// runs cmake
|
||||
//
|
||||
void do_generate();
|
||||
void do_build();
|
||||
void do_install();
|
||||
|
||||
// returns a list of generators handled by this tool, same ones as in the
|
||||
// `generators` enum on top
|
||||
|
||||
Reference in New Issue
Block a user