【问题标题】:No Idea Why I'm getting std::__1 Undefined Symbols Error [duplicate]不知道为什么我会收到 std::__1 未定义符号错误 [重复]
【发布时间】:2022-01-12 12:13:55
【问题描述】:

我对 C++/CMake 还是很陌生,我正在尝试创建一个可以编译 GRPC 项目的 CMake 文件。我可以使用这个 CMake 生成客户端(只需要客户端)文件,但我正在尝试创建另一个文件(base.cpp),它将从其中一个文件中导入一个类(ManagerClient)。我决定为这个我想要的文件创建一个头文件,名为manager_client.h

我不太确定要在 CMake 文件的哪个位置编译 base.cpp,因此将其添加为目标目录之一,并假设我制作的头文件会自动链接。运行make 后,出现此错误:

Undefined symbols for architecture x86_64:
  "ManagerClient::ManagerClient(std::__1::shared_ptr<grpc::Channel>)", referenced from:
      ReadUntilClient::ReadUntilClient() in base.cpp.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [base] Error 1
make[1]: *** [CMakeFiles/base.dir/all] Error 2
make: *** [all] Error 2

我找到了这个question,但并没有真正解释如何解决我的问题。奇怪的是在制作base.cpp 之前,我能够在manager_client.cpp 的主函数中运行base.cpp 逻辑而没有任何问题,所以我怀疑我是通过CMake 还是我的头文件编译错了是错的。有什么想法吗?

代码如下:

manager_client.cpp

#include <grpcpp/grpcpp.h>
#include <grpc/grpc.h>
#include <grpcpp/channel.h>
#include <grpcpp/client_context.h>
#include <grpcpp/create_channel.h>
#include <grpcpp/security/credentials.h>
#include <string>
#include <memory>

#include "minknow_api/manager.grpc.pb.h"

using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using grpc::ClientReader;
using minknow_api::manager::ManagerService;
using minknow_api::manager::FlowCellPositionsRequest;
using minknow_api::manager::FlowCellPositionsResponse;


class ManagerClient {
  public:
    ManagerClient(std::shared_ptr<Channel> channel) : stub_(ManagerService::NewStub(channel)) {}

  std::unique_ptr<ClientReader<FlowCellPositionsResponse> > flow_cell_positions(FlowCellPositionsRequest request) {
      ClientContext context;
      return stub_->flow_cell_positions(&context, request);
  }
  private:
    std::unique_ptr<ManagerService::Stub> stub_;
};

int main(int argc, char* argv[]) {
  return 0;
}

manager_client.h

#pragma once

#include <grpcpp/grpcpp.h>
#include <grpc/grpc.h>
#include <grpcpp/channel.h>
#include <grpcpp/client_context.h>
#include <grpcpp/create_channel.h>
#include <grpcpp/security/credentials.h>
#include <string>
#include <memory>

#include "minknow_api/manager.grpc.pb.h"

using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using grpc::ClientReader;
using minknow_api::manager::ManagerService;
using minknow_api::manager::FlowCellPositionsRequest;
using minknow_api::manager::FlowCellPositionsResponse;

class ManagerClient {
  public:
    ManagerClient(std::shared_ptr<Channel> channel);
    std::unique_ptr<ClientReader<FlowCellPositionsResponse> > flow_cell_positions(FlowCellPositionsRequest request);
  private:
    std::unique_ptr<ManagerService::Stub> stub_;
};

base.cpp

#include <grpcpp/grpcpp.h>
#include <grpc/grpc.h>
#include <grpcpp/channel.h>
#include <grpcpp/client_context.h>
#include <grpcpp/create_channel.h>
#include <grpcpp/security/credentials.h>
#include <string>
#include <thread>
#include <memory>
#include <iostream>

#include "manager_client.h"
#include "minknow_api/manager.grpc.pb.h"

using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using grpc::ClientReader;
using minknow_api::manager::FlowCellPositionsRequest;
using minknow_api::manager::FlowCellPositionsResponse;

class ReadUntilClient {
  public:
    ManagerClient manager;
    ReadUntilClient() : manager(grpc::CreateChannel("127.0.0.1:9501",
                          grpc::InsecureChannelCredentials())) {}
};

int main(int argc, char* argv[]) {
  ReadUntilClient client;
  return 0;
}

CMakeLists.txt

// Above this I compile the proto files & I only included the code for relevant files
add_library(rg_grpc_proto
  ${man_grpc_srcs}
  ${man_grpc_hdrs}
  ${man_proto_srcs}
  ${man_proto_hdrs})
target_link_libraries(rg_grpc_proto
  ${_REFLECTION}
  ${_GRPC_GRPCPP}
  ${_PROTOBUF_LIBPROTOBUF})

foreach(_target
  manager_client
  base)
  add_executable(${_target}
    "${_target}.cpp")
  target_link_libraries(${_target}
    rg_grpc_proto
    ${_REFLECTION}
    ${_GRPC_GRPCPP}
    ${_PROTOBUF_LIBPROTOBUF})
endforeach()

【问题讨论】:

  • 你有一个ODR违规,ManagerClientmanager_client.cppmanager_client.h中的声明是不同的,manager_client.cpp应该包括manager_client.h而不是声明ManagerClient的新副本,只需定义构造函数和方法

标签: c++ cmake grpc


【解决方案1】:

您似乎误解了具有多个源文件的项目的工作原理。

在具有多个源文件的项目中,通常将源文件一个一个地构建到目标文件中,然后将目标文件(与任何库一起)链接到可执行程序文件中。

使用 CMake,这是通过添加 一个 可执行目标(带有add_executable)来完成的,该目标列出了要用于程序的所有源文件。喜欢:

add_executable(program base.cpp manager_client.cpp)

这将导致构建从两个源文件base.cppmanager_client.cpp 创建可执行程序文件program(使用上述中间目标文件和链接器步骤)。


如前所述,此更改意味着您不应在源文件中重新定义 ManagerClient 类,而是在头文件中重新定义 #include

您也不应该在每个源文件中都有main 函数,只应在单个源文件中定义它。

【讨论】:

    猜你喜欢
    • 2015-01-13
    • 2019-08-25
    • 1970-01-01
    • 2021-12-10
    • 2012-01-30
    • 1970-01-01
    • 2021-12-18
    • 2019-02-14
    • 1970-01-01
    相关资源
    最近更新 更多