事情源于我最近在使用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
I7
I7UQBVV3.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