emscripten链接全局命名符号多重定义

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了emscripten链接全局命名符号多重定义相关的知识,希望对你有一定的参考价值。

我有一个c ++ CMAKE(版本3.10.2 -std = c ++ 17)项目,我可以编译该项目并与购买的gcc和clang链接。购买它们会产生可以按预期工作的目标二进制文件。最近,我决定尝试添加另一个目标,即webassembly。该项目正在按预期进行编译,但是当执行EMscripten构建时,即在链接阶段,出现以下错误:

Elapsed time: 1 s. (time), 0.002241 s. (clock)
[100%] Linking CXX executable wasmExec.js
cd /Projects/time/time.cpp/build/src/wasm && /usr/bin/cmake -E cmake_link_script CMakeFiles/wasmExec.dir/link.txt --verbose=1
/Projects/emscripten/emsdk/emscripten/1.38.12/em++    -s WASM=1  -s NO_EXIT_RUNTIME=1  -s VERBOSE=1  --pre-js /Projects/time/time.cpp/src/wasm/preModule.js -s DEMANGLE_SUPPORT=1 -s DISABLE_EXCEPTION_CATCHING=0 -s ERROR_ON_UNDEFINED_SYMBOLS=0 @CMakeFiles/wasmExec.dir/objects1.rsp  -o wasmExec.js @CMakeFiles/wasmExec.dir/linklibs.rsp
error: Linking globals named '_ZTVN9timeproto3time8defaults20TimeDefaultParametersE': symbol multiply defined!
WARNING:root:Note: Input file "@/tmp/tmpUeJ6zc.response" did not exist.
ERROR:root:Failed to run llvm optimizations: 

当我这样做

c++filt _ZTVN9timeproto3time8defaults20TimeDefaultParametersE

我得到

vtable for timeproto::time::defaults::TimeDefaultParameters

来自Stackoverflow的另一个答案,即

Possible reasons for symbol multiply defined other than 'extern'

我确实知道我再定义一次该类,但是我的问题是我无法找到第二个定义出错的地方。在上一个答案中,此人有提示,即cpp文件,在该文件中他犯了这个错误,但就我而言,管教者并不那么慷慨。

此类在许多文件中的代码库中广泛使用,并且经过长时间的手动搜索,我无法找到任何至少可以使我指向第二个定义的位置的东西。因此,我希望有人可以帮助我解决以下问题

1)如何进一步排除故障,以查找确切地在哪里发生了该类的第二个定义,可能是gcc或clang的标志?2)为什么仅当我尝试编译/构建webassmbly目标时才会显示此错误。常规的Linux64构建目标为successefull,并且测试也正常进行。

3)我正在使用以下“ add_definitions”来运行cmake,即

if(UNIX)
    add_definitions(" -pedantic -pedantic-errors -W ")
    add_definitions(" -Wall -Wextra  -Werror -Wshadow -Wnon-virtual-dtor ")
    add_definitions(" -v ")
#   add_definitions(" -Worl-style-cast -Wcast-align ")
#   add_definitions(" -Wunused -Woverloaded-virtual ")
    add_definitions(" -g  ")
endif(UNIX)

如果TimeDefaultParameters已经定义了很多,那么一次不应该对上面的“ add_definitions”进行linux构建不抱怨吗?

这里是TimeDefaultParameters.cpp下面的代码。这是一个非常简单的文件,不包含任何对象,而是具有43个“ static const uint32_t”变量。

#include "TimeDefaultParameters.h"

namespace timeproto::time::defaults
    {

            TimeDefaultParameters::TimeDefaultParameters() {

            }

            TimeDefaultParameters::~TimeDefaultParameters() {

            }


            const uint32_t TimeDefaultParameters::SIGNED_SHORT_MAX_VALUE = 32767; 

.... (another 42 static const uint32_t)


}

和头文件TimeDefaultParameters.h:

