情源于我最近在使用gRPC库,在编译时下意识使用了makefile编译,然后,编译时报错找不到库文件。
makefile 文件:
CC = g++ CFLAGS = -std=c++11 -I. -I/usr/local/include -L/usr/localb GFLAGS = -lgrpc++ -lgrpc -lprotobuf -lpthread -lz -lgpr all: measurement_client measurement_server measurement_client: client.cpp measurement.grpc.pb.cc $(CC) $(CFLAGS) -o measurement_client client.cpp measurement.grpc.pb.cc $(GFLAGS) measurement_server: server.cpp measurement.grpc.pb.cc $(CC) $(CFLAGS) -o measurement_server server.cpp measurement.grpc.pb.cc $(GFLAGS) run_server: ./measurement_server run_client: ./measurement_client clean: rm -f measurement_client measurement_server
在编译时报错一些库未定义:
![[TXYXKM`851N63V7SRX98E%V.png]]![[CBQGJRNZ0L8M{I 7 I7I7UQBVV3.png]]![[SP]]VXW3A_M9SJW5JOPV7K9.png]]
从这里看到缺失的都是它自己的一些库依赖。
然后就开始了漫长的查找过程,期间发现使用的是静态库,尝试编译成动态库,发现反而让库文件彻底混乱损坏了。
这里写一个列表,这是gRPC 需要的依赖库文件,可以看看有多少:
$ ls cmake libabsl_log_severity.a libabsl_throw_delegate.a libgrpc.a libgrpc_plugin_support.a libssl.a libabsl_bad_optional_access.a libabsl_raw_logging_internal.a libaddress_sorting.a libgrpc++.a libgrpcpp_channelz.a libupb.a libabsl_base.a libabsl_spinlock_wait.a libcares.a libgrpc++_alts.a libgrpc++_reflection.a libz.a libabsl_dynamic_annotations.a libabsl_strings.a libcrypto.a libgrpc_cronet.a libgrpc_unsecure.a pkgconfig libabsl_int128.a libabsl_strings_internal.a libgpr.a libgrpc++_error_details.a libgrpc++_unsecure.a
你可以尝试使用这个makefile
# Protobuf - 必须为 Protobuf3 PROTOBUF_HOME=/usr/local/protobuf PROTOBUF_INCL=-I${PROTOBUF_HOME}/include PROTOBUF_LIB=${PROTOBUF_HOME}/lib/libprotobuf.a ${PROTOBUF_HOME}/lib/libprotobuf-lite.a # gRPC GRPC_HOME=/usr/local GRPC_INCL=-I${GRPC_HOME}/include ABSL_LIB=${GRPC_HOME}/lib/libabsl_strings.a ${GRPC_HOME}/lib/libabsl_strings_internal.a ${GRPC_HOME}/lib/libabsl_throw_delegate.a ${GRPC_HOME}/lib/libabsl_base.a GRPC_LIB=${ABSL_LIB} ${GRPC_HOME}/lib/libgpr.a ${GRPC_HOME}/lib/libgrpc++.a ${GRPC_HOME}/lib/libgrpc.a ${GRPC_HOME}/lib/libupb.a ${GRPC_HOME}/lib/libssl.a ${GRPC_HOME}/lib/libcrypto.a ${GRPC_HOME}/lib/libcares.a ${GRPC_HOME}/lib/libaddress_sorting.a INCLS=${GRPC_INCL} ${PROTOBUF_INCL} LIBS=-pthread -ldl -lrt -lz -Wl,--start-group ${GRPC_LIB} ${PROTOBUF_LIB} -Wl,--end-group .PHONY: build build: g++ -std=c++11 -Wno-deprecated-declarations -o test test.cpp ../grpc/common.pb.cc ../grpc/proxy.pb.cc ../grpc/proxy.grpc.pb.cc -I../grpc ${INCLS} $(LIBS) .PHONY: clean clean: rm -f test
上述的“-Wno-deprecated-declarations”是为消除下列编译警告:
/usr/local/include/grpcpp/impl/codegen/proto_utils.h:52:32: 警告:不建议使用‘int google::protobuf::MessageLite::ByteSize() const’(声明于 /usr/local/include/google/protobuf/message_lite.h:402):Please use ByteSizeLong() instead [-Wdeprecated-declarations]
因为库实在有点多,为避免因为静态库顺序的坑,直接使用了“–start-group”和“–end-group”忽略顺序关系。建议使用CMake或automake编译,以省去处理依赖的麻烦。
以下是官方给出的 cmake 更加的简洁:
# Copyright 2018 gRPC authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # cmake build file for C++ DeviceData example. # Assumes protobuf and gRPC have been installed using cmake. # See cmake_externalproject/CMakeLists.txt for all-in-one cmake build # that automatically builds all the dependencies before building DeviceData. cmake_minimum_required(VERSION 3.5.1) project(DeviceData C CXX) include(../cmake/common.cmake) # Proto file get_filename_component(dev_proto "../../protos/DeviceData.proto" ABSOLUTE) get_filename_component(dev_proto_path "${dev_proto}" PATH) # Generated sources set(dev_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/DeviceData.pb.cc") set(dev_proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/DeviceData.pb.h") set(dev_grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/DeviceData.grpc.pb.cc") set(dev_grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/DeviceData.grpc.pb.h") add_custom_command( OUTPUT "${dev_proto_srcs}" "${dev_proto_hdrs}" "${dev_grpc_srcs}" "${dev_grpc_hdrs}" COMMAND ${_PROTOBUF_PROTOC} ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}" --cpp_out "${CMAKE_CURRENT_BINARY_DIR}" -I "${dev_proto_path}" --plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}" "${dev_proto}" DEPENDS "${dev_proto}") # Include generated *.pb.h files include_directories("${CMAKE_CURRENT_BINARY_DIR}") # dev_grpc_proto add_library(dev_grpc_proto ${dev_grpc_srcs} ${dev_grpc_hdrs} ${dev_proto_srcs} ${dev_proto_hdrs}) target_link_libraries(dev_grpc_proto ${_REFLECTION} ${_GRPC_GRPCPP} ${_PROTOBUF_LIBPROTOBUF}) # Targets greeter_[async_](client|server) foreach(_target greeter_client greeter_server # greeter_callback_client greeter_callback_server # greeter_async_client greeter_async_client2 greeter_async_server ) add_executable(${_target} "${_target}.cc") target_link_libraries(${_target} dev_grpc_proto ${_REFLECTION} ${_GRPC_GRPCPP} ${_PROTOBUF_LIBPROTOBUF}) endforeach()
其中引用的上级cmake 为common.cmake
:
# Copyright 2018 gRPC authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # cmake build file for C++ route_guide example. # Assumes protobuf and gRPC have been installed using cmake. # See cmake_externalproject/CMakeLists.txt for all-in-one cmake build # that automatically builds all the dependencies before building route_guide. cmake_minimum_required(VERSION 3.5.1) set (CMAKE_CXX_STANDARD 11) if(MSVC) add_definitions(-D_WIN32_WINNT=0x600) endif() find_package(Threads REQUIRED) if(GRPC_AS_SUBMODULE) # One way to build a projects that uses gRPC is to just include the # entire gRPC project tree via "add_subdirectory". # This approach is very simple to use, but the are some potential # disadvantages: # * it includes gRPC's CMakeLists.txt directly into your build script # without and that can make gRPC's internal setting interfere with your # own build. # * depending on what's installed on your system, the contents of submodules # in gRPC's third_party/* might need to be available (and there might be # additional prerequisites required to build them). Consider using # the gRPC_*_PROVIDER options to fine-tune the expected behavior. # # A more robust approach to add dependency on gRPC is using # cmake's ExternalProject_Add (see cmake_externalproject/CMakeLists.txt). # Include the gRPC's cmake build (normally grpc source code would live # in a git submodule called "third_party/grpc", but this example lives in # the same repository as gRPC sources, so we just look a few directories up) add_subdirectory(../../.. ${CMAKE_CURRENT_BINARY_DIR}/grpc EXCLUDE_FROM_ALL) message(STATUS "Using gRPC via add_subdirectory.") # After using add_subdirectory, we can now use the grpc targets directly from # this build. set(_PROTOBUF_LIBPROTOBUF libprotobuf) set(_REFLECTION grpc++_reflection) if(CMAKE_CROSSCOMPILING) find_program(_PROTOBUF_PROTOC protoc) else() set(_PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>) endif() set(_GRPC_GRPCPP grpc++) if(CMAKE_CROSSCOMPILING) find_program(_GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin) else() set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:grpc_cpp_plugin>) endif() elseif(GRPC_FETCHCONTENT) # Another way is to use CMake's FetchContent module to clone gRPC at # configure time. This makes gRPC's source code available to your project, # similar to a git submodule. message(STATUS "Using gRPC via add_subdirectory (FetchContent).") include(FetchContent) FetchContent_Declare( grpc GIT_REPOSITORY https://github.com/grpc/grpc.git # when using gRPC, you will actually set this to an existing tag, such as # v1.25.0, v1.26.0 etc.. # For the purpose of testing, we override the tag used to the commit # that's currently under test. GIT_TAG vGRPC_TAG_VERSION_OF_YOUR_CHOICE) FetchContent_MakeAvailable(grpc) # Since FetchContent uses add_subdirectory under the hood, we can use # the grpc targets directly from this build. set(_PROTOBUF_LIBPROTOBUF libprotobuf) set(_REFLECTION grpc++_reflection) set(_PROTOBUF_PROTOC $<TARGET_FILE:protoc>) set(_GRPC_GRPCPP grpc++) if(CMAKE_CROSSCOMPILING) find_program(_GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin) else() set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:grpc_cpp_plugin>) endif() else() # This branch assumes that gRPC and all its dependencies are already installed # on this system, so they can be located by find_package(). # Find Protobuf installation # Looks for protobuf-config.cmake file installed by Protobuf's cmake installation. set(protobuf_MODULE_COMPATIBLE TRUE) find_package(Protobuf CONFIG REQUIRED) message(STATUS "Using protobuf ${Protobuf_VERSION}") set(_PROTOBUF_LIBPROTOBUF protobuf::libprotobuf) set(_REFLECTION gRPC::grpc++_reflection) if(CMAKE_CROSSCOMPILING) find_program(_PROTOBUF_PROTOC protoc) else() set(_PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>) endif() # Find gRPC installation # Looks for gRPCConfig.cmake file installed by gRPC's cmake installation. find_package(gRPC CONFIG REQUIRED) message(STATUS "Using gRPC ${gRPC_VERSION}") set(_GRPC_GRPCPP gRPC::grpc++) if(CMAKE_CROSSCOMPILING) find_program(_GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin) else() set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_cpp_plugin>) endif() endif()
分享一个有趣的 学习链接:https://xxetb.xet.tech/s/HY8za