不知道为什么我会收到 std::__1 未定义符号错误
No Idea Why I'm getting std::__1 Undefined Symbols Error
我对 C++/CMake 很陌生,正在尝试创建一个可以编译 GRPC 项目的 CMake 文件。我可以使用此 CMake 生成客户端(只需要客户端)文件,但我正在尝试创建另一个文件(base.cpp
),它将从一个导入 class(ManagerClient
)这些文件。我决定为我想要的这个文件创建一个头文件 manager_client.h
.
我不太确定在 CMake 文件中的哪个位置编译 base.cpp
所以将其添加为目标目录之一并假设我制作的头文件会自动链接。在 运行ning 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
我找到了这个 ,但没有真正解释我如何解决我的问题。奇怪的是在制作 base.cpp
之前,我能够在 manager_client.cpp
的主要功能中 运行 base.cpp
逻辑没有任何问题,所以我怀疑我' m 通过 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()
您似乎误解了具有多个源文件的项目是如何工作的。
在一个有多个源文件的项目中,源文件通常被一个一个地构建成目标文件,然后目标文件被链接(与任何库一起)成为可执行程序文件。
使用 CMake,这是通过添加 one 可执行目标(带有 add_executable
)来完成的,该目标列出了要用于该程序的所有源文件。喜欢:
add_executable(program base.cpp manager_client.cpp)
这将导致构建从两个源文件 base.cpp
和 manager_client.cpp
创建可执行程序文件 program
(使用上述中间目标文件和链接器步骤)。
如前所述,此更改意味着您不应在源文件中重新定义 ManagerClient
class,而是 #include
头文件。
您也不应该在每个源文件中都有一个 main
函数,应该只在一个源文件中定义它。
我对 C++/CMake 很陌生,正在尝试创建一个可以编译 GRPC 项目的 CMake 文件。我可以使用此 CMake 生成客户端(只需要客户端)文件,但我正在尝试创建另一个文件(base.cpp
),它将从一个导入 class(ManagerClient
)这些文件。我决定为我想要的这个文件创建一个头文件 manager_client.h
.
我不太确定在 CMake 文件中的哪个位置编译 base.cpp
所以将其添加为目标目录之一并假设我制作的头文件会自动链接。在 运行ning 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
我找到了这个 base.cpp
之前,我能够在 manager_client.cpp
的主要功能中 运行 base.cpp
逻辑没有任何问题,所以我怀疑我' m 通过 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()
您似乎误解了具有多个源文件的项目是如何工作的。
在一个有多个源文件的项目中,源文件通常被一个一个地构建成目标文件,然后目标文件被链接(与任何库一起)成为可执行程序文件。
使用 CMake,这是通过添加 one 可执行目标(带有 add_executable
)来完成的,该目标列出了要用于该程序的所有源文件。喜欢:
add_executable(program base.cpp manager_client.cpp)
这将导致构建从两个源文件 base.cpp
和 manager_client.cpp
创建可执行程序文件 program
(使用上述中间目标文件和链接器步骤)。
如前所述,此更改意味着您不应在源文件中重新定义 ManagerClient
class,而是 #include
头文件。
您也不应该在每个源文件中都有一个 main
函数,应该只在一个源文件中定义它。