I noticed that Godot's build system will attempt to correctly use LLVM's version of LTO if the use_lto=yes option is specified when using LLVM/Clang to build.

I know the docs only mention using LTO when building with gcc, but since the build system recognizes and tries to use it correctly for LLVM/Clang, I figured it might work. I tried building using it out of curiosity to see how the build size and build time compared to the build size and time when using gcc. Unfortunately, I got an error during the final link phase and the build fails. This happens both with the master branch, and with the 3.2.1 stable branch.

Here's the command line I'm using: scons -j12 platform=x11 target=release_debug use_lto=yes use_llvm=yes use_lld=yes

Is there something I'm doing wrong? Is anyone able to build Godot using LLVM with LTO? I'm using LLVM 10 if that matters.

I tried again using the use_thinlto=yes option. It went way faster, but also produced a lot more warnings about ignoring invalid debug info, and quite a few error messages. lld/clang hadn't displayed any error messages before, only SCons had mentioned an error.

Here are the error messages, I hope they're useful:

ld.lld-10: error: undefined symbol: register_module_types()
>>> referenced by main.cpp
>>>               lto.tmp:(Main::setup2(unsigned long))

ld.lld-10: error: undefined symbol: unregister_module_types()
>>> referenced by main.cpp
>>>               lto.tmp:(Main::cleanup())

ld.lld-10: error: undefined symbol: vtable for GDScriptTokenizerText
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(GDScriptTokenizerText::~GDScriptTokenizerText())
the vtable symbol may be undefined because the class is missing its key function (see https://lld.llvm.org/missingkeyfunction)

ld.lld-10: error: undefined symbol: GDScriptTokenizerText::set_code(String const&)
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))

ld.lld-10: error: undefined symbol: GDScriptTokenizerText::get_token(int) const
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))

ld.lld-10: error: undefined symbol: GDScriptTokenizerText::get_token_identifier(int) const
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))

ld.lld-10: error: undefined symbol: GDScriptTokenizerText::get_token_constant(int) const
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))

ld.lld-10: error: undefined symbol: GDScriptTokenizerText::get_token_error(int) const
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))

ld.lld-10: error: undefined symbol: GDScriptTokenizerText::get_token_line(int) const
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))

ld.lld-10: error: undefined symbol: GDScriptTokenizerText::get_token_line_indent(int) const
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))

ld.lld-10: error: undefined symbol: GDScriptTokenizerText::get_token_built_in_func(int) const
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))

ld.lld-10: error: undefined symbol: GDScriptFunctions::get_func_name(GDScriptFunctions::Function)
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::_disassemble_class(Ref<GDScript> const&, Vector<String> const&))
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::_parser_expr(GDScriptParser::Node const*))

ld.lld-10: error: undefined symbol: GDScriptTokenizerText::get_token_column(int) const
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))

ld.lld-10: error: undefined symbol: GDScriptTokenizerText::advance(int)
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))

ld.lld-10: error: undefined symbol: GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token)
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))

ld.lld-10: error: undefined symbol: GDScriptParser::GDScriptParser()
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))

ld.lld-10: error: undefined symbol: GDScriptParser::parse(String const&, String const&, bool, String const&, bool, Set<int, Comparator<int>, DefaultAllocator>*, bool)
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))

ld.lld-10: error: undefined symbol: GDScriptParser::get_error_line() const
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))

ld.lld-10: error: undefined symbol: GDScriptParser::get_error_column() const
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))

ld.lld-10: error: undefined symbol: GDScriptParser::get_error() const
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))
>>> referenced by test_gdscript.cpp
>>>               lto.tmp:(TestGDScript::test(TestGDScript::TestType))

ld.lld-10: error: too many errors emitted, stopping now (use -error-limit=0 to see all errors)
clang: error: linker command failed with exit code 1 (use -v to see invocation)
scons: *** [bin/godot.x11.opt.tools.64.llvm] Error 1
scons: building terminated because of errors.
13 days later

I think it would be better to report a bug on GitHub. Make sure to include the logs like you did here.

See also this comment which may be of use.

12 days later
2 years later