
简介这份资源是面向Windows平台C开发者的glog日志库集成包适合需要在Visual Studio 2017环境下为项目引入高效日志系统的中高级开发者。glog作为Google开源的跨平台日志工具支持INFO、WARNING、ERROR、FATAL多级别输出与堆栈回溯能帮助快速定位致命错误并分析程序运行状态。压缩包共13个文件约80KB包含5个cmake构建脚本、5个h头文件、1个lib静态库、1个dll动态库及1个pc配置文件覆盖编译、链接与pkgconfig集成所需的核心组件可直接用于VS2017工程配置。目前已有298人学习下载。通过该资源读者可获得在Windows下编译并调用glog的完整依赖文件结合头文件与库文件快速完成初始化、日志宏调用及输出目的地定制为大规模系统的日志管理与问题排查提供稳定支撑。1. glog for windows把 Linux 上那套日志库搬到 Windows 到底要改什么如果你在 Linux 上写 C 服务大概率用过 glogLOG(INFO) xxx一行就能打出带文件名、行号、时间戳、线程 ID 的日志还能按级别过滤、按大小滚动、崩溃时自动 dump。等到项目要出 Windows 版本很多人第一反应是「glog 不是跨平台吗直接编不就行了」。真动手就会发现CMake 能过不代表能跑能跑不代表日志文件落得下来落得下来不代表多线程下不串行、不丢行。这篇讲的就是 glog 在 Windows 上的完整落地路径从源码拉取、CMake 配置、静态库/动态库选择到google::InitGoogleLogging在 Windows 下的路径规则、FLAGS_logtostderr与文件输出的取舍再到 MSVC 运行库冲突、ERROR宏撞名、中文路径乱码这些血泪坑。适合两类人一是要把现有 Linux C 工程移植到 Windows 的工程师二是新项目直接想在 Windows 上用 glog 做日志底座的人。读完你应该能自己编出一份可用的 glog并知道哪些参数必须改、哪些默认值在 Windows 上会翻车。2. 在 Windows 上把 glog 编出来CMake 配置与三种产物形态2.1 先想清楚要静态库还是动态库Windows 下 glog 的产物形态直接决定后面链接和部署的方式选错了会在链接期或运行期反复折腾。常见三种形态产物适用场景注意点静态库glog.lib单 exe 分发、不想带 dll运行库必须和主工程一致动态库glog.dllglog.lib(导入库)多个模块共用、想统一升级需要导出宏、部署要带 dll源码内嵌直接把 src 加进主工程小项目、想省构建步骤编译选项要自己对齐我一般优先静态库因为 Windows 上 dll 的部署和版本对齐是额外成本除非你有多个 exe 共用同一份日志实现的需求。动态库那条路要额外处理GLOG_NO_ABBREVIATED_SEVERITIES和导出符号后面避坑章会细说。2.2 拉源码与 CMake 生成假设你已经装了 Visual Studio2019 或 2022 都行和 CMake并且cmake在 PATH 里。先拿源码git clone https://github.com/google/glog.git cd glog git checkout v0.6.0版本号按你实际需要的来这里只是给一个可复现的锚点。接着生成工程。关键是把BUILD_SHARED_LIBS、WITH_GFLAGS、CMAKE_INSTALL_PREFIX三个变量定死否则默认行为在不同版本间会变cmake -S . -B build -G Visual Studio 17 2022 -A x64 ^ -DBUILD_SHARED_LIBSOFF ^ -DWITH_GFLAGSOFF ^ -DWITH_UNWINDOFF ^ -DCMAKE_INSTALL_PREFIXD:/libs/glog ^ -DCMAKE_MSVC_RUNTIME_LIBRARYMultiThreadedDLL参数逐个说清楚-G Visual Studio 17 2022 -A x64生成 VS 工程目标 64 位。32 位就把-A x64换成-A Win32但别混用主工程和 glog 位数必须一致。BUILD_SHARED_LIBSOFF出静态库。要 dll 就设 ON。WITH_GFLAGSOFFglog 可以用 gflags 接管命令行参数但多数项目不需要关掉能少一个依赖。WITH_UNWINDOFFWindows 上没有 libunwind必须关否则配置阶段就报错。CMAKE_MSVC_RUNTIME_LIBRARYMultiThreadedDLL对应 MSVC 的/MD。这一项是 Windows 上最容易翻车的地方主工程用/MD你就得用/MD用/MT就统一/MT混用会在链接期报LNK2038运行库不匹配。生成完编译安装cmake --build build --config Release --target install装完在D:/libs/glog下会有include和lib或bin目录。Debug 配置同理把--config Release换成Debug但注意 Debug 和 Release 的运行库后缀不同/MDdvs/MD别拿 Debug 库去链 Release 主工程。2.3 在主工程里接上 glogCMake 主工程里最省事的接法是find_packagefind_package(glog REQUIRED) target_link_libraries(your_target PRIVATE glog::glog)如果find_package找不到就手动指定set(GLOG_ROOT D:/libs/glog) target_include_directories(your_target PRIVATE ${GLOG_ROOT}/include) target_link_libraries(your_target PRIVATE ${GLOG_ROOT}/lib/glog.lib)手动指定时别忘了把GLOG_ROOT/bin加进运行时 dll 搜索路径动态库形态才需要。静态库形态下链接完还要确保ws2_32.lib、dbghelp.lib这些系统库被带上glog 内部会用到通常 CMake 的 imported target 已经处理好手动链接时可能要自己补。3. 初始化与日志落盘Windows 路径规则和几个必调 FLAGS3.1 InitGoogleLogging 在 Windows 下到底做了什么google::InitGoogleLogging(argv[0])这个调用在 Linux 上很直观在 Windows 上它的行为差异集中在两点日志目录的默认值和路径分隔符处理。默认情况下glog 会把日志写到「当前工作目录」文件名形如your_program.HOSTNAME.user.log.INFO.20240101-120000.1234。Windows 上「当前工作目录」不一定是 exe 所在目录——你从资源管理器双击启动、从快捷方式启动、从命令行启动工作目录可能都不一样。这是新手最常见的「日志不知道跑哪去了」的原因。稳妥做法是显式指定目录并且用绝对路径#include glog/logging.h #include filesystem int main(int argc, char** argv) { // 用 exe 所在目录下的 logs 子目录避免依赖工作目录 std::filesystem::path exe_dir std::filesystem::absolute(argv[0]).parent_path(); std::filesystem::path log_dir exe_dir / logs; std::filesystem::create_directories(log_dir); // FLAGS_log_dir 接受窄字符串Windows 下中文路径要小心编码 FLAGS_log_dir log_dir.string(); google::InitGoogleLogging(argv[0]); // 同时输出到 stderr 和文件调试期很有用 FLAGS_alsologtostderr true; // 日志文件按大小滚动单位 MB FLAGS_max_log_size 50; // 保留最近 7 天的日志 FLAGS_logbufsecs 0; // 0 表示立即 flush调试期用生产别开 LOG(INFO) glog on windows started; LOG(WARNING) this is a warning; LOG(ERROR) this is an error; google::ShutdownGoogleLogging(); return 0; }逻辑说明argv[0]在 Windows 下可能是相对路径所以先absolute再取parent_path这样无论从哪启动日志都落在 exe 旁边。create_directories保证目录存在glog 自己不会建多级目录。参数说明FLAGS_log_dir日志目录。Windows 下如果路径含中文std::string的编码取决于你的源文件编码和系统区域设置可能乱码。稳妥做法是路径全用 ASCII或者用std::filesystem::path的宽字符接口自己转换后再赋值。FLAGS_alsologtostderr同时输出到 stderr。调试期开生产环境一般关避免控制台 IO 拖慢。FLAGS_max_log_size单文件上限单位 MB。默认值偏小服务类程序建议调到 50 或 100。FLAGS_logbufsecs缓冲刷新间隔秒数。默认 30 秒意味着崩溃时最后 30 秒日志可能丢。调试期设 0 立即刷生产环境权衡性能后设 1~5。3.2 日志级别与条件日志的常用写法glog 的级别是INFO/WARNING/ERROR/FATALFATAL会直接 abort。Windows 上FATAL触发的是abort()会弹「程序已停止工作」对话框服务类程序要提前用SetErrorMode抑制或者干脆别用FATAL。条件日志和频率限制是 glog 比裸printf好用的地方// 条件日志只有满足条件才打 LOG_IF(INFO, retry_count 3) retry exceeded, count retry_count; // 每 N 次打一条避免刷屏 LOG_EVERY_N(INFO, 1000) processed google::COUNTER items; // 前 N 次都打之后不打 LOG_FIRST_N(WARNING, 5) first 5 warnings only; // 限流每秒最多打 N 条 LOG_IF_EVERY_N(ERROR, has_error, 10) error sampled;google::COUNTER是 glog 提供的计数器配合LOG_EVERY_N用。这些宏在 Windows 上行为一致没有平台差异可以放心用。3.3 崩溃时的日志Windows 下要额外做什么glog 的InstallFailureSignalHandler在 Linux 上能捕获 SIGSEGV 等信号并打印堆栈但 Windows 的异常模型是 SEH不是 POSIX 信号。glog 在 Windows 上对InstallFailureSignalHandler的支持有限不能指望它像 Linux 那样工作。Windows 下要拿到崩溃堆栈常见做法是配合SetUnhandledExceptionFilter或直接用MiniDumpWriteDump生成 dump 文件再用 WinDbg 或 VS 分析。glog 在这里的角色是保证崩溃前的日志已经 flush 到磁盘FLAGS_logbufsecs 0; // 崩溃前日志不丢代价是每条日志都同步写盘性能下降明显。生产环境的折中是设一个较小的值1~2 秒并接受可能丢最后几条。4. Windows 上编 glog 最容易踩的五个坑4.1 坑一LNK2038 运行库不匹配现象链接时报LNK2038: 检测到RuntimeLibrary的不匹配项: 值MD_DynamicRelease不匹配值MT_StaticRelease。原因glog 编译时用的 MSVC 运行库和主工程不一致。/MD对应动态运行库/MT对应静态运行库两者不能混链。解决统一。要么两边都用/MD推荐和大多数第三方库一致要么都用/MT。在 CMake 里用CMAKE_MSVC_RUNTIME_LIBRARY显式指定别依赖默认值。改完记得清 build 目录重新生成CMake 缓存会记住旧设置。4.2 坑二ERROR 宏撞名现象包含glog/logging.h后代码里用到的ERROR标识符编译报错或者 Windows 头文件里的ERROR宏和 glog 冲突。原因Windows 的wingdi.h里定义了ERROR宏值为 0glog 的ERROR是日志级别枚举。谁先包含谁赢顺序不同报错不同。解决在包含 Windows 头文件之前定义GLOG_NO_ABBREVIATED_SEVERITIES这样 glog 用GLOG_ERROR而不是ERROR#define GLOG_NO_ABBREVIATED_SEVERITIES #include windows.h #include glog/logging.h注意这个宏必须在包含 glog 头文件之前定义且整个工程要一致否则会出现同一个符号两种定义。4.3 坑三日志文件不生成或生成在奇怪的地方现象程序跑了LOG(INFO)也执行了但找不到日志文件。原因三种可能。一是没调InitGoogleLoggingglog 在初始化前会丢弃日志。二是FLAGS_log_dir指向的目录不存在glog 不会自动创建。三是工作目录和你以为的不一样日志落在了别处。解决先确认InitGoogleLogging被调用且返回值正常再确认FLAGS_log_dir是绝对路径且目录已存在最后在InitGoogleLogging后立刻打一条LOG(INFO)并检查FLAGS_log_dir的实际值。调试期把FLAGS_alsologtostderr打开至少能在控制台看到日志确认日志系统本身是活的。4.4 坑四中文日志乱码现象LOG(INFO) 中文内容输出到文件或控制台是乱码。原因Windows 控制台默认代码页是 GBK936而源文件可能是 UTF-8std::string里存的是 UTF-8 字节直接输出到 GBK 控制台就乱码。文件输出同理取决于你用什么编辑器打开。解决统一编码。源文件存 UTF-8 with BOM 或 UTF-8 without BOM 都行但要在项目里统一。控制台输出前用SetConsoleOutputCP(CP_UTF8)把控制台切到 UTF-8。日志文件用支持 UTF-8 的编辑器打开。如果下游系统要求 GBK就在写日志前做一次编码转换别指望 glog 帮你转。4.5 坑五多线程下日志交错或丢失现象多线程程序里日志行互相穿插或者某些线程的日志莫名消失。原因glog 本身是线程安全的每条LOG宏展开后是一次完整的写入不会交错。出现交错通常是你在一条日志里用了多次且中间有耗时操作或者用了LOG_IF但条件判断本身有竞态。日志丢失则可能是FLAGS_logbufsecs太大程序退出时没调ShutdownGoogleLogging缓冲区没 flush。解决确保程序退出路径上调用google::ShutdownGoogleLogging()它会 flush 所有缓冲。多线程下如果对日志顺序有要求自己在业务层加锁别依赖 glog 的写入顺序。FLAGS_logbufsecs生产环境设 1~5别设太大。5. 进阶把 glog 接进 Windows 服务的几个实用技巧5.1 服务模式下日志目录该放哪Windows 服务默认工作目录是C:\Windows\System32如果你不显式设FLAGS_log_dir日志会写到系统目录普通用户没权限直接失败。服务里必须用绝对路径常见选择是%ProgramData%\YourApp\logs或 exe 同级的logs。// 服务里拿 ProgramData 路径 char program_data[MAX_PATH]; if (GetEnvironmentVariableA(ProgramData, program_data, MAX_PATH)) { std::filesystem::path log_dir std::filesystem::path(program_data) / YourApp / logs; std::filesystem::create_directories(log_dir); FLAGS_log_dir log_dir.string(); }服务账户对ProgramData下的自建目录通常有写权限比System32靠谱。5.2 用日志文件名区分实例同一台机器跑多个实例时glog 默认文件名里的 hostname 和 pid 能区分但不够直观。可以在InitGoogleLogging前改FLAGS_log_dir到不同子目录或者用google::SetLogDestination按级别指定不同文件前缀google::SetLogDestination(google::INFO, D:/logs/app_info_); google::SetLogDestination(google::ERROR, D:/logs/app_error_);这样 INFO 和 ERROR 分开文件排查时直接看 error 文件不用在几万行里 grep。5.3 验证日志系统是否真的在工作写完接入代码别急着上生产用一个最小验证程序跑一遍启动、打各级别日志、触发一次条件日志、正常退出然后检查日志文件是否存在、内容是否完整、时间戳是否正确、中文是否正常。再模拟一次崩溃LOG(FATAL)或空指针确认崩溃前日志已落盘。我自己的习惯是每个新项目接入 glog 后先写一个glog_smoke_test.cpp把上面这些场景跑一遍通过了再往业务代码里铺。这个习惯帮我省过好几次「上线后才发现日志根本没写」的后悔药。Windows 上的坑大多不在 glog 本身而在运行库、路径、编码这些平台细节上提前用最小程序验证一遍比在业务代码里 debug 快得多。希望帮到你。本文还有配套的精品资源点击获取