feat: add various detector.

- add endian and compiler detector, and modify os detector.
- now we use CMake to add detector-used macro, instead of using some C++ features to detect them.
- change Windows environment detection according to the change of os detector.
This commit is contained in:
2025-07-23 10:18:01 +08:00
parent 6043609709
commit 821a592f02
29 changed files with 84 additions and 49 deletions

View File

@ -73,7 +73,7 @@ Assume \c blabla() function is Windows specific.
We have following example code: We have following example code:
\code \code
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
blabla(); blabla();
#endif #endif
\endcode \endcode

View File

@ -11,7 +11,7 @@ Due to legacy reason, Windows defines various things which are not compatible wi
YYCC has a way to solve the issue introduced above. YYCC has a way to solve the issue introduced above.
\code \code
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
#include <WinImportPrefix.hpp> #include <WinImportPrefix.hpp>
#include <Windows.h> #include <Windows.h>
#include "other_header_depend_on_windows.h" #include "other_header_depend_on_windows.h"

View File

@ -45,6 +45,8 @@ FILES
yycc/macro/version_cmp.hpp yycc/macro/version_cmp.hpp
yycc/macro/feature_probe.hpp yycc/macro/feature_probe.hpp
yycc/macro/os_detector.hpp yycc/macro/os_detector.hpp
yycc/macro/endian_detector.hpp
yycc/macro/compiler_detector.hpp
yycc/macro/class_copy_move.hpp yycc/macro/class_copy_move.hpp
yycc/string.hpp yycc/string.hpp
yycc/string/reinterpret.hpp yycc/string/reinterpret.hpp
@ -124,6 +126,16 @@ PUBLIC
$<$<BOOL:${YYCC_DEBUG_UE_FILTER}>:YYCC_DEBUG_UE_FILTER> $<$<BOOL:${YYCC_DEBUG_UE_FILTER}>:YYCC_DEBUG_UE_FILTER>
# Iconv environment macro # Iconv environment macro
$<$<BOOL:${YYCC_ENFORCE_ICONV}>:YYCC_FEAT_ICONV> $<$<BOOL:${YYCC_ENFORCE_ICONV}>:YYCC_FEAT_ICONV>
# OS macro
$<$<BOOL:${WIN32}>:YYCC_OS_WINDOWS>
$<$<PLATFORM_ID:Linux>:YYCC_OS_LINUX>
# Compiler macro
$<$<CXX_COMPILER_ID:GNU>:YYCC_CC_GCC>
$<$<CXX_COMPILER_ID:Clang>:YYCC_CC_CLANG>
$<$<CXX_COMPILER_ID:MSVC>:YYCC_CC_MSVC>
# Endian macro
$<$<STREQUAL:${CMAKE_CXX_BYTE_ORDER},LITTLE_ENDIAN>:YYCC_ENDIAN_LITTLE>
$<$<STREQUAL:${CMAKE_CXX_BYTE_ORDER},BIG_ENDIAN>:YYCC_ENDIAN_BIG>
PRIVATE PRIVATE
# Unicode charset for private using # Unicode charset for private using
$<$<CXX_COMPILER_ID:MSVC>:UNICODE> $<$<CXX_COMPILER_ID:MSVC>:UNICODE>
@ -135,6 +147,8 @@ PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:/utf-8> $<$<CXX_COMPILER_ID:MSVC>:/utf-8>
) )
# TODO: Fix GCC stacktrace link issue
# Install binary and headers # Install binary and headers
install(TARGETS YYCCommonplace install(TARGETS YYCCommonplace
EXPORT YYCCommonplaceTargets EXPORT YYCCommonplaceTargets

View File

@ -3,7 +3,7 @@
#include "EncodingHelper.hpp" #include "EncodingHelper.hpp"
#include "ConsoleHelper.hpp" #include "ConsoleHelper.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
#include "WinImportPrefix.hpp" #include "WinImportPrefix.hpp"
#include <Windows.h> #include <Windows.h>
#include <shellapi.h> #include <shellapi.h>
@ -24,7 +24,7 @@ namespace YYCC::ArgParser {
return ArgumentList(std::move(args)); return ArgumentList(std::move(args));
} }
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
ArgumentList ArgumentList::CreateFromWin32() { ArgumentList ArgumentList::CreateFromWin32() {
// Reference: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw // Reference: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw

View File

@ -37,7 +37,7 @@ namespace YYCC::ArgParser {
* and should not be seen as a part of arguments. * and should not be seen as a part of arguments.
*/ */
static ArgumentList CreateFromStd(int argc, char* argv[]); static ArgumentList CreateFromStd(int argc, char* argv[]);
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
/** /**
* @brief Create argument list from Win32 function. * @brief Create argument list from Win32 function.
* @details * @details

View File

@ -1,5 +1,5 @@
#include "COMHelper.hpp" #include "COMHelper.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
namespace YYCC::COMHelper { namespace YYCC::COMHelper {

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "YYCCInternal.hpp" #include "YYCCInternal.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
#include <memory> #include <memory>

View File

@ -5,7 +5,7 @@
#include <iostream> #include <iostream>
// Include Windows used headers in Windows. // Include Windows used headers in Windows.
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
#include "WinImportPrefix.hpp" #include "WinImportPrefix.hpp"
#include <Windows.h> #include <Windows.h>
#include <io.h> #include <io.h>
@ -16,7 +16,7 @@
namespace YYCC::ConsoleHelper { namespace YYCC::ConsoleHelper {
#pragma region Windows Specific Functions #pragma region Windows Specific Functions
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
static bool RawEnableColorfulConsole(FILE* fs) { static bool RawEnableColorfulConsole(FILE* fs) {
if (!_isatty(_fileno(fs))) return false; if (!_isatty(_fileno(fs))) return false;
@ -161,7 +161,7 @@ namespace YYCC::ConsoleHelper {
#pragma endregion #pragma endregion
bool EnableColorfulConsole() { bool EnableColorfulConsole() {
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
bool ret = true; bool ret = true;
ret &= RawEnableColorfulConsole(stdout); ret &= RawEnableColorfulConsole(stdout);
@ -177,7 +177,7 @@ namespace YYCC::ConsoleHelper {
} }
yycc_u8string ReadLine() { yycc_u8string ReadLine() {
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
// get stdin mode // get stdin mode
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
@ -221,7 +221,7 @@ namespace YYCC::ConsoleHelper {
strl += YYCC_U8("\n"); strl += YYCC_U8("\n");
} }
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
// call Windows specific writer // call Windows specific writer
WinConsoleWrite(strl, bIsErr); WinConsoleWrite(strl, bIsErr);
#else #else

View File

@ -1,5 +1,5 @@
#include "DialogHelper.hpp" #include "DialogHelper.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
#include "EncodingHelper.hpp" #include "EncodingHelper.hpp"
#include "StringHelper.hpp" #include "StringHelper.hpp"

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "YYCCInternal.hpp" #include "YYCCInternal.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
#include "COMHelper.hpp" #include "COMHelper.hpp"
#include <string> #include <string>

View File

@ -1,5 +1,5 @@
#include "ExceptionHelper.hpp" #include "ExceptionHelper.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
#include "WinFctHelper.hpp" #include "WinFctHelper.hpp"
#include "ConsoleHelper.hpp" #include "ConsoleHelper.hpp"

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "YYCCInternal.hpp" #include "YYCCInternal.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
/** /**
* @brief Windows specific unhandled exception processor. * @brief Windows specific unhandled exception processor.

View File

@ -7,7 +7,7 @@
#include <stdexcept> #include <stdexcept>
#include <memory> #include <memory>
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
#include "WinImportPrefix.hpp" #include "WinImportPrefix.hpp"
#include <Windows.h> #include <Windows.h>
#include "WinImportSuffix.hpp" #include "WinImportSuffix.hpp"
@ -16,7 +16,7 @@
namespace YYCC::IOHelper { namespace YYCC::IOHelper {
std::FILE* UTF8FOpen(const yycc_char8_t* u8_filepath, const yycc_char8_t* u8_mode) { std::FILE* UTF8FOpen(const yycc_char8_t* u8_filepath, const yycc_char8_t* u8_mode) {
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
// convert mode and file path to wchar // convert mode and file path to wchar
std::wstring wmode, wpath; std::wstring wmode, wpath;

View File

@ -1,5 +1,5 @@
#include "WinFctHelper.hpp" #include "WinFctHelper.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
#include "EncodingHelper.hpp" #include "EncodingHelper.hpp"
#include "COMHelper.hpp" #include "COMHelper.hpp"

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "YYCCInternal.hpp" #include "YYCCInternal.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
#include <string> #include <string>

View File

@ -50,7 +50,7 @@
// If we are in Windows, // If we are in Windows,
// we need add 2 macros to disable Windows shitty warnings and errors of // we need add 2 macros to disable Windows shitty warnings and errors of
// depracted functions and not secure functions. // depracted functions and not secure functions.
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
#if !defined(_CRT_SECURE_NO_WARNINGS) #if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS

View File

@ -1,8 +1,9 @@
#include "iconv.hpp" #include "iconv.hpp"
#if YYCC_FEAT_ICONV || (YYCC_OS != YYCC_OS_WINDOWS) #if YYCC_FEAT_ICONV || !defined(YYCC_OS_WINDOWS)
#include "../string/reinterpret.hpp" #include "../string/reinterpret.hpp"
#include "../macro/endian_detector.hpp"
#include <cerrno> #include <cerrno>
#include <stdexcept> #include <stdexcept>
#include <cstdint> #include <cstdint>
@ -190,20 +191,30 @@ namespace yycc::encoding::iconv {
// That's not what we expected. // That's not what we expected.
// So we need manually check runtime endian and explicitly specify endian in code name. // So we need manually check runtime endian and explicitly specify endian in code name.
// TODO: fix this encoding endian issue.
static const NS_YYCC_STRING::u8char* UTF8_CODENAME_LITERAL = YYCC_U8("UTF-8"); static const NS_YYCC_STRING::u8char* UTF8_CODENAME_LITERAL = YYCC_U8("UTF-8");
static const NS_YYCC_STRING::u8char* WCHAR_CODENAME_LITERAL = YYCC_U8("WCHAR_T"); static const NS_YYCC_STRING::u8char* WCHAR_CODENAME_LITERAL = YYCC_U8("WCHAR_T");
static const NS_YYCC_STRING::u8char* fetch_utf16_codename() { static const NS_YYCC_STRING::u8char* fetch_utf16_codename() {
return YYCC_U8("UTF16"); #if defined(YYCC_ENDIAN_LITTLE)
return YYCC_U8("UTF16LE");
#else
return YYCC_U8("UTF16BE");
#endif
} }
static const NS_YYCC_STRING::u8char* UTF16_CODENAME_LITERAL = fetch_utf16_codename(); static const NS_YYCC_STRING::u8char* UTF16_CODENAME_LITERAL = fetch_utf16_codename();
static const NS_YYCC_STRING::u8char* fetch_utf32_codename() { static const NS_YYCC_STRING::u8char* fetch_utf32_codename() {
return YYCC_U8("UTF32"); #if defined(YYCC_ENDIAN_LITTLE)
return YYCC_U8("UTF32LE");
#else
return YYCC_U8("UTF32BE");
#endif
} }
static const NS_YYCC_STRING::u8char* UTF32_CODENAME_LITERAL = fetch_utf32_codename(); static const NS_YYCC_STRING::u8char* UTF32_CODENAME_LITERAL = fetch_utf32_codename();
// TODO: There is a memory copy in this function. Consider removing it in future. // TODO:
// There is a memory copy in this function. Consider optimizing it in future.
// A possible solution is that create a std::vector-like wrapper for std::basic_string and std::basic_string_view.
// We call them VecString and VecStringView, and use them in "iconv_kernel" instead of real std::vector.
// They exposed interface are std::vector-like but its inner is std::basic_string and std::basic_string_view.
#define CONVFN_TYPE0(src_char_type, dst_char_type) \ #define CONVFN_TYPE0(src_char_type, dst_char_type) \
namespace expected = NS_YYCC_PATCH_EXPECTED; \ namespace expected = NS_YYCC_PATCH_EXPECTED; \
auto rv = iconv_kernel(this->token, reinterpret_cast<const uint8_t*>(src.data()), src.size()); \ auto rv = iconv_kernel(this->token, reinterpret_cast<const uint8_t*>(src.data()), src.size()); \

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "../macro/os_detector.hpp" #include "../macro/os_detector.hpp"
#if YYCC_FEAT_ICONV || (YYCC_OS != YYCC_OS_WINDOWS) #if YYCC_FEAT_ICONV || !defined(YYCC_OS_WINDOWS)
#include "../macro/class_copy_move.hpp" #include "../macro/class_copy_move.hpp"
#include "../patch/expected.hpp" #include "../patch/expected.hpp"

View File

@ -1,6 +1,6 @@
#include "windows.hpp" #include "windows.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
#include "../string/reinterpret.hpp" #include "../string/reinterpret.hpp"
#include <limits> #include <limits>

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "../macro/os_detector.hpp" #include "../macro/os_detector.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
#include "../patch/expected.hpp" #include "../patch/expected.hpp"
#include "../string.hpp" #include "../string.hpp"

View File

@ -0,0 +1,5 @@
#pragma once
#if (defined(YYCC_CC_MSVC) + defined(YYCC_CC_GCC) + defined(YYCC_CC_CLANG)) != 1
#error "Current compiler is not supported!"
#endif

View File

@ -0,0 +1,7 @@
#pragma once
// Check endian
#if (defined(YYCC_ENDIAN_LITTLE) + defined(YYCC_ENDIAN_BIG)) != 1
#error "Current system endian (byte order) is not supported!"
#endif

View File

@ -1,11 +1,6 @@
#pragma once #pragma once
// Define operating system macros // Check OS macro
#define YYCC_OS_WINDOWS 2 #if (defined(YYCC_OS_WINDOWS) + defined(YYCC_OS_LINUX)) != 1
#define YYCC_OS_LINUX 3 #error "Current operating system is not supported!"
// Check current operating system.
#if defined(_WIN32)
#define YYCC_OS YYCC_OS_WINDOWS
#else
#define YYCC_OS YYCC_OS_LINUX
#endif #endif

View File

@ -12,7 +12,7 @@ namespace yycc::patch::path {
// So we need add feature test macro at the same time. // So we need add feature test macro at the same time.
std::filesystem::path to_std_path(const NS_YYCC_STRING::u8string_view& u8_path) { std::filesystem::path to_std_path(const NS_YYCC_STRING::u8string_view& u8_path) {
// #if YYCC_OS == YYCC_OS_WINDOWS // #if defined(YYCC_OS_WINDOWS)
// // convert path to wchar // // convert path to wchar
// std::wstring wpath; // std::wstring wpath;
@ -29,7 +29,7 @@ namespace yycc::patch::path {
} }
NS_YYCC_STRING::u8string to_u8string(const std::filesystem::path& path) { NS_YYCC_STRING::u8string to_u8string(const std::filesystem::path& path) {
// #if YYCC_OS == YYCC_OS_WINDOWS // #if defined(YYCC_OS_WINDOWS)
// // get and convert to utf8 // // get and convert to utf8
// NS_YYCC_STRING::u8string u8_path; // NS_YYCC_STRING::u8string u8_path;

View File

@ -1,5 +1,8 @@
#pragma once #pragma once
// Suppress unsafe warning on Windows
#include "../windows/unsafe_suppressor.hpp"
// Prelude section // Prelude section
#include "../string.hpp" #include "../string.hpp"
namespace yycc::prelude { namespace yycc::prelude {

View File

@ -4,7 +4,7 @@
#include "../macro/os_detector.hpp" #include "../macro/os_detector.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
// Define 2 macros to disallow Windows generate MIN and MAX macros // Define 2 macros to disallow Windows generate MIN and MAX macros
// which cause std::min and std::max can not function as normal. // which cause std::min and std::max can not function as normal.

View File

@ -4,7 +4,7 @@
#include "../macro/os_detector.hpp" #include "../macro/os_detector.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
// Windows also will generate following macros // Windows also will generate following macros
// which may cause the function sign is different in Windows and other platforms. // which may cause the function sign is different in Windows and other platforms.

View File

@ -4,7 +4,7 @@
// If we are in Windows, // If we are in Windows,
// we need add 2 macros to disable Windows shitty warnings and errors of // we need add 2 macros to disable Windows shitty warnings and errors of
// depracted functions and not secure functions. // depracted functions and not secure functions.
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
#if !defined(_CRT_SECURE_NO_WARNINGS) #if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS

View File

@ -167,7 +167,7 @@ namespace YYCCTestbench {
} }
// check wstring convertion on windows // check wstring convertion on windows
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
for (size_t i = 0u; i < count; ++i) { for (size_t i = 0u; i < count; ++i) {
// get item // get item
const auto& u8str = c_UTF8TestStrTable[i]; const auto& u8str = c_UTF8TestStrTable[i];
@ -306,7 +306,7 @@ namespace YYCCTestbench {
} }
static void DialogTestbench() { static void DialogTestbench() {
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
YYCC::yycc_u8string ret; YYCC::yycc_u8string ret;
std::vector<YYCC::yycc_u8string> rets; std::vector<YYCC::yycc_u8string> rets;
@ -340,7 +340,7 @@ namespace YYCCTestbench {
} }
static void ExceptionTestbench() { static void ExceptionTestbench() {
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
YYCC::ExceptionHelper::Register([](const YYCC::yycc_u8string& log_path, const YYCC::yycc_u8string& coredump_path) -> void { YYCC::ExceptionHelper::Register([](const YYCC::yycc_u8string& log_path, const YYCC::yycc_u8string& coredump_path) -> void {
MessageBoxW( MessageBoxW(
@ -374,7 +374,7 @@ namespace YYCCTestbench {
} }
static void WinFctTestbench() { static void WinFctTestbench() {
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
HMODULE test_current_module; HMODULE test_current_module;
Assert((test_current_module = YYCC::WinFctHelper::GetCurrentModule()) != nullptr, YYCC_U8("YYCC::WinFctHelper::GetCurrentModule")); Assert((test_current_module = YYCC::WinFctHelper::GetCurrentModule()) != nullptr, YYCC_U8("YYCC::WinFctHelper::GetCurrentModule"));
@ -412,7 +412,7 @@ namespace YYCCTestbench {
} }
YYCC::yycc_u8string test_slashed_path(YYCC::StdPatch::ToUTF8Path(test_path)); YYCC::yycc_u8string test_slashed_path(YYCC::StdPatch::ToUTF8Path(test_path));
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
std::wstring wdelimiter(1u, std::filesystem::path::preferred_separator); std::wstring wdelimiter(1u, std::filesystem::path::preferred_separator);
YYCC::yycc_u8string delimiter(YYCC::EncodingHelper::WcharToUTF8(wdelimiter)); YYCC::yycc_u8string delimiter(YYCC::EncodingHelper::WcharToUTF8(wdelimiter));
#else #else
@ -622,7 +622,7 @@ namespace YYCCTestbench {
YYCC::ConsoleHelper::FormatLine(YYCC_U8("\t%s"), result.Argument().c_str()); YYCC::ConsoleHelper::FormatLine(YYCC_U8("\t%s"), result.Argument().c_str());
} }
} }
#if YYCC_OS == YYCC_OS_WINDOWS #if defined(YYCC_OS_WINDOWS)
{ {
YYCC::ConsoleHelper::WriteLine(YYCC_U8("YYCC::ArgParser::ArgumentList::CreateFromWin32")); YYCC::ConsoleHelper::WriteLine(YYCC_U8("YYCC::ArgParser::ArgumentList::CreateFromWin32"));
auto result = YYCC::ArgParser::ArgumentList::CreateFromWin32(); auto result = YYCC::ArgParser::ArgumentList::CreateFromWin32();