使用jsoncpp库时出现链接问题

Linking problem when using jsoncpp library

本文关键字:链接 问题 jsoncpp 使用      更新时间:2023-10-16

我遇到了一个与解析JSON文件有关的问题。它由一组JSON对象组成,我开发的程序通过迭代文件中的各种{ ... }元素来解析它。

元素(在JSON文件中,这些是文件的行(的结构使得每一行中都可以有其他内部元素,但这超出了我现在必须处理的问题。

简而言之,我有一个Block;在它内部,除了其他字段之外,我还有一个类型为Operation的向量Operations,在这个向量中,每个元素都可以是Operation的子类型,例如VoteCommentFollowRepost...

为了处理这个问题,我创建了一个BlockStructure.hpp文件头,其中包括类Operation的定义以及(仅(虚拟方法print()和前面列出的类的定义。除了这些定义之外,还有TransactionBlockTransactionBlockStructure的定义

// BlockStructure.hpp
#include <string>
#include <list>
#include <utility>
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
using ui = unsigned int;

class Operation{
public:
string kind = "";
virtual string print();
};
class Vote : public Operation {
private:
string voter, author;
public:
Vote(string voter, string author);
virtual string print();
string get_voter();
string get_author();
};
class Comment : Operation{
private:
string parent_author, author, title, body;
public:
Comment(string parent_author, string author, string title, string body);
string get_author();
virtual string print();
};
class Follow : Operation{
private:
string follower, following;
vector<string> common_follows{};
public:
CustomJsonFollow(string follower, string following, vector<string> common_follows);
static void strip(vector<string> *w); // implements the common strip function
static void stripLeadingAndtrailingSpaces(string *stng); // implements the strip by removing the whitespaces 
string get_follower();
string get_following();
vector<string> get_common_follows();
virtual string print();
};
class Reblog : Operation{
private:
string account, author;
public:
CustomJsonReblog(string account, string author);
string get_account();
string get_author();
virtual string print();
};
class TransactionBlock{
private:
vector<Operation*> operations{};
string transaction_id;
int transaction_num = -1;
public:
TransactionBlock(vector<Operation*> ops);
TransactionBlock();
vector<Operation*> get_operations();
void set_operations(vector<Operation*> ops);
string get_transaction_id();
void set_transaction_id(string tid);
int get_transaction_num();
void set_transaction_num(int trn);
string print();
};

class Transaction{
private:
string transaction_id;
TransactionBlock transactionBlock;
public:
Transaction(string tr_id, TransactionBlock  transactionBlock);
string get_transaction_id();
void set_transaction_id(string tid);
TransactionBlock get_transaction_block();
void set_transaction_block(TransactionBlock tbl);
void print();
};
class BlockStructure{
private:
list<Transaction> transactions{};
string timestamp;
list<int> transaction_ids;
TransactionBlock transactionBlock;
public:
BlockStructure();
void set_transactions(list<Transaction> transact);
void set_transaction_block(TransactionBlock transactBlock);
void set_timestamp(string ts);
void set_transaction_ids(list<int> tr_ids);
void set_transaction_block(const TransactionBlock& tb);
TransactionBlock get_transaction_block();
void print_block();
};

然后,在另一个名为BlockStructure.cpp的文件中,我实现了头中定义的所有方法,因此:

// BlockStructure.cpp
#include "BlockStructure.hpp"
using namespace std;
using ui = unsigned int;
// Operation
string Operation::print(){
return "";
}

// Vote
Vote::Vote(string voter, string author) : voter(move(voter)), author(move(author)) { this->kind = "VOTE"; }
string Vote::print(){
string toret = "Vn";
toret += "voter: " + this->voter + "n";
toret += "auth: " + this->author + "n";
return toret;
}
string Vote::get_voter(){
return this->voter;
}
string Vote::get_author(){
return this->author;
}

// Comment
Comment::Comment(string parent_author, string author, string title, string body){
this->parent_author = move(parent_author);
this->author = move(author);
this->title = move(title);
this->body = move(body);
this->kind = "COMMENT";
}
string Comment::get_author(){
return this->author;
}
string Comment::print(){
string toret = "Cn";
toret += "par_auth: " + this->parent_author + "n";
toret += "auth: " + this->author + "n";
toret += "title: " + this->title + "n";
toret += "body: " + this->body + "n";
return toret;
}

// Follow
void Follow::strip(vector<string> *w) {
auto it = w->begin();
for (ui i = 0; i < w->size(); i++) {
stripLeadingAndtrailingSpaces(&(*it));
advance(it, 1);
}
}
void Follow::stripLeadingAndtrailingSpaces(string *stng) {
char *cur = const_cast<char *>(stng->c_str());
/* First remove leading spaces */
const char *firstNonSpace = cur;
while (*firstNonSpace != '' && isspace(*firstNonSpace))
++firstNonSpace;
size_t len = strlen(firstNonSpace) + 1;
memmove(cur, firstNonSpace, len);
/* Now remove trailing spaces */
char *endOfString = cur + len;
while (cur < endOfString && isspace(*endOfString))
--endOfString;
*endOfString = '';
}
Follow::Follow(string follower, string following, vector<string> common_follows, vector<string> required_posting_auths) {
this->follower = move(follower);
stripLeadingAndtrailingSpaces(&this->follower);
this->following = move(following);
stripLeadingAndtrailingSpaces(&this->following);
this->common_follows = move(common_follows);
strip(&this->common_follows);
this->kind = "FOLLOW";
}
string Follow::get_follower() {
return this->follower;
}
string Follow::get_following(){
return this->following;
}
vector<string> Follow::get_common_follows(){
return this->common_follows;
}
string Follow::print(){
string toret = "Fn";
toret += "follower: " + this->follower + "n";
toret += "following: " + this->following + "n";
if (!this->common_follows.empty()){
toret += "common_follows: n";
for (const string& w : this->common_follows)
toret += w + "n";
} else
toret += "common_follows: []n";
return toret;
}

// Reblog
Reblog::Reblog(string account, string author){
this->account = move(account);
this->author = move(author);
this->kind = "REBLOG";
}
string Reblog::get_account(){
return this->account;
}
string Reblog::get_author(){
return this->author;
}
string Reblog::print(){
string toret = "RBn";
toret += "account: " + this->account + "n";
toret += "author: " + this->author + "n";
return toret;
}

(类似于TransactionBlockTransactionBlockStructure(


然后,我将BlockStructure.hpp包含在下面定义的文件ParsingBlocks.cpp中。

"jsoncpp/dist/json/json.h"
"jsoncpp/dist/jsoncpp.cpp"

我在开头包含的文件是python amalgamate.py脚本的结果(该脚本也生成jsoncpp/dist/json/json-forward.h,但我读到它不常用于项目(。我读到这是一种在项目中集成JsonCpp的方法。

#include <fstream>
#include "jsoncpp/dist/json/json.h"
#include "jsoncpp/dist/jsoncpp.cpp"
#include "BlockStructure.hpp"
class ParsingBlocks {
private:
string path;
public:
ParsingBlocks(string path) : path(move(path)) {}
vector<Operation*> fill_ops(const Value& trans_operations){
vector<Operation*> op_array = {};
for(Value op : trans_operations) {
if (op[(UInt) 0].asString() == "vote") {
string voter = op[1]["voter"].asString();
Vote vt = Vote(op[1]["voter"].asString(), op[1]["author"].asString());
op_array.push_back((Operation*)&vt);
} else if (op[(UInt) 0].asString() == "comment") {
Comment cmt = Comment(op[1]["parent_author"].asString(),
op[1]["author"].asString(),
op[1]["title"].asString(),
op[1]["body"].asString());
op_array.push_back((Operation*)&cmt);
} else if (op[(UInt) 0].asString() == "custom_json") {
auto custom = op[(UInt) 1];
if (custom["id"].asString() == "follow") {
Value injs = custom["id"];
if (injs[(UInt) 0].asString() == "follow") {
vector<string> common_follows = {};
for (const auto &itr : injs[(UInt) 1]["common_follows"])
common_follows.push_back(itr.asString());
CustomJsonFollow follow = CustomJsonFollow(
injs[1]["follower"].asCString(),
injs[1]["following"].asCString(),
common_follows);
op_array.push_back((Operation*)&follow);
} else {
if (injs[(UInt) 0].asString() == "reblog") {
CustomJsonReblog reblog = CustomJsonReblog(
injs[(UInt) 1]["account"].asCString(),
injs[(UInt) 1]["author"].asCString());
op_array.push_back((Operation*)&reblog);
}
}
}
}
}
return op_array;

BlockStructure evaluate_block(const string& line){
ifstream ifs(line);
CharReaderBuilder reader;
Value data;
string errs;
Json::parseFromStream(reader, ifs, &data, &errs);
BlockStructure bs = BlockStructure();
for(Value::ArrayIndex i = 0; i != data.size(); i++){
bs.set_timestamp(data[i]["timestamp"].asString());
list<Transaction> transss{};
for(const Value& transaction : data[i]["transactions"]){
vector<Operation*> operations = fill_ops(transaction["operations"]);
auto t_block = new TransactionBlock();
t_block->set_transaction_num(transaction["transaction_num"].asInt());
if (!operations.empty()){
t_block->set_operations(operations);
}
Transaction t = Transaction(transaction["transaction_id"].asString(), *t_block);
transss.push_back(t);
}
bs.set_transactions(transss);
bs.set_witness_name(data[i]["witness"].asString());
}
return bs;
}
list<BlockStructure> parsing_blocks(){
string line;
ifstream file;
file.open(this->path);
list<BlockStructure> blocks{};
if(!file.is_open()){
perror("Error open");
exit(EXIT_FAILURE);
}
while (getline(file, line)){
BlockStructure b = evaluate_block(line);
blocks.push_back(b);
}
return blocks;
}
}

抛开可能的复制和粘贴错误(我认为我还没有做到(不谈,现在,我使用ParsingBlocks.cppmain.cpp中,定义如下:

#include "ParsingBlocks.cpp"
using namespace std;
int main() {
ParsingBlocks *pb = new ParsingBlocks("jsonfile.json");
list<BlockStructure> blocks = pb->parsing_blocks();
for(BlockStructure bl : blocks){
bl.print_block();
}
return 0;
}

我没有显示编译中使用的另一个类(UserStructure.cpp(,因为它对于问题来说是无用的。

我现在的问题是了解如何编译main.cpp文件。

我依赖jsoncpp外部库,所以在编译时,我从命令行执行以下命令:

c++ -std=c++17 -Wall -pedantic -I. .UserStructure.cpp .BlockStructure.hpp .BlockStructure.cpp .ParsingBlocks.cpp .main.cpp -o parsing.out

其中-I.标志用于链接当前目录中ParsingBlock.cpp文件开头的#includes中定义的jsoncpp.cppjson/json.h,如前所示。

编译给了我以下错误:

C:UsersUtenteAppDataLocalTempccDGeveZ.o:ParsingBlocks.cpp:(.text+0x2b6): first defined here
C:UsersUtenteAppDataLocalTempcc8uGWcY.o:main.cpp:(.text+0x2e0): multiple definition of `Json::Features::all()'
C:UsersUtenteAppDataLocalTempccDGeveZ.o:ParsingBlocks.cpp:(.text+0x2e0): first defined here
C:UsersUtenteAppDataLocalTempcc8uGWcY.o:main.cpp:(.text+0x2fe): multiple definition of `Json::Features::strictMode()'
C:UsersUtenteAppDataLocalTempccDGeveZ.o:ParsingBlocks.cpp:(.text+0x2fe): first defined here
C:UsersUtenteAppDataLocalTempcc8uGWcY.o:main.cpp:(.text+0x32c): multiple definition of `Json::Reader::containsNewLine(char const*, char const*)'
C:UsersUtenteAppDataLocalTempccDGeveZ.o:ParsingBlocks.cpp:(.text+0x32c): first defined here
C:UsersUtenteAppDataLocalTempcc8uGWcY.o:main.cpp:(.text+0x36e): multiple definition of `Json::Reader::Reader()'
C:UsersUtenteAppDataLocalTempccDGeveZ.o:ParsingBlocks.cpp:(.text+0x36e): first defined here
C:UsersUtenteAppDataLocalTempcc8uGWcY.o:main.cpp:(.text+0x36e): multiple definition of `Json::Reader::Reader()'
C:UsersUtenteAppDataLocalTempccDGeveZ.o:ParsingBlocks.cpp:(.text+0x36e): first defined here
C:UsersUtenteAppDataLocalTempcc8uGWcY.o:main.cpp:(.text+0x44a): multiple definition of `Json::Reader::Reader(Json::Features const&)'
C:UsersUtenteAppDataLocalTempccDGeveZ.o:ParsingBlocks.cpp:(.text+0x44a): first defined here
C:UsersUtenteAppDataLocalTempcc8uGWcY.o:main.cpp:(.text+0x44a): multiple definition of `Json::Reader::Reader(Json::Features const&)'
C:UsersUtenteAppDataLocalTempccDGeveZ.o:ParsingBlocks.cpp:(.text+0x44a): first defined here
C:UsersUtenteAppDataLocalTempcc8uGWcY.o:main.cpp:(.text+0x52a): multiple definition of `Json::Reader::parse(std::__cxx11::basic_string<char, 
std::char_traits<char>, std::allocator<char> > const&, Json::Value&, bool)'
C:UsersUtenteAppDataLocalTempccDGeveZ.o:ParsingBlocks.cpp:(.text+0x52a): first defined here
C:UsersUtenteAppDataLocalTempcc8uGWcY.o:main.cpp:(.text+0x5de): multiple definition of `Json::Reader::parse(std::istream&, Json::Value&, bool)'
C:UsersUtenteAppDataLocalTempccDGeveZ.o:ParsingBlocks.cpp:(.text+0x5de): first defined here
C:UsersUtenteAppDataLocalTempcc8uGWcY.o:main.cpp:(.text+0x698): multiple definition of `Json::Reader::parse(char const*, char const*, Json::Value&, bool)'
C:UsersUtenteAppDataLocalTempccDGeveZ.o:ParsingBlocks.cpp:(.text+0x698): first defined here
C:UsersUtenteAppDataLocalTempcc8uGWcY.o:main.cpp:(.text+0x934): multiple definition of `Json::Reader::readValue()'
C:UsersUtenteAppDataLocalTempccDGeveZ.o:ParsingBlocks.cpp:(.text+0x934): first defined here
C:UsersUtenteAppDataLocalTempcc8uGWcY.o:main.cpp:(.text+0x1032): multiple definition of `Json::Reader::skipCommentTokens(Json::Reader::Token&)'
C:UsersUtenteAppDataLocalTempccDGeveZ.o:ParsingBlocks.cpp:(.text+0x1032): first defined here
C:UsersUtenteAppDataLocalTempcc8uGWcY.o:main.cpp:(.text+0x1086): multiple definition of `Json::Reader::readToken(Json::Reader::Token&)'
C:UsersUtenteAppDataLocalTempccDGeveZ.o:ParsingBlocks.cpp:(.text+0x1086): first defined here
C:UsersUtenteAppDataLocalTempcc8uGWcY.o:main.cpp:(.text+0x1246): multiple definition of `Json::Reader::skipSpaces()'
C:UsersUtenteAppDataLocalTempccDGeveZ.o:ParsingBlocks.cpp:(.text+0x1246): first defined here

所以,很明显,这个问题正处于连接阶段,但我无法解决它!

我试着阅读stackoverflow.com上的文档和其他问题,但一无所获。

提前感谢您的帮助,如果这个问题有点大,我很抱歉。

EDIT:stderr输出并没有就此停止:至少有1000行错误,但每一行都涉及相同的multiple definition of ..., C:...: first defined here

保持#include为源文件("ParsingBlocks.cpp"answers"jsoncpp/dist/jsoncpp.cpp"(。

不要那样做。

它导致定义在您的最终程序中多次存在。

你的main.cpp应该是#include "ParsingBlocks.h",这样它就可以访问事物的声明

您应该编译jsoncpp/dist/jsoncpp.cpp并将其链接到构建工具中的可执行文件中,就像其他cpp文件一样:

c++ -std=c++17 -Wall -pedantic -I. 
UserStructure.cpp 
BlockStructure.cpp 
ParsingBlocks.cpp 
main.cpp 
jsoncpp/dist/jsoncpp.cpp 
-o parsing.out

反斜线换行是为了清楚起见,这样我们可以更容易地读取命令。

请注意,我还删除了您在头文件中链接的尝试。

有关如何构建程序的更多信息,请参阅您的C++手册。

在主文件中包含头文件,而不是源文件:

#include "ParsingBlocks.hpp"

C和C++中的#include不像许多其他语言那样是基于模块的include,而是直接插入文件的文本。这意味着ParsingBlocks.cpp中的所有内容都被编译器读取了两次:一次是在编译主文件时,另一次是编译ParsingBlocks.cpp本身时,因此重复。

此外,您不需要在编译器命令行中指定头文件。

您刚刚包含了一个cpp文件。只应包括头文件。通过包含cpp文件,编译器尝试多次定义方法。这基本上就是头文件存在的原因。