pybind11模块中fopen返回NULL及spdlog日志失效问题求助
让我帮你一步步排查这两个问题——先从fopen返回NULL的情况说起,再解决spdlog的日志问题:
fopen("log/module_cc.log", "w")返回NULL的问题 fopen返回NULL通常是路径、权限或工作目录的问题,你可以按以下顺序排查:
目标目录不存在:
fopen不会自动创建上级目录,如果log/文件夹不存在,写入会直接失败。你可以在调用fopen前先检查并创建目录:#ifdef _WIN32 #include <windows.h> CreateDirectoryA("log", NULL); #else #include <sys/stat.h> mkdir("log", 0755); #endif或者用C++17及以上的
std::filesystem来跨平台处理:#include <filesystem> std::filesystem::create_directory("log");权限不足:如果目标路径是系统只读目录(比如
/usr/bin或Windows的C:\Windows),当前进程没有写入权限会导致失败。建议先测试绝对路径,比如Linux/macOS用"/tmp/module_cc.log",Windows用"C:\\temp\\module_cc.log",看是否能成功写入。当前工作目录不符合预期:Python脚本运行时的工作目录可能和你设想的不一样(比如你在项目根目录跑脚本,但模块的当前目录是Python的site-packages目录)。你可以先打印当前工作目录确认:
// Linux/macOS #include <unistd.h> char cwd[256]; getcwd(cwd, sizeof(cwd)); printf("Current working dir: %s\n", cwd); // Windows #include <windows.h> char cwd[256]; GetCurrentDirectoryA(sizeof(cwd), cwd); printf("Current working dir: %s\n", cwd);或者在Python侧先执行
import os; print(os.getcwd()),确认相对路径的基准位置。打印具体错误信息:调用
fopen后用perror输出错误原因,能快速定位问题:FILE *fp = fopen("log/module_cc.log", "w"); if (!fp) { perror("fopen failed"); // 会输出类似 "fopen failed: No such file or directory" 的信息 }
你的spdlog初始化代码可能存在初始化时机、路径或日志级别的问题,结合fopen的排查思路,你可以尝试以下修复:
调整初始化时机:你的
ModuleInitializer静态对象定义在PYBIND11_MODULE宏之后,可能模块加载时的初始化顺序导致日志初始化未正确执行。建议把init_logger()直接放到PYBIND11_MODULE块内:PYBIND11_MODULE(my_module, m) { init_logger(); // 其他模块绑定代码 }使用绝对路径测试:和
fopen一样,相对路径可能找不到正确位置,把日志路径改成绝对路径试试:auto rotate_logger = spdlog::rotating_logger_mt( "my_module", "/tmp/my_module.log", MAX_ROTATE_SIZE, MAX_ROTATE_FILES);检查日志级别匹配:你设置的日志级别是
spdlog::level::info,但初始化时调用了SPDLOG_DEBUG("logging initialized");——debug级别低于info,这条日志会被过滤掉。可以把日志级别改成debug,或者换成SPDLOG_INFO来测试:const spdlog::level::level_enum LOG_LEVEL = spdlog::level::debug; // 或者 SPDLOG_INFO("logging initialized");开启错误回调捕获问题:spdlog默认会静默失败,添加错误回调可以看到具体错误:
static void init_logger() { spdlog::set_error_handler([](const std::string& msg) { std::cerr << "spdlog error: " << msg << std::endl; }); // 后续初始化代码 }确认spdlog链接正确:如果编译时没有正确链接spdlog库,日志功能会静默失效。确保你的构建脚本(比如CMake)里正确链接了spdlog:
find_package(spdlog REQUIRED) target_link_libraries(my_module PRIVATE spdlog::spdlog)
另外补充一点:Python的stdout/stderr重定向不影响文件描述符的使用,文件操作是直接调用系统API的,所以核心问题还是路径、权限或初始化时机。
内容的提问来源于stack exchange,提问作者linrongbin

