CMakeLists.txt 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. cmake_minimum_required(VERSION 3.12)
  2. # 项目名称:log4cpp_wrapper(避免与系统log4cpp库冲突),版本1.0.0
  3. project(log4cpp_wrapper VERSION 1.0.0 LANGUAGES CXX)
  4. # === 1. 基础配置 ===
  5. # 强制C++17标准,禁用扩展
  6. set(CMAKE_CXX_STANDARD 17)
  7. set(CMAKE_CXX_STANDARD_REQUIRED ON)
  8. set(CMAKE_CXX_EXTENSIONS OFF)
  9. # 动态库必须开启位置无关代码
  10. set(CMAKE_POSITION_INDEPENDENT_CODE ON)
  11. # 编译选项:调试信息、位置无关代码、警告增强
  12. add_compile_options(-g -fPIC)
  13. # Debug模式启用地址 sanitizer(检测内存错误,Release模式自动关闭)
  14. set(SANITIZE_OPTIONS -fsanitize=address)
  15. add_compile_options($<$<CONFIG:Debug>:${SANITIZE_OPTIONS}>)
  16. link_libraries($<$<CONFIG:Debug>:${SANITIZE_OPTIONS}>)
  17. # === 2. 输出目录配置(统一产物路径) ===
  18. set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) # 静态库
  19. set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) # 动态库(.so)
  20. set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # 可执行文件(如测试程序)
  21. # === 3. 路径配置(明确源文件/头文件/交付目录) ===
  22. set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) # 源文件目录(当前CMake所在目录)
  23. set(INCLUDE_DIR ${SRC_DIR}) # 头文件目录(Log4CPP.h在当前目录)
  24. # 交付目录:参考你的示例路径,可通过外部参数修改
  25. set(DELIVER_DIR "${CMAKE_BINARY_DIR}/../../Deliver" CACHE PATH "动态库交付目录(供其他模块使用)")
  26. get_filename_component(DELIVER_DIR ${DELIVER_DIR} ABSOLUTE) # 转为绝对路径
  27. message(STATUS "=== 路径配置 ===")
  28. message(STATUS "源文件目录: ${SRC_DIR}")
  29. message(STATUS "头文件目录: ${INCLUDE_DIR}")
  30. message(STATUS "交付目录: ${DELIVER_DIR}")
  31. # === 4. 源文件与头文件列表(仅包含核心Log4CPP代码,排除测试文件) ===
  32. set(SRC_FILES
  33. ${SRC_DIR}/Log4CPP.cpp # 核心实现文件
  34. )
  35. set(HEADER_FILES
  36. ${INCLUDE_DIR}/Log4CPP.h # 对外暴露的头文件(供其他模块引用)
  37. )
  38. # 验证核心文件是否存在(避免编译失败)
  39. message(STATUS "=== 文件验证 ===")
  40. foreach(file ${SRC_FILES} ${HEADER_FILES})
  41. if(NOT EXISTS ${file})
  42. message(FATAL_ERROR "关键文件缺失: ${file}")
  43. else()
  44. message(STATUS "找到文件: ${file}")
  45. endif()
  46. endforeach()
  47. # === 5. 依赖查找(关键:找到系统中的log4cpp库) ===
  48. message(STATUS "=== 依赖查找(log4cpp) ===")
  49. # 1. 查找log4cpp头文件(需包含 <log4cpp/Category.hh>)
  50. find_path(LOG4CPP_INCLUDE_DIR
  51. NAMES log4cpp/Category.hh # 要查找的头文件路径
  52. PATHS /usr/include # 系统默认头文件目录(apt安装后路径)
  53. NO_DEFAULT_PATH # 仅搜索指定路径,避免冲突
  54. )
  55. # 2. 查找log4cpp库文件(动态库:liblog4cpp.so)
  56. find_library(LOG4CPP_LIB
  57. NAMES log4cpp liblog4cpp # 库名(Linux下会自动加lib前缀,故两种都检查)
  58. PATHS /usr/lib/${CMAKE_SYSTEM_PROCESSOR}-linux-gnu # 系统库目录(aarch64架构)
  59. NO_DEFAULT_PATH
  60. )
  61. # 验证log4cpp依赖是否找到
  62. if(NOT LOG4CPP_INCLUDE_DIR)
  63. message(FATAL_ERROR "未找到log4cpp头文件!请先安装:sudo apt install liblog4cpp5-dev")
  64. endif()
  65. if(NOT LOG4CPP_LIB)
  66. message(FATAL_ERROR "未找到log4cpp库文件!请先安装:sudo apt install liblog4cpp5-dev")
  67. else()
  68. message(STATUS "找到log4cpp头文件: ${LOG4CPP_INCLUDE_DIR}")
  69. message(STATUS "找到log4cpp库: ${LOG4CPP_LIB}")
  70. endif()
  71. # === 6. 构建动态库(核心目标:log4cpp_wrapper.so) ===
  72. add_library(log4cpp_wrapper SHARED # SHARED表示动态库
  73. ${SRC_FILES}
  74. ${HEADER_FILES} # 头文件加入目标,便于IDE识别(非编译必需)
  75. )
  76. # === 7. 动态库属性配置(控制库的版本、名称等) ===
  77. set_target_properties(log4cpp_wrapper PROPERTIES
  78. VERSION ${PROJECT_VERSION} # 完整版本:1.0.0
  79. SOVERSION 1 # 主版本:1(兼容1.x.x版本)
  80. OUTPUT_NAME "log4cpp_wrapper" # 最终库文件名:liblog4cpp_wrapper.so
  81. PUBLIC_HEADER "${HEADER_FILES}" # 对外暴露的头文件(安装时会复制到include目录)
  82. # CXX_VISIBILITY_PRESET hidden # 隐藏内部符号,仅暴露必要接口(减少冲突)
  83. # VISIBILITY_INLINES_HIDDEN ON
  84. )
  85. # === 8. 编译选项(增强代码质量与兼容性) ===
  86. message(STATUS "=== 编译选项 ===")
  87. if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") # 适配GCC和Clang编译器
  88. target_compile_options(log4cpp_wrapper PRIVATE
  89. -Wall # 开启所有警告
  90. -Wextra # 额外警告
  91. -Wpedantic # 严格遵循C++标准
  92. -Werror=return-type # 函数无返回值时报错(避免逻辑漏洞)
  93. -Wno-unused-parameter # 可选:关闭未使用参数警告(根据需求调整)
  94. )
  95. message(STATUS "启用警告选项:-Wall -Wextra -Wpedantic -Werror=return-type")
  96. endif()
  97. # === 9. 依赖关联(让动态库知道去哪里找头文件和链接库) ===
  98. # 1. 头文件路径(当前项目头文件 + log4cpp头文件)
  99. target_include_directories(log4cpp_wrapper
  100. PUBLIC # 外部模块引用此库时,会自动包含这些目录
  101. $<BUILD_INTERFACE:${INCLUDE_DIR}> # 编译时:当前项目头文件
  102. $<BUILD_INTERFACE:${LOG4CPP_INCLUDE_DIR}> # 编译时:log4cpp头文件
  103. $<INSTALL_INTERFACE:include> # 安装后:外部引用时的头文件目录
  104. )
  105. # 添加 tinyxml2 依赖
  106. find_package(PkgConfig REQUIRED)
  107. pkg_check_modules(TINYXML2 REQUIRED tinyxml2)
  108. # 添加包含目录
  109. include_directories(
  110. ${TINYXML2_INCLUDE_DIRS}
  111. )
  112. # 添加链接库
  113. target_link_libraries(log4cpp_wrapper
  114. PUBLIC
  115. ${LOG4CPP_LIB}
  116. ${TINYXML2_LIBRARIES}
  117. PRIVATE
  118. pthread
  119. dl
  120. )
  121. message(STATUS "链接依赖:${LOG4CPP_LIB} pthread dl")
  122. # === 10. 交付配置(改为创建符号链接,而非复制) ===
  123. message(STATUS "=== 交付配置 ===")
  124. # 创建交付目录
  125. file(MAKE_DIRECTORY ${DELIVER_DIR}/lib ${DELIVER_DIR}/include)
  126. # 1. 复制核心文件(只有这一个是真实文件,其他两个是链接)
  127. add_custom_command(TARGET log4cpp_wrapper POST_BUILD
  128. COMMENT "=== 复制核心库+创建符号链接到交付目录: ${DELIVER_DIR} ==="
  129. # 第一步:复制核心文件(liblog4cpp_wrapper.so.1.0.0)到交付目录
  130. COMMAND ${CMAKE_COMMAND} -E copy_if_different
  131. $<TARGET_FILE:log4cpp_wrapper> # 源:核心文件(.so.1.0.0)
  132. ${DELIVER_DIR}/lib/ # 目标:交付目录的lib文件夹
  133. # 第二步:创建主版本符号链接(.so.1 → .so.1.0.0)
  134. COMMAND ${CMAKE_COMMAND} -E create_symlink
  135. $<TARGET_FILE_NAME:log4cpp_wrapper> # 链接指向的目标文件名(.so.1.0.0)
  136. ${DELIVER_DIR}/lib/$<TARGET_SONAME_FILE_NAME:log4cpp_wrapper> # 链接文件本身(.so.1)
  137. # 第三步:创建通用符号链接(.so → .so.1)
  138. COMMAND ${CMAKE_COMMAND} -E create_symlink
  139. $<TARGET_SONAME_FILE_NAME:log4cpp_wrapper> # 链接指向的目标文件名(.so.1)
  140. ${DELIVER_DIR}/lib/$<TARGET_LINKER_FILE_NAME:log4cpp_wrapper> # 链接文件本身(.so)
  141. # 复制头文件(这部分不变)
  142. COMMAND ${CMAKE_COMMAND} -E copy_if_different
  143. ${HEADER_FILES}
  144. ${DELIVER_DIR}/include/
  145. )
  146. # === 11. 安装配置(支持通过sudo make install安装到系统,便于全局引用) ===
  147. message(STATUS "=== 安装配置 ===")
  148. install(TARGETS log4cpp_wrapper
  149. EXPORT log4cppWrapperTargets # 导出目标配置(供其他项目find_package使用)
  150. LIBRARY DESTINATION lib # 安装动态库到系统/lib目录
  151. ARCHIVE DESTINATION lib # 若有静态库,安装到系统/lib目录
  152. PUBLIC_HEADER DESTINATION include # 安装头文件到系统/include目录
  153. PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ # 设置文件权限
  154. )
  155. # 导出配置文件(让其他项目通过find_package(log4cpp_wrapper)找到此库)
  156. install(EXPORT log4cppWrapperTargets
  157. FILE log4cppWrapperConfig.cmake
  158. DESTINATION lib/cmake/log4cpp_wrapper # 配置文件安装路径
  159. EXPORT_LINK_INTERFACE_LIBRARIES # 导出链接依赖(避免外部项目手动链接log4cpp)
  160. )
  161. message(STATUS "安装路径:系统lib -> /usr/local/lib,系统include -> /usr/local/include")
  162. # === 13. 调试信息输出(确认所有配置正确) ===
  163. message(STATUS "=== 最终配置汇总 ===")
  164. message(STATUS "动态库名称: lib${CMAKE_PROJECT_NAME}.so (实际:liblog4cpp_wrapper.so)")
  165. message(STATUS "动态库输出: ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
  166. message(STATUS "交付目录: ${DELIVER_DIR}")
  167. message(STATUS "是否构建测试: ${BUILD_TEST}")