diff options
| author | Stefan Boberg <[email protected]> | 2023-11-06 20:36:30 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-11-06 20:36:30 +0100 |
| commit | 07f288d6e119fc6bb524fb634bc9094109a2ab05 (patch) | |
| tree | 8531bd38d0d8c3567ba3d0a5603f549faf99632b /src/zencore/include | |
| parent | gc v2 tests (#512) (diff) | |
| download | zen-07f288d6e119fc6bb524fb634bc9094109a2ab05.tar.xz zen-07f288d6e119fc6bb524fb634bc9094109a2ab05.zip | |
spdlog implementation hiding (#498)
this change aims to hide logging internals from client code, in order to make it easier to extend and take more control over the logging process in the future.
As a bonus side effect, the generated code is much tighter (net delta around 2.5% on the resulting executable which includes lots of thirdparty code) and should take less time to compile and link.
Client usage via macros is pretty much unchanged. The main exposure client code had to spdlog internals before was the use of custom loggers per subsystem, where it would be common to have `spdlog::logger` references to keep a reference to a logger within a class. This is now replaced by `zen::LoggerRef` which currently simply encapsulates an actual `spdlog::logger` instance, but this is intended to be an implementation detail which will change in the future.
The way the change works is that we now handle any formatting of log messages in the zencore logging subsystem instead of relying on `spdlog` to manage this. We use the `fmt` library to do the formatting which means the client usage is identical to using `spdlog`. The formatted message is then forwarded onto any sinks etc which are still implememted via `spdlog`.
Diffstat (limited to 'src/zencore/include')
| -rw-r--r-- | src/zencore/include/zencore/fmtutils.h | 23 | ||||
| -rw-r--r-- | src/zencore/include/zencore/logbase.h | 96 | ||||
| -rw-r--r-- | src/zencore/include/zencore/logging.h | 269 | ||||
| -rw-r--r-- | src/zencore/include/zencore/string.h | 22 | ||||
| -rw-r--r-- | src/zencore/include/zencore/zencore.h | 2 |
5 files changed, 270 insertions, 142 deletions
diff --git a/src/zencore/include/zencore/fmtutils.h b/src/zencore/include/zencore/fmtutils.h index 3d29625be..9c5bdae66 100644 --- a/src/zencore/include/zencore/fmtutils.h +++ b/src/zencore/include/zencore/fmtutils.h @@ -16,6 +16,26 @@ ZEN_THIRD_PARTY_INCLUDES_END // Custom formatting for some zencore types +template<typename T> +requires DerivedFrom<T, zen::StringBuilderBase> +struct fmt::formatter<T> : fmt::formatter<std::string_view> +{ + auto format(const zen::StringBuilderBase& a, format_context& ctx) const + { + return fmt::formatter<std::string_view>::format(a.ToView(), ctx); + } +}; + +template<typename T> +requires DerivedFrom<T, zen::NiceBase> +struct fmt::formatter<T> : fmt::formatter<std::string_view> +{ + auto format(const zen::NiceBase& a, format_context& ctx) const + { + return fmt::formatter<std::string_view>::format(std::string_view(a), ctx); + } +}; + template<> struct fmt::formatter<zen::IoHash> : formatter<string_view> { @@ -74,7 +94,8 @@ struct fmt::formatter<std::filesystem::path> : formatter<string_view> }; template<typename T> -struct fmt::formatter<T, std::enable_if_t<std::is_base_of<zen::PathBuilderBase, T>::value, char>> : fmt::formatter<std::string_view> +requires DerivedFrom<T, zen::PathBuilderBase> +struct fmt::formatter<T> : fmt::formatter<std::string_view> { auto format(const zen::PathBuilderBase& a, format_context& ctx) const { diff --git a/src/zencore/include/zencore/logbase.h b/src/zencore/include/zencore/logbase.h new file mode 100644 index 000000000..ad873aa51 --- /dev/null +++ b/src/zencore/include/zencore/logbase.h @@ -0,0 +1,96 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include <string_view> + +#define ZEN_LOG_LEVEL_TRACE 0 +#define ZEN_LOG_LEVEL_DEBUG 1 +#define ZEN_LOG_LEVEL_INFO 2 +#define ZEN_LOG_LEVEL_WARN 3 +#define ZEN_LOG_LEVEL_ERROR 4 +#define ZEN_LOG_LEVEL_CRITICAL 5 +#define ZEN_LOG_LEVEL_OFF 6 + +#define ZEN_LEVEL_NAME_TRACE std::string_view("trace", 5) +#define ZEN_LEVEL_NAME_DEBUG std::string_view("debug", 5) +#define ZEN_LEVEL_NAME_INFO std::string_view("info", 4) +#define ZEN_LEVEL_NAME_WARNING std::string_view("warning", 7) +#define ZEN_LEVEL_NAME_ERROR std::string_view("error", 5) +#define ZEN_LEVEL_NAME_CRITICAL std::string_view("critical", 8) +#define ZEN_LEVEL_NAME_OFF std::string_view("off", 3) + +namespace zen::logging::level { + +enum LogLevel : int +{ + Trace = ZEN_LOG_LEVEL_TRACE, + Debug = ZEN_LOG_LEVEL_DEBUG, + Info = ZEN_LOG_LEVEL_INFO, + Warn = ZEN_LOG_LEVEL_WARN, + Err = ZEN_LOG_LEVEL_ERROR, + Critical = ZEN_LOG_LEVEL_CRITICAL, + Off = ZEN_LOG_LEVEL_OFF, + LogLevelCount +}; + +LogLevel ParseLogLevelString(std::string_view String); +std::string_view ToStringView(LogLevel Level); + +} // namespace zen::logging::level + +namespace zen::logging { + +void SetLogLevel(level::LogLevel NewLogLevel); +level::LogLevel GetLogLevel(); + +} // namespace zen::logging + +namespace spdlog { +class logger; +} + +namespace zen::logging { + +struct SourceLocation +{ + constexpr SourceLocation() = default; + constexpr SourceLocation(const char* filename_in, int line_in, const char* funcname_in) + : filename(filename_in) + , line(line_in) + , funcname(funcname_in) + { + } + + constexpr bool empty() const noexcept { return line == 0; } + + // IMPORTANT NOTE: the layout of this class must match the spdlog::source_loc class + // since we currently pass a pointer to it into spdlog after casting it to + // spdlog::source_loc* + // + // This is intended to be an intermediate state, before we (probably) transition off + // spdlog entirely + + const char* filename{nullptr}; + int line{0}; + const char* funcname{nullptr}; +}; + +} // namespace zen::logging + +namespace zen { + +struct LoggerRef +{ + LoggerRef() = default; + LoggerRef(spdlog::logger& InLogger) : SpdLogger(&InLogger) {} + + LoggerRef Logger() { return *this; } + + bool ShouldLog(int Level) const; + inline operator bool() const { return SpdLogger != nullptr; } + + spdlog::logger* SpdLogger = nullptr; +}; + +} // namespace zen diff --git a/src/zencore/include/zencore/logging.h b/src/zencore/include/zencore/logging.h index c0d966475..e3eb524e9 100644 --- a/src/zencore/include/zencore/logging.h +++ b/src/zencore/include/zencore/logging.h @@ -2,138 +2,179 @@ #pragma once +#include <zencore/logbase.h> #include <zencore/zencore.h> -ZEN_THIRD_PARTY_INCLUDES_START -#include <spdlog/spdlog.h> -#undef GetObject -ZEN_THIRD_PARTY_INCLUDES_END - -#include <string_view> +#include <fmt/args.h> + +#if ZEN_PLATFORM_WINDOWS +# define ZEN_LOG_SECTION(Id) ZEN_DATA_SECTION(Id) +# pragma section(".zlog$f", read) +# pragma section(".zlog$l", read) +# pragma section(".zlog$m", read) +# pragma section(".zlog$s", read) +# define ZEN_DECLARE_FUNCTION static constinit ZEN_LOG_SECTION(".zlog$f") char FuncName[] = __FUNCTION__; +# define ZEN_LOG_FUNCNAME FuncName +#else +# define ZEN_LOG_SECTION(Id) +# define ZEN_DECLARE_FUNCTION +# define ZEN_LOG_FUNCNAME static_cast<const char*>(__func__) +#endif namespace zen::logging { -spdlog::logger& Default(); -void SetDefault(std::shared_ptr<spdlog::logger> NewDefaultLogger); -spdlog::logger& ConsoleLog(); -void SuppressConsoleLog(); -spdlog::logger& Get(std::string_view Name); -spdlog::logger* ErrorLog(); -void SetErrorLog(std::shared_ptr<spdlog::logger>&& NewErrorLogger); - void InitializeLogging(); void ShutdownLogging(); - bool EnableVTMode(); +LoggerRef Default(); +void SetDefault(std::string_view NewDefaultLoggerId); +LoggerRef ConsoleLog(); +void SuppressConsoleLog(); +LoggerRef ErrorLog(); +void SetErrorLog(std::string_view LoggerId); +LoggerRef Get(std::string_view Name); + +struct LogCategory +{ + inline LogCategory(std::string_view InCategory) : CategoryName(InCategory) {} + + inline zen::LoggerRef Logger() + { + if (LoggerRef) + { + return LoggerRef; + } + + LoggerRef = zen::logging::Get(CategoryName); + return LoggerRef; + } + + std::string CategoryName; + zen::LoggerRef LoggerRef; +}; + +void EmitConsoleLogMessage(int LogLevel, std::string_view Message); +void EmitConsoleLogMessage(int LogLevel, std::string_view Format, fmt::format_args Args); +void EmitLogMessage(LoggerRef& Logger, int LogLevel, std::string_view Message); +void EmitLogMessage(LoggerRef& Logger, const SourceLocation& Location, int LogLevel, std::string_view Message); +void EmitLogMessage(LoggerRef& Logger, int LogLevel, std::string_view Format, fmt::format_args Args); +void EmitLogMessage(LoggerRef& Logger, const SourceLocation& Location, int LogLevel, std::string_view Format, fmt::format_args Args); + } // namespace zen::logging namespace zen { -extern spdlog::logger* TheDefaultLogger; -inline spdlog::logger& +extern LoggerRef TheDefaultLogger; + +inline LoggerRef Log() { - if (TheDefaultLogger == nullptr) + if (TheDefaultLogger) { - return zen::logging::ConsoleLog(); + return TheDefaultLogger; } - return *TheDefaultLogger; + return zen::logging::ConsoleLog(); } using logging::ConsoleLog; using logging::ErrorLog; + } // namespace zen using zen::ConsoleLog; using zen::ErrorLog; using zen::Log; -struct LogCategory -{ - LogCategory(std::string_view InCategory) : Category(InCategory) {} - - spdlog::logger& Logger() - { - static spdlog::logger& Inst = zen::logging::Get(Category); - return Inst; - } - - std::string Category; -}; - inline consteval bool -LogIsErrorLevel(int level) +LogIsErrorLevel(int LogLevel) { - return (level == spdlog::level::err || level == spdlog::level::critical); + return (LogLevel == zen::logging::level::Err || LogLevel == zen::logging::level::Critical); }; -#define ZEN_LOG_WITH_LOCATION(logger, loc, level, fmtstr, ...) \ - do \ - { \ - using namespace std::literals; \ - if (logger.should_log(level)) \ - { \ - logger.log(loc, level, fmtstr, ##__VA_ARGS__); \ - if (LogIsErrorLevel(level)) \ - { \ - if (auto ErrLogger = zen::logging::ErrorLog(); ErrLogger != nullptr) \ - { \ - ErrLogger->log(loc, level, fmtstr, ##__VA_ARGS__); \ - } \ - } \ - } \ +#if ZEN_BUILD_DEBUG +# define ZEN_CHECK_FORMAT_STRING(fmtstr, ...) \ + while (false) \ + { \ + (void)fmt::format(fmtstr, ##__VA_ARGS__); \ + } +#else +# define ZEN_CHECK_FORMAT_STRING(fmtstr, ...) \ + while (false) \ + { \ + } +#endif + +#define ZEN_LOG_WITH_LOCATION(InLogger, InLevel, fmtstr, ...) \ + do \ + { \ + using namespace std::literals; \ + ZEN_DECLARE_FUNCTION \ + static constinit ZEN_LOG_SECTION(".zlog$s") char FileName[] = __FILE__; \ + static constinit ZEN_LOG_SECTION(".zlog$m") char FormatString[] = fmtstr; \ + static constinit ZEN_LOG_SECTION(".zlog$l") zen::logging::SourceLocation Location{FileName, __LINE__, ZEN_LOG_FUNCNAME}; \ + zen::LoggerRef Logger = InLogger; \ + ZEN_CHECK_FORMAT_STRING(fmtstr##sv, ##__VA_ARGS__); \ + if (Logger.ShouldLog(InLevel)) \ + { \ + zen::logging::EmitLogMessage(Logger, \ + Location, \ + InLevel, \ + std::string_view(FormatString, sizeof FormatString - 1), \ + fmt::make_format_args(__VA_ARGS__)); \ + } \ } while (false); -#define ZEN_LOG(logger, level, fmtstr, ...) ZEN_LOG_WITH_LOCATION(logger, spdlog::source_loc{}, level, fmtstr, ##__VA_ARGS__) - -#define ZEN_DEFINE_LOG_CATEGORY_STATIC(Category, Name) \ - static struct LogCategory##Category : public LogCategory \ - { \ - LogCategory##Category() : LogCategory(Name) {} \ - } Category; - -#define ZEN_LOG_TRACE(Category, fmtstr, ...) ZEN_LOG(Category.Logger(), spdlog::level::trace, fmtstr##sv, ##__VA_ARGS__) -#define ZEN_LOG_DEBUG(Category, fmtstr, ...) ZEN_LOG(Category.Logger(), spdlog::level::debug, fmtstr##sv, ##__VA_ARGS__) -#define ZEN_LOG_INFO(Category, fmtstr, ...) ZEN_LOG(Category.Logger(), spdlog::level::info, fmtstr##sv, ##__VA_ARGS__) -#define ZEN_LOG_WARN(Category, fmtstr, ...) ZEN_LOG(Category.Logger(), spdlog::level::warn, fmtstr##sv, ##__VA_ARGS__) -#define ZEN_LOG_ERROR(Category, fmtstr, ...) \ - ZEN_LOG_WITH_LOCATION(Category.Logger(), \ - spdlog::source_loc(__FILE__, __LINE__, SPDLOG_FUNCTION), \ - spdlog::level::err, \ - fmtstr##sv, \ - ##__VA_ARGS__) - -#define ZEN_LOG_CRITICAL(Category, fmtstr, ...) \ - ZEN_LOG_WITH_LOCATION(Category.Logger(), \ - spdlog::source_loc(__FILE__, __LINE__, SPDLOG_FUNCTION), \ - spdlog::level::critical, \ - fmtstr##sv, \ - ##__VA_ARGS__) - - // Helper macros for logging - -#define ZEN_TRACE(fmtstr, ...) ZEN_LOG(Log(), spdlog::level::trace, fmtstr##sv, ##__VA_ARGS__) -#define ZEN_DEBUG(fmtstr, ...) ZEN_LOG(Log(), spdlog::level::debug, fmtstr##sv, ##__VA_ARGS__) -#define ZEN_INFO(fmtstr, ...) ZEN_LOG(Log(), spdlog::level::info, fmtstr##sv, ##__VA_ARGS__) -#define ZEN_WARN(fmtstr, ...) ZEN_LOG(Log(), spdlog::level::warn, fmtstr##sv, ##__VA_ARGS__) -#define ZEN_ERROR(fmtstr, ...) \ - ZEN_LOG_WITH_LOCATION(Log(), spdlog::source_loc(__FILE__, __LINE__, SPDLOG_FUNCTION), spdlog::level::err, fmtstr##sv, ##__VA_ARGS__) - -#define ZEN_CRITICAL(fmtstr, ...) \ - ZEN_LOG_WITH_LOCATION(Log(), \ - spdlog::source_loc(__FILE__, __LINE__, SPDLOG_FUNCTION), \ - spdlog::level::critical, \ - fmtstr##sv, \ - ##__VA_ARGS__) - -#define ZEN_CONSOLE(fmtstr, ...) \ - do \ - { \ - using namespace std::literals; \ - ConsoleLog().info(fmtstr##sv, ##__VA_ARGS__); \ +#define ZEN_LOG(InLogger, InLevel, fmtstr, ...) \ + do \ + { \ + using namespace std::literals; \ + static constinit ZEN_LOG_SECTION(".zlog$m") char FormatString[] = fmtstr; \ + zen::LoggerRef Logger = InLogger; \ + ZEN_CHECK_FORMAT_STRING(fmtstr##sv, ##__VA_ARGS__); \ + if (Logger.ShouldLog(InLevel)) \ + { \ + zen::logging::EmitLogMessage(Logger, \ + InLevel, \ + std::string_view(FormatString, sizeof FormatString - 1), \ + fmt::make_format_args(__VA_ARGS__)); \ + } \ + } while (false); + +#define ZEN_DEFINE_LOG_CATEGORY_STATIC(Category, Name) \ + static zen::logging::LogCategory Category { Name } + +#define ZEN_LOG_TRACE(Category, fmtstr, ...) ZEN_LOG(Category.Logger(), zen::logging::level::Trace, fmtstr, ##__VA_ARGS__) +#define ZEN_LOG_DEBUG(Category, fmtstr, ...) ZEN_LOG(Category.Logger(), zen::logging::level::Debug, fmtstr, ##__VA_ARGS__) +#define ZEN_LOG_INFO(Category, fmtstr, ...) ZEN_LOG(Category.Logger(), zen::logging::level::Info, fmtstr, ##__VA_ARGS__) +#define ZEN_LOG_WARN(Category, fmtstr, ...) ZEN_LOG(Category.Logger(), zen::logging::level::Warn, fmtstr, ##__VA_ARGS__) +#define ZEN_LOG_ERROR(Category, fmtstr, ...) ZEN_LOG_WITH_LOCATION(Category.Logger(), zen::logging::level::Err, fmtstr, ##__VA_ARGS__) +#define ZEN_LOG_CRITICAL(Category, fmtstr, ...) \ + ZEN_LOG_WITH_LOCATION(Category.Logger(), zen::logging::level::Critical, fmtstr, ##__VA_ARGS__) + +#define ZEN_TRACE(fmtstr, ...) ZEN_LOG(Log(), zen::logging::level::Trace, fmtstr, ##__VA_ARGS__) +#define ZEN_DEBUG(fmtstr, ...) ZEN_LOG(Log(), zen::logging::level::Debug, fmtstr, ##__VA_ARGS__) +#define ZEN_INFO(fmtstr, ...) ZEN_LOG(Log(), zen::logging::level::Info, fmtstr, ##__VA_ARGS__) +#define ZEN_WARN(fmtstr, ...) ZEN_LOG(Log(), zen::logging::level::Warn, fmtstr, ##__VA_ARGS__) +#define ZEN_ERROR(fmtstr, ...) ZEN_LOG_WITH_LOCATION(Log(), zen::logging::level::Err, fmtstr, ##__VA_ARGS__) +#define ZEN_CRITICAL(fmtstr, ...) ZEN_LOG_WITH_LOCATION(Log(), zen::logging::level::Critical, fmtstr, ##__VA_ARGS__) + +#define ZEN_CONSOLE_LOG(InLevel, fmtstr, ...) \ + do \ + { \ + using namespace std::literals; \ + ZEN_CHECK_FORMAT_STRING(fmtstr##sv, ##__VA_ARGS__); \ + zen::logging::EmitConsoleLogMessage(InLevel, fmtstr, fmt::make_format_args(__VA_ARGS__)); \ } while (false) +#define ZEN_CONSOLE(fmtstr, ...) ZEN_CONSOLE_LOG(zen::logging::level::Info, fmtstr, ##__VA_ARGS__) +#define ZEN_CONSOLE_TRACE(fmtstr, ...) ZEN_CONSOLE_LOG(zen::logging::level::Trace, fmtstr, ##__VA_ARGS__) +#define ZEN_CONSOLE_DEBUG(fmtstr, ...) ZEN_CONSOLE_LOG(zen::logging::level::Debug, fmtstr, ##__VA_ARGS__) +#define ZEN_CONSOLE_INFO(fmtstr, ...) ZEN_CONSOLE_LOG(zen::logging::level::Info, fmtstr, ##__VA_ARGS__) +#define ZEN_CONSOLE_WARN(fmtstr, ...) ZEN_CONSOLE_LOG(zen::logging::level::Warn, fmtstr, ##__VA_ARGS__) +#define ZEN_CONSOLE_ERROR(fmtstr, ...) ZEN_CONSOLE_LOG(zen::logging::level::Err, fmtstr, ##__VA_ARGS__) +#define ZEN_CONSOLE_CRITICAL(fmtstr, ...) ZEN_CONSOLE_LOG(zen::logging::level::Critical, fmtstr, ##__VA_ARGS__) + ////////////////////////////////////////////////////////////////////////// namespace zen { @@ -187,30 +228,20 @@ std::string_view EmitActivitiesForLogging(StringBuilderBase& OutString); #define ZEN_LOG_SCOPE(...) ScopedLazyActivity $Activity##__LINE__([&](StringBuilderBase& Out) { Out << fmt::format(__VA_ARGS__); }) -#define ZEN_SCOPED_ERROR(fmtstr, ...) \ - do \ - { \ - ExtendableStringBuilder<256> ScopeString; \ - const std::string_view Scopes = EmitActivitiesForLogging(ScopeString); \ - ZEN_LOG_WITH_LOCATION(Log(), \ - spdlog::source_loc(__FILE__, __LINE__, SPDLOG_FUNCTION), \ - spdlog::level::err, \ - fmtstr "{}"sv, \ - ##__VA_ARGS__, \ - Scopes); \ +#define ZEN_SCOPED_ERROR(fmtstr, ...) \ + do \ + { \ + ExtendableStringBuilder<256> ScopeString; \ + const std::string_view Scopes = EmitActivitiesForLogging(ScopeString); \ + ZEN_LOG_WITH_LOCATION(Log(), zen::logging::level::Err, fmtstr "{}", ##__VA_ARGS__, Scopes); \ } while (false) -#define ZEN_SCOPED_CRITICAL(fmtstr, ...) \ - do \ - { \ - ExtendableStringBuilder<256> ScopeString; \ - const std::string_view Scopes = EmitActivitiesForLogging(ScopeString); \ - ZEN_LOG_WITH_LOCATION(Log(), \ - spdlog::source_loc(__FILE__, __LINE__, SPDLOG_FUNCTION), \ - spdlog::level::critical, \ - fmtstr "{}"sv, \ - ##__VA_ARGS__, \ - Scopes); \ +#define ZEN_SCOPED_CRITICAL(fmtstr, ...) \ + do \ + { \ + ExtendableStringBuilder<256> ScopeString; \ + const std::string_view Scopes = EmitActivitiesForLogging(ScopeString); \ + ZEN_LOG_WITH_LOCATION(Log(), zen::logging::level::Critical, fmtstr "{}", ##__VA_ARGS__, Scopes); \ } while (false) ScopedActivityBase* GetThreadActivity(); diff --git a/src/zencore/include/zencore/string.h b/src/zencore/include/zencore/string.h index d0bd38acc..e3de2224c 100644 --- a/src/zencore/include/zencore/string.h +++ b/src/zencore/include/zencore/string.h @@ -17,10 +17,6 @@ #include <type_traits> -ZEN_THIRD_PARTY_INCLUDES_START -#include <fmt/format.h> -ZEN_THIRD_PARTY_INCLUDES_END - namespace zen { ////////////////////////////////////////////////////////////////////////// @@ -1141,21 +1137,3 @@ private: void string_forcelink(); // internal } // namespace zen - -template<typename T> -struct fmt::formatter<T, std::enable_if_t<std::is_base_of<zen::StringBuilderBase, T>::value, char>> : fmt::formatter<std::string_view> -{ - auto format(const zen::StringBuilderBase& a, format_context& ctx) const - { - return fmt::formatter<std::string_view>::format(a.ToView(), ctx); - } -}; - -template<typename T> -struct fmt::formatter<T, std::enable_if_t<std::is_base_of<zen::NiceBase, T>::value, char>> : fmt::formatter<std::string_view> -{ - auto format(const zen::NiceBase& a, format_context& ctx) const - { - return fmt::formatter<std::string_view>::format(std::string_view(a), ctx); - } -}; diff --git a/src/zencore/include/zencore/zencore.h b/src/zencore/include/zencore/zencore.h index 299fa2c31..562376c95 100644 --- a/src/zencore/include/zencore/zencore.h +++ b/src/zencore/include/zencore/zencore.h @@ -229,10 +229,12 @@ static_assert(sizeof(wchar_t) == 2, "wchar_t is expected to be two bytes in size #if ZEN_PLATFORM_WINDOWS // Tells the compiler to put the decorated function in a certain section (aka. segment) of the executable. # define ZEN_CODE_SECTION(Name) __declspec(code_seg(Name)) +# define ZEN_DATA_SECTION(Name) __declspec(allocate(Name)) # define ZEN_FORCENOINLINE __declspec(noinline) /* Force code to NOT be inline */ # define LINE_TERMINATOR_ANSI "\r\n" #else # define ZEN_CODE_SECTION(Name) +# define ZEN_DATA_SECTION(Name) # define ZEN_FORCENOINLINE # define LINE_TERMINATOR_ANSI "\n" #endif |