CMAKE GOOGLETEST在集合集合中会重新定义错误
CMake + GoogleTest gives redefinitions errors in collection of small libraries
我在学校使用了多个非常小的库。每个库都与Google测试文件一起放在自己的文件夹中。这使我可以在各种作业中利用这些功能。库有时会互相依赖。
我正在尝试使用cmake构建单个测试可执行文件,该测试结合了所有库的测试,因此我可以使用更改的库更改库本身或其他库中的某些行为。不幸的是,我正在挣扎:有一个库的CSV和另一个使用该CSV库的库AnterVector。运行Cmake生成的制造时,这会以某种方式给出重新分配错误,但我不明白为什么以及如何解决此问题。
项目的结构(可以在此处找到:https://github.com/martenbe/algoritmen):
.
├── chrono
│ ├── chrono-simple.cpp
│ ├── chrono-simple.h
│ └── chrono-simple-test.cpp
├── CMakeLists.txt
├── CMakeLists.txt.in
├── csv
│ ├── csv.h
│ └── csv-test.cpp
├── generate_makefile.sh
├── intstring
│ ├── intstring.h
│ └── intstring-test.cpp
├── README.md
└── sorteren
├── sorteermethode.h
├── sorteermethode-test.cpp
├── sortvector.h
└── sortvector-test.cpp
如何运行
./generate_makefile.sh
cd build
make
./unittest
cmake文件将直接从此处指定的github a中拉动googletest(这是根目录中的cmakelists的底部,并进行一些修改):https://github.com/google/google/googletest/blob/blob/master/master/master/googletest/readme.md#commutation-into-and an-an-and and and and and an-project
运行时的错误输出:
- 配置完成
-- Generating done
-- Build files have been written to: /home/martijn/git/Algoritmen-I/labos/libraries/build/googletest-download
gmake[1]: Entering directory '/home/martijn/git/Algoritmen-I/labos/libraries/build/googletest-download'
gmake[2]: Entering directory '/home/martijn/git/Algoritmen-I/labos/libraries/build/googletest-download'
gmake[3]: Entering directory '/home/martijn/git/Algoritmen-I/labos/libraries/build/googletest-download'
gmake[3]: Leaving directory '/home/martijn/git/Algoritmen-I/labos/libraries/build/googletest-download'
gmake[3]: Entering directory '/home/martijn/git/Algoritmen-I/labos/libraries/build/googletest-download'
[ 11%] Performing update step for 'googletest'
Current branch master is up to date.
[ 22%] No configure step for 'googletest'
[ 33%] No build step for 'googletest'
[ 44%] No install step for 'googletest'
[ 55%] No test step for 'googletest'
[ 66%] Completed 'googletest'
gmake[3]: Leaving directory '/home/martijn/git/Algoritmen-I/labos/libraries/build/googletest-download'
[100%] Built target googletest
gmake[2]: Leaving directory '/home/martijn/git/Algoritmen-I/labos/libraries/build/googletest-download'
gmake[1]: Leaving directory '/home/martijn/git/Algoritmen-I/labos/libraries/build/googletest-download'
Created test "unittest"
-- Configuring done
-- Generating done
-- Build files have been written to: /home/martijn/git/Algoritmen-I/labos/libraries/build
[ 16%] Built target gtest
[ 33%] Built target gtest_main
[ 50%] Built target gmock
Scanning dependencies of target unittest
[ 58%] Linking CXX executable unittest
/usr/bin/ld: CMakeFiles/unittest.dir/sorteren/sorteermethode-test.cpp.o: in function `CsvData::voeg_data_toe(std::vector<double, std::allocator<double> > const&)':
/home/martijn/git/Algoritmen-I/labos/libraries/sorteren/../csv/csv.h:83: multiple definition of `CsvData::voeg_data_toe(std::vector<double, std::allocator<double> > const&)'; CMakeFiles/unittest.dir/csv/csv-test.cpp.o:/home/martijn/git/Algoritmen-I/labos/libraries/csv/csv.h:83: first defined here
/usr/bin/ld: CMakeFiles/unittest.dir/sorteren/sorteermethode-test.cpp.o:(.bss+0x8): multiple definition of `CsvData::extensie[abi:cxx11]'; CMakeFiles/unittest.dir/csv/csv-test.cpp.o:(.bss+0x8): first defined here
/usr/bin/ld: CMakeFiles/unittest.dir/sorteren/sorteermethode-test.cpp.o: in function `testing::Test::TearDownTestSuite()':
/home/martijn/git/Algoritmen-I/labos/libraries/sorteren/../csv/csv.h:49: multiple definition of `CsvData::CsvData(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char, char)'; CMakeFiles/unittest.dir/csv/csv-test.cpp.o:/home/martijn/git/Algoritmen-I/labos/libraries/csv/csv.h:49: first defined here
/usr/bin/ld: CMakeFiles/unittest.dir/sorteren/sorteermethode-test.cpp.o: in function `testing::Test::TearDownTestSuite()':
/home/martijn/git/Algoritmen-I/labos/libraries/sorteren/../csv/csv.h:49: multiple definition of `CsvData::CsvData(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char, char)'; CMakeFiles/unittest.dir/csv/csv-test.cpp.o:/home/martijn/git/Algoritmen-I/labos/libraries/csv/csv.h:49: first defined here
/usr/bin/ld: CMakeFiles/unittest.dir/sorteren/sorteermethode-test.cpp.o: in function `CsvData::write_to_file() const':
/home/martijn/git/Algoritmen-I/labos/libraries/sorteren/../csv/csv.h:129: multiple definition of `CsvData::write_to_file() const'; CMakeFiles/unittest.dir/csv/csv-test.cpp.o:/home/martijn/git/Algoritmen-I/labos/libraries/csv/csv.h:129: first defined here
/usr/bin/ld: CMakeFiles/unittest.dir/sorteren/sorteermethode-test.cpp.o: in function `CsvData::geef_bestandsnaam[abi:cxx11]() const':
/home/martijn/git/Algoritmen-I/labos/libraries/sorteren/../csv/csv.h:124: multiple definition of `CsvData::geef_bestandsnaam[abi:cxx11]() const'; CMakeFiles/unittest.dir/csv/csv-test.cpp.o:/home/martijn/git/Algoritmen-I/labos/libraries/csv/csv.h:124: first defined here
/usr/bin/ld: CMakeFiles/unittest.dir/sorteren/sorteermethode-test.cpp.o: in function `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::operator=(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&)':
/home/martijn/git/Algoritmen-I/labos/libraries/sorteren/../csv/csv.h:94: multiple definition of `CsvData::to_string[abi:cxx11]() const'; CMakeFiles/unittest.dir/csv/csv-test.cpp.o:/home/martijn/git/Algoritmen-I/labos/libraries/csv/csv.h:94: first defined here
clang-7: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [CMakeFiles/unittest.dir/build.make:147: unittest] Error 1
make[1]: *** [CMakeFiles/Makefile2:75: CMakeFiles/unittest.dir/all] Error 2
make: *** [Makefile:141: all] Error 2
如何解决这些问题?是否有更好的方法来构建由小型库组成的项目?我真的更喜欢将每个库保留在自己的子文件夹中。
ps:我现在的代码不是很漂亮,它是给我们的,我在此过程中对其进行了重构,所以它仍然很混乱,而且不是最佳练习。
cmakelists.txt
set(SOURCES
)
set(ADDITIONAL_INPUT_FILES
)
set(TEST_SOURCES
chrono/chrono-simple-test.cpp
csv/csv-test.cpp
intstring/intstring-test.cpp
sorteren/sorteermethode-test.cpp
sorteren/sortvector-test.cpp
)
set(ADDITIONAL_TEST_FILES
)
### executable #################################################################
cmake_minimum_required(VERSION 3.9)
project (proj)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_BUILD_TYPE debug)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -Wextra -O0")
# set(CMAKE_CXX_CLANG_TIDY "clang-tidy;-checks=*,-boost-*,-google-*,-llvm-*;-header-filter=.*")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -Wextra")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
endif()
if (SOURCES)
foreach(FILE ${ADDITIONAL_INPUT_FILES})
message("Copying file ${FILE}")
configure_file(${FILE} ${FILE} COPYONLY)
endforeach(FILE)
add_executable(${PROJECT_NAME} ${SOURCES})
endif()
### unittest ###################################################################
if (TEST_SOURCES)
# Download and unpack googletest at configure time
configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download)
if(result)
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
endif()
execute_process(COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download)
if(result)
message(FATAL_ERROR "Build step for googletest failed: ${result}")
endif()
# Prevent overriding the parent project's compiler/linker
# settings on Windows
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
# Add googletest directly to our build. This defines
# the gtest and gtest_main targets.
add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
${CMAKE_BINARY_DIR}/googletest-build
EXCLUDE_FROM_ALL)
# The gtest/gtest_main targets carry header search path
# dependencies automatically when using CMake 2.8.11 or
# later. Otherwise we have to add them here ourselves.
if (CMAKE_VERSION VERSION_LESS 2.8.11)
include_directories("${gtest_SOURCE_DIR}/include")
endif()
foreach(FILE ${ADDITIONAL_TEST_FILES})
message("Copying file ${FILE}")
get_filename_component(FILE_NAME ${FILE} NAME)
configure_file(${FILE} ${FILE_NAME} COPYONLY)
endforeach(FILE)
enable_testing()
# Create the build executable
set(TEST_EXECUTABLE_NAME "unittest")
add_executable(${TEST_EXECUTABLE_NAME} ${TEST_SOURCES})
target_link_libraries(${TEST_EXECUTABLE_NAME} gtest_main gmock)
add_test("${TEST_EXECUTABLE_NAME}_ctest" ${TEST_EXECUTABLE_NAME})
message("Created test "${TEST_EXECUTABLE_NAME}"")
endif()
csv.h:
#ifndef CSV_H
#define CSV_H
#include <algorithm>
#include <cassert>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
class CsvData
{
public:
// Scheidingsteken: teken in vlottendekommagetallen
// Voor een Nederlandstalige excel, scheidingsteken ',' opgeven
CsvData(const std::string& bestandsnaam, char scheidingsteken = '.', char delimiter = 't');
template <class T> // T kan int, unsigned int, float, ... zijn
void voeg_data_toe(const std::vector<T>& toe_te_voegen_data);
void voeg_data_toe(const std::vector<double>& nieuwe_data);
std::string to_string() const;
std::string geef_bestandsnaam() const;
void write_to_file() const;
protected:
std::vector<std::vector<double>> data;
char scheidingsteken;
char delimiter;
std::string bestandsnaam;
int max_kolom_grootte = 0;
static constexpr int kolombreedte = 12;
static constexpr int precisie = 6;
static const std::string extensie;
};
const std::string CsvData::extensie{".csv"};
// Scheidingsteken: teken in vlottendekommagetallen
// Voor een Nederlandstalige excel, scheidingsteken ',' opgeven
CsvData::CsvData(const std::string& bestandsnaam, char scheidingsteken, char delimiter)
: scheidingsteken{scheidingsteken}, delimiter{delimiter}, bestandsnaam{bestandsnaam}
{
if (bestandsnaam.empty())
{
throw "Lege bestandsnaam";
}
int begin_extensie = bestandsnaam.rfind(extensie);
if (begin_extensie == 0)
{
throw "Ongeldige bestandsnaam";
}
if ((begin_extensie == std::string::npos) || (begin_extensie != (bestandsnaam.size() - extensie.size())))
{
this->bestandsnaam.append(extensie);
}
}
template <class T> // T kan int, unsigned int, float, ... zijn
void CsvData::voeg_data_toe(const std::vector<T>& toe_te_voegen_data)
{
std::vector<double> nieuwe_data;
nieuwe_data.reserve(toe_te_voegen_data.size());
for (const T& d : toe_te_voegen_data)
{
nieuwe_data.push_back(static_cast<double>(d));
}
voeg_data_toe(nieuwe_data);
}
void CsvData::voeg_data_toe(const std::vector<double>& nieuwe_data)
{
data.push_back(nieuwe_data);
int kolom_grootte = nieuwe_data.size();
if (kolom_grootte > max_kolom_grootte)
{
max_kolom_grootte = kolom_grootte;
}
}
std::string CsvData::to_string() const
{
std::stringstream out;
for (int i = 0; i < max_kolom_grootte; i++)
{
for (int j = 0; j < data.size(); j++)
{
if (i < data[j].size())
{
out << std::setprecision(precisie) << std::scientific << data[j][i];
}
if (j == (data.size() - 1))
{
out << 'n';
}
else
{
out << delimiter;
}
}
}
std::string content = out.str();
std::replace(content.begin(), content.end(), '.', scheidingsteken);
return content;
}
std::string CsvData::geef_bestandsnaam() const
{
return bestandsnaam;
}
void CsvData::write_to_file() const
{
std::ofstream out(bestandsnaam);
assert(out);
out << to_string();
}
#endif
sortVector.h
#ifndef SORTVECTOR_H
#define SORTVECTOR_H
/**
class sortvector
brief is een klasse van sorteerbare vectoren
Bovenop de vectoreigenschappen zijn er hulpfuncties om sorteervergelijkingen
te vergemakkelijken.
*/
#include <algorithm>
#include <cassert>
#include <iomanip>
#include <iostream>
#include <limits>
#include <random>
#include <vector>
template <class T>
class Sortvector : public std::vector<T>
{
public:
/// fn Constructor: het argument geeft de grootte aan
/// bij constructie zal de tabel opgevuld worden met
/// n verschillende Ts in random volgorde
/// (zie hulplidfuncties)
Sortvector(int);
Sortvector(const Sortvector<T>& v) = delete;
Sortvector<T>& operator=(const Sortvector<T>& v) = delete;
Sortvector<T>& operator=(Sortvector<T>&& v) = delete;
Sortvector(Sortvector<T>&& v) = delete;
/// fn vul_range vul vector met de waarden T(0)...T(size()-1) in volgorde
void vul_range();
void draai_om();
void vul_omgekeerd();
void shuffle();
void vul_random_zonder_dubbels();
void vul_random(); //< nog niet implementeren
bool is_gesorteerd() const;
/// fn is_range controleert of *this eruit ziet als het resultaat van vul_range(), d.w.z.
/// dat, voor alle i, (*this)[i]==T(i);
bool is_range() const;
friend std::ostream& operator<<(std::ostream& os, const Sortvector<T>& s)
{
s.schrijf(os);
return os;
}
private:
void schrijf(std::ostream& os) const;
};
template <class T>
Sortvector<T>::Sortvector(int grootte) : std::vector<T>(grootte)
{
vul_random();
}
template <class T>
void Sortvector<T>::vul_range()
{
T waarde{0};
for (auto& data : (*this))
{
data = waarde;
waarde++;
}
}
template <class T>
void Sortvector<T>::draai_om()
{
std::reverse(this->begin(), this->end());
}
template <class T>
void Sortvector<T>::shuffle()
{
std::random_device rd;
std::mt19937 eng{rd()};
std::shuffle(this->begin(), this->end(), eng);
}
template <class T>
void Sortvector<T>::vul_omgekeerd()
{
T waarde{0};
std::for_each(this->rbegin(), this->rend(), [&](T& data) {
data = waarde;
waarde++;
});
}
template <class T>
void Sortvector<T>::vul_random_zonder_dubbels()
{
vul_range();
shuffle();
}
template <class T>
void Sortvector<T>::vul_random()
{
std::random_device rd;
std::mt19937 eng{rd()};
assert((this->size() - 1) < std::numeric_limits<int>::max());
std::uniform_int_distribution<int> dist{0, static_cast<int>(this->size() - 1)};
for (auto& i : (*this))
{
i = dist(rd);
}
}
template <class T>
bool Sortvector<T>::is_gesorteerd() const
{
if (this->size() <= 1)
{
return true;
}
for (int i = 1; i < this->size(); i++)
{
if ((*this)[i - 1] > (*this)[i])
{
return false;
}
}
return true;
}
template <class T>
bool Sortvector<T>::is_range() const
{
if (this->size() <= 1)
{
return true;
}
for (int i = 1; i < this->size(); i++)
{
if ((*this)[i] != ((*this)[i - 1] + 1))
{
return false;
}
}
return true;
}
template <class T>
void Sortvector<T>::schrijf(std::ostream& os) const
{
for (auto&& t : *this)
{
os << t << " ";
}
os << "n";
}
#endif
您需要将实现放在csv.cpp
文件中,除了模板:
const std::string CsvData::extensie{".csv"};
// Scheidingsteken: teken in vlottendekommagetallen
// Voor een Nederlandstalige excel, scheidingsteken ',' opgeven
CsvData::CsvData(const std::string& bestandsnaam, char scheidingsteken, char delimiter)
: scheidingsteken{scheidingsteken}, delimiter{delimiter}, bestandsnaam{bestandsnaam}
{
if (bestandsnaam.empty())
{
throw "Lege bestandsnaam";
}
int begin_extensie = bestandsnaam.rfind(extensie);
if (begin_extensie == 0)
{
throw "Ongeldige bestandsnaam";
}
if ((begin_extensie == std::string::npos) || (begin_extensie != (bestandsnaam.size() - extensie.size())))
{
this->bestandsnaam.append(extensie);
}
}
void CsvData::voeg_data_toe(const std::vector<double>& nieuwe_data)
{
data.push_back(nieuwe_data);
int kolom_grootte = nieuwe_data.size();
if (kolom_grootte > max_kolom_grootte)
{
max_kolom_grootte = kolom_grootte;
}
}
std::string CsvData::to_string() const
{
std::stringstream out;
for (int i = 0; i < max_kolom_grootte; i++)
{
for (int j = 0; j < data.size(); j++)
{
if (i < data[j].size())
{
out << std::setprecision(precisie) << std::scientific << data[j][i];
}
if (j == (data.size() - 1))
{
out << 'n';
}
else
{
out << delimiter;
}
}
}
std::string content = out.str();
std::replace(content.begin(), content.end(), '.', scheidingsteken);
return content;
}
std::string CsvData::geef_bestandsnaam() const
{
return bestandsnaam;
}
void CsvData::write_to_file() const
{
std::ofstream out(bestandsnaam);
assert(out);
out << to_string();
}
- 从具有自定义排序的向量创建集合
- 查询数据库以在 C++ 中创建自定义类集合的最佳方法
- 在具有自定义对象的集合中查找值
- 如何使用自定义重复的法官功能制作集合
- 如何定义[] =和at()=自定义集合
- CMAKE GOOGLETEST在集合集合中会重新定义错误
- 设置要与无序集合一起使用的自定义类 - 在集合中找不到元素
- 自定义集合中每个的C++
- C 11按几个属性的自定义对象集合
- 集合元素类中定义的集合的比较器
- 自定义比较器,将唯一元素插入到c++中的集合中
- 集合<向量<int>>必须定义比较函数吗?
- 如何在定义映射/集合时实例化比较函数(函子)
- C++ 为类中的集合定义顺序
- 具有单个成员的自定义结构(包装器)的集合(也是自定义结构)到单个成员的集合
- 使用Functor在集合中生成自定义排序方法
- 从自定义集合(struct Array)中读取数据
- 在C++中定义和搜索相关订单上的集合
- 在包含自定义类型的集合中查找
- 如何为已显式定义了比较函数的集合定义迭代器