奇怪的CMake链接器错误

时间:2019-02-24 16:13:04

标签: c++ cmake googletest

我正在尝试通过使用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的完全新手,所以我不知道自己做错了什么... 任何帮助将不胜感激!

0 个答案:

没有答案