我正在尝试通过使用Google测试并做一些基本的事情来学习CMake,但是我一直在面对Linker错误,因为我可能做错了什么,我也不知道...我有在Visual Studio解决方案中,同样的东西可以编译并完美运行,但可惜我无法复制CMake的成功,但是...据我所知,Linker错误是我的ElementContainer文件没有目标文件,这很奇怪,因为我确保将我的cpp文件全部添加为可执行文件... CMakeLists
cmake_minimum_required(VERSION 3.12)
project(Median)
file(GLOB_RECURSE Median_HEADERS "*.h")
set (Median_INCLUDE_DIRS "")
foreach (_headerFile ${Median_HEADERS})
get_filename_component(_dir ${_headerFile} PATH)
list (APPEND Median_INCLUDE_DIRS ${_dir})
endforeach()
list(REMOVE_DUPLICATES Median_INCLUDE_DIRS)
set(project_sources
MedianElementContainer.cpp
RunTests.cpp)
set(CMAKE_CXX_STANDARD 17)
############# Google Test ############
if (CMAKE_VERSION VERSION_LESS 3.2)
set(UPDATE_DISCONNECTED_IF_AVAILABLE "")
else()
set(UPDATE_DISCONNECTED_IF_AVAILABLE "UPDATE_DISCONNECTED 1")
endif()
include(DownloadProject.cmake)
download_project(PROJ googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG master
${UPDATE_DISCONNECTED_IF_AVAILABLE}
)
# Prevent GoogleTest from overriding our compiler/linker options
# when building with Visual Studio
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR})
# When using CMake 2.8.11 or later, header path dependencies
# are automatically added to the gtest and gmock targets.
# For earlier CMake versions, we have to explicitly add the
# required directories to the header search path ourselves.
if (CMAKE_VERSION VERSION_LESS 2.8.11)
include_directories("${gtest_SOURCE_DIR}/include"
"${gmock_SOURCE_DIR}/include")
endif()
# Trivial example using gtest and gmock
add_executable(RunAllTests ${project_sources})
target_include_directories(RunAllTests PRIVATE ${Median_INCLUDE_DIRS})
target_link_libraries(RunAllTests gtest gmock_main)
add_test(NAME Run_all_tests COMMAND RunAllTests)
RunTests.cpp
#include "iostream"
#include "thread"
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "MedianElementContainer.h"
#include "random"
int main(){
::testing::InitGoogleTest();
return RUN_ALL_TESTS();
}
class MedianTests : public ::testing::Test{
public:
void SetUp() override {
}
void TearDown() override {
}
};
TEST_F(MedianTests, MedianElementContainerOfIntsTest)
{
MedianElementContainer<int> container;
const int numElements = 100;
std::random_device rd;
std::mt19937 generator(rd());
std::uniform_int_distribution<int> uni(0, numElements);
container.insertElement(0);
/*for(int i = 0 ; i < numElements; ++i)
{
container.insertElement(uni(generator));
}*/
}
Element.h
template <class Type> Divisible{
public: virtual Type operator/(Type const& other) = 0;
}
template <class Type> Addable{
public: virtual Type operator+(Type const& other) = 0;
}
template <class Type> Comparable{
public: virtual bool operator<(Type const& other) = 0;
}
template <typename Type>
class Element : public Divisible<Type>, public Addable<Type>, public Comparable<Type>
{
Type _value;
public:
Element() = default;
Element(Type const& value) : _value(value)
{
}
operator Type() const
{
return _value;
}
Type operator+(Type const &other) const override {
return _value + other;
}
bool operator<(const Type &other) override {
return _value < other;
}
Type operator/(Type const &other) const override {
return _value / other;
}
};
MedianElementContainer.h
#include "Element.h"
#include "vector"
#include "mutex"
template <typename Type>
class MedianElementContainer {
using value_type = Element<Type>;
using lock_type = std::lock_guard<std::mutex>;
std::vector<value_type> _medianElements;
mutable std::mutex _mutex;
void insertElement(value_type const& element, lock_type & lock);
public:
MedianElementContainer() = default;
MedianElementContainer(std::initializer_list<Type> const& list);
MedianElementContainer(int size);
void insertElement(Type const& element);
Type getMedian() const;
std::vector<Type> getElements() const;
};
MedianElementContainer.cpp
#include "MedianElementContainer.h"
template<typename Type>
void MedianElementContainer<Type>::insertElement(const value_type &element, lock_type &lock) {
auto compareFunction = [](value_type const & first, value_type const& second) {
return (Type)first < (Type)second;
};
auto insertPos = std::lower_bound(_medianElements.begin(), _medianElements.end(), element, compareFunction);
_medianElements.insert(insertPos, element);
}
template<typename Type>
MedianElementContainer<Type>::MedianElementContainer(const std::initializer_list<Type> &list)
{
lock_type lock{ _mutex };
_medianElements.reserve(list.size());
std::for_each(list.begin(), list.end(), [&](Type const& element)
{
insertElement(element);
});
}
template<typename Type>
MedianElementContainer<Type>::MedianElementContainer(int size)
{
_medianElements.reserve(size);
}
template<typename Type>
void MedianElementContainer<Type>::insertElement(const Type &element)
{
lock_type lock(_mutex);
insertElement(Element<Type>(element), lock);
}
template<typename Type>
Type MedianElementContainer<Type>::getMedian() const
{
lock_type lock{ _mutex };
auto medianSize = _medianElements.size();
if (medianSize % 2)
{
return _medianElements[medianSize / 2];
}
else
{
auto midPosition = medianSize / 2;
return (_medianElements[midPosition] + _medianElements[midPosition - 1]) / Element<Type>(2);
}
}
template<typename Type>
std::vector<Type> MedianElementContainer<Type>::getElements() const {
std::vector<Type> result;
lock_type lock{ _mutex };
result.reserve(_medianElements.size());
std::transform(_medianElements.begin(), _medianElements.end(), std::back_inserter(result), [](Element<Type> const& element) -> Type
{
return Type(element);
});
return result;
}
您可以看到我已经将所有内容添加到CMakeLists中,但是,每当我尝试对RunTests.cpp中的ElementContainer进行任何操作时,我都会收到一个Linker错误,这可能是因为在设置可执行文件的源时做错了,而且我可能没有为我的elementcontainer获取obj文件,但是由于我是使用CMake的完全新手,所以我不知道自己做错了什么... 任何帮助将不胜感激!