freebasic / fbc

FreeBASIC is a completely free, open-source, multi-platform BASIC compiler, with syntax similar to MS-QuickBASIC, that adds new features such as pointers, object orientation, unsigned data types, inline assembly, and many others.
https://www.freebasic.net
877 stars 137 forks source link

Compilation failed: plugin needed to handle lto object #354

Closed martin-ms closed 2 years ago

martin-ms commented 2 years ago

After update to version 1.09.0 I got on every project the error /usr/bin/../bin/ld: /usr/bin/../lib/freebasic/linux-x86_64/fbrt0.o: plugin needed to handle lto object. After downgrade to version 1.08.1 all works well for me. I cant find any infiormation about it in the changelog, so what kind of plugin does I need & miss to get version 1.09.0 working again?

Operating System: Arch Linux KDE Plasma Version: 5.23.5 KDE Frameworks Version: 5.90.0 Qt Version: 5.15.2 Kernel Version: 5.16.0-arch1-1 (64-bit)

martin-ms commented 2 years ago

Thanks for your response. Output of gcc -v is

Es werden eingebaute Spezifikationen verwendet. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/lto-wrapper Ziel: x86_64-pc-linux-gnu Konfiguriert mit: /build/gcc/src/gcc/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++,d --with-isl --with-linker-hash-style=gnu --with-system-zlib --enable-__cxa_atexit --enable-cet=auto --enable-checking=release --enable-clocale=gnu --enable-default-pie --enable-default-ssp --enable-gnu-indirect-function --enable-gnu-unique-object --enable-install-libiberty --enable-linker-build-id --enable-lto --enable-multilib --enable-plugin --enable-shared --enable-threads=posix --disable-libssp --disable-libstdcxx-pch --disable-libunwind-exceptions --disable-werror gdc_include_dir=/usr/include/dlang/gdc Thread-Modell: posix Unterstützte LTO-Kompressionsalgorithmen: zlib zstd gcc-Version 11.1.0 (GCC)

Meanwhile I tried to build the package again from the official ressources of the distributor and got the same error during the build process. I suppose that there is a missing dependency the packager has resolved on his system but not in a clean environment. I will file another report at the bug system of the distributor, because at least the buildung of the package should be work.

rversteegen commented 2 years ago

Oh, so you aren't using one of the provided Linux builds of FreeBASIC but an Arch package? I checked that in the officiaI build, lib/freebasic/linux-x86_64/fbrt0.o does not seem to be an LTO object file.

If it doesn't work even when you compile it yourself (rather surprising), then it might be because of some environmental variables the Arch script sets or passes to make, such as CFLAGS or LDFLAGS. How is make invoked?

martin-ms commented 2 years ago

This is the script the Arch-packager used to build the package: https://github.com/archlinux/svntogit-community/blob/packages/freebasic/trunk/PKGBUILD The "build"-section shows the used flags.

Link to my bugreport on Arch: https://bugs.archlinux.org/task/73467

martin-ms commented 2 years ago

It's not from AUR, it is the binary package taken from the official repository: https://archlinux.org/packages/community/x86_64/freebasic

rversteegen commented 2 years ago

You can either fix the PKGBUILD yourself (see below) and run it, or download a precompiled build of FB, or just do what you did and use an an older Arch build of FB, before Arch switched to LTO.

After you have your bootstrapped FBC, add it to PATH then download the FBC source and compile and install it, now you have a working FBC.

Why bother recompiling fbc using a bootstrapped fbc, rather than just use the bootstrap fbc? It's not linked in exactly the same way, but all the code is identical.

The "build"-section shows the used flags.

