windows中使用vcpkg安装gprc并在clion中调试过程总结
本文也可以认为是vcpkg安装包并在cmake中使用的教程,其中踩了很多坑,记录一下。
1.安装vcpkg
参考链接:
在D盘新建一个目录 D:dev用于安装vcpkg和存储后续安装的库,然后打开git bush,拿去vcpkg库:
git clone https://github.com/microsoft/vcpkg.git
然后执行命令:
# windows
.\bootstrap-vcpkg.bat
# 设置全局包含
.\vcpkg.exe integrate install
#linux
./bootstrap-vcpkg.sh
./vcpkg integrate install
结束后会在 D:\dev\vcpkg目录下看到一个 vcpkg.exe的可执行文件,将目录添加到环境变量path中,然后就可以在任意地方使用vcpkg命令了。
2.安装grpc
在这一步,需要注意的点就是选择合适的生成工具链,特别是在windows上。一般来说,vcpkg会选择默认工具链作为生成工具链,如果你的电脑上只有一种开发环境,比如vs2019,那么默认工具链就是vs2019。但是,如果电脑上安装有多个开发环境,比如安装vs2022,但同时安装了vs2019的开发环境,那么默认情况下会选择vs2022用作生成工具链,如果你的需求是使用vs2019生成动态库并与其他人一起开发,那么就会遇到问题,因为vs2022的工具链生成的动态库无法被vs2019工具链编译,在链接阶段会报错,因此混合开发环境的情况下需要手动指定生成工具链。
2.1永久修改工具链
#指定生成器为ninja
VCPKG_CMAKE_GENERATOR = Ninja
#指定生成工具链为vs2019
VCPKG_PLATFORM_TOOLSET = v142
#指定默认的编译环境为x64-windows
VCPKG_DEFAULT_TRIPLET = x64-windows
2.2临时修改工具链
set VCPKG_CMAKE_GENERATOR=Ninja
set VCPKG_PLATFORM_TOOLSET=v142
set VCPKG_DEFAULT_TRIPLET=x64-windows
2.3安装grpc
安装grpc会自动安装protobuf,因此只需要安装grpc即可:
vcpkg install grpc:x64-windows
注意,在安装过程中可能遇到下载文件卡壳的情况,这时可以检查是否是链接本身错误,或者手动下载文件,然后放到 D:\dev\vcpkg\downloads目录下,再重新安装。
安装完成后,在 D:\dev\vcpkg\installed\x64-windows目录下可以看到grpc的安装目录,其中包含了grpc的库文件和头文件。
3.在clion中使用grpc
文件内容放到文末。
在cmake中配置vcpkg中的包,需要做出额外的配置,否则会报错找不到库文件。
假设在安装包的时候选择的vs2022工具链,那么在clion中需要添加如下配置:

