【问题标题】:Why linker error 'multiple definitions' with only one library? Using CMake (3.4.1) in Android Studio为什么只有一个库的链接器错误“多个定义”?在 Android Studio 中使用 CMake (3.4.1)
【发布时间】:2018-07-30 22:07:41
【问题描述】:

如上所述,我尝试编译一个本地库以在 JNI 中使用它。但我收到以下错误:

/src/main/cpp/app1.cpp.o: '...'的多重定义

/src/main/cpp/mylib.cpp.o:这里是之前的定义

这仅在我使用“包含完整模板代码”的 .hh 数据时出现。多重定义的东西在一个预编译的库中,头文件包含在“HEADER_FILES”中。

这是我的 CMakeLists.txt:

set(HEARDER_SRC_DIRECTORY ${CMAKE_SOURCE_DIR}/../../header/src)
include_directories(${HEADER_SRC_DIRECTORY})
set(HEADER_FILES ${HEADER_SRC_DIRECTORY}/header1.h ${HEADER_SRC_DIRECTORY}/header2.h ${HEADER_SRC_DIRECTORY}/header1.hh ${HEADER_SRC_DIRECTORY}/header2.hh)
add_library(
    mylib
    SHARED
    src/main/mylib.cpp
    ${HEADER_FILES}
    src/main/app1.h
    src/main/app1.cpp
)
find_library(
    log-lib
    log 
)
target_link_libraries(  
    mylib
    ${CMAKE_SOURCE_DIR}/libs/liby.a     # precompiled lib
    ${CMAKE_SOURCE_DIR}/libs/libz.a     # precompiled lib
    ${log-lib}
)

我该如何解决这个问题?据我了解,每个 .cpp 在链接之前都会自行编译,然后它们已经具有相同的定义。当然,他们有,这就是为什么我在mylib中链接app1,所以我可以访问一些功能。我的逻辑错误在哪里?将它们分开会有帮助吗?

mylib.cpp 包含的内容:

#include <jni.h>
#include <string>
#include "app1.h"

app1.h 包含的内容:

#include "jni.h"
#include "header1.h"
#include "header1.hh"
#include <vector>
#include <cmath>
#include <iostream>
#include <fstream>
#include <string>

这里是双重定义的一部分(在 header1.h 中):

namespace nsp {

Class::Class(Able& able, std::string name)
  : _able(able), _iBlock(0), _size(0), _name(name)
{ }

void Serializer::resetCounter()
{ 
  _iBlock = 0;
}

....

}

【问题讨论】:

  • 查找“一个定义规则”。
  • 谢谢,这是非常基本的,我明白了,但我不知道我的代码中的什么地方可能是这样的。如果我在 Android Studio 之外使用这个库,它就可以工作。一旦我将它与 CMake 中的 header1.hh 链接起来,它就不会。 mylib.cpp 只调用了这个库的一个函数,没有更多的内容。
  • This only appears when I use the .hh data, which "include full template code" - 显示该文件(以minimal reproducible example 的形式)。否则,揭示你的问题只是一个猜谜游戏
  • 好吧,我猜是这样,因为在这些上下文中,使用 .hh,标题中已经有一些定义(见问题)。所以这将使用 mylib 和 app1 编译,所以它是多重的。有没有办法在不接触库的情况下改变它?

标签: c++ cmake


【解决方案1】:

Serializer::resetCounter() 的定义没有内联。这意味着每个包含"header1.h"(直接或间接)的翻译单元(源文件)都将有自己的函数定义。这可能会导致编译器抱怨违反单一定义规则。

如果您打算在头文件中将其作为内联函数,您可以通过将定义移动到类 Serializer 本身或使用 inline 关键字来实现。

inline void Serializer::resetCounter()
{ 
  _iBlock = 0;
}

【讨论】:

猜你喜欢
  • 2019-12-22
  • 1970-01-01
  • 2018-05-05
  • 1970-01-01
  • 2019-02-01
  • 1970-01-01
  • 2013-02-18
  • 1970-01-01
  • 2019-09-05
相关资源
最近更新 更多