So it passes on the external CFLAGS, and that's the problem. I read that Arch recently switched to compiling with LTO by default, so I tried compiling FB's rtlib (libfb) with -flto. This produced the error message: ar: src/rtlib/obj/linux-x86_64/array_boundchk.o: plugin needed to handle lto object but libfb.a was created anyway (I didn't check whether it works). To avoid the error message, you could compile with make AR=gcc-ar rtlib. (In detail, you can either pass --plugin=$(gcc --print-file-name=liblto_plugin.so) to ar, or use gcc-ar, which is a wrapper around ar that searches for liblto_plugin.so and passes it as an arg.)

Anyway, attempting to use this libfb.a with fbc produces the error you reported:

ld: /home/ralph/local/fbc-git/bin/../lib/freebasic/linux-x86_64/fbrt0.o: plugin needed to handle lto object
ld: /home/ralph/local/fbc-git/bin/../lib/freebasic/linux-x86_64/libfbmt.a(array_boundchk.o): plugin needed to handle lto object
...

followed by thousands of others.

It simply isn't possible for fbc to successfully link against runtime libraries (mis)compiled with lto, because fbc always goes from .bas (optionally to .c) to .asm/.S to .o and then links to an executable/.so. But LTO requires going from source (.bas/.c) straight to .o, and then producing the assembly at link time.

Conclusion: fbc does not support LTO and isn't going to support it without partially rewriting how it compiles and links. You should not pass CFLAGS=-flto to make when when compiling FB. You could modify the PKGBUILD to:

make CFLAGS="$CFLAGS $(pkg-config --cflags libffi) -fno-lto"

The most we can do here is add -fno-lto to makefile to override CFLAGS. However, someone might actually want to compile FB with LTO...

Although fbc itself doesn't support LTO, it is possible to compile FB programs with LTO by invoking gcc manually for compiling and linking. In fact I already added it to the OHRRPGCE's build system a while ago. So I just tried it with an LTO runtime library and it compiled. But looking at the disassembly, I can't find any cases of it actually inlining any library functions. I was really hoping for ubound, lbound, len. It would not even inline the most trivial function possible, fb_RndGetState, although it does inline functions between .bas files.

I then tried compiling a simple .bas and in this case it did inline lots of rtlib functions. Still trying to figure out the difference.

If you want to link a FB program against the FB LTO libraries, you can do so with something like:

fbc -m ltotest ltotest.bas -gen gcc -asm att -r
gcc -flto -o ltotest ltotest.c -fno-strict-aliasing -frounding-math -fno-math-errno -fwrapv -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables  -L "/home/ralph/local/fbc-git/bin/../lib/freebasic/linux-x86_64" -lfb "/home/ralph/local/fbc-git/bin/../lib/freebasic/linux-x86_64/fbrt0.o" -ltinfo -lpthread -lm -O2

Or if you wish, you can call gcc twice, to produce an .o and to link; that works too. Attempting to use ld to link produces "plugin needed to handle lto object" again, but at least on my system there is no gcc-ld wrapper.

You need to avoid intel asm syntax or else you will get errors like /tmp/ccQeFWXM.s:9: Error: junk '(%rdi)' after expression when linking.

To produce that commandline, I first ran fbc -m ltotest ltotest.bas -gen gcc -asm att -rr -v which shows the commandlines fbc passes to gcc and ld. I didn't bother passing many of the options.

martin-ms commented 2 years ago

@rversteegen Many thanks for your effort and to guide me in the right direction.

I am just a user, not a developer, thats why I didn't notice that Arch switches over to compiling with LTO by default, also because that are still not the default settings. I only realized that in recent packages the LTO-option has been set; probably the developer override the default settings. And I didn't realize that FreeBasic does not support LTO and need to compile without it.

Meanwhile I found also the reason why the packge currently can't built: since the packager use not the bootstrap concept and instead his own previously built "freebasic" package as a dependency, the first built with the previous version 1.08.1-1 was still successfull, but after his release of the corrupted version 1.09.0 all following builts fail. If I force the installation of version 1.08.1 I was able to build the package.

I enabled LTO now as a default setting to follow the Arch guidelines, and use options=('!lto') in the PKGBUILD to disable it for this build. After building the package again (using for a last time fbc-1.08.1) compilation with fcb works again without error and the produced program file is also usuable.

Is it in your opinion a suitable solution? The bugreport on Arch is still open and if you confirm that disabling LTO on building is a solution, I will report it there.

rversteegen commented 2 years ago

Ah, so options=('!lto') would be the solution then. I did wonder about the commented out bootstrap stuff though.

Doing a normal compile of FB from source using the bootstrapped FB is a good idea for a distributed package (it helps to confirm everything is working), I just think it's too much bother for most users.

I decided not to add -fno-lto to makefile, because in all other cases the user-supplied CFLAGS (as an arg to make or in config.mk) overrides all flags set by default in the makefile (though note the CFLAGS environmental variable get overridden).