- 首先,将工具链调整到编译库对应的工具链;
- 然后,在cmake选项中添加如下命令(指定生成器为ninja,工具链为vs,最后指定vcpkg包目录):
-G Ninja -DCMAKE_C_COMPILER=cl -DCMAKE_CXX_COMPILER=cl -DCMAKE_TOOLCHAIN_FILE=D:/dev/vcpkg/scripts/buildsystems/vcpkg.cmake
为什么要做第二步的配置?
- 修改工具链到编译库时使用的工具链,确保项目能正常进行库链接;
- clion对vs生成器的兼容存在问题,导致无法高亮显示代码,因此需要指定生成器为ninja,这样clion就能正常高亮显示代码了。
4.项目文件
4.1 test.proto
syntax = "proto3";
package test;
service TestService {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
4.2 server.cpp
#include <grpcpp/grpcpp.h>
#include <iostream>
#include "test.grpc.pb.h"
using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using test::HelloRequest;
using test::HelloReply;
using test::TestService;
class ServiceImpl final : public TestService::Service {
Status SayHello(ServerContext* context, const HelloRequest* request,
HelloReply* reply) override {
std::string prefix("Hello from server ");
reply->set_message(prefix + request->name());
return Status::OK;
}
};
void RunServer() {
std::string server_address("0.0.0.0:50051");
ServiceImpl service;
ServerBuilder builder;
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
builder.RegisterService(&service);
std::unique_ptr<Server> server(builder.BuildAndStart());
std::cout << "Server listening on " << server_address << std::endl;
server->Wait();
}
int main() {
RunServer();
return 0;
}
4.3 client.cpp
#include <grpcpp/grpcpp.h>
#include <iostream>
#include "test.grpc.pb.h"
using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using test::HelloRequest;
using test::HelloReply;
using test::TestService;
class TestClient {
public:
TestClient(std::shared_ptr<Channel> channel)
: stub_(TestService::NewStub(channel)) {}
std::string SayHello(const std::string& name) {
HelloRequest request;
request.set_name(name);
HelloReply reply;
ClientContext context;
Status status = stub_->SayHello(&context, request, &reply);
if (status.ok()) {
return reply.message();
}
else {
return "RPC failed: " + status.error_message();
}
}
private:
std::unique_ptr<TestService::Stub> stub_;
};
int main() {
TestClient client(grpc::CreateChannel(
"localhost:50051", grpc::InsecureChannelCredentials()));
std::string name("World");
std::string response = client.SayHello(name);
std::cout << "Response: " << response << std::endl;
return 0;
}
4.4 CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(my_grpc_project)
# 设置 C++ 标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 查找依赖
find_package(protobuf REQUIRED)
find_package(gRPC REQUIRED)
message(STATUS "gRPC found: ${gRPC_FOUND}")
message(STATUS "gRPC version: ${gRPC_VERSION}")
message(STATUS "Protobuf found: ${protobuf_FOUND}")
message(STATUS "Protobuf version: ${protobuf_VERSION}")
# 生成 protobuf 和 gRPC 代码
set(PROTO_FILE "test.proto")
get_filename_component(PROTO_PATH ${PROTO_FILE} ABSOLUTE)
# 查找 protoc 和插件
find_program(PROTOC protoc)
find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin)
# 手动生成代码
set(PROTO_SRCS "${CMAKE_CURRENT_BINARY_DIR}/test.pb.cc")
set(PROTO_HDRS "${CMAKE_CURRENT_BINARY_DIR}/test.pb.h")
set(GRPC_SRCS "${CMAKE_CURRENT_BINARY_DIR}/test.grpc.pb.cc")
set(GRPC_HDRS "${CMAKE_CURRENT_BINARY_DIR}/test.grpc.pb.h")
add_custom_command(
OUTPUT ${PROTO_SRCS} ${PROTO_HDRS} ${GRPC_SRCS} ${GRPC_HDRS}
COMMAND ${PROTOC}
ARGS --grpc_out=${CMAKE_CURRENT_BINARY_DIR}
--cpp_out=${CMAKE_CURRENT_BINARY_DIR}
--plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
-I ${CMAKE_CURRENT_SOURCE_DIR}
${PROTO_FILE}
DEPENDS ${PROTO_FILE}
)
# 创建可执行文件
add_executable(server server.cpp
${PROTO_SRCS} ${PROTO_HDRS}
${GRPC_SRCS} ${GRPC_HDRS}
)
target_include_directories(server
PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
)
# 链接库
target_link_libraries(server PRIVATE
protobuf::libprotobuf
protobuf::libprotoc
gRPC::grpc++
gRPC::grpc++_reflection
)
# 创建可执行文件
add_executable(client client.cpp
${PROTO_SRCS} ${PROTO_HDRS}
${GRPC_SRCS} ${GRPC_HDRS}
)
target_include_directories(client
PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
)
# 链接库
target_link_libraries(client PRIVATE
protobuf::libprotobuf
protobuf::libprotoc
gRPC::grpc++
gRPC::grpc++_reflection
)