RESOLVED: GCC link-time optimization (LTO) and GType registration


We have broken builds of Tracker when it’s configured with -Db_lto=true. The problem is that some get_type() functions are being inlined, which causes errors like this at runtime:

(tracker-miner-fs:3082): GLib-GObject-WARNING **: 08:51:14.685: cannot register existing type 'TrackerSparqlConnection'

I can think of a few ways to avoid these problems, but since I don’t know everything about GType or LTO I thought it best to ask for advice on what the “correct” approach would be.

What we know

In the bug report you can see 2 tracebacks from the same process, which show two functions named tracker_sparql_connection_get_type() with different addresses.

This function is generated by the Vala compiler from src/libtracker-sparql/tracker-connection.vala. The generated code is:

tracker_sparql_connection_get_type (void)
	static volatile gsize tracker_sparql_connection_type_id__volatile = 0;
	if (g_once_init_enter (&tracker_sparql_connection_type_id__volatile)) {
		static const GTypeInfo g_define_type_info = { sizeof (TrackerSparqlConnectionClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) tracker_sparql_connection_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (TrackerSparqlConnection), 0, (GInstanceInitFunc) tracker_sparql_connection_instance_init, NULL };
		GType tracker_sparql_connection_type_id;
		tracker_sparql_connection_type_id = g_type_register_static (G_TYPE_OBJECT, "TrackerSparqlConnection", &g_define_type_info, G_TYPE_FLAG_ABSTRACT);
		g_once_init_leave (&tracker_sparql_connection_type_id__volatile, tracker_sparql_connection_type_id);
	return tracker_sparql_connection_type_id__volatile;

Since we have 2 copies of the function, we get 2 copies of tracker_sparql_connection_type_id__volatile and this must be what causes the duplicate type registration.

Tracker’s compile pipeline is rather byzantine, for various reasons[1]. Here’s part of how we link tracker-miner-fs

|libtracker-sparql (shared)+------------------+
+---------+----------------+                  |
          |                   +---------------v-----------------+
          |                   |libtracker-miner-private (static)|
          |                   +---------------+-----------------+
          |                                   |
          |                   +---------------v---------+
          |                   |libtracker-miner (shared)|
          |                   +---------------+---------+
          |                                   |
          |  +----------------+               |

The symbol tracker_sparql_connection_get_type() is defined in libtracker-sparql, and I guess is being inlined in the static libtracker-miner-private library, and also accessed publicly through libtracker-sparql, hence the 2 versions.

It’s likely that we can rearrange things to avoid this situation, and that might be a good idea anyway, but I want to understand more about why things are broken first.

What we don’t know

  • Has anyone else had trouble or success with LTO and GType? Especially with Vala involved?

  • Should we modify valac to add G_GNUC_NO_INLINE to the generated get_type() functions?

  • Does LTO bring restrictions on the compile pipeline? i.e. are we wrong to link shared library -> static library -> shared library and expect it to work?

Thanks in advance for your help!

[1]. reasons the compile pipeline is complex include: separation of functionality, keeping API private but still sharing it with unit tests, Vala code mixed with C, multiple backends implementing one API, and my own general confusion and laziness.

As sometimes happens, this turned out to be a lot simpler than I was making it.

There are 2 intermediate static libraries used to create Due to a mistake in these static libraries were being linked into everything that depends on Fixing that seems to fix the LTO issue.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.