| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- cmake_minimum_required(VERSION 3.10)
- project(devGrpcClient VERSION 1.0.0 LANGUAGES CXX)
- # 设置编译选项
- set(CMAKE_CXX_STANDARD 17)
- set(CMAKE_CXX_STANDARD_REQUIRED ON)
- add_compile_options(-fPIC -g -Wall)
- # 目标目录
- set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
- get_filename_component(DELIVER_DIR "${CMAKE_BINARY_DIR}/../../Deliver" ABSOLUTE)
- file(MAKE_DIRECTORY "${DELIVER_DIR}/lib" "${DELIVER_DIR}/include")
- # ========== 强制使用动态链接和共享库 ==========
- # ARM Ubuntu 的系统静态库没有 -fPIC,无法链接到共享库
- # 使用 CACHE FORCE 确保覆盖任何缓存中的旧值
- set(GRPC_STATIC_LINK OFF CACHE BOOL "静态链接gRPC和Protobuf" FORCE)
- set(BUILD_SHARED_LIBS ON CACHE BOOL "编译为共享库(.so)" FORCE)
- # 强制输出消息确认配置
- message(STATUS "强制配置: GRPC_STATIC_LINK=${GRPC_STATIC_LINK}, BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}")
- # ========== 依赖查找:使用系统安装的 gRPC 和 Protobuf ==========
- # 强制使用系统路径,避免 /usr/local 下的多版本冲突
- set(CMAKE_FIND_USE_CMAKE_SYSTEM_PATH TRUE)
- set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH FALSE)
- # 1. 查找 Protobuf(优先使用系统路径)
- # 设置提示路径为系统目录
- set(Protobuf_ROOT "/usr")
- set(CMAKE_PREFIX_PATH "/usr" ${CMAKE_PREFIX_PATH})
- find_package(Protobuf REQUIRED HINTS /usr NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH)
- message(STATUS "找到系统Protobuf版本: ${Protobuf_VERSION}")
- message(STATUS "Protobuf头文件路径: ${Protobuf_INCLUDE_DIRS}")
- # 2. 查找 gRPC(通过CONFIG模式,适用于现代gRPC安装)
- find_package(gRPC CONFIG QUIET)
- if (gRPC_FOUND)
- message(STATUS "通过CONFIG模式找到系统gRPC版本: ${gRPC_VERSION}")
- else()
- # 回退到MODULE模式(旧版或自定义安装)
- find_package(gRPC MODULE QUIET)
- if (gRPC_FOUND)
- message(STATUS "通过MODULE模式找到gRPC")
- else()
- message(STATUS "未通过find_package找到gRPC,尝试使用pkg-config")
- find_package(PkgConfig REQUIRED)
- pkg_check_modules(GRPC REQUIRED grpc++ grpc)
- set(GRPC_LIBRARIES ${GRPC_LIBRARIES})
- set(GRPC_INCLUDE_DIRS ${GRPC_INCLUDE_DIRS})
- endif()
- endif()
- # 3. 查找gRPC代码生成器插件(增强查找逻辑)
- find_program(_GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin
- HINTS
- ${GRPC_CPP_PLUGIN_DIR}
- /usr/bin
- /usr/local/bin
- /usr/lib/grpc
- /usr/local/lib/grpc
- PATH_SUFFIXES bin
- )
- # 如果还是找不到,尝试从gRPC目标获取
- if(NOT _GRPC_CPP_PLUGIN_EXECUTABLE AND TARGET gRPC::grpc_cpp_plugin)
- get_target_property(_GRPC_CPP_PLUGIN_EXECUTABLE gRPC::grpc_cpp_plugin LOCATION)
- endif()
- # 最后尝试:直接使用which命令查找
- if(NOT _GRPC_CPP_PLUGIN_EXECUTABLE)
- execute_process(
- COMMAND which grpc_cpp_plugin
- OUTPUT_VARIABLE _GRPC_CPP_PLUGIN_EXECUTABLE
- OUTPUT_STRIP_TRAILING_WHITESPACE
- ERROR_QUIET
- )
- endif()
- if(NOT _GRPC_CPP_PLUGIN_EXECUTABLE)
- message(FATAL_ERROR
- "未找到 'grpc_cpp_plugin' 程序。\n"
- "请安装gRPC开发包:\n"
- " Ubuntu/Debian: sudo apt install protobuf-compiler-grpc libgrpc++-dev\n"
- " 或者设置 GRPC_CPP_PLUGIN_DIR 变量指向插件所在目录"
- )
- else()
- message(STATUS "找到gRPC编译器插件: ${_GRPC_CPP_PLUGIN_EXECUTABLE}")
- endif()
- # 4. 查找protoc编译器(优先使用与libprotobuf匹配的版本)
- # 首先尝试从 Protobuf 包获取
- if(TARGET protobuf::protoc)
- get_target_property(_PROTOBUF_PROTOC protobuf::protoc IMPORTED_LOCATION)
- if(NOT _PROTOBUF_PROTOC)
- get_target_property(_PROTOBUF_PROTOC protobuf::protoc LOCATION)
- endif()
- endif()
- # 如果没找到,使用 Protobuf_PROTOC_EXECUTABLE(由 find_package 设置)
- if(NOT _PROTOBUF_PROTOC AND Protobuf_PROTOC_EXECUTABLE)
- set(_PROTOBUF_PROTOC "${Protobuf_PROTOC_EXECUTABLE}")
- endif()
- # 最后回退到系统路径
- if(NOT _PROTOBUF_PROTOC)
- find_program(_PROTOBUF_PROTOC protoc
- HINTS
- /usr/bin
- /usr/local/bin
- )
- endif()
- if(NOT _PROTOBUF_PROTOC)
- message(FATAL_ERROR "未找到protoc编译器")
- endif()
- # 获取 protoc 版本并验证
- execute_process(
- COMMAND ${_PROTOBUF_PROTOC} --version
- OUTPUT_VARIABLE PROTOC_VERSION_OUTPUT
- OUTPUT_STRIP_TRAILING_WHITESPACE
- ERROR_QUIET
- )
- message(STATUS "找到Protobuf编译器: ${_PROTOBUF_PROTOC}")
- message(STATUS "Protoc版本: ${PROTOC_VERSION_OUTPUT}")
- message(STATUS "Protobuf库版本: ${Protobuf_VERSION}")
- # 警告版本不匹配
- string(REGEX MATCH "[0-9]+\\.[0-9]+" PROTOC_MAJOR_MINOR "${PROTOC_VERSION_OUTPUT}")
- string(REGEX MATCH "^[0-9]+\\.[0-9]+" PROTOBUF_MAJOR_MINOR "${Protobuf_VERSION}")
- if(NOT "${PROTOC_MAJOR_MINOR}" STREQUAL "${PROTOBUF_MAJOR_MINOR}")
- message(WARNING
- "protoc版本(${PROTOC_MAJOR_MINOR})与protobuf库版本(${PROTOBUF_MAJOR_MINOR})不匹配!\n"
- "这可能导致编译错误。请确保 protoc 和 libprotobuf-dev 版本一致。"
- )
- endif()
- # ========== 包含头文件目录 ==========
- # 强制优先使用系统 protobuf 头文件(/usr/include),避免 /usr/local 下的冲突版本
- include_directories(BEFORE SYSTEM
- /usr/include
- )
- include_directories(
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- ${CMAKE_CURRENT_BINARY_DIR}
- )
- # 只有当 Protobuf_INCLUDE_DIRS 是系统路径时才添加
- if(Protobuf_INCLUDE_DIRS AND "${Protobuf_INCLUDE_DIRS}" MATCHES "^/usr/include")
- include_directories(${Protobuf_INCLUDE_DIRS})
- endif()
- if(DEFINED GRPC_INCLUDE_DIRS)
- # 过滤掉 /usr/local 路径,只保留系统路径
- foreach(_dir ${GRPC_INCLUDE_DIRS})
- if(NOT "${_dir}" MATCHES "^/usr/local")
- include_directories(${_dir})
- endif()
- endforeach()
- endif()
- # ========== 编译Proto文件 ==========
- get_filename_component(DEV_PROTO "${CMAKE_CURRENT_SOURCE_DIR}/protos/device-sm.proto" ABSOLUTE)
- get_filename_component(DEV_PROTO_DIR "${DEV_PROTO}" PATH)
- set(DEV_PROTO_SRC "${CMAKE_CURRENT_BINARY_DIR}/device-sm.pb.cc")
- set(DEV_PROTO_HDR "${CMAKE_CURRENT_BINARY_DIR}/device-sm.pb.h")
- set(DEV_GRPC_SRC "${CMAKE_CURRENT_BINARY_DIR}/device-sm.grpc.pb.cc")
- set(DEV_GRPC_HDR "${CMAKE_CURRENT_BINARY_DIR}/device-sm.grpc.pb.h")
- # 清理旧的proto生成文件(防止跨版本不兼容)
- # 检查是否存在旧文件,如果protobuf版本变化则删除重新生成
- set(PROTO_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/.protobuf_version")
- if(EXISTS "${PROTO_VERSION_FILE}")
- file(READ "${PROTO_VERSION_FILE}" CACHED_PROTOBUF_VERSION)
- string(STRIP "${CACHED_PROTOBUF_VERSION}" CACHED_PROTOBUF_VERSION)
- if(NOT "${CACHED_PROTOBUF_VERSION}" STREQUAL "${Protobuf_VERSION}")
- message(STATUS "Protobuf版本变化 (${CACHED_PROTOBUF_VERSION} -> ${Protobuf_VERSION}),清理旧的proto文件")
- file(REMOVE "${DEV_PROTO_SRC}" "${DEV_PROTO_HDR}" "${DEV_GRPC_SRC}" "${DEV_GRPC_HDR}")
- endif()
- endif()
- file(WRITE "${PROTO_VERSION_FILE}" "${Protobuf_VERSION}")
- # 使用找到的protoc路径(兼容不同版本)
- add_custom_command(
- OUTPUT "${DEV_PROTO_SRC}" "${DEV_PROTO_HDR}" "${DEV_GRPC_SRC}" "${DEV_GRPC_HDR}"
- COMMAND ${_PROTOBUF_PROTOC}
- ARGS
- --grpc_out="${CMAKE_CURRENT_BINARY_DIR}"
- --cpp_out="${CMAKE_CURRENT_BINARY_DIR}"
- -I "${DEV_PROTO_DIR}"
- --plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}"
- "${DEV_PROTO}"
- DEPENDS "${DEV_PROTO}"
- COMMENT "生成gRPC proto代码 (protobuf ${Protobuf_VERSION})"
- )
- add_custom_target(GenerateProto ALL
- DEPENDS "${DEV_PROTO_SRC}" "${DEV_PROTO_HDR}" "${DEV_GRPC_SRC}" "${DEV_GRPC_HDR}"
- )
- # ========== 编译动态库 ==========
- set(SRC_FILES
- ${CMAKE_CURRENT_SOURCE_DIR}/src/devGrpcClient.cpp
- ${DEV_PROTO_SRC}
- ${DEV_GRPC_SRC}
- )
- # 根据选项编译为共享库或静态库
- if(BUILD_SHARED_LIBS)
- add_library(devGrpcClient SHARED ${SRC_FILES})
- else()
- add_library(devGrpcClient STATIC ${SRC_FILES})
- endif()
- add_dependencies(devGrpcClient GenerateProto)
- set_target_properties(devGrpcClient PROPERTIES
- VERSION ${PROJECT_VERSION}
- SOVERSION 1
- OUTPUT_NAME "devGrpcClient"
- )
- # ========== 链接依赖库 ==========
- if(GRPC_STATIC_LINK)
- message(STATUS "使用静态链接模式(提高跨系统兼容性)")
- # 查找静态库
- find_library(GRPC_STATIC_LIB libgrpc.a grpc PATHS /usr/lib /usr/local/lib /usr/lib/aarch64-linux-gnu /usr/lib/x86_64-linux-gnu)
- find_library(GRPCPP_STATIC_LIB libgrpc++.a grpc++ PATHS /usr/lib /usr/local/lib /usr/lib/aarch64-linux-gnu /usr/lib/x86_64-linux-gnu)
- find_library(GPR_STATIC_LIB libgpr.a gpr PATHS /usr/lib /usr/local/lib /usr/lib/aarch64-linux-gnu /usr/lib/x86_64-linux-gnu)
- find_library(ADDRESS_SORTING_LIB libaddress_sorting.a address_sorting PATHS /usr/lib /usr/local/lib /usr/lib/aarch64-linux-gnu /usr/lib/x86_64-linux-gnu)
- find_library(PROTOBUF_STATIC_LIB libprotobuf.a protobuf PATHS /usr/lib /usr/local/lib /usr/lib/aarch64-linux-gnu /usr/lib/x86_64-linux-gnu)
- find_library(CARES_LIB cares PATHS /usr/lib /usr/local/lib /usr/lib/aarch64-linux-gnu /usr/lib/x86_64-linux-gnu)
- find_library(RE2_LIB re2 PATHS /usr/lib /usr/local/lib /usr/lib/aarch64-linux-gnu /usr/lib/x86_64-linux-gnu)
- find_library(UPBDEFS_LIB upb_json_lib upb PATHS /usr/lib /usr/local/lib /usr/lib/aarch64-linux-gnu /usr/lib/x86_64-linux-gnu)
- # 检查是否找到静态库
- if(GRPCPP_STATIC_LIB AND GRPC_STATIC_LIB AND PROTOBUF_STATIC_LIB)
- message(STATUS "找到gRPC静态库: ${GRPCPP_STATIC_LIB}")
- message(STATUS "找到Protobuf静态库: ${PROTOBUF_STATIC_LIB}")
- # 构建静态链接列表
- set(GRPC_LINK_LIBS
- ${GRPCPP_STATIC_LIB}
- ${GRPC_STATIC_LIB}
- ${GPR_STATIC_LIB}
- ${PROTOBUF_STATIC_LIB}
- )
- # 添加可选依赖
- if(ADDRESS_SORTING_LIB)
- list(APPEND GRPC_LINK_LIBS ${ADDRESS_SORTING_LIB})
- endif()
- if(CARES_LIB)
- list(APPEND GRPC_LINK_LIBS ${CARES_LIB})
- endif()
- if(RE2_LIB)
- list(APPEND GRPC_LINK_LIBS ${RE2_LIB})
- endif()
- if(UPBDEFS_LIB)
- list(APPEND GRPC_LINK_LIBS ${UPBDEFS_LIB})
- endif()
- target_link_libraries(devGrpcClient PRIVATE
- -Wl,--start-group
- ${GRPC_LINK_LIBS}
- -Wl,--end-group
- pthread dl z ssl crypto
- )
- else()
- message(WARNING "未找到gRPC静态库,回退到动态链接模式")
- set(GRPC_STATIC_LINK OFF)
- endif()
- endif()
- if(NOT GRPC_STATIC_LINK)
- message(STATUS "使用动态链接模式")
- # 优先使用CMake目标
- if(TARGET gRPC::grpc++)
- target_link_libraries(devGrpcClient PRIVATE
- gRPC::grpc++
- protobuf::libprotobuf
- pthread dl z ssl crypto
- )
- elseif(DEFINED GRPC_LIBRARIES)
- # 使用pkg-config找到的库
- target_link_libraries(devGrpcClient PRIVATE
- ${GRPC_LIBRARIES}
- ${Protobuf_LIBRARIES}
- pthread dl z ssl crypto
- )
- else()
- # 最后回退:直接链接库名
- target_link_libraries(devGrpcClient PRIVATE
- grpc++ grpc gpr
- protobuf
- pthread dl z ssl crypto
- )
- endif()
- endif()
- # ========== 输出到交付目录 ==========
- if(BUILD_SHARED_LIBS)
- add_custom_command(TARGET devGrpcClient POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:devGrpcClient>" "${DELIVER_DIR}/lib/"
- COMMAND ${CMAKE_COMMAND} -E create_symlink "$<TARGET_FILE_NAME:devGrpcClient>" "${DELIVER_DIR}/lib/$<TARGET_SONAME_FILE_NAME:devGrpcClient>"
- COMMAND ${CMAKE_COMMAND} -E create_symlink "$<TARGET_SONAME_FILE_NAME:devGrpcClient>" "${DELIVER_DIR}/lib/$<TARGET_LINKER_FILE_NAME:devGrpcClient>"
- COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/src/devGrpcClient.h" "${DELIVER_DIR}/include/"
- )
- else()
- # 静态库只需要复制 .a 文件
- add_custom_command(TARGET devGrpcClient POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:devGrpcClient>" "${DELIVER_DIR}/lib/"
- COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/src/devGrpcClient.h" "${DELIVER_DIR}/include/"
- )
- endif()
- # ========== 打印配置摘要 ==========
- message(STATUS "========== devGrpcClient 配置摘要 ==========")
- message(STATUS "Protobuf版本: ${Protobuf_VERSION}")
- message(STATUS "gRPC版本: ${gRPC_VERSION}")
- message(STATUS "静态链接gRPC: ${GRPC_STATIC_LINK}")
- message(STATUS "编译为共享库: ${BUILD_SHARED_LIBS}")
- message(STATUS "交付目录: ${DELIVER_DIR}")
- message(STATUS "============================================")
|