diff --git a/CMakeLists.txt b/CMakeLists.txt index ca2b3af6fe..90e34acc91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -308,6 +308,14 @@ if(CMAKE_SYSTEM_NAME MATCHES "Darwin") # Drop unreachable code and data. set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-dead_strip,-dead_strip_dylibs") + # Set -fno-objc-exceptions, for consistency with -fno-exceptions earlier. + # If we set only -fno-exceptions, fmt fails to compile when included from + # Objective-C++ because fmt tries try to use throw because __EXCEPTIONS is defined. + # + # TODO: Only enable this for Objective-C(++). + # We get warnings if we enable this when building regular C(++) code. + check_and_add_flag(NO_OBJC_EXCEPTIONS -fno-objc-exceptions) + find_library(APPKIT_LIBRARY AppKit) find_library(APPSERV_LIBRARY ApplicationServices) find_library(CARBON_LIBRARY Carbon) diff --git a/Languages/update-source-strings.sh b/Languages/update-source-strings.sh index 0f9c678587..0d86964e56 100755 --- a/Languages/update-source-strings.sh +++ b/Languages/update-source-strings.sh @@ -9,6 +9,7 @@ find $SRCDIR -name '*.cpp' -o -name '*.h' -o -name '*.c' | \ xgettext -d dolphin-emu -s --keyword=_ --keyword=wxTRANSLATE --keyword=SuccessAlertT \ --keyword=PanicAlertT --keyword=PanicYesNoT --keyword=AskYesNoT --keyword=CriticalAlertT \ --keyword=GetStringT --keyword=_trans --keyword=tr:1,1t --keyword=tr:1,2c --keyword=QT_TR_NOOP \ + --keyword=FmtFormatT \ --add-comments=i18n -p ./Languages/po -o dolphin-emu.pot -f - --package-name="Dolphin Emulator" \ --from-code=utf-8 diff --git a/Source/Android/jni/AndroidCommon/CMakeLists.txt b/Source/Android/jni/AndroidCommon/CMakeLists.txt index e8bcc22863..c9c48e067a 100644 --- a/Source/Android/jni/AndroidCommon/CMakeLists.txt +++ b/Source/Android/jni/AndroidCommon/CMakeLists.txt @@ -8,6 +8,7 @@ add_library(androidcommon STATIC target_link_libraries(androidcommon PRIVATE android + common log "-Wl,--no-warn-mismatch" "-Wl,--whole-archive" diff --git a/Source/Android/jni/CMakeLists.txt b/Source/Android/jni/CMakeLists.txt index 2b8329f99a..7f31a144aa 100644 --- a/Source/Android/jni/CMakeLists.txt +++ b/Source/Android/jni/CMakeLists.txt @@ -10,6 +10,7 @@ add_library(main SHARED target_link_libraries(main PRIVATE androidcommon + common core uicommon ) diff --git a/Source/Core/AudioCommon/CMakeLists.txt b/Source/Core/AudioCommon/CMakeLists.txt index 908c60ed5e..1ee5e17ed4 100644 --- a/Source/Core/AudioCommon/CMakeLists.txt +++ b/Source/Core/AudioCommon/CMakeLists.txt @@ -75,4 +75,11 @@ if(WIN32) ) endif() -target_link_libraries(audiocommon PRIVATE cubeb SoundTouch FreeSurround) +target_link_libraries(audiocommon +PUBLIC + common + +PRIVATE + cubeb + SoundTouch + FreeSurround) diff --git a/Source/Core/Common/MsgHandler.h b/Source/Core/Common/MsgHandler.h index aadef05ea7..737640361c 100644 --- a/Source/Core/Common/MsgHandler.h +++ b/Source/Core/Common/MsgHandler.h @@ -5,6 +5,9 @@ #pragma once #include +#include + +#include namespace Common { @@ -30,6 +33,13 @@ bool MsgAlert(bool yes_no, MsgType style, const char* format, ...) #endif ; void SetEnableAlert(bool enable); + +// Like fmt::format, except the string becomes translatable +template +std::string FmtFormatT(const char* string, Args&&... args) +{ + return fmt::format(Common::GetStringT(string), std::forward(args)...); +} } // namespace Common #define SuccessAlert(format, ...) \ diff --git a/Source/Core/DiscIO/CMakeLists.txt b/Source/Core/DiscIO/CMakeLists.txt index 604d9e8914..fcaede29b3 100644 --- a/Source/Core/DiscIO/CMakeLists.txt +++ b/Source/Core/DiscIO/CMakeLists.txt @@ -58,11 +58,13 @@ add_library(discio target_link_libraries(discio PUBLIC + common BZip2::BZip2 LibLZMA::LibLZMA zstd PRIVATE + fmt::fmt minizip pugixml ZLIB::ZLIB diff --git a/Source/Core/DiscIO/CompressedBlob.cpp b/Source/Core/DiscIO/CompressedBlob.cpp index 4486b54827..9667e87fbb 100644 --- a/Source/Core/DiscIO/CompressedBlob.cpp +++ b/Source/Core/DiscIO/CompressedBlob.cpp @@ -15,6 +15,7 @@ #include #include #include + #include #include "Common/Assert.h" @@ -24,7 +25,6 @@ #include "Common/Hash.h" #include "Common/Logging/Log.h" #include "Common/MsgHandler.h" -#include "Common/StringUtil.h" #include "DiscIO/Blob.h" #include "DiscIO/CompressedBlob.h" #include "DiscIO/DiscScrubber.h" @@ -255,9 +255,8 @@ static ConversionResultCode Output(OutputParameters parameters, File::IOFile* ou const int ratio = parameters.inpos == 0 ? 0 : static_cast(100 * *position / parameters.inpos); - const std::string text = - StringFromFormat(Common::GetStringT("%i of %i blocks. Compression ratio %i%%").c_str(), - parameters.block_number, num_blocks, ratio); + const std::string text = Common::FmtFormatT("{0} of {1} blocks. Compression ratio {2}%", + parameters.block_number, num_blocks, ratio); const float completion = static_cast(parameters.block_number) / num_blocks; diff --git a/Source/Core/DiscIO/DiscExtractor.cpp b/Source/Core/DiscIO/DiscExtractor.cpp index b12b56b5c2..c9b01759a1 100644 --- a/Source/Core/DiscIO/DiscExtractor.cpp +++ b/Source/Core/DiscIO/DiscExtractor.cpp @@ -9,10 +9,11 @@ #include #include +#include + #include "Common/CommonTypes.h" #include "Common/File.h" #include "Common/FileUtil.h" -#include "Common/StringUtil.h" #include "DiscIO/Enums.h" #include "DiscIO/Filesystem.h" #include "DiscIO/Volume.h" @@ -45,7 +46,7 @@ std::string NameForPartitionType(u32 partition_type, bool include_prefix) return include_prefix ? "P-" + type_as_game_id : type_as_game_id; } - return StringFromFormat(include_prefix ? "P%u" : "%u", partition_type); + return fmt::format(include_prefix ? "P{}" : "{}", partition_type); } } diff --git a/Source/Core/DiscIO/NANDImporter.cpp b/Source/Core/DiscIO/NANDImporter.cpp index 9c161bcc02..beb84e8357 100644 --- a/Source/Core/DiscIO/NANDImporter.cpp +++ b/Source/Core/DiscIO/NANDImporter.cpp @@ -9,12 +9,13 @@ #include #include +#include + #include "Common/Crypto/AES.h" #include "Common/File.h" #include "Common/FileUtil.h" #include "Common/Logging/Log.h" #include "Common/MsgHandler.h" -#include "Common/StringUtil.h" #include "Common/Swap.h" #include "Core/IOS/ES/Formats.h" @@ -132,9 +133,10 @@ std::string NANDImporter::GetPath(const NANDFSTEntry& entry, const std::string& std::string NANDImporter::FormatDebugString(const NANDFSTEntry& entry) { - return StringFromFormat("%12.12s 0x%02x 0x%02x 0x%04x 0x%04x 0x%08x 0x%04x 0x%04x 0x%04x 0x%08x", - entry.name, entry.mode, entry.attr, entry.sub, entry.sib, entry.size, - entry.x1, entry.uid, entry.gid, entry.x3); + return fmt::format( + "{:12.12} {:#04x} {:#04x} {:#06x} {:#06x} {:#010x} {:#06x} {:#06x} {:#06x} {:#010x}", + entry.name, entry.mode, entry.attr, entry.sub, entry.sib, entry.size, entry.x1, entry.uid, + entry.gid, entry.x3); } void NANDImporter::ProcessEntry(u16 entry_number, const std::string& parent_path) @@ -216,7 +218,7 @@ bool NANDImporter::ExtractCertificates(const std::string& nand_root) return false; } - File::IOFile content_file(content_dir + StringFromFormat("%08x.app", content_metadata.id), "rb"); + File::IOFile content_file(content_dir + fmt::format("{:08x}.app", content_metadata.id), "rb"); std::vector content_bytes(content_file.GetSize()); if (!content_file.ReadBytes(content_bytes.data(), content_bytes.size())) { diff --git a/Source/Core/DiscIO/VolumeVerifier.cpp b/Source/Core/DiscIO/VolumeVerifier.cpp index 6dee5b8796..c8cb3ba5bf 100644 --- a/Source/Core/DiscIO/VolumeVerifier.cpp +++ b/Source/Core/DiscIO/VolumeVerifier.cpp @@ -519,10 +519,8 @@ bool VolumeVerifier::CheckPartition(const Partition& partition) if (partition.offset % VolumeWii::BLOCK_TOTAL_SIZE != 0 || m_volume.PartitionOffsetToRawOffset(0, partition) % VolumeWii::BLOCK_TOTAL_SIZE != 0) { - AddProblem( - Severity::Medium, - StringFromFormat(Common::GetStringT("The %s partition is not properly aligned.").c_str(), - name.c_str())); + AddProblem(Severity::Medium, + Common::FmtFormatT("The {0} partition is not properly aligned.", name)); } if (!m_is_datel) @@ -540,19 +538,15 @@ bool VolumeVerifier::CheckPartition(const Partition& partition) IOS::HLE::Device::ES::VerifyMode::DoNotUpdateCertStore, m_volume.GetTMD(partition), cert_chain)) { - AddProblem( - Severity::Low, - StringFromFormat(Common::GetStringT("The %s partition is not correctly signed.").c_str(), - name.c_str())); + AddProblem(Severity::Low, + Common::FmtFormatT("The {0} partition is not correctly signed.", name)); } } if (m_volume.SupportsIntegrityCheck() && !m_volume.CheckH3TableIntegrity(partition)) { - std::string text = StringFromFormat( - Common::GetStringT("The H3 hash table for the %s partition is not correct.").c_str(), - name.c_str()); - AddProblem(Severity::Low, std::move(text)); + AddProblem(Severity::Low, + Common::FmtFormatT("The H3 hash table for the {0} partition is not correct.", name)); } bool invalid_disc_header = false; @@ -581,13 +575,11 @@ bool VolumeVerifier::CheckPartition(const Partition& partition) } if (invalid_disc_header) { - // This can happen when certain programs that create WBFS files scrub the entirety of - // the Masterpiece partitions in Super Smash Bros. Brawl without removing them from - // the partition table. https://bugs.dolphin-emu.org/issues/8733 - std::string text = StringFromFormat( - Common::GetStringT("The %s partition does not seem to contain valid data.").c_str(), - name.c_str()); - AddProblem(severity, std::move(text)); + AddProblem(severity, + // This can happen when certain programs that create WBFS files scrub the entirety of + // the Masterpiece partitions in Super Smash Bros. Brawl without removing them from + // the partition table. https://bugs.dolphin-emu.org/issues/8733 + Common::FmtFormatT("The {0} partition does not seem to contain valid data.", name)); return false; } @@ -614,10 +606,8 @@ bool VolumeVerifier::CheckPartition(const Partition& partition) return true; } - std::string text = StringFromFormat( - Common::GetStringT("The %s partition does not have a valid file system.").c_str(), - name.c_str()); - AddProblem(severity, std::move(text)); + AddProblem(severity, + Common::FmtFormatT("The {0} partition does not have a valid file system.", name)); return false; } @@ -675,7 +665,7 @@ std::string VolumeVerifier::GetPartitionName(std::optional type) const // (French), Clásicos (Spanish), Capolavori (Italian), 클래식 게임 체험판 (Korean). // If your language is not one of the languages above, consider leaving the string untranslated // so that people will recognize it as the name of the game mode. - name = StringFromFormat(Common::GetStringT("%s (Masterpiece)").c_str(), name.c_str()); + name = Common::FmtFormatT("{0} (Masterpiece)", name); } return name; } @@ -903,10 +893,8 @@ void VolumeVerifier::CheckMisc() // Hacked version of the Wii Backup Disc (aka "pinkfish" disc). std::string proper_game_id = game_id_unencrypted; proper_game_id[0] = '4'; - AddProblem( - Severity::Low, - StringFromFormat(Common::GetStringT("The game ID is %s but should be %s.").c_str(), - game_id_unencrypted.c_str(), proper_game_id.c_str())); + AddProblem(Severity::Low, Common::FmtFormatT("The game ID is {0} but should be {1}.", + game_id_unencrypted, proper_game_id)); inconsistent_game_id = false; } } @@ -960,9 +948,9 @@ void VolumeVerifier::CheckMisc() if (region == Region::NTSC_K && ios_id < 40 && ios_id != 4 && ios_id != 9 && ios_id != 21 && ios_id != 37) { - // This is intended to catch pirated Korean games that have had the IOS slot set to 36 - // as a side effect of having to fakesign after changing the common key slot to 0. - // (IOS36 was the last IOS to have the Trucha bug.) https://bugs.dolphin-emu.org/issues/10319 + // This is intended to catch Korean games (usually but not always pirated) that have the IOS + // slot set to 36 as a side effect of having to fakesign after changing the common key slot to + // 0. (IOS36 was the last IOS with the Trucha bug.) https://bugs.dolphin-emu.org/issues/10319 AddProblem( Severity::High, // i18n: You may want to leave the term "ERROR #002" untranslated, @@ -973,7 +961,7 @@ void VolumeVerifier::CheckMisc() if (ios_id >= 0x80) { - // This is also intended to catch fakesigned pirated Korean games, + // This is intended to catch the same kind of fakesigned Korean games, // but this time with the IOS slot set to cIOS instead of IOS36. AddProblem(Severity::High, Common::GetStringT("This title is set to use an invalid IOS.")); } @@ -1000,11 +988,10 @@ void VolumeVerifier::CheckMisc() { // Many fakesigned WADs have the common key index set to a (random?) bogus value. // For WADs, Dolphin will detect this and use the correct key, making this low severity. - std::string text = StringFromFormat( - // i18n: This is "common" as in "shared", not the opposite of "uncommon" - Common::GetStringT("The specified common key index is %u but should be %u.").c_str(), - specified_common_key_index, fixed_common_key_index); - AddProblem(Severity::Low, std::move(text)); + AddProblem(Severity::Low, + // i18n: This is "common" as in "shared", not the opposite of "uncommon" + Common::FmtFormatT("The specified common key index is {0} but should be {1}.", + specified_common_key_index, fixed_common_key_index)); } } } @@ -1214,9 +1201,7 @@ void VolumeVerifier::Process() m_content_future = std::async(std::launch::async, [this, read_succeeded, content] { if (!read_succeeded || !m_volume.CheckContentIntegrity(content, m_data, m_ticket)) { - AddProblem( - Severity::High, - StringFromFormat(Common::GetStringT("Content %08x is corrupt.").c_str(), content.id)); + AddProblem(Severity::High, Common::FmtFormatT("Content {0:08x} is corrupt.", content.id)); } }); @@ -1331,10 +1316,9 @@ void VolumeVerifier::Finish() if (blocks > 0) { const std::string name = GetPartitionName(m_volume.GetPartitionType(partition)); - std::string text = StringFromFormat( - Common::GetStringT("Errors were found in %zu blocks in the %s partition.").c_str(), - blocks, name.c_str()); - AddProblem(Severity::Medium, std::move(text)); + AddProblem(Severity::Medium, + Common::FmtFormatT("Errors were found in {0} blocks in the {1} partition.", blocks, + name)); } } @@ -1343,10 +1327,9 @@ void VolumeVerifier::Finish() if (blocks > 0) { const std::string name = GetPartitionName(m_volume.GetPartitionType(partition)); - std::string text = StringFromFormat( - Common::GetStringT("Errors were found in %zu unused blocks in the %s partition.").c_str(), - blocks, name.c_str()); - AddProblem(Severity::Low, std::move(text)); + AddProblem(Severity::Low, + Common::FmtFormatT("Errors were found in {0} unused blocks in the {1} partition.", + blocks, name)); } } diff --git a/Source/Core/DiscIO/WIABlob.cpp b/Source/Core/DiscIO/WIABlob.cpp index 999d3136ac..8b309267d1 100644 --- a/Source/Core/DiscIO/WIABlob.cpp +++ b/Source/Core/DiscIO/WIABlob.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -27,7 +28,6 @@ #include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/ScopeGuard.h" -#include "Common/StringUtil.h" #include "Common/Swap.h" #include "DiscIO/Blob.h" @@ -617,9 +617,9 @@ std::string WIARVZFileReader::VersionToString(u32 version) const u8 d = version & 0xff; if (d == 0 || d == 0xff) - return StringFromFormat("%u.%02x.%02x", a, b, c); + return fmt::format("{}.{:02x}.{:02x}", a, b, c); else - return StringFromFormat("%u.%02x.%02x.beta%u", a, b, c, d); + return fmt::format("{}.{:02x}.{:02x}.beta{}", a, b, c, d); } template @@ -1694,9 +1694,8 @@ ConversionResultCode WIARVZFileReader::RunCallback(size_t groups_written, u if (bytes_read != 0) ratio = static_cast(100 * bytes_written / bytes_read); - const std::string text = - StringFromFormat(Common::GetStringT("%i of %i blocks. Compression ratio %i%%").c_str(), - groups_written, total_groups, ratio); + const std::string text = Common::FmtFormatT("{0} of {1} blocks. Compression ratio {2}%", + groups_written, total_groups, ratio); const float completion = static_cast(bytes_read) / iso_size; diff --git a/Source/Core/UICommon/GameFile.cpp b/Source/Core/UICommon/GameFile.cpp index ba7676ae80..102075e510 100644 --- a/Source/Core/UICommon/GameFile.cpp +++ b/Source/Core/UICommon/GameFile.cpp @@ -677,7 +677,7 @@ std::string GameFile::GetFileFormatName() const { std::string name = DiscIO::GetName(m_blob_type, true); if (m_is_nkit) - name = fmt::format(Common::GetStringT("{0} (NKit)"), name); + name = Common::FmtFormatT("{0} (NKit)", name); return name; } }