- 实现了括号深度跟踪来正确分割带括号的宏参数 - 添加了对 GNU 扩展中 `##` 操作符逗号删除的支持 - 新增辅助函数 `got_left_non_blank` 和 `got_right_non_blank` 来优化查找非空白 token 的逻辑 - 改进了错误消息以显示预期但得到的实际值类型 fix(pproc): 修复条件编译和包含文件路径的错误消息 - 在 `scc_pproc_parse_if_condition` 中改进错误消息格式 - 修复 `switch_file_stack` 函数中的日志字符串格式问题 test(pproc): 添加宏处理相关的单元测试 - 增加了连接操作符、嵌套宏、括号处理等测试用例 - 添加了 C99 标准示例和 GNU 变参宏删除逗号的测试 - 包含了复杂的宏展开场景测试 chore(justfile): 更新构建脚本添加调试目标 - 为 `test-scc` 目标添加了 `debug-scc` 调试版本 - 更新构建命令以支持开发模式 feat(cbuild): 添加 dry-run 模式和改进编译器参数 - 为编译器类添加 dry-run 功能,只打印命令不执行 - 改进 scc 编译器的包含路径处理逻辑 - 为命令行解析器添加 dry-run 参数选项 refactor(log): 重命名 static_assert 为 StaticAssert 避免冲突 - 为了避免与标准库冲突,将自定义 static_assert 重命名为 StaticAssert style(scc_core): 移除未使用的预定义宏定义 - 删除了不再需要的基础类型前缀宏定义 fix(scc_core): 初始化 ring 测试中的未初始化变量 - 为测试函数中的字符变量添加初始化值避免未定义行为
201 lines
8.0 KiB
C
201 lines
8.0 KiB
C
/**
|
||
* @file log.h
|
||
* @brief 日志系统核心模块(支持多级日志、断言和异常处理)
|
||
*/
|
||
|
||
#ifndef __SCC_LOG_IMPL_H__
|
||
#define __SCC_LOG_IMPL_H__
|
||
|
||
#include "color.h"
|
||
#ifndef __SCC__
|
||
#include <stdarg.h>
|
||
#else
|
||
// TODO
|
||
#warning "TODO: implement stdarg.h"
|
||
#endif
|
||
|
||
#ifdef __SCC_LOG_IMPL_USE_STD_IMPL__
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#define log_vsnprintf vsnprintf
|
||
#define log_puts puts
|
||
#define log_exit scc_exit
|
||
#endif
|
||
|
||
#ifdef __GNUC__ // GCC, Clang, ICC
|
||
#define __smcc_log_unreachable() (__builtin_unreachable())
|
||
#elif defined _MSC_VER // MSVC
|
||
#define __smcc_log_unreachable() (__assume(false))
|
||
#elif defined __SCC_BUILT_IN__ // The SCC Compiler (my compiler)
|
||
#define __smcc_log_unreachable() (__smcc_builtin_unreachable())
|
||
#else
|
||
#define __smcc_log_unreachable()
|
||
#endif
|
||
|
||
#ifndef log_vsnprintf
|
||
#define log_vsnprintf(...)
|
||
#warning "log_vsnprintf not defined"
|
||
#endif
|
||
|
||
#ifndef log_puts
|
||
#define log_puts(...)
|
||
#warning "log_puts not defined"
|
||
#endif
|
||
|
||
#ifndef log_exit
|
||
#define log_exit(...)
|
||
#warning "log_exit not defined"
|
||
#endif
|
||
|
||
/**
|
||
* @brief 日志级别枚举
|
||
*
|
||
* 定义日志系统的输出级别和组合标志位
|
||
*/
|
||
typedef enum log_level {
|
||
LOG_LEVEL_NOTSET = 0, ///< 未设置级别(继承默认配置)
|
||
LOG_LEVEL_DEBUG = 1 << 0, ///< 调试信息(开发阶段详细信息)
|
||
LOG_LEVEL_INFO = 1 << 1, ///< 常规信息(系统运行状态)
|
||
LOG_LEVEL_WARN = 1 << 2, ///< 警告信息(潜在问题提示)
|
||
LOG_LEVEL_ERROR = 1 << 3, ///< 错误信息(可恢复的错误)
|
||
LOG_LEVEL_FATAL = 1 << 4, ///< 致命错误(导致程序终止的严重错误)
|
||
LOG_LEVEL_TRACE = 1 << 5, ///< 追踪(性能追踪或者栈帧追踪)
|
||
LOG_LEVEL_ALL = 0xFF, ///< 全级别标志(组合所有日志级别)
|
||
} log_level_t;
|
||
|
||
#ifndef LOGGER_MAX_BUF_SIZE
|
||
#define LOGGER_MAX_BUF_SIZE 512 ///< 单条日志最大缓冲区尺寸
|
||
#endif
|
||
|
||
typedef struct logger logger_t;
|
||
|
||
typedef int (*log_handler)(logger_t *module, log_level_t level,
|
||
const char *file, int line, const char *func,
|
||
const char *fmt, ...);
|
||
|
||
/**
|
||
* @brief 日志器实例结构体
|
||
*
|
||
* 每个日志器实例维护独立的配置和缓冲区
|
||
*/
|
||
struct logger {
|
||
const char *name; ///< 日志器名称(用于模块区分)
|
||
log_level_t level; ///< 当前设置的日志级别
|
||
log_handler handler; ///< 日志处理回调函数
|
||
char buf[LOGGER_MAX_BUF_SIZE]; ///< 格式化缓冲区
|
||
};
|
||
|
||
int log_default_handler(logger_t *module, log_level_t level, const char *file,
|
||
int line, const char *func, const char *fmt, ...);
|
||
extern logger_t __default_logger_root;
|
||
|
||
/**
|
||
* @brief 初始化日志实例 其余参数设置为默认值
|
||
* @param[in] logger 日志器实例指针
|
||
* @param[in] name 日志器名称(NULL表示获取默认日志器名称)
|
||
*/
|
||
void init_logger(logger_t *logger, const char *name);
|
||
|
||
/**
|
||
* @brief 设置日志级别
|
||
* @param[in] logger 目标日志器实例
|
||
* @param[in] level 要设置的日志级别(可组合多个级别)
|
||
*/
|
||
void log_set_level(logger_t *logger, int level);
|
||
|
||
/**
|
||
* @brief 设置自定义日志处理器
|
||
* @param[in] logger 目标日志器实例
|
||
* @param[in] handler 自定义处理函数(NULL恢复默认处理)
|
||
*/
|
||
void log_set_handler(logger_t *logger, log_handler handler);
|
||
|
||
#ifndef LOG_MAX_MAROC_BUF_SIZE
|
||
#define LOG_MAX_MAROC_BUF_SIZE LOGGER_MAX_BUF_SIZE ///< 宏展开缓冲区尺寸
|
||
#endif
|
||
|
||
#define SCC_LOG_HANDLE_ARGS(_module_, _level_, ...) \
|
||
(_module_), (_level_), __FILE__, __LINE__, __func__, ##__VA_ARGS__
|
||
|
||
#define SCC_LOG_IMPL(_module_, _level_, _fmt_, ...) \
|
||
do { \
|
||
/* TODO check _module_ is NULL */ \
|
||
if ((_module_)->handler && ((_module_)->level & (_level_))) \
|
||
(_module_)->handler( \
|
||
SCC_LOG_HANDLE_ARGS(_module_, _level_, _fmt_, ##__VA_ARGS__)); \
|
||
} while (0)
|
||
|
||
/* clang-format off */
|
||
/// @name 模块日志宏
|
||
/// @{
|
||
#define MLOG_NOTSET(module, ...)SCC_LOG_IMPL(module, LOG_LEVEL_NOTSET, __VA_ARGS__) ///< 未分类日志
|
||
#define MLOG_DEBUG(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_DEBUG, __VA_ARGS__) ///< 调试日志(需启用DEBUG级别)
|
||
#define MLOG_INFO(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_INFO, __VA_ARGS__) ///< 信息日志(常规运行日志)
|
||
#define MLOG_WARN(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_WARN, __VA_ARGS__) ///< 警告日志(潜在问题)
|
||
#define MLOG_ERROR(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_ERROR, __VA_ARGS__) ///< 错误日志(可恢复错误)
|
||
#define MLOG_FATAL(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_FATAL, __VA_ARGS__) ///< 致命错误日志(程序终止前)
|
||
#define MLOG_TRACE(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_TRACE, __VA_ARGS__) ///< 追踪日志(调用栈跟踪)
|
||
/// @}
|
||
|
||
/// @name 快捷日志宏
|
||
/// @{
|
||
#define LOG_NOTSET(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_NOTSET, __VA_ARGS__) ///< 未分类日志
|
||
#define LOG_DEBUG(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_DEBUG, __VA_ARGS__) ///< 调试日志(需启用DEBUG级别)
|
||
#define LOG_INFO(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_INFO, __VA_ARGS__) ///< 信息日志(常规运行日志)
|
||
#define LOG_WARN(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_WARN, __VA_ARGS__) ///< 警告日志(潜在问题)
|
||
#define LOG_ERROR(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_ERROR, __VA_ARGS__) ///< 错误日志(可恢复错误)
|
||
#define LOG_FATAL(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_FATAL, __VA_ARGS__) ///< 致命错误日志(程序终止前)
|
||
#define LOG_TRACE(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_TRACE, __VA_ARGS__) ///< 追踪日志(调用栈跟踪)
|
||
/// @}
|
||
/* clang-format on */
|
||
|
||
/**
|
||
* @def _Assert
|
||
* @brief 断言检查内部宏
|
||
* @param cond 检查条件表达式
|
||
* @param ... 错误信息参数(格式字符串+参数)
|
||
*/
|
||
#define _Assert(cond, ...) \
|
||
((void)((cond) || \
|
||
(__default_logger_root.handler(SCC_LOG_HANDLE_ARGS( \
|
||
&__default_logger_root, LOG_LEVEL_FATAL, __VA_ARGS__)), \
|
||
log_exit(1), __smcc_log_unreachable(), 0)))
|
||
|
||
/// @name 断言工具宏
|
||
/// @{
|
||
#define __INNERSCC_LOG_IMPL_STR(str) #str
|
||
#define _SCC_LOG_IMPL_STR(str) __INNERSCC_LOG_IMPL_STR(str)
|
||
#define AssertFmt(cond, format, ...) \
|
||
_Assert(cond, "Assertion Failure: " format, \
|
||
##__VA_ARGS__) ///< 带格式的断言检查
|
||
#define PanicFmt(format, ...) \
|
||
_Assert(0, "Panic: " format, ##__VA_ARGS__) ///< 立即触发致命错误
|
||
#define Assert(cond) \
|
||
AssertFmt(cond, "cond is `" _SCC_LOG_IMPL_STR(cond) "`") ///< 基础断言检查
|
||
#define Panic(...) PanicFmt(__VA_ARGS__) ///< 触发致命错误(带自定义消息)
|
||
#define TODO() \
|
||
PanicFmt("TODO please implement me") ///< 标记未实现代码(触发致命错误)
|
||
#define UNREACHABLE() PanicFmt("UNREACHABLE") ///< 触发致命错误(代码不可达)
|
||
#define FIXME(str) \
|
||
PanicFmt("FIXME " _SCC_LOG_IMPL_STR( \
|
||
str)) ///< 提醒开发者修改代码(触发致命错误)
|
||
/// @}
|
||
|
||
/**
|
||
* @brief 静态断言(编译时)
|
||
*
|
||
* 利用数组大小不能为负的特性
|
||
* 或使用 _Static_assert (C11)
|
||
*/
|
||
#if __STDC_VERSION__ >= 201112L
|
||
#define StaticAssert static_assert
|
||
#else
|
||
#define StaticAssert(cond, msg) extern char __static_assertion[(cond) ? 1 : -1]
|
||
#endif
|
||
|
||
#ifdef __SCC_LOG_IMPL_IMPORT_SRC__
|
||
#include "log.c"
|
||
#endif
|
||
|
||
#endif /* __SCC_LOG_IMPL_H__ */
|