After few successful tests with LTO optimisation on smaller and less complicated projects, I've started testing LTO on bigger projects. I've chosen evolution. So I've added in evoution.spec file in %build section before %cmake: LDFLAGS="%{build_ldflags} -Wl,--as-needed -flto -fwhole-program" \ CFLAGS="%{build_cflags} -flto -fwhole-program" \ AR="gcc-ar" RANLIB="gcc-ranlib" NM="gcc-nm" \ %cmake -G "Unix Makefiles" \ Package build failed with: [ 59%] Linking C executable evolution-alarm-notify cd /home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/calendar/alarm-notify && /usr/bin/cmake -E cmake_link_script CMakeFiles/evolution-alarm-notify.dir/link.txt --verbose=1 /usr/bin/cc -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -mcet -fcf-protection -flto -fwhole-program -Werror-implicit-function-declaration -Wformat -Wformat-security -Winit-self -Wmissing-declarations -Wmissing-noreturn -Wpointer-arith -Wredundant-decls -Wundef -Wwrite-strings -fno-strict-aliasing -Wno-deprecated-declarations -Wdeclaration-after-statement -Wno-missing-field-initializers -Wno-sign-compare -Wno-unused-parameter -Wnested-externs -Wl,-z,relro -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -Wl,--as-needed -flto -Wl,--no-undefined -rdynamic CMakeFiles/evolution-alarm-notify.dir/alarm.c.o CMakeFiles/evolution-alarm-notify.dir/alarm-notify.c.o CMakeFiles/evolution-alarm-notify.dir/alarm-notify-dialog.c.o CMakeFiles/evolution-alarm-notify.dir/alarm-queue.c.o CMakeFiles/evolution-alarm-notify.dir/config-data.c.o CMakeFiles/evolution-alarm-notify.dir/notify-main.c.o CMakeFiles/evolution-alarm-notify.dir/util.c.o -o evolution-alarm-notify -Wl,-rpath,/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/calendar/gui:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/calendar/importers:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/composer:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/em-format:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/addressbook/gui/contact-list-editor:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/addressbook/gui/contact-editor:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/addressbook/gui/widgets:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/addressbook/printing:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/addressbook/util:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/smime/gui:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/smime/lib:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/libemail-engine:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/shell:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/e-util:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/libgnomecanvas: ../gui/libevolution-calendar.so ../importers/libevolution-calendar-importers.so ../../composer/libevolution-mail-composer.so ../../em-format/libevolution-mail-formatter.so -lcanberra-gtk3 -lX11 -lcanberra -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lcamel-1.2 -lsqlite3 -lssl3 -lsmime3 -lnss3 -lnssutil3 -lplds4 -lplc4 -lnspr4 -lpthread -ldl -lebook-1.2 -lglib-2.0 -lglib-2.0 -ledata-book-1.2 -lglib-2.0 -lebook-contacts-1.2 -lglib-2.0 -lecal-1.2 -L/usr/lib -lical -licalss -licalvcal -lglib-2.0 -lglib-2.0 -ledataserverui-1.2 -lglib-2.0 -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lglib-2.0 -lebackend-1.2 -ledataserver-1.2 -Wl,--export-dynamic -lgmodule-2.0 -pthread -lglib-2.0 -lsecret-1 -lxml2 -lsoup-2.4 -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lgailutil-3 -lgcr-ui-3 -lgcr-base-3 -lgck-1 -lp11-kit -Wl,--export-dynamic -lgmodule-2.0 -pthread -lglib-2.0 -lgnome-desktop-3 -lxml2 -lwebkit2gtk-4.0 -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lsoup-2.4 -lgio-2.0 -lgobject-2.0 -ljavascriptcoregtk-4.0 -lglib-2.0 -lnotify -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 ../../addressbook/gui/contact-list-editor/libecontactlisteditor.so ../../addressbook/gui/contact-editor/libecontacteditor.so ../../addressbook/gui/widgets/libeabwidgets.so ../../addressbook/printing/libecontactprint.so ../../addressbook/util/libeabutil.so ../../smime/gui/libevolution-smime.so ../../smime/lib/libessmime.so ../../libemail-engine/libemail-engine.so ../../shell/libevolution-shell.so ../../e-util/libevolution-util.so -lgnome-autoar-0 -larchive -lgnome-autoar-gtk-0 -lenchant -lgtkspell3-3 -lenchant -lgtkspell3-3 -L/usr/lib64 -lresolv -llber -lldap -L/usr/lib ../../libgnomecanvas/libgnomecanvas.so -Wl,--export-dynamic -pthread -lm -lcamel-1.2 -lsqlite3 -lssl3 -lsmime3 -lnss3 -lnssutil3 -lplds4 -lplc4 -lnspr4 -lpthread -ldl -lebook-1.2 -ledata-book-1.2 -lebook-contacts-1.2 -lecal-1.2 -lical -licalss -licalvcal -ledataserverui-1.2 -lebackend-1.2 -ledataserver-1.2 -lsecret-1 -lgailutil-3 -lgcr-ui-3 -lgcr-base-3 -lgck-1 -lp11-kit -lgmodule-2.0 -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lxml2 -lsoup-2.4 -lgnome-desktop-3 -lwebkit2gtk-4.0 -ljavascriptcoregtk-4.0 -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lxml2 -lsoup-2.4 -lgnome-desktop-3 -lwebkit2gtk-4.0 -ljavascriptcoregtk-4.0 /usr/bin/ld: Dwarf Error: Could not find abbrev number 1473. /tmp/ccNTk8fA.ltrans0.ltrans.o: In function `timet_to_str_with_zone': <artificial>:(.text+0x445): undefined reference to `e_datetime_format_format_tm' /tmp/ccNTk8fA.ltrans0.ltrans.o: In function `ensure_inited.part.0': <artificial>:(.text+0x4cc): undefined reference to `e_util_ref_settings' /tmp/ccNTk8fA.ltrans0.ltrans.o: In function `location_activate_link_cb': <artificial>:(.text+0x12d2): undefined reference to `e_show_uri' /tmp/ccNTk8fA.ltrans0.ltrans.o: In function `fill_in_labels.isra.0': <artificial>:(.text+0x2dd4): undefined reference to `e_buffer_tagger_disconnect' <artificial>:(.text+0x2e74): undefined reference to `e_buffer_tagger_connect' <artificial>:(.text+0x2e87): undefined reference to `e_buffer_tagger_update_tags' /tmp/ccNTk8fA.ltrans0.ltrans.o: In function `open_alarm_dialog': <artificial>:(.text+0x357b): undefined reference to `e_load_ui_builder_definition' <artificial>:(.text+0x358a): undefined reference to `e_builder_get_widget' <artificial>:(.text+0x359d): undefined reference to `e_builder_get_widget' <artificial>:(.text+0x35b0): undefined reference to `e_builder_get_widget' <artificial>:(.text+0x35c3): undefined reference to `e_builder_get_widget' <artificial>:(.text+0x35d6): undefined reference to `e_builder_get_widget' /tmp/ccNTk8fA.ltrans0.ltrans.o:<artificial>:(.text+0x35e9): more undefined references to `e_builder_get_widget' follow /tmp/ccNTk8fA.ltrans0.ltrans.o: In function `open_alarm_dialog': <artificial>:(.text+0x37dc): undefined reference to `e_buffer_tagger_connect' <artificial>:(.text+0x394c): undefined reference to `e_builder_get_widget' /tmp/ccNTk8fA.ltrans0.ltrans.o: In function `display_notification.isra.12': <artificial>:(.text+0x4081): undefined reference to `e_util_is_running_gnome' /tmp/ccNTk8fA.ltrans0.ltrans.o: In function `notify_dialog_cb': <artificial>:(.text+0x58a6): undefined reference to `print_comp' /tmp/ccNTk8fA.ltrans0.ltrans.o: In function `main': <artificial>:(.text.startup+0x17d): undefined reference to `e_util_cleanup_settings' collect2: error: ld returned 1 exit status make[2]: *** [src/calendar/alarm-notify/CMakeFiles/evolution-alarm-notify.dir/build.make:192: src/calendar/alarm-notify/evolution-alarm-notify] Error 1 make[2]: Leaving directory '/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0' make[1]: *** [CMakeFiles/Makefile2:3012: src/calendar/alarm-notify/CMakeFiles/evolution-alarm-notify.dir/all] Error 2 make[1]: Leaving directory '/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0' make: *** [Makefile:144: all] Error 2 error: Bad exit status from /var/tmp/rpm-tmp.JiQnYF (%build) Looks like LTO optimisation caused not add some symbols to some libraries. Is it a bug or a normal result of optimizing libraries?
Hi Tomasz, Would you mind running a test for me please ? I have had reports that that the annobin plugin does not interact with LTO very well, although I have never been able to track the problem down myself. So, please could you try adding: %undefine _annotated_build to your LTO-enabled version of the evolution.spec file, and see if this fixes the problem. Personally I am hoping that it will not, but it does seem to work for some people. Cheers Nick
It failed in exactly the same place. BTW. I found another issue with the same LTO optimisation settings in case zabbix. After add LTO zabbix_agentd binary crashes with SEGV. Should I open new ticket?
I've spend today a bit more time to investigate this case. I found that issue is with libevolution-util.so which is generated in src/e-util in evolution source code tree. Looks like really this library is almost completely empty. [tkloczko@domek e-util]$ size libevolution-util.so text data bss dec hex filename 1076 616 1920 3612 e1c libevolution-util.so However: [tkloczko@domek e-util]$ nm libevolution-util.so | wc -l; ls -la libevolution-util.so 14829 -rwxrwxr-x 1 tkloczko tkloczko 5172088 Apr 13 08:02 libevolution-util.so The same library when evolution is build without LTO compile and linking options looks like: [tkloczko@domek e-util]$ size libevolution-util.so; ls -l libevolution-util.so text data bss dec hex filename 2565949 56328 7464 2629741 28206d libevolution-util.so -rwxr-xr-x 1 tkloczko tkloczko 2677136 Apr 7 23:26 libevolution-util.so but it is stripped library: $ file libevolution-util.so libevolution-util.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=3fe671f280e875feaf0d378615c00f477b9dccd1, stripped, too many notes (256) I see some possible explanation of above. As long I don't see that during linking is used not used something like '-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libevolution-util.sym"' and because this is library and by this there is no main() in linked library LTO on linking removed almost everything. If it is true I see one possible cure in form of force combining --version-script or similar regexp param specifying list of symbols which needs to be provided by linked library when -shared options is used. This if widely used may even cause better control of ABI of all libraries as library developer/maintainer will be forced to maintain sym file or similar with versioned ABI interface definition :)
Just tested the same on libdtrace-ctf which has versioned ABI interface and seems effect is the same. Library without LTO: $ size libdtrace-ctf.so.1.3.0 text data bss dec hex filename 58683 2244 16 60943 ee0f libdtrace-ctf.so.1.3.0 $ nm -C -D libdtrace-ctf.so.1.3.0 U __assert_fail U close U compress U compressBound 0000000000006670 T ctf_add_array 0000000000006d50 T ctf_add_const 0000000000006ae0 T ctf_add_enum 0000000000006d70 T ctf_add_enumerator 0000000000006650 T ctf_add_float 0000000000006bc0 T ctf_add_forward 00000000000067a0 T ctf_add_function 0000000000006640 T ctf_add_integer 0000000000007390 T ctf_add_member 0000000000006fc0 T ctf_add_member_offset 0000000000006660 T ctf_add_pointer 0000000000006d60 T ctf_add_restrict 0000000000006920 T ctf_add_struct 00000000000074b0 T ctf_add_type 0000000000006cb0 T ctf_add_typedef 0000000000006a00 T ctf_add_union 00000000000073a0 T ctf_add_variable 0000000000006d40 T ctf_add_volatile 0000000000004c70 T ctf_arc_close 0000000000004e10 T ctf_archive_iter 0000000000004af0 T ctf_arc_open 0000000000004c90 T ctf_arc_open_by_name 0000000000004450 T ctf_arc_write 000000000000ac50 T ctf_array_info 00000000000031a0 T ctf_bufopen 0000000000002d70 T ctf_close 0000000000008ec0 T ctf_compress_write 00000000000051b0 T ctf_create 0000000000006610 T ctf_discard 000000000000a090 T ctf_enum_iter 000000000000b320 T ctf_enum_name 000000000000b440 T ctf_enum_value 0000000000007f00 T ctf_errmsg 0000000000007f50 T ctf_errno 00000000000085f0 T ctf_fdopen 00000000000097f0 T ctf_func_args 0000000000009680 T ctf_func_info 0000000000004400 T ctf_getmodel 0000000000004420 T ctf_getspecific 0000000000008e40 T ctf_gzwrite 0000000000003060 T ctf_import 00000000000084e0 T ctf_label_info 00000000000083e0 T ctf_label_iter 0000000000008350 T ctf_label_topmost 0000000000009160 T ctf_lookup_by_name 0000000000009540 T ctf_lookup_by_symbol 0000000000009470 T ctf_lookup_variable 000000000000aaa0 T ctf_member_info 0000000000009ef0 T ctf_member_iter 0000000000008de0 T ctf_open 0000000000002ff0 T ctf_parent_file 0000000000003000 T ctf_parent_name 0000000000003010 T ctf_parent_name_set 0000000000006500 T ctf_rollback 0000000000006710 T ctf_set_array 0000000000003140 T ctf_setmodel 0000000000004410 T ctf_setspecific 00000000000064d0 T ctf_snapshot 000000000000ae60 T ctf_type_align 000000000000aa30 T ctf_type_cmp 000000000000b060 T ctf_type_compat 000000000000a960 T ctf_type_encoding 0000000000009cf0 T ctf_type_iter 000000000000a7c0 T ctf_type_kind 000000000000a3c0 T ctf_type_lname 000000000000a780 T ctf_type_name 000000000000a880 T ctf_type_pointer 000000000000a800 T ctf_type_reference 0000000000009e20 T ctf_type_resolve 000000000000ad10 T ctf_type_size 000000000000b570 T ctf_type_visit 0000000000005390 T ctf_update 0000000000009d80 T ctf_variable_iter 00000000000090e0 T ctf_version 0000000000009060 T ctf_write U __ctype_b_loc w __cxa_finalize U __errno_location U free U fwrite U __fxstat U getenv U getpagesize w __gmon_start__ U gzwrite w _ITM_deregisterTMCloneTable w _ITM_registerTMCloneTable 0000000000000000 A LIBDTRACE_CTF_1.0 0000000000000000 A LIBDTRACE_CTF_1.1 0000000000000000 A LIBDTRACE_CTF_1.2 0000000000000000 A LIBDTRACE_CTF_1.3 U lseek U malloc U memmove U memset U mmap U mprotect U msync U munmap U open U pread U qsort_r U __stack_chk_fail U stderr U strchr U strcmp U strcpy U strerror U strlen U strncmp U strpbrk U uncompress U unlink U __vfprintf_chk U __vsnprintf_chk U write U zError And the same with LTO: $ size libdtrace-ctf.so.1.3.0 text data bss dec hex filename 1409 648 8 2065 811 libdtrace-ctf.so.1.3.0 $ nm -C -D libdtrace-ctf.so.1.3.0 w __cxa_finalize U getenv w __gmon_start__ w _ITM_deregisterTMCloneTable w _ITM_registerTMCloneTable 0000000000000000 A LIBDTRACE_CTF_1.0 0000000000000000 A LIBDTRACE_CTF_1.1 0000000000000000 A LIBDTRACE_CTF_1.2 0000000000000000 A LIBDTRACE_CTF_1.3
(In reply to Tomasz Kłoczko from comment #2) > It failed in exactly the same place. Darn. (Well actually this is good - it means that annobin is not blame). > BTW. I found another issue with the same LTO optimisation settings in case > zabbix. After add LTO zabbix_agentd binary crashes with SEGV. Should I open > new ticket? Yes please. Cheers Nick
Just FTR: I found what has been causing emptying shared library during linking. It happens when combination of two flags during linking are used: -flto and -fwhole-program As I've changed to "-flto -fuse-linker-plugin" everything seems is OK. This set of flags gives the same size reduction on linking executables as with "-flto -fwhole-program" flags. I was told on #gcc irc channel that -fwhole-program flag should be not used now because -fwhole-program is obsolete. If it is true this flag should be removed or at least someone should investigate why it causes generate empty shared libraries. In other words as long as I found kind of solution I think that this ticket should be kept as opened as long as something with -fwhole-program will be not done. PS. I've already have second LTO related ticket which address crashing issue #1567112.
Linking a shared library with -fwhole-program makes no sense at all, unless you mark all the external entrypoints from the shared library with externally_visible attribute (as documented). The only exception is main, but most shared libraries don't contain main...
That is the problem that even if library is linked with linking script which specifies precise list of symbols which needs to be provided by linked library what is produces does NOT contain any of those symbols!!! In other words in such cases -fwhole-program is used is produced wrong library and/or it looks like it works when main() is present (on linking executable. What I've presented about libdtrace-ctf in my prev comment describes exactly such case.
If you want the linker to provide what needs to stay and what can be optimized away, then don't use -fwhole-program. -fwhole-program does what is documented, it assumes the single TU or in case of LTO everything you link with LTO together is the whole program and exports only main and externally_visible marked functions. It works exactly as documented.
Jakub IMO -fwhole-program option is useless in rall case scenarios. It can be replaced by -fuse-linker-plugin and it trashes linking libraries (it does not produce for example error that main() is missing in linked binary). As compile and linking optimisation options are passed over CFLAGS and LDFLAGS in env variables during configure source code tree and if in such tree are build executables and libraries are linked all libraries will be broken/empty. Whole idea of use cmake or automake is to hide compiler and linker specific options and use/add them on source code configuration stage. Because -fwhole-program is linking some libraries files without even warning that ell has been removed from linked library it causes that in project which produces libraries and executables it would be necessary to specify -fuse-linker-plugin or -fwhole-program depends on what is linked. However thi is in collision course with hiding in build framework all linker types details. Using -fuse-linker-plugin on linking libraries I don't see any size reduction as looks like this option assumes that all library function should be added to public symbols list. If -fwhole-program would be able to produce non-empty library when it is used with --version-script=<sym_file> it would allow produce some class of OSS project with strict control of ABI interface. So far looks like LTO does not support/is not going to stimulate such long term changes.