Author SHA1 Message Date
Mikaël Capelle 1bb0c4ce3d Add scripts to generate prebuilt. 2024-06-30 19:43:50 +02:00
Mikaël Capelle f99e777433 Add -d option to mob cmake to build in debug mode. (#137) 2024-06-21 17:14:11 +02:00
Mikaël Capelle ecd210d700 More flexibility to build Debug components (#136)
* Build components in all variant for boost to avoid issue with USVFS.
* Build googletest in both Debug and Release.
* Allow build configurations other than RelWithDebInfo.
2024-06-15 22:19:35 +02:00
Mikaël Capelle d1965acd1a Remove option to use USVFS prebuilt. (#135) 2024-06-03 07:35:28 +02:00
Twinki 27483d6ddc Updated README for 6.7.0 (#134)
* Updated README for 6.7.0
2024-05-27 20:51:48 +02:00
Mikaël Capelle 73d7d3dd2b Use MO2 formatting action. (#133)
* Use MO2 formatting action.
* Fix format for clang-format 17.
2024-05-26 10:26:44 +02:00
Twinki 11dafd063b Update installation README (#131)
* Update installation README
2024-05-25 14:26:18 +02:00
Mikaël CapelleandJeremy Rimpo b0688f81b9 WIP: Upgrade dependencies. (#132)
* Upgrade dependencies.
* Upgrade to Python 3.12
* Remove fmt tasks switch from fmt to std::format internally.

---------

Co-authored-by: Jeremy Rimpo <jrim@rimpo.org>
2024-05-25 14:25:40 +02:00
Mikaël Capelle eaae1e44c9 Merge pull request #129 from ModOrganizer2/version_updates
libloot 0.22.3, openssl 3.2.0
2024-05-17 18:42:19 +02:00
57 changed files with 642 additions and 11707 deletions
+2 -3
View File
@@ -10,9 +10,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run clang-format
uses: jidicula/clang-format-action@v4.11.0
- name: Check format
uses: ModOrganizer2/check-formatting-action@master
with:
clang-format-version: "16"
check-path: "."
exclude-regex: "third-party"
+29 -25
View File
@@ -22,13 +22,14 @@ super = cmake_common modorganizer* githubpp
plugins = check_fnis bsapacker bsa_extractor diagnose_basic installer_* plugin_python preview_base preview_bsa tool_* game_*
[task]
enabled = true
mo_org = ModOrganizer2
mo_branch = master
mo_fallback =
no_pull = false
ignore_ts = false
revert_ts = false
enabled = true
mo_org = ModOrganizer2
mo_branch = master
mo_fallback =
no_pull = false
ignore_ts = false
revert_ts = false
configuration = RelWithDebInfo
git_url_prefix = https://github.com/
git_shallow = true
@@ -89,37 +90,35 @@ lz4 = true
openssl = true
pyqt = true
python = true
usvfs = false
[versions]
vs = 17
vs_year = 2022
vs_toolset = 14.3
sdk = 10.0.22621.0
sevenz = 23.01
boost = 1.83.0
sevenz = 24.05
boost = 1.85.0
boost_vs = 14.3
fmt = 8.1.1
fmt = 10.2.1
gtest = main
libloot = 0.22.3
libloot = 0.22.4
lz4 = v1.9.4
nmm = 0.71.2
openssl = 3.2.0
pyqt = 6.5.3.dev2309101249
pyqt_builder = 1.15.3
pyqt_sip = 13.6.0
python = v3.11.5
pybind11 = v2.11.1
openssl = 3.3.0
pyqt = 6.7.0
pyqt_builder = 1.16.2
pyqt_sip = 13.7.0
python = v3.12.3
pybind11 = v2.12.0
bzip2 = 1.0.8
sip = 6.7.12
spdlog = v1.10.0
qt = 6.5.0
sip = 6.8.3
spdlog = v1.14.1
qt = 6.7.0
qt_vs = 2019
zlib = v1.3
zlib = v1.3.1
libbsarch = 0.0.9
usvfs = qt6
explorerpp = 1.3.5
usvfs = master
explorerpp = 1.4.0
ss_paper_lad_6788 = 7.2
ss_paper_automata_6788 = 3.2
ss_paper_mono_6788 = 3.2
@@ -130,6 +129,11 @@ 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 =
+46 -22
View File
@@ -25,26 +25,51 @@
## Quick start
```
```powershell
> git clone https://github.com/ModOrganizer2/mob
> cd mob
> bootstrap
> mob -d c:\somewhere build
```
## Slow start
- Install Qt 6.5.1 ([Installer](https://download.qt.io/official_releases/online_installers/qt-unified-windows-x64-online.exe)) and select these components:
## Extended start
### Qt - CLI based install using [aqt](https://github.com/miurahr/aqtinstall)
[aqt](https://github.com/miurahr/aqtinstall) is a CLI installer for Qt, it makes installing Qt extremely quick and painless, and doesn't require a login
#### Installing aqt via package manager
- Start an administrative terminal
- Install aqt using one of the two popular packaage managers
- `winget install --id=miurahr.aqtinstall -e`
- `choco install aqt`
#### Installing aqt via python/pip
- Install [Python 3.9](https://www.python.org/downloads/release/python-390/)
- Install [aqt](https://github.com/miurahr/aqtinstall) using `pip`
#### Using aqt
- Open a terminal with administrative rights, and run
```powershell
aqt install-qt --outputdir "C:\Qt" windows desktop 6.7.0 win64_msvc2019_64 -m qtwebengine qtimageformats qtpositioning qtserialport qtwebchannel qtwebsockets
```
### Qt - Manual installation
- Install Qt 6.7.0 ([Installer](https://download.qt.io/official_releases/online_installers/qt-unified-windows-x64-online.exe)) and select these components:
- MSVC 2019 64-bit
- Additional Libraries:
- Qt WebEngine (display nexus pages)
- Qt Image Formats (display images in image tab and preview)
- Qt Positioning (required by QtWebEngine)
- Qt Serial Port (required by Qt Core)
- Qt Web Channel (required by QtWebEngine)
- Qt WebChannel (required by QtWebEngine)
- Qt WebSockets (Nexus api/download)
- Optional:
- Qt Source Files
- Qt Debug Files
### Visual Studio
- Install Visual Studio 2022 ([Installer](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community&channel=Release&version=VS2022&source=VSLandingPage&cid=2030&passive=false))
- Desktop development with C++
- Desktop .NET desktop development (needed by OMOD and FOMOD installers)
@@ -56,22 +81,20 @@
- C++ /CLI support for v143 build Tools (Latest) (for OMOD and FOMOD installers)
- Windows 11 SDK (get latest)
- C++ Build Tools core features
- Optional:
- Git for Windows (if you don't have git already installed)
- Start a shell
- If you have git in your path, a regular cmd shell works.
- If not, start the _x64 Native Tools Command Prompt for VS 2019_, it'll use Git for Windows installed above.
- Do:
```
mkdir C:\dev
cd C:\dev
git clone https://github.com/ModOrganizer2/mob
cd mob
bootstrap
mob -d C:\dev\modorganizer build
```
- Once `mob` is finished, everything will be in `C:\dev\modorganizer`. Mod Organizer can be run from `install\bin\ModOrganizer.exe`. The Visual Studio solution for Mod Organizer itself is `build\modorganizer_super\modorganizer\vsbuild\organizer.sln`.
- Git for Windows (Skip if you have this already installed outside of the VS installer)
- CMake tools for Windows (Skip if you have this already installed outside of the VS installer)
## Setting up MOB
- Open a shell. If you've installed Git or CMake through the VS installer, they won't be on your PATH, so you must use x64 Native Tools Command Prompt for VS 2022.- Pick a folder to develop MO2 in, for these steps it'll be `C:\dev`
- Execute these commands
```powershell
mkdir C:\dev
cd C:\dev
git clone https://github.com/ModOrganizer2/mob
./bootstrap.ps1
mob -d C:\dev\modorganizer build
```
- Once `mob` is finished, everything will be in `C:\dev\modorganizer`. Mod Organizer can be run from `install\bin\ModOrganizer.exe`. The Visual Studio solution for Mod Organizer itself is `build\modorganizer_super\modorganizer\vsbuild\organizer.sln`.
### Prebuilts
Some third-parties are not normally built from source, but this can be changed in the options by setting the various tasks in `[prebuilt]` to `false`. If OpenSSL is built from source, perl is required ([Strawberry Perl 5.30.2.1 installer](http://strawberryperl.com/download/5.30.2.1/strawberry-perl-5.30.2.1-64bit.msi)).
@@ -118,9 +141,10 @@ Inside the INI file are `[sections]` and `key = value` pairs. The `[task]` secti
### `[task]`
Options for individual tasks. Can be `[task_name:task]`, where `task_name` is the name of a task (see `mob list`) , `super` for all MO tasks or a glob like `installer_*`.
| Option | Type | Description |
| --- | --- | --- |
| `enabled` | bool | Whether this task is enabled. Disabled tasks are never built. When specifying task names with `mob build task1 task2...`, all tasks except those given are turned off. |
| Option | Type | Description |
| --- | --- | --- |
| `enabled` | bool | Whether this task is enabled. Disabled tasks are never built. When specifying task names with `mob build task1 task2...`, all tasks except those given are turned off. |
| `configuration` | enum | Which configuration to build, should be one of Debug, Release or RelWithDebInfo with RelWithDebInfo being the default.|
#### Common git options
Unless otherwise stated, applies to any task that is a git repo.
+9
View File
@@ -0,0 +1,9 @@
param(
[Parameter(Mandatory = $true)][String]$Path,
[Parameter(Mandatory = $true)][String]$Output
)
7z a $Output (Join-Path -Path $Path -ChildPath "boost")
7z a $Output (Join-Path -Path $Path -ChildPath "lib32-msvc-14.3")
7z a $Output (Join-Path -Path $Path -ChildPath "lib64-msvc-14.3")
7z a $Output (Join-Path -Path $Path -ChildPath "LICENSE_1_0.txt")
+13
View File
@@ -0,0 +1,13 @@
param(
[Parameter(Mandatory = $true)][String]$PyQtPath,
[Parameter(Mandatory = $true)][String]$PythonPath,
[Parameter(Mandatory = $true)][String]$Output
)
$Output = [IO.Path]::GetFullPath($Output)
7z a $Output (Join-Path -Path $PyQtPath -ChildPath "LICENSE")
Push-Location $PythonPath
7z a $Output "Lib/site-packages/PyQt6" "-xr!__pycache__"
Pop-Location
+10
View File
@@ -0,0 +1,10 @@
param(
[Parameter(Mandatory = $true)][String]$Path,
[Parameter(Mandatory = $true)][String]$Output
)
7z a $Output (Join-Path -Path $Path -ChildPath "PCbuild/amd64") "-xr!pythoncore_temp"
7z rn $Output "amd64" "PCbuild/amd64"
7z a $Output (Join-Path -Path $Path -ChildPath "Include") "-xr!internal" "-xr!sip.h"
7z a $Output (Join-Path -Path $Path -ChildPath "Lib") "-xr!__pycache__" "-xr!site-packages"
7z a $Output (Join-Path -Path $Path -ChildPath "LICENSE")
+6 -1
View File
@@ -33,12 +33,17 @@ namespace mob {
(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_)));
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_);
+2 -1
View File
@@ -382,7 +382,8 @@ namespace mob {
private:
std::string gen_;
std::string cmd_;
bool x64_ = true;
bool x64_ = true;
bool debug_ = false;
std::string prefix_;
std::string path_;
};
+5 -8
View File
@@ -122,7 +122,7 @@ namespace mob {
git_wrap g(task->source_path());
g.fetch(task->git_url().string(),
fmt::format("pull/{}/head", pr.number));
std::format("pull/{}/head", pr.number));
g.checkout("FETCH_HEAD");
}
@@ -208,13 +208,10 @@ namespace mob {
{
nlohmann::json json;
constexpr auto* pattern =
"https://api.github.com/search/issues?per_page=100&q="
"is:pr+org:{org:}+author:{author:}+is:open+head:{branch:}";
constexpr auto* pattern = "https://api.github.com/search/issues?per_page=100&q="
"is:pr+org:{0:}+author:{1:}+is:open+head:{2:}";
const auto search_url =
fmt::format(pattern, fmt::arg("org", org), fmt::arg("author", author),
fmt::arg("branch", branch));
const auto search_url = std::format(pattern, org, author, branch);
u8cout << "search url is " << search_url << "\n";
@@ -275,7 +272,7 @@ namespace mob {
return {};
}
const url u(fmt::format("https://api.github.com/repos/{}/{}/pulls/{}",
const url u(std::format("https://api.github.com/repos/{}/{}/pulls/{}",
task->org(), task->repo(), pr));
curl_downloader dl;
+2 -2
View File
@@ -367,7 +367,7 @@ namespace mob {
}
const auto q =
fmt::format("prefix {} already exists, delete?", path_to_utf8(prefix));
std::format("prefix {} already exists, delete?", path_to_utf8(prefix));
if (ask_yes_no(q, yn::no) != yn::yes)
return false;
@@ -489,7 +489,7 @@ namespace mob {
const auto* lcp = static_cast<LANGANDCODEPAGE*>(value_pointer);
const auto sub_block =
fmt::format(L"\\StringFileInfo\\{:04x}{:04x}\\FileVersion", lcp->wLanguage,
std::format(L"\\StringFileInfo\\{:04x}{:04x}\\FileVersion", lcp->wLanguage,
lcp->wCodePage);
ret = VerQueryValueW(buffer.get(), sub_block.c_str(), &value_pointer,
+90 -38
View File
@@ -14,6 +14,11 @@ namespace mob::details {
using key_value_map = std::map<std::string, std::string, std::less<>>;
using section_map = std::map<std::string, key_value_map, std::less<>>;
static std::unordered_map<mob::config, std::string_view> s_configuration_values{
{mob::config::release, "Release"},
{mob::config::debug, "Debug"},
{mob::config::relwithdebinfo, "RelWithDebInfo"}};
// holds all the options not related to tasks (global, tools, paths, etc.)
static section_map g_conf;
@@ -27,6 +32,18 @@ namespace mob::details {
static int g_file_log_level = 5;
static bool g_dry = false;
// check if the two given string are equals case-insensitive
//
bool case_insensitive_equals(std::string_view lhs, std::string_view rhs)
{
// _strcmpi does not have a n-overload, and since string_view is not
// necessarily null-terminated, _strmcpi cannot be safely used
return std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs),
std::end(rhs), [](auto&& c1, auto&& c2) {
return ::tolower(c1) == ::tolower(c2);
});
}
bool bool_from_string(std::string_view s)
{
return (s == "true" || s == "yes" || s == "1");
@@ -85,6 +102,17 @@ namespace mob::details {
kitor->second = value;
}
config string_to_config(std::string_view value)
{
for (const auto& [c, v] : s_configuration_values) {
if (case_insensitive_equals(value, v)) {
return c;
}
}
gcx().bail_out(context::conf, "invalid configuration '{}'", value);
}
// sets the given option, adds it if it doesn't exist; used when setting options
// from the master ini
//
@@ -184,6 +212,28 @@ namespace mob::details {
g_tasks[task_name][key] = std::move(value);
}
// read a CMake constant from the configuration
//
template <typename T>
T parse_cmake_value(std::string_view section, std::string_view key,
std::string_view value,
std::unordered_map<T, std::string_view> const& values)
{
for (const auto& [value_c, value_s] : values) {
if (case_insensitive_equals(value_s, value)) {
return value_c;
}
}
// build a string containing allowed value for logging
std::vector<std::string_view> values_s;
for (const auto& [value_c, value_s] : values) {
values_s.push_back(value_s);
}
gcx().bail_out(context::conf, "bad value '{}' for {}/{} (expected one of {})",
value, section, key, join(values_s, ", ", std::string{}));
}
} // namespace mob::details
namespace mob {
@@ -644,6 +694,11 @@ namespace mob {
return {};
}
conf_build_types conf::build_types()
{
return {};
}
conf_paths conf::path()
{
return {};
@@ -666,6 +721,34 @@ namespace mob {
return details::g_dry;
}
// use appropriate case for the below constants since we will be using them in
// to_string, although most of cmake and msbuild is case-insensitive so it will
// not matter much in the end
static std::unordered_map<conf_cmake::constant, std::string_view> constant_values{
{conf_cmake::always, "ALWAYS"},
{conf_cmake::lazy, "LAZY"},
{conf_cmake::never, "NEVER"}};
std::string conf_cmake::to_string(constant c)
{
return std::string{constant_values.at(c)};
}
conf_cmake::conf_cmake() : conf_section("cmake") {}
conf_cmake::constant conf_cmake::install_message() const
{
return details::parse_cmake_value(
name(), "install_message", details::get_string(name(), "install_message"),
constant_values);
}
std::string conf_cmake::host() const
{
return details::get_string(name(), "host");
}
conf_task::conf_task(std::vector<std::string> names) : names_(std::move(names)) {}
std::string conf_task::get(std::string_view key) const
@@ -678,45 +761,12 @@ namespace mob {
return details::get_bool_for_task(names_, key);
}
bool conf_cmake::cmake_constant::is_equivalent(std::string_view other) const
mob::config conf_task::configuration() const
{
// _strcmpi does not have a n-overload, and since string_view is not
// necessarily null-terminated, _strmcpi cannot be safely used
return std::equal(std::begin(value_), std::end(value_), std::begin(other),
std::end(other), [](auto&& c1, auto&& c2) {
return ::tolower(c1) == ::tolower(c2);
});
}
conf_cmake::conf_cmake() : conf_section("cmake") {}
const conf_cmake::cmake_constant conf_cmake::ALWAYS{"always"};
const conf_cmake::cmake_constant conf_cmake::LAZY{"lazy"};
const conf_cmake::cmake_constant conf_cmake::NEVER{"never"};
conf_cmake::cmake_constant conf_cmake::install_message() const
{
return read_cmake_constant("install_message", {ALWAYS, LAZY, NEVER});
}
std::string conf_cmake::host() const
{
return details::get_string(name(), "host");
}
conf_cmake::cmake_constant
conf_cmake::read_cmake_constant(std::string_view key,
std::vector<cmake_constant> const& allowed) const
{
const auto value = details::get_string(name(), key);
for (const auto& constant : allowed) {
if (constant.is_equivalent(value)) {
return constant;
}
}
gcx().bail_out(context::conf, "bad value '{}' for {}/{} (expected one of {})",
value, name(), key, join(allowed, ", ", std::string{}));
return details::parse_cmake_value(
names_[0], "configuration",
details::get_string_for_task(names_, "configuration"),
details::s_configuration_values);
}
conf_tools::conf_tools() : conf_section("tools") {}
@@ -725,6 +775,8 @@ namespace mob {
conf_versions::conf_versions() : conf_section("versions") {}
conf_build_types::conf_build_types() : conf_section("build-types") {}
conf_prebuilt::conf_prebuilt() : conf_section("prebuilt") {}
conf_paths::conf_paths() : conf_section("paths") {}
+57 -53
View File
@@ -1,5 +1,7 @@
#pragma once
#include "../utility.h"
// these shouldn't be called directly, they're used by some of the template
// below
//
@@ -9,6 +11,18 @@ namespace mob::details {
//
std::string get_string(std::string_view section, std::string_view key);
// convert a string to the given type
template <class T>
T string_to(std::string_view value);
config string_to_config(std::string_view value);
template <>
inline config string_to<config>(std::string_view value)
{
return string_to_config(value);
}
// calls get_string(), converts to bool
//
bool get_bool(std::string_view section, std::string_view key);
@@ -48,7 +62,14 @@ namespace mob {
public:
DefaultType get(std::string_view key) const
{
return details::get_string(name_, key);
const auto value = details::get_string(name_, key);
if constexpr (std::is_convertible_v<std::string, DefaultType>) {
return value;
}
else {
return details::string_to<DefaultType>(value);
}
}
// undefined
@@ -102,6 +123,29 @@ namespace mob {
bool build() const { return get<bool>("build_task"); }
};
// options in [cmake]
//
class conf_cmake : conf_section<std::string> {
public:
enum class constant { always, lazy, never };
using enum constant;
static std::string to_string(constant m);
conf_cmake();
// specify the value for CMAKE_INSTALL_MESSAGE
//
constant install_message() const;
// specify the toolset host configuration, if any, this is equivalent
// to -T host=XXX on the command line
//
// an empty string means no host configured
//
std::string host() const;
};
// options in [task] or [task_name:task]
//
class conf_task {
@@ -141,64 +185,16 @@ namespace mob {
return get<bool>("remote_push_default_origin");
}
// specify the configuration to build
//
mob::config configuration() const;
private:
std::vector<std::string> names_;
bool get_bool(std::string_view name) const;
};
// options in [task] or [task_name:task]
//
class conf_cmake : conf_section<std::string> {
public:
class cmake_constant {
std::string value_;
// check if the given string is equivalent to this constant
//
bool is_equivalent(std::string_view other) const;
friend class conf_cmake;
public:
constexpr cmake_constant(std::string_view value) : value_{value} {}
constexpr const auto& value() const { return value_; }
constexpr operator const std::string&() const { return value(); }
friend bool operator==(cmake_constant const& lhs, cmake_constant const& rhs)
{
return lhs.is_equivalent(rhs.value());
}
friend bool operator!=(cmake_constant const& lhs, cmake_constant const& rhs)
{
return !(lhs == rhs);
}
};
static const cmake_constant ALWAYS;
static const cmake_constant LAZY;
static const cmake_constant NEVER;
public:
conf_cmake();
// specify the value for CMAKE_INSTALL_MESSAGE
//
cmake_constant install_message() const;
// specify the toolset host configuration, if any, this is equivalent
// to -T host=XXX on the command line
//
// an empty string means no host configured
//
std::string host() const;
private:
cmake_constant
read_cmake_constant(std::string_view key,
std::vector<cmake_constant> const& allowed) const;
};
// options in [tools]
//
class conf_tools : public conf_section<fs::path> {
@@ -220,6 +216,13 @@ namespace mob {
conf_versions();
};
// options in [build-types]
//
class conf_build_types : public conf_section<config> {
public:
conf_build_types();
};
// options in [prebuilt]
//
class conf_prebuilt : public conf_section<std::string> {
@@ -284,6 +287,7 @@ namespace mob {
conf_transifex transifex();
conf_prebuilt prebuilt();
conf_versions version();
conf_build_types build_types();
conf_paths path();
// opens the log file, creates the directory if needed
-19
View File
@@ -5,25 +5,6 @@
#include "../utility.h"
#include "conf.h"
namespace mob::details {
std::string converter<std::wstring>::convert(const std::wstring& s)
{
return utf16_to_utf8(s);
}
std::string converter<fs::path>::convert(const fs::path& s)
{
return utf16_to_utf8(s.native());
}
std::string converter<url>::convert(const url& u)
{
return u.string();
}
} // namespace mob::details
namespace mob {
// timestamps are relative to this
+14 -52
View File
@@ -1,45 +1,7 @@
#pragma once
#include "../utility.h"
// T to std::string converters
//
// those are kept in this namespace so they don't leak all over the place;
// they're used directly by context::do_log() below
namespace mob::details {
class mob::url;
template <class T, class = void>
struct converter {
static const T& convert(const T& t) { return t; }
};
template <>
struct converter<std::wstring> {
static std::string convert(const std::wstring& s);
};
template <>
struct converter<fs::path> {
static std::string convert(const fs::path& s);
};
template <>
struct converter<url> {
static std::string convert(const url& u);
};
template <class T>
struct converter<T, std::enable_if_t<std::is_enum_v<T>>> {
static std::string convert(T e)
{
return std::to_string(static_cast<std::underlying_type_t<T>>(e));
}
};
} // namespace mob::details
#include "./formatters.h"
namespace mob {
@@ -57,7 +19,7 @@ namespace mob {
// in places where there is no context available, there's a global one can that
// be retrieved with gcx() for logging
//
// all log functions will use fmt::format() internally, so they can be used
// all log functions will use std::format() internally, so they can be used
// like:
//
// cx.log(context::generic, "eat more {}", "potatoes");
@@ -161,7 +123,7 @@ namespace mob {
// logs a formatted string with the dump level
//
template <class... Args>
void dump(reason r, const char* f, Args&&... args) const
void dump(reason r, std::format_string<Args...> f, Args&&... args) const
{
do_log(false, r, level::dump, f, std::forward<Args>(args)...);
}
@@ -169,7 +131,7 @@ namespace mob {
// logs a formatted string with the trace level
//
template <class... Args>
void trace(reason r, const char* f, Args&&... args) const
void trace(reason r, std::format_string<Args...> f, Args&&... args) const
{
do_log(false, r, level::trace, f, std::forward<Args>(args)...);
}
@@ -177,7 +139,7 @@ namespace mob {
// logs a formatted string with the debug level
//
template <class... Args>
void debug(reason r, const char* f, Args&&... args) const
void debug(reason r, std::format_string<Args...> f, Args&&... args) const
{
do_log(false, r, level::debug, f, std::forward<Args>(args)...);
}
@@ -185,7 +147,7 @@ namespace mob {
// logs a formatted string with the info level
//
template <class... Args>
void info(reason r, const char* f, Args&&... args) const
void info(reason r, std::format_string<Args...> f, Args&&... args) const
{
do_log(false, r, level::info, f, std::forward<Args>(args)...);
}
@@ -193,7 +155,7 @@ namespace mob {
// logs a formatted string with the warning level
//
template <class... Args>
void warning(reason r, const char* f, Args&&... args) const
void warning(reason r, std::format_string<Args...> f, Args&&... args) const
{
do_log(false, r, level::warning, f, std::forward<Args>(args)...);
}
@@ -201,7 +163,7 @@ namespace mob {
// logs a formatted string with the error level
//
template <class... Args>
void error(reason r, const char* f, Args&&... args) const
void error(reason r, std::format_string<Args...> f, Args&&... args) const
{
do_log(false, r, level::error, f, std::forward<Args>(args)...);
}
@@ -211,7 +173,8 @@ namespace mob {
// tasks
//
template <class... Args>
[[noreturn]] void bail_out(reason r, const char* f, Args&&... args) const
[[noreturn]] void bail_out(reason r, std::format_string<Args...> f,
Args&&... args) const
{
do_log(true, r, level::error, f, std::forward<Args>(args)...);
}
@@ -227,7 +190,8 @@ namespace mob {
// bailed exception after logging
//
template <class... Args>
void do_log(bool bail, reason r, level lv, const char* f, Args&&... args) const
void do_log(bool bail, reason r, level lv, std::format_string<Args...> f,
Args&&... args) const
{
// discard log if it's not enabled and it's not bailing out
if (!bail && !enabled(lv))
@@ -235,9 +199,7 @@ namespace mob {
try {
// formatting string
const std::string s =
fmt::format(f, details::converter<std::decay_t<Args>>::convert(
std::forward<Args>(args))...);
const std::string s = std::format(f, std::forward<Args>(args)...);
do_log_impl(bail, r, lv, s);
}
@@ -253,7 +215,7 @@ namespace mob {
// a ghetto conversion and hope it gives enough info
std::wstring s;
const char* p = f;
const char* p = f.get().data();
while (*p) {
s += (wchar_t)*p;
++p;
+35
View File
@@ -0,0 +1,35 @@
#pragma once
#include "../utility/string.h"
template <>
struct std::formatter<std::wstring, char> : std::formatter<std::string, char> {
template <class FmtContext>
FmtContext::iterator format(std::wstring const& s, FmtContext& ctx) const
{
return std::formatter<std::string, char>::format(mob::utf16_to_utf8(s), ctx);
}
};
template <>
struct std::formatter<std::filesystem::path, char>
: std::formatter<std::basic_string<std::filesystem::path::value_type>, char> {
template <class FmtContext>
FmtContext::iterator format(std::filesystem::path const& s, FmtContext& ctx) const
{
return std::formatter<std::basic_string<std::filesystem::path::value_type>,
char>::format(s.native(), ctx);
}
};
template <class Enum, class CharT>
requires std::is_enum_v<Enum>
struct std::formatter<Enum, CharT>
: std::formatter<std::underlying_type_t<Enum>, CharT> {
template <class FmtContext>
FmtContext::iterator format(Enum v, FmtContext& ctx) const
{
return std::formatter<std::underlying_type_t<Enum>, CharT>::format(
static_cast<std::underlying_type_t<Enum>>(v), ctx);
}
};
+2 -2
View File
@@ -10,11 +10,11 @@
namespace mob {
template <class... Args>
void ini_error(const ini_data& ini, std::size_t line, std::string_view f,
void ini_error(const ini_data& ini, std::size_t line, std::format_string<Args...> f,
Args&&... args)
{
gcx().bail_out(context::conf, "{}:{}: {}", path_to_utf8(ini.path), (line + 1),
fmt::format(f, std::forward<Args>(args)...));
std::format(f, std::forward<Args>(args)...));
}
ini_data::kv_map& ini_data::get_section(std::string_view name)
+1 -1
View File
@@ -326,7 +326,7 @@ namespace mob {
// check known installation paths for a bunch of versions
for (int v : {5, 6, 7, 8}) {
const fs::path inno_dir = fmt::format("Inno Setup {}", v);
const fs::path inno_dir = std::format("Inno Setup {}", v);
// check for both architectures
for (fs::path pf : {conf().path().pf_x86(), conf().path().pf_x64()}) {
-2
View File
@@ -29,12 +29,10 @@ namespace mob {
add_task<parallel_tasks>()
.add_task<sevenz>()
.add_task<zlib>()
.add_task<fmt>()
.add_task<gtest>()
.add_task<libbsarch>()
.add_task<libloot>()
.add_task<openssl>()
.add_task<libffi>()
.add_task<bzip2>();
add_task<parallel_tasks>()
+9
View File
@@ -115,3 +115,12 @@ namespace mob {
};
} // namespace mob
template <>
struct std::formatter<mob::url, char> : std::formatter<std::string, char> {
template <class FmtContext>
FmtContext::iterator format(mob::url const& u, FmtContext& ctx) const
{
return std::formatter<std::string, char>::format(u.string(), ctx);
}
};
-1
View File
@@ -1,2 +1 @@
#include "pch.h"
#include <fmt/format.cc>

Some files were not shown because too many files have changed in this diff Show More