Hello!
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)|
| +---------------+---------+
| |
| +----------------+ |
+->+tracker-miner-fs+<--------------+
+----------------+
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 generatedget_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!
Sam
[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.