gcc 链接器无法找到在链接库中明确定义的方法的定义[重复]

sirbozc5  于 2022-11-13  发布在  其他
关注(0)|答案(1)|浏览(187)

此问题在此处已有答案

C++ undefined references to functions in namespace(2个答案)
四个月前关门了。
在我正在处理的项目中,我遇到了一个问题,我得到了以下错误:

[ 97%] Linking CXX executable Test_formatters
CMakeFiles/Test_formatters.dir/formatters.cpp.o: In function `FormatterTests::JsonFormattter::test_method()':
formatters.cpp:(.text+0xa9e7): undefined reference to `core::log::make_formatter(core::log::FormatterType)'
collect2: error: ld returned 1 exit status
core/log/test/CMakeFiles/Test_formatters.dir/build.make:104: recipe for target 'core/log/test/Test_formatters' failed
make[2]: *** [core/log/test/Test_formatters] Error 1
CMakeFiles/Makefile2:504: recipe for target 'core/log/test/CMakeFiles/Test_formatters.dir/all' failed
make[1]: *** [core/log/test/CMakeFiles/Test_formatters.dir/all] Error 2
Makefile:135: recipe for target 'all' failed
make: *** [all] Error 2

这个函数是一个名为distro_core_log_static的函数库的一部分。下面是为这个函数库创建测试目标的cmake,这也是这个错误的来源:

ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK) 

set(DEPENDENCIES
    distro_core_log_static
    ${Boost_FILESYSTEM_LIBRARY}
    ${Boost_SYSTEM_LIBRARY}
    ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})

# formatters
add_executable(Test_formatters formatters.cpp)
target_link_libraries(Test_formatters PUBLIC ${DEPENDENCIES})

特别奇怪的是,我在日志库内部使用了这个据说未定义的方法,却没有得到这样的错误。下面是这个目录结构:
enter image description here
最后,您还可以看到该方法声明为:

namespace core
{
    namespace log
    {
        class Formatter;

        enum class FormatterType
        {
            invalid = -1,
            json

        }; // enum class FormatterType

        // Factory method for log formatters
        Formatter* make_formatter(FormatterType type);

        // Convert the provided FormatterType to a string representation
        std::string formatter_type_to_string(FormatterType type);

        // Convert the provided FormatterType string to a FormatterType
        FormatterType string_to_formatter_type(const std::string& formatter_type_str);

        // String representations
        static constexpr const char* const FORMATTER_INVALID_STR = "invalid";
        static constexpr const char* const JSON_FORMATTER_STR = "json";

    } // namespace log

} // namespace core

和定义:

#include "FormatterFactory.hpp"

#include "Formatter.hpp"
#include "JsonFormatter.hpp"

using namespace core::log;

// Factory method for log formatters
Formatter* make_formatter(FormatterType type)
{
    switch (type)
    {
        case FormatterType::json:
        {
            return new JsonFormatter;
        }
        case FormatterType::invalid:
        {
            return nullptr;
        }
    }

    return nullptr;
}
vpfxa7rd

vpfxa7rd1#

make_formatter函数的定义假定命名空间解析将理解您正在定义core::log中声明的命名空间解析。
然而,事实并非如此。虽然using namespace会将标识符导入到当前命名空间中,但它不会以相反的方式工作。当您定义make_formatter时,它不会仅仅因为该标识符存在而被推回到core::log命名空间中。
实际上,它将通过在全局名称空间中定义一个新函数来重载它:

// This function is NOT implementing the one in the core::log namespace
core::log::Formatter* make_formatter(core::log::FormatterType type)
{
    //...
    return nullptr;
}

问题的论证在这里:https://godbolt.org/z/4WTW4e1cf
所以链接器没有说谎。没有core::log::make_formatter的实现。
您的选项包括:
1.明确限定它:

using namespace core::log;

Formatter* core::log::make_formatter(FormatterType type)
{
    //...
    return nullptr;
}

1.在正确的命名空间中定义它:

namespace core 
{
    namespace log
    {
        Formatter* core::log::make_formatter(FormatterType type)
        {
            //...
            return nullptr;
        }
    }
}

相关问题