#ifndef _TIME_DEFAULT_PARAMETERS_
#define _TIME_DEFAULT_PARAMETERS_

#include <stdint.h>

namespace timeproto::time::defaults
    {


    class TimeDefaultParameters final
        {

    public:

        explicit TimeDefaultParameters();
        virtual ~TimeDefaultParameters();

        static const uint32_t SIGNED_SHORT_MAX_VALUE; 
        .....

.... (another 42 static const uint32_t)



        };

    }


#endif  //#ifndef _TIME_DEFAULT_PARAMETERS_

在cmake中,我已设置了我的目标属性,例如:

set_target_properties(wasmExec PROPERTIES LINK_FLAGS "-s WASM=1  -s NO_EXIT_RUNTIME=1  -s VERBOSE=1  --pre-js /Projects/time/time.cpp/src/wasm/preModule.js -s DEMANGLE_SUPPORT=1 -s DISABLE_EXCEPTION_CATCHING=0 -s ERROR_ON_UNDEFINED_SYMBOLS=0" )

这是我如何调用cmake来从构建目录中进行构建

emconfigure cmake -DCMAKE_BUILD_TYPE=Emscripten -G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=/Projects/emscripten/emsdk/emscripten/1.38.12/cmake/Modules/Platform/Emscripten.cmake ../

make -j8

任何想法都将不胜感激。

添加日期:2020年1月5日

我能够找到解决此问题的方法,但是我仍然对错误的性质提出了一些疑问。

所讨论的类是动态创建和加载的档案的一部分,即我在CMAKE部分中使用的此库“ set(LIB_TYPE SHARED)”。这是完整示例,说明cmake如何生成该存档,即CMakeLists.txt。

set( TIME_DEFAULTS_SRC

    ...
    TimeDefaultParameters.h TimeDefaultParameters.cpp
    ...

)

set(LIB_TYPE STATIC)
#set(LIB_TYPE SHARED)

add_library(time_defaults ${LIB_TYPE} ${TIME_DEFAULTS_SRC} ) 
target_include_directories(time_defaults PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/")

我已经从动态更改为静态,并且我能够创建wasm而未显示任何错误。在编译期间,我还看到了在编译过程之间的某个警告,即:

WARNING:root:When Emscripten compiles to a typical native suffix for shared libraries (.so, .dylib, .dll) then it emits an LLVM bitcode file. You should then compile that to an emscripten SIDE_MODULE (using that flag) with suffix .wasm (for wasm) or .js (for asm.js). (You may also want to adapt your build system to emit the more standard suffix for a file with LLVM bitcode, '.bc', which would avoid this warning.)

此警告现在已消失。但是,很容易监督类似的事情,尤其是在编译过程花费很长时间的情况下。但是我的理解是,第一个错误消息告诉我们,“看起来您已经在代码中对某些符号进行了重复定义,请找到位置并确保该类仅定义一次”。那正是我正在做的事情,即在代码库中搜索重复的定义。因此,现在的问题是:为什么emscripten在动态链接方面存在问题,即我知道它已得到正式支持,即

https://webassembly.org/docs/dynamic-linking/

这是错误的根源,还是其他原因?为什么当我更改为静态时此错误消失。我可以通过简单地更改库类型来重现它!

我想我已经在这里找到了答案

https://github.com/emscripten-core/emscripten/wiki/Linking

答案

因此,在我的情况下,解决方案是在CMAKE文件中查找动态添加了库的事件,并将其更改为静态链接,即。

#set(LIB_TYPE SHARED)
set(LIB_TYPE STATIC) 

以上是关于emscripten链接全局命名符号多重定义的主要内容,如果未能解决你的问题,请参考以下文章

符号解析

在多文件中C语言中全局变量的重定义

在多文件中C语言中全局变量的重定义

在多文件中C语言中全局变量的重定义

出现“error LNK1169: 找到一个或多个多重定义的符号”的原因

C++ 链接问题:多重定义