cmake_minimum_required(VERSION 3.12) # 项目名称:log4cpp_wrapper(避免与系统log4cpp库冲突),版本1.0.0 project(log4cpp_wrapper VERSION 1.0.0 LANGUAGES CXX) # === 1. 基础配置 === # 强制C++17标准,禁用扩展 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # 动态库必须开启位置无关代码 set(CMAKE_POSITION_INDEPENDENT_CODE ON) # 编译选项:调试信息、位置无关代码、警告增强 add_compile_options(-g -fPIC) # Debug模式启用地址 sanitizer(检测内存错误,Release模式自动关闭) set(SANITIZE_OPTIONS -fsanitize=address) add_compile_options($<$:${SANITIZE_OPTIONS}>) link_libraries($<$:${SANITIZE_OPTIONS}>) # === 2. 输出目录配置(统一产物路径) === set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) # 静态库 set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) # 动态库(.so) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # 可执行文件(如测试程序) # === 3. 路径配置(明确源文件/头文件/交付目录) === set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) # 源文件目录(当前CMake所在目录) set(INCLUDE_DIR ${SRC_DIR}) # 头文件目录(Log4CPP.h在当前目录) # 交付目录:参考你的示例路径,可通过外部参数修改 set(DELIVER_DIR "${CMAKE_BINARY_DIR}/../../Deliver" CACHE PATH "动态库交付目录(供其他模块使用)") get_filename_component(DELIVER_DIR ${DELIVER_DIR} ABSOLUTE) # 转为绝对路径 message(STATUS "=== 路径配置 ===") message(STATUS "源文件目录: ${SRC_DIR}") message(STATUS "头文件目录: ${INCLUDE_DIR}") message(STATUS "交付目录: ${DELIVER_DIR}") # === 4. 源文件与头文件列表(仅包含核心Log4CPP代码,排除测试文件) === set(SRC_FILES ${SRC_DIR}/Log4CPP.cpp # 核心实现文件 ) set(HEADER_FILES ${INCLUDE_DIR}/Log4CPP.h # 对外暴露的头文件(供其他模块引用) ) # 验证核心文件是否存在(避免编译失败) message(STATUS "=== 文件验证 ===") foreach(file ${SRC_FILES} ${HEADER_FILES}) if(NOT EXISTS ${file}) message(FATAL_ERROR "关键文件缺失: ${file}") else() message(STATUS "找到文件: ${file}") endif() endforeach() # === 5. 依赖查找(关键:找到系统中的log4cpp库) === message(STATUS "=== 依赖查找(log4cpp) ===") # 1. 查找log4cpp头文件(需包含 ) find_path(LOG4CPP_INCLUDE_DIR NAMES log4cpp/Category.hh # 要查找的头文件路径 PATHS /usr/include # 系统默认头文件目录(apt安装后路径) NO_DEFAULT_PATH # 仅搜索指定路径,避免冲突 ) # 2. 查找log4cpp库文件(动态库:liblog4cpp.so) find_library(LOG4CPP_LIB NAMES log4cpp liblog4cpp # 库名(Linux下会自动加lib前缀,故两种都检查) PATHS /usr/lib/${CMAKE_SYSTEM_PROCESSOR}-linux-gnu # 系统库目录(aarch64架构) NO_DEFAULT_PATH ) # 验证log4cpp依赖是否找到 if(NOT LOG4CPP_INCLUDE_DIR) message(FATAL_ERROR "未找到log4cpp头文件!请先安装:sudo apt install liblog4cpp5-dev") endif() if(NOT LOG4CPP_LIB) message(FATAL_ERROR "未找到log4cpp库文件!请先安装:sudo apt install liblog4cpp5-dev") else() message(STATUS "找到log4cpp头文件: ${LOG4CPP_INCLUDE_DIR}") message(STATUS "找到log4cpp库: ${LOG4CPP_LIB}") endif() # === 6. 构建动态库(核心目标:log4cpp_wrapper.so) === add_library(log4cpp_wrapper SHARED # SHARED表示动态库 ${SRC_FILES} ${HEADER_FILES} # 头文件加入目标,便于IDE识别(非编译必需) ) # === 7. 动态库属性配置(控制库的版本、名称等) === set_target_properties(log4cpp_wrapper PROPERTIES VERSION ${PROJECT_VERSION} # 完整版本:1.0.0 SOVERSION 1 # 主版本:1(兼容1.x.x版本) OUTPUT_NAME "log4cpp_wrapper" # 最终库文件名:liblog4cpp_wrapper.so PUBLIC_HEADER "${HEADER_FILES}" # 对外暴露的头文件(安装时会复制到include目录) # CXX_VISIBILITY_PRESET hidden # 隐藏内部符号,仅暴露必要接口(减少冲突) # VISIBILITY_INLINES_HIDDEN ON ) # === 8. 编译选项(增强代码质量与兼容性) === message(STATUS "=== 编译选项 ===") if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") # 适配GCC和Clang编译器 target_compile_options(log4cpp_wrapper PRIVATE -Wall # 开启所有警告 -Wextra # 额外警告 -Wpedantic # 严格遵循C++标准 -Werror=return-type # 函数无返回值时报错(避免逻辑漏洞) -Wno-unused-parameter # 可选:关闭未使用参数警告(根据需求调整) ) message(STATUS "启用警告选项:-Wall -Wextra -Wpedantic -Werror=return-type") endif() # === 9. 依赖关联(让动态库知道去哪里找头文件和链接库) === # 1. 头文件路径(当前项目头文件 + log4cpp头文件) target_include_directories(log4cpp_wrapper PUBLIC # 外部模块引用此库时,会自动包含这些目录 $ # 编译时:当前项目头文件 $ # 编译时:log4cpp头文件 $ # 安装后:外部引用时的头文件目录 ) # 添加 tinyxml2 依赖 find_package(PkgConfig REQUIRED) pkg_check_modules(TINYXML2 REQUIRED tinyxml2) # 添加包含目录 include_directories( ${TINYXML2_INCLUDE_DIRS} ) # 添加链接库 target_link_libraries(log4cpp_wrapper PUBLIC ${LOG4CPP_LIB} ${TINYXML2_LIBRARIES} PRIVATE pthread dl ) message(STATUS "链接依赖:${LOG4CPP_LIB} pthread dl") # === 10. 交付配置(改为创建符号链接,而非复制) === message(STATUS "=== 交付配置 ===") # 创建交付目录 file(MAKE_DIRECTORY ${DELIVER_DIR}/lib ${DELIVER_DIR}/include) # 1. 复制核心文件(只有这一个是真实文件,其他两个是链接) add_custom_command(TARGET log4cpp_wrapper POST_BUILD COMMENT "=== 复制核心库+创建符号链接到交付目录: ${DELIVER_DIR} ===" # 第一步:复制核心文件(liblog4cpp_wrapper.so.1.0.0)到交付目录 COMMAND ${CMAKE_COMMAND} -E copy_if_different $ # 源:核心文件(.so.1.0.0) ${DELIVER_DIR}/lib/ # 目标:交付目录的lib文件夹 # 第二步:创建主版本符号链接(.so.1 → .so.1.0.0) COMMAND ${CMAKE_COMMAND} -E create_symlink $ # 链接指向的目标文件名(.so.1.0.0) ${DELIVER_DIR}/lib/$ # 链接文件本身(.so.1) # 第三步:创建通用符号链接(.so → .so.1) COMMAND ${CMAKE_COMMAND} -E create_symlink $ # 链接指向的目标文件名(.so.1) ${DELIVER_DIR}/lib/$ # 链接文件本身(.so) # 复制头文件(这部分不变) COMMAND ${CMAKE_COMMAND} -E copy_if_different ${HEADER_FILES} ${DELIVER_DIR}/include/ ) # === 11. 安装配置(支持通过sudo make install安装到系统,便于全局引用) === message(STATUS "=== 安装配置 ===") install(TARGETS log4cpp_wrapper EXPORT log4cppWrapperTargets # 导出目标配置(供其他项目find_package使用) LIBRARY DESTINATION lib # 安装动态库到系统/lib目录 ARCHIVE DESTINATION lib # 若有静态库,安装到系统/lib目录 PUBLIC_HEADER DESTINATION include # 安装头文件到系统/include目录 PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ # 设置文件权限 ) # 导出配置文件(让其他项目通过find_package(log4cpp_wrapper)找到此库) install(EXPORT log4cppWrapperTargets FILE log4cppWrapperConfig.cmake DESTINATION lib/cmake/log4cpp_wrapper # 配置文件安装路径 EXPORT_LINK_INTERFACE_LIBRARIES # 导出链接依赖(避免外部项目手动链接log4cpp) ) message(STATUS "安装路径:系统lib -> /usr/local/lib,系统include -> /usr/local/include") # === 13. 调试信息输出(确认所有配置正确) === message(STATUS "=== 最终配置汇总 ===") message(STATUS "动态库名称: lib${CMAKE_PROJECT_NAME}.so (实际:liblog4cpp_wrapper.so)") message(STATUS "动态库输出: ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") message(STATUS "交付目录: ${DELIVER_DIR}") message(STATUS "是否构建测试: ${BUILD_TEST}")