Link 小项目上 abi:cxx11 的问题
Link problems with abi:cxx11 on small project
我正在使用 here 中的 C++ 项目模板,它使用 CMake/Make 来构建项目并且包含很多电池(我对 C++ 比较陌生,但一般不会编程) .
我开始通过在头文件中实现所有内容来处理我的项目,现在想试用我的代码。但是,当我尝试编译代码(使用 ./configure
和 make
)时,我 运行 在链接期间出现以下错误。
[ 40%] Linking CXX executable ../../bin/projectname
/usr/bin/ld: CMakeFiles/projectname.dir/main.cxx.o: in function `Coordinator::get_price_at(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, boost::gregorian::date)':
/usr/include/c++/8.2.1/bits/unordered_map.h:977: undefined reference to `Coordinator::stocks[abi:cxx11]'
/usr/bin/ld: CMakeFiles/projectname.dir/main.cxx.o: in function `RandomStrategy::rebalance(boost::gregorian::date)':
/usr/include/c++/8.2.1/bits/hashtable.h:1256: undefined reference to `Coordinator::stocks[abi:cxx11]'
/usr/bin/ld: CMakeFiles/projectname.dir/main.cxx.o: in function `Coordinator::read_stock_data(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
/usr/include/c++/8.2.1/bits/fs_path.h:183: undefined reference to `std::filesystem::__cxx11::path::_M_split_cmpts()'
/usr/bin/ld: CMakeFiles/projectname.dir/main.cxx.o: in function `Coordinator::read_stock_data(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
/usr/include/c++/8.2.1/bits/fs_dir.h:356: undefined reference to `std::filesystem::__cxx11::directory_iterator::directory_iterator(std::filesystem::__cxx11::path const&, std::filesystem::directory_options, std::error_code*)'
/usr/bin/ld: CMakeFiles/projectname.dir/main.cxx.o: in function `Coordinator::read_stock_data(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
/home/jan/StockAnalyzer/src/Coordinator.h:55: undefined reference to `std::filesystem::__cxx11::directory_iterator::operator*() const'
/usr/bin/ld: CMakeFiles/projectname.dir/main.cxx.o: in function `Coordinator::read_stock_data(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
/usr/include/c++/8.2.1/bits/unordered_map.h:977: undefined reference to `Coordinator::stocks[abi:cxx11]'
/usr/bin/ld: CMakeFiles/projectname.dir/main.cxx.o: in function `Coordinator::read_stock_data(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
/home/jan/StockAnalyzer/src/Coordinator.h:55: undefined reference to `std::filesystem::__cxx11::directory_iterator::operator++()'
collect2: error: ld returned 1 exit status
经过大量搜索,我在基本目录的 CMakeLists.txt
文件中尝试了 add_definitions(-D_GLIBCXX_USE_CXX11ABI=0)
。我还通过添加 -v
进行了检查,这将传递给 gcc
。然而,它几乎没有任何改变。在另一个线程中,我发现在访问之前忘记 ClassName::
时会出现相同的错误
static_variables
,所以我检查了(相关行中没有发生)。
代码的相关部分:
main.cxx
:
#include <cstdlib>
#include <boost/program_options.hpp>
#include "app.h"
#include "Coordinator.h"
#include "RandomStrategy.h"
namespace po = boost::program_options;
po::options_description getDescription() {
po::options_description desc("Options");
desc.add_options()
("help,h", "Display this message")
("version,v", "Display the version number");
return desc;
}
void start() {
std::string RESOURCES_PATH = "/home/jan/StockAnalyzer/resources/";
long double investment_money = 50000;
Coordinator::read_stock_data(RESOURCES_PATH);
RNGType rng;
boost::uniform_real<> zero_to_one( 0.0, 1.0 );
RandomStrategy r(investment_money, rng, zero_to_one);
Strategy* cur_strat = &r;
}
int main(int argc, char **argv) {
start();
return 0;
}
Coordinator.h
:
#ifndef SRC_COORDINATOR_H_
#define SRC_COORDINATOR_H_
#include <vector>
#include <unordered_map>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/optional.hpp>
#include <boost/tokenizer.hpp>
#include <fstream>
#include <string>
#include <iostream>
#include <filesystem>
#include "StockData.h"
#include "Utility.h"
class Coordinator {
private:
static std::unordered_map<std::string, StockData> stocks;
public:
static StockData get_price_history(const std::string& stock_name) {
return Coordinator::stocks[stock_name];
}
static boost::optional<StockDataPoint> get_price_at(const std::string& stock_name, boost::gregorian::date date) {
StockData sd = Coordinator::stocks[stock_name];
for(StockDataPoint sdp : sd.get_price_history()) {
if(sdp.get_date() == date) {
return boost::optional<StockDataPoint>(sdp);
}
}
return boost::optional<StockDataPoint>();
}
static std::vector<std::string> get_all_stocks() {
return get_keys(Coordinator::stocks);
}
static void read_stock_data(const std::string& path_name) {
for (auto& file_name : std::filesystem::directory_iterator(path_name)) {
std::string file_name_string = file_name.path().string();
StockData cur_data;
std::vector<StockDataPoint> price_history;
std::ifstream stock_file(file_name_string);
std::string line;
while (std::getline(stock_file, line)) {
std::vector<std::string> split_input;
boost::split(split_input, line, [](char c){return c == ',';});
price_history.push_back(StockDataPoint(split_input));
}
cur_data.price_history = std::move(price_history);
Coordinator::stocks[file_name_string] = cur_data;
}
}
};
#endif
我在我的项目中同时使用了 Boost 库和 Qt - Boost 已经包含在内,并且由于 repo 已有 4 年历史,我怀疑 Cxx11 ABI 可能存在这个问题。但也许我只是忽略了 Coordinator.h
中的一些简单内容。我的 .cpp
文件只包含一个 #include "<File>.h"
如果在class中声明一个静态数据成员,类似于将一个变量声明为extern。此代码
class Foo {
static int data;
};
声明Foo::data。您需要将变量定义为 this
int Foo:data;
在编译单元中。
您的数据成员 Coordinator::stocks
需要类似的定义:
class Coordinator {
private:
typedef std::unordered_map<std::string, StockData> stocks_t;
static stocks_t stocks; // declaration
};
Coordinator::stocks_t Coordinator::stocks;// definition.
这将修复错误
undefined reference to `Coordinator::stocks'
我使用了 DRY(不要重复你自己)模式并引入了 typedef 以避免输入两次 STL 映射。
编辑:(根据 OP 给出的评论完成答案)。
未解决的外部问题
undefined reference to `std::filesystem::...
可以通过链接stdc++fs
库来解决。为此,应将 stdc++fs
添加到 CMakeFile 中的 TARGET_LINK_LIBRARIES。
我正在使用 here 中的 C++ 项目模板,它使用 CMake/Make 来构建项目并且包含很多电池(我对 C++ 比较陌生,但一般不会编程) .
我开始通过在头文件中实现所有内容来处理我的项目,现在想试用我的代码。但是,当我尝试编译代码(使用 ./configure
和 make
)时,我 运行 在链接期间出现以下错误。
[ 40%] Linking CXX executable ../../bin/projectname
/usr/bin/ld: CMakeFiles/projectname.dir/main.cxx.o: in function `Coordinator::get_price_at(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, boost::gregorian::date)':
/usr/include/c++/8.2.1/bits/unordered_map.h:977: undefined reference to `Coordinator::stocks[abi:cxx11]'
/usr/bin/ld: CMakeFiles/projectname.dir/main.cxx.o: in function `RandomStrategy::rebalance(boost::gregorian::date)':
/usr/include/c++/8.2.1/bits/hashtable.h:1256: undefined reference to `Coordinator::stocks[abi:cxx11]'
/usr/bin/ld: CMakeFiles/projectname.dir/main.cxx.o: in function `Coordinator::read_stock_data(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
/usr/include/c++/8.2.1/bits/fs_path.h:183: undefined reference to `std::filesystem::__cxx11::path::_M_split_cmpts()'
/usr/bin/ld: CMakeFiles/projectname.dir/main.cxx.o: in function `Coordinator::read_stock_data(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
/usr/include/c++/8.2.1/bits/fs_dir.h:356: undefined reference to `std::filesystem::__cxx11::directory_iterator::directory_iterator(std::filesystem::__cxx11::path const&, std::filesystem::directory_options, std::error_code*)'
/usr/bin/ld: CMakeFiles/projectname.dir/main.cxx.o: in function `Coordinator::read_stock_data(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
/home/jan/StockAnalyzer/src/Coordinator.h:55: undefined reference to `std::filesystem::__cxx11::directory_iterator::operator*() const'
/usr/bin/ld: CMakeFiles/projectname.dir/main.cxx.o: in function `Coordinator::read_stock_data(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
/usr/include/c++/8.2.1/bits/unordered_map.h:977: undefined reference to `Coordinator::stocks[abi:cxx11]'
/usr/bin/ld: CMakeFiles/projectname.dir/main.cxx.o: in function `Coordinator::read_stock_data(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
/home/jan/StockAnalyzer/src/Coordinator.h:55: undefined reference to `std::filesystem::__cxx11::directory_iterator::operator++()'
collect2: error: ld returned 1 exit status
经过大量搜索,我在基本目录的 CMakeLists.txt
文件中尝试了 add_definitions(-D_GLIBCXX_USE_CXX11ABI=0)
。我还通过添加 -v
进行了检查,这将传递给 gcc
。然而,它几乎没有任何改变。在另一个线程中,我发现在访问之前忘记 ClassName::
时会出现相同的错误
static_variables
,所以我检查了(相关行中没有发生)。
代码的相关部分:
main.cxx
:
#include <cstdlib>
#include <boost/program_options.hpp>
#include "app.h"
#include "Coordinator.h"
#include "RandomStrategy.h"
namespace po = boost::program_options;
po::options_description getDescription() {
po::options_description desc("Options");
desc.add_options()
("help,h", "Display this message")
("version,v", "Display the version number");
return desc;
}
void start() {
std::string RESOURCES_PATH = "/home/jan/StockAnalyzer/resources/";
long double investment_money = 50000;
Coordinator::read_stock_data(RESOURCES_PATH);
RNGType rng;
boost::uniform_real<> zero_to_one( 0.0, 1.0 );
RandomStrategy r(investment_money, rng, zero_to_one);
Strategy* cur_strat = &r;
}
int main(int argc, char **argv) {
start();
return 0;
}
Coordinator.h
:
#ifndef SRC_COORDINATOR_H_
#define SRC_COORDINATOR_H_
#include <vector>
#include <unordered_map>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/optional.hpp>
#include <boost/tokenizer.hpp>
#include <fstream>
#include <string>
#include <iostream>
#include <filesystem>
#include "StockData.h"
#include "Utility.h"
class Coordinator {
private:
static std::unordered_map<std::string, StockData> stocks;
public:
static StockData get_price_history(const std::string& stock_name) {
return Coordinator::stocks[stock_name];
}
static boost::optional<StockDataPoint> get_price_at(const std::string& stock_name, boost::gregorian::date date) {
StockData sd = Coordinator::stocks[stock_name];
for(StockDataPoint sdp : sd.get_price_history()) {
if(sdp.get_date() == date) {
return boost::optional<StockDataPoint>(sdp);
}
}
return boost::optional<StockDataPoint>();
}
static std::vector<std::string> get_all_stocks() {
return get_keys(Coordinator::stocks);
}
static void read_stock_data(const std::string& path_name) {
for (auto& file_name : std::filesystem::directory_iterator(path_name)) {
std::string file_name_string = file_name.path().string();
StockData cur_data;
std::vector<StockDataPoint> price_history;
std::ifstream stock_file(file_name_string);
std::string line;
while (std::getline(stock_file, line)) {
std::vector<std::string> split_input;
boost::split(split_input, line, [](char c){return c == ',';});
price_history.push_back(StockDataPoint(split_input));
}
cur_data.price_history = std::move(price_history);
Coordinator::stocks[file_name_string] = cur_data;
}
}
};
#endif
我在我的项目中同时使用了 Boost 库和 Qt - Boost 已经包含在内,并且由于 repo 已有 4 年历史,我怀疑 Cxx11 ABI 可能存在这个问题。但也许我只是忽略了 Coordinator.h
中的一些简单内容。我的 .cpp
文件只包含一个 #include "<File>.h"
如果在class中声明一个静态数据成员,类似于将一个变量声明为extern。此代码
class Foo {
static int data;
};
声明Foo::data。您需要将变量定义为 this
int Foo:data;
在编译单元中。
您的数据成员 Coordinator::stocks
需要类似的定义:
class Coordinator {
private:
typedef std::unordered_map<std::string, StockData> stocks_t;
static stocks_t stocks; // declaration
};
Coordinator::stocks_t Coordinator::stocks;// definition.
这将修复错误
undefined reference to `Coordinator::stocks'
我使用了 DRY(不要重复你自己)模式并引入了 typedef 以避免输入两次 STL 映射。
编辑:(根据 OP 给出的评论完成答案)。
未解决的外部问题
undefined reference to `std::filesystem::...
可以通过链接stdc++fs
库来解决。为此,应将 stdc++fs
添加到 CMakeFile 中的 TARGET_LINK_LIBRARIES。