emscripten-core / emscripten

Emscripten: An LLVM-to-WebAssembly Compiler
Other
25.62k stars 3.28k forks source link

"wasm-ld: error: Expected at most one ThinLTO module per bitcode file" #12763

Closed icculus closed 2 years ago

icculus commented 3 years ago

Emscripten fails to link if using -flto=thin and one of the inputs is a static library (.a file) that contains two object files with the same name. This happens to me because I'm building mRuby into a library, which has two unrelated source files in different directories named "array.c" (and others, too).

This seems to be an error inherited from LLVM, based on limited results from Googling, but here's how to reproduce this (tested against 2.0.8) ...

echo 'int a(int x) { return x + 3; }' > a.c
echo 'int b(int x) { return x + 1; }' > b.c
echo 'int a(int); int b(int); int main(int argc, char **argv) { return a(1) + b(2); }' > m.c
mkdir -p subdir
emcc -c -flto=thin -o a.o a.c
emcc -c -flto=thin -o subdir/a.o b.c
emar r a.ar a.o subdir/a.o
emcc -c -flto=thin -o m.o m.c
emcc -flto=thin -s WASM=1 -o a.js a.ar m.o

On the last emcc command, it generates the error:

wasm-ld: error: Expected at most one ThinLTO module per bitcode file

Changing one of the object names to something other than "a.o" works around this--as does linking against the .o files instead of the .a--but a proper fix would be appreciated, especially if it just needs something pulled in or adapted from LLVM: https://reviews.llvm.org/D79880

kripken commented 3 years ago

Looks like that commit has landed on LLVM months ago, so it should be in 2.0.8 definitely, unless LLVM backed it out.

Can you test to see if the error happens with plain clang as well? I'd expect it to since I think we just let LLVM do this linking stuff now. If so, it's an LLVM bug we should file there.

sbc100 commented 3 years ago

Does this only happen with -flto=thin and not with -flto?

Note that we do basically no testing with -flto=thin either in emscripten or in upstream llvm. We should fix that.. but you might be first person to try to use in the real world, so expect issues.

icculus commented 3 years ago

Following up, this works with Clang 10.0.0 with -flto=thin ...

clang -c -flto=thin -o a.o a.c
clang -c -flto=thin -o subdir/a.o b.c
llvm-ar r a.ar a.o subdir/a.o
clang -c -flto=thin -o m.o m.c
clang -fuse-ld=lld -flto=thin -o a.out a.ar m.o

(I had to use -fuse-ld=lld because of the way this Clang was built, and it's worth noting that this could totally be what avoids this bug in the first place.)

I am absolutely unfamiliar with all these details, but the LLVM fix I linked to appears to be ELF-specific, so possibly it doesn't apply to Emscripten output?

As for -flto vs -flto=thin: using -flto works (at least, it links, I haven't tested the results further yet); this bug only reproduces with -flto=thin.

It's worth noting, however, that when you set CMAKE_INTERPROCEDURAL_OPTIMIZATION to True in a CMake project, it sets -flto=thin without any way to specify the specific option directly, which is how I came to stumble into this problem, so others will eventually hit this, too, I assume.

haraldF commented 3 years ago

It's worth noting, however, that when you set CMAKE_INTERPROCEDURAL_OPTIMIZATION to True in a CMake project, it sets -flto=thin without any way to specify the specific option directly

Seems you can override it in CMake via:

set(CMAKE_CXX_COMPILE_OPTIONS_IPO "-flto")
icculus commented 3 years ago

@haraldF oh, nice, I'll try that, thanks!

andrewevstyukhin commented 2 years ago

Hi there, problem exists in emscripten 2.0.32 also.

This happens with -flto=thin and not with -flto.

LTO::addThinLTO if (!ThinLTO.ModuleMap.insert({BM.getModuleIdentifier(), BM}).second) return make_error( "Expected at most one ThinLTO module per bitcode file", inconvertibleErrorCode());

ModuleIdentifier = "engine/libengine.aUtils.cpp.o" ModuleIdentifier = "engine/libengine.aPath.cpp.o"

sbc100 commented 2 years ago

It will take a few hours for this fix to show up in tot version emsdk and then it will be in the next release (2.0.33).