diff options
author | Carlos Garnacho <carlosg@gnome.org> | 2022-12-10 23:25:24 +0100 |
---|---|---|
committer | Carlos Garnacho <carlosg@gnome.org> | 2022-12-11 19:38:27 +0100 |
commit | 8c56e45da7b1e0972264ba9a1f7e2e5d1a54bdf2 (patch) | |
tree | bc72f7222e26e6bb2f834187be6f09044310c723 | |
parent | cbd74b3c95d6569c27c3a7a7c574802acd198a85 (diff) | |
download | tracker-8c56e45da7b1e0972264ba9a1f7e2e5d1a54bdf2.tar.gz |
build: Build GVDB as a Meson subproject
Since recently, GVDB repository includes a minimal meson.build
file to allow building as a subproject without additional
hassles (e.g. shipping supporting files at /subprojects/repofiles/)
Drop our internal copy of GVDB in favor of a subproject built
through Meson.
Since we're updating many years across, there has been GVDB API
updates that we need to adapt to: GvdbTable is no longer a refcounted
object, and gvdb_table_walk() is no longer offered to iterate across
values.
These largely affect our own set of GVDB tests though, the test
for gvdb_table_walk() was dropped, and so is the ref/unref one
(it basically does the same than gvdb/flat_strings, after dropping
the refcounting). These remaining tests stay useful, and should
ideally move into the GVDB repository, so it can run as a separate
suite here.
-rw-r--r-- | .gitmodules | 6 | ||||
-rw-r--r-- | meson.build | 2 | ||||
-rw-r--r-- | src/gvdb/gvdb-builder.c | 514 | ||||
-rw-r--r-- | src/gvdb/gvdb-builder.h | 55 | ||||
-rw-r--r-- | src/gvdb/gvdb-format.h | 85 | ||||
-rw-r--r-- | src/gvdb/gvdb-reader.c | 673 | ||||
-rw-r--r-- | src/gvdb/gvdb-reader.h | 78 | ||||
-rw-r--r-- | src/gvdb/meson.build | 14 | ||||
-rw-r--r-- | src/libtracker-sparql/core/meson.build | 2 | ||||
-rw-r--r-- | src/libtracker-sparql/core/tracker-ontologies.c | 8 | ||||
-rw-r--r-- | src/libtracker-sparql/meson.build | 2 | ||||
-rw-r--r-- | src/meson.build | 2 | ||||
m--------- | subprojects/gvdb | 0 | ||||
-rw-r--r-- | subprojects/gvdb.wrap | 8 | ||||
-rw-r--r-- | tests/gvdb/gvdb-test.c | 110 | ||||
-rw-r--r-- | tests/gvdb/meson.build | 2 |
16 files changed, 26 insertions, 1535 deletions
diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..259754f84 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "subprojects/gvdb"] + path = subprojects/gvdb + url = https://gitlab.gnome.org/GNOME/gvdb.git + branch = 0854af0fdb6d527a8d1999835ac2c5059976c210 + shallow = true + diff --git a/meson.build b/meson.build index a72b21b70..67ddb0901 100644 --- a/meson.build +++ b/meson.build @@ -55,6 +55,8 @@ libxml2 = dependency('libxml-2.0', version: '> 2.6') sqlite = dependency('sqlite3', version: '>' + sqlite_required) dbus = dependency('dbus-1') +gvdb_dep = dependency('gvdb') + soup = get_option('soup') if soup.contains('soup2') or soup.contains('auto') libsoup2 = dependency('libsoup-2.4', version: '> 2.40', diff --git a/src/gvdb/gvdb-builder.c b/src/gvdb/gvdb-builder.c deleted file mode 100644 index 48fe3e41c..000000000 --- a/src/gvdb/gvdb-builder.c +++ /dev/null @@ -1,514 +0,0 @@ -/* - * Copyright © 2010 Codethink Limited - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the licence, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - * Author: Ryan Lortie <desrt@desrt.ca> - */ - -#include "gvdb-builder.h" -#include "gvdb-format.h" - -#include <glib.h> -#include <fcntl.h> -#if !defined(G_OS_WIN32) || !defined(_MSC_VER) -#include <unistd.h> -#endif -#include <string.h> - - -struct _GvdbItem -{ - gchar *key; - guint32 hash_value; - guint32_le assigned_index; - GvdbItem *parent; - GvdbItem *sibling; - GvdbItem *next; - - /* one of: - * this: - */ - GVariant *value; - - /* this: */ - GHashTable *table; - - /* or this: */ - GvdbItem *child; -}; - -static void -gvdb_item_free (gpointer data) -{ - GvdbItem *item = data; - - g_free (item->key); - - if (item->value) - g_variant_unref (item->value); - - if (item->table) - g_hash_table_unref (item->table); - - g_slice_free (GvdbItem, item); -} - -GHashTable * -gvdb_hash_table_new (GHashTable *parent, - const gchar *name_in_parent) -{ - GHashTable *table; - - table = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, gvdb_item_free); - - if (parent) - { - GvdbItem *item; - - item = gvdb_hash_table_insert (parent, name_in_parent); - gvdb_item_set_hash_table (item, table); - } - - return table; -} - -static guint32 -djb_hash (const gchar *key) -{ - guint32 hash_value = 5381; - - while (*key) - hash_value = hash_value * 33 + *(signed char *)key++; - - return hash_value; -} - -GvdbItem * -gvdb_hash_table_insert (GHashTable *table, - const gchar *key) -{ - GvdbItem *item; - - item = g_slice_new0 (GvdbItem); - item->key = g_strdup (key); - item->hash_value = djb_hash (key); - - g_hash_table_insert (table, g_strdup (key), item); - - return item; -} - -void -gvdb_hash_table_insert_string (GHashTable *table, - const gchar *key, - const gchar *value) -{ - GvdbItem *item; - - item = gvdb_hash_table_insert (table, key); - gvdb_item_set_value (item, g_variant_new_string (value)); -} - -void -gvdb_item_set_value (GvdbItem *item, - GVariant *value) -{ - g_return_if_fail (!item->value && !item->table && !item->child); - - item->value = g_variant_ref_sink (value); -} - -void -gvdb_item_set_hash_table (GvdbItem *item, - GHashTable *table) -{ - g_return_if_fail (!item->value && !item->table && !item->child); - - item->table = g_hash_table_ref (table); -} - -void -gvdb_item_set_parent (GvdbItem *item, - GvdbItem *parent) -{ - GvdbItem **node; - - g_return_if_fail (g_str_has_prefix (item->key, parent->key)); - g_return_if_fail (!parent->value && !parent->table); - g_return_if_fail (!item->parent && !item->sibling); - - for (node = &parent->child; *node; node = &(*node)->sibling) - if (strcmp ((*node)->key, item->key) > 0) - break; - - item->parent = parent; - item->sibling = *node; - *node = item; -} - -typedef struct -{ - GvdbItem **buckets; - gint n_buckets; -} HashTable; - -static HashTable * -hash_table_new (gint n_buckets) -{ - HashTable *table; - - table = g_slice_new (HashTable); - table->buckets = g_new0 (GvdbItem *, n_buckets); - table->n_buckets = n_buckets; - - return table; -} - -static void -hash_table_free (HashTable *table) -{ - g_free (table->buckets); - - g_slice_free (HashTable, table); -} - -static void -hash_table_insert (gpointer key, - gpointer value, - gpointer data) -{ - guint32 hash_value, bucket; - HashTable *table = data; - GvdbItem *item = value; - - hash_value = djb_hash (key); - bucket = hash_value % table->n_buckets; - item->next = table->buckets[bucket]; - table->buckets[bucket] = item; -} - -static guint32_le -item_to_index (GvdbItem *item) -{ - if (item != NULL) - return item->assigned_index; - - return guint32_to_le (-1u); -} - -typedef struct -{ - GQueue *chunks; - guint64 offset; - gboolean byteswap; -} FileBuilder; - -typedef struct -{ - gsize offset; - gsize size; - gpointer data; -} FileChunk; - -static gpointer -file_builder_allocate (FileBuilder *fb, - guint alignment, - gsize size, - struct gvdb_pointer *pointer) -{ - FileChunk *chunk; - - if (size == 0) - return NULL; - - fb->offset += (-fb->offset) & (alignment - 1); - chunk = g_slice_new (FileChunk); - chunk->offset = fb->offset; - chunk->size = size; - chunk->data = g_malloc (size); - - pointer->start = guint32_to_le (fb->offset); - fb->offset += size; - pointer->end = guint32_to_le (fb->offset); - - g_queue_push_tail (fb->chunks, chunk); - - return chunk->data; -} - -static void -file_builder_add_value (FileBuilder *fb, - GVariant *value, - struct gvdb_pointer *pointer) -{ - GVariant *variant, *normal; - gpointer data; - gsize size; - - if (fb->byteswap) - { - value = g_variant_byteswap (value); - variant = g_variant_new_variant (value); - g_variant_unref (value); - } - else - variant = g_variant_new_variant (value); - - normal = g_variant_get_normal_form (variant); - g_variant_unref (variant); - - size = g_variant_get_size (normal); - data = file_builder_allocate (fb, 8, size, pointer); - g_variant_store (normal, data); - g_variant_unref (normal); -} - -static void -file_builder_add_string (FileBuilder *fb, - const gchar *string, - guint32_le *start, - guint16_le *size) -{ - FileChunk *chunk; - gsize length; - - length = strlen (string); - - chunk = g_slice_new (FileChunk); - chunk->offset = fb->offset; - chunk->size = length; - chunk->data = g_malloc (length); - memcpy (chunk->data, string, length); - - *start = guint32_to_le (fb->offset); - *size = guint16_to_le (length); - fb->offset += length; - - g_queue_push_tail (fb->chunks, chunk); -} - -static void -file_builder_allocate_for_hash (FileBuilder *fb, - gsize n_buckets, - gsize n_items, - guint bloom_shift, - gsize n_bloom_words, - guint32_le **bloom_filter, - guint32_le **hash_buckets, - struct gvdb_hash_item **hash_items, - struct gvdb_pointer *pointer) -{ - guint32_le bloom_hdr, table_hdr; - guchar *data; - gsize size; - - g_assert (n_bloom_words < (1u << 27)); - - bloom_hdr = guint32_to_le (bloom_shift << 27 | n_bloom_words); - table_hdr = guint32_to_le (n_buckets); - - size = sizeof bloom_hdr + sizeof table_hdr + - n_bloom_words * sizeof (guint32_le) + - n_buckets * sizeof (guint32_le) + - n_items * sizeof (struct gvdb_hash_item); - - data = file_builder_allocate (fb, 4, size, pointer); - -#define chunk(s) (size -= (s), data += (s), data - (s)) - memcpy (chunk (sizeof bloom_hdr), &bloom_hdr, sizeof bloom_hdr); - memcpy (chunk (sizeof table_hdr), &table_hdr, sizeof table_hdr); - *bloom_filter = (guint32_le *) chunk (n_bloom_words * sizeof (guint32_le)); - *hash_buckets = (guint32_le *) chunk (n_buckets * sizeof (guint32_le)); - *hash_items = (struct gvdb_hash_item *) chunk (n_items * - sizeof (struct gvdb_hash_item)); - g_assert (size == 0); -#undef chunk - - memset (*bloom_filter, 0, n_bloom_words * sizeof (guint32_le)); -} - -static void -file_builder_add_hash (FileBuilder *fb, - GHashTable *table, - struct gvdb_pointer *pointer) -{ - guint32_le *buckets, *bloom_filter; - struct gvdb_hash_item *items; - HashTable *mytable; - GvdbItem *item; - guint32 index; - gint bucket; - - mytable = hash_table_new (g_hash_table_size (table)); - g_hash_table_foreach (table, hash_table_insert, mytable); - index = 0; - - for (bucket = 0; bucket < mytable->n_buckets; bucket++) - for (item = mytable->buckets[bucket]; item; item = item->next) - item->assigned_index = guint32_to_le (index++); - - file_builder_allocate_for_hash (fb, mytable->n_buckets, index, 5, 0, - &bloom_filter, &buckets, &items, pointer); - - index = 0; - for (bucket = 0; bucket < mytable->n_buckets; bucket++) - { - buckets[bucket] = guint32_to_le (index); - - for (item = mytable->buckets[bucket]; item; item = item->next) - { - struct gvdb_hash_item *entry = items++; - const gchar *basename; - - g_assert (index == guint32_from_le (item->assigned_index)); - entry->hash_value = guint32_to_le (item->hash_value); - entry->parent = item_to_index (item->parent); - entry->unused = 0; - - if (item->parent != NULL) - basename = item->key + strlen (item->parent->key); - else - basename = item->key; - - file_builder_add_string (fb, basename, - &entry->key_start, - &entry->key_size); - - if (item->value != NULL) - { - g_assert (item->child == NULL && item->table == NULL); - - file_builder_add_value (fb, item->value, &entry->value.pointer); - entry->type = 'v'; - } - - if (item->child != NULL) - { - guint32 children = 0, i = 0; - guint32_le *offsets; - GvdbItem *child; - - g_assert (item->table == NULL); - - for (child = item->child; child; child = child->sibling) - children++; - - offsets = file_builder_allocate (fb, 4, 4 * children, - &entry->value.pointer); - entry->type = 'L'; - - for (child = item->child; child; child = child->sibling) - offsets[i++] = child->assigned_index; - - g_assert (children == i); - } - - if (item->table != NULL) - { - entry->type = 'H'; - file_builder_add_hash (fb, item->table, &entry->value.pointer); - } - - index++; - } - } - - hash_table_free (mytable); -} - -static FileBuilder * -file_builder_new (gboolean byteswap) -{ - FileBuilder *builder; - - builder = g_slice_new (FileBuilder); - builder->chunks = g_queue_new (); - builder->offset = sizeof (struct gvdb_header); - builder->byteswap = byteswap; - - return builder; -} - -static GString * -file_builder_serialise (FileBuilder *fb, - struct gvdb_pointer root) -{ - struct gvdb_header header = { { 0, }, }; - GString *result; - - if (fb->byteswap) - { - header.signature[0] = GVDB_SWAPPED_SIGNATURE0; - header.signature[1] = GVDB_SWAPPED_SIGNATURE1; - } - else - { - header.signature[0] = GVDB_SIGNATURE0; - header.signature[1] = GVDB_SIGNATURE1; - } - - result = g_string_new (NULL); - - header.root = root; - g_string_append_len (result, (gpointer) &header, sizeof header); - - while (!g_queue_is_empty (fb->chunks)) - { - FileChunk *chunk = g_queue_pop_head (fb->chunks); - - if (result->len != chunk->offset) - { - gchar zero[8] = { 0, }; - - g_assert (chunk->offset > result->len); - g_assert (chunk->offset - result->len < 8); - - g_string_append_len (result, zero, chunk->offset - result->len); - g_assert (result->len == chunk->offset); - } - - g_string_append_len (result, chunk->data, chunk->size); - g_free (chunk->data); - - g_slice_free (FileChunk, chunk); - } - - g_queue_free (fb->chunks); - g_slice_free (FileBuilder, fb); - - return result; -} - -gboolean -gvdb_table_write_contents (GHashTable *table, - const gchar *filename, - gboolean byteswap, - GError **error) -{ - struct gvdb_pointer root; - gboolean status; - FileBuilder *fb; - GString *str; - - fb = file_builder_new (byteswap); - file_builder_add_hash (fb, table, &root); - str = file_builder_serialise (fb, root); - - status = g_file_set_contents (filename, str->str, str->len, error); - g_string_free (str, TRUE); - - return status; -} diff --git a/src/gvdb/gvdb-builder.h b/src/gvdb/gvdb-builder.h deleted file mode 100644 index 8ec05c8be..000000000 --- a/src/gvdb/gvdb-builder.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright © 2010 Codethink Limited - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the licence, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - * Author: Ryan Lortie <desrt@desrt.ca> - */ - -#ifndef __gvdb_builder_h__ -#define __gvdb_builder_h__ - -#include <gio/gio.h> - -typedef struct _GvdbItem GvdbItem; - -G_GNUC_INTERNAL -GHashTable * gvdb_hash_table_new (GHashTable *parent, - const gchar *key); - -G_GNUC_INTERNAL -GvdbItem * gvdb_hash_table_insert (GHashTable *table, - const gchar *key); -G_GNUC_INTERNAL -void gvdb_hash_table_insert_string (GHashTable *table, - const gchar *key, - const gchar *value); - -G_GNUC_INTERNAL -void gvdb_item_set_value (GvdbItem *item, - GVariant *value); -G_GNUC_INTERNAL -void gvdb_item_set_hash_table (GvdbItem *item, - GHashTable *table); -G_GNUC_INTERNAL -void gvdb_item_set_parent (GvdbItem *item, - GvdbItem *parent); - -G_GNUC_INTERNAL -gboolean gvdb_table_write_contents (GHashTable *table, - const gchar *filename, - gboolean byteswap, - GError **error); - -#endif /* __gvdb_builder_h__ */ diff --git a/src/gvdb/gvdb-format.h b/src/gvdb/gvdb-format.h deleted file mode 100644 index 486e85474..000000000 --- a/src/gvdb/gvdb-format.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright © 2010 Codethink Limited - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the licence, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - * Author: Ryan Lortie <desrt@desrt.ca> - */ - -#ifndef __gvdb_format_h__ -#define __gvdb_format_h__ - -#include <glib.h> - -typedef struct { guint16 value; } guint16_le; -typedef struct { guint32 value; } guint32_le; - -struct gvdb_pointer { - guint32_le start; - guint32_le end; -}; - -struct gvdb_hash_header { - guint32_le n_bloom_words; - guint32_le n_buckets; -}; - -struct gvdb_hash_item { - guint32_le hash_value; - guint32_le parent; - - guint32_le key_start; - guint16_le key_size; - gchar type; - gchar unused; - - union - { - struct gvdb_pointer pointer; - gchar direct[8]; - } value; -}; - -struct gvdb_header { - guint32 signature[2]; - guint32_le version; - guint32_le options; - - struct gvdb_pointer root; -}; - -static inline guint32_le guint32_to_le (guint32 value) { - guint32_le result = { GUINT32_TO_LE (value) }; - return result; -} - -static inline guint32 guint32_from_le (guint32_le value) { - return GUINT32_FROM_LE (value.value); -} - -static inline guint16_le guint16_to_le (guint16 value) { - guint16_le result = { GUINT16_TO_LE (value) }; - return result; -} - -static inline guint16 guint16_from_le (guint16_le value) { - return GUINT16_FROM_LE (value.value); -} - -#define GVDB_SIGNATURE0 1918981703 -#define GVDB_SIGNATURE1 1953390953 -#define GVDB_SWAPPED_SIGNATURE0 GUINT32_SWAP_LE_BE (GVDB_SIGNATURE0) -#define GVDB_SWAPPED_SIGNATURE1 GUINT32_SWAP_LE_BE (GVDB_SIGNATURE1) - -#endif /* __gvdb_format_h__ */ diff --git a/src/gvdb/gvdb-reader.c b/src/gvdb/gvdb-reader.c deleted file mode 100644 index 60c722894..000000000 --- a/src/gvdb/gvdb-reader.c +++ /dev/null @@ -1,673 +0,0 @@ -/* - * Copyright © 2010 Codethink Limited - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the licence, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - * Author: Ryan Lortie <desrt@desrt.ca> - */ - -#include "gvdb-reader.h" -#include "gvdb-format.h" - -#include <string.h> - -struct _GvdbTable { - gint ref_count; - - const gchar *data; - gsize size; - - GMappedFile *mapped; - gboolean byteswapped; - gboolean trusted; - - const guint32_le *bloom_words; - guint32 n_bloom_words; - guint bloom_shift; - - const guint32_le *hash_buckets; - guint32 n_buckets; - - struct gvdb_hash_item *hash_items; - guint32 n_hash_items; -}; - -static const gchar * -gvdb_table_item_get_key (GvdbTable *file, - const struct gvdb_hash_item *item, - gsize *size) -{ - guint32 start, end; - - start = guint32_from_le (item->key_start); - *size = guint16_from_le (item->key_size); - end = start + *size; - - if G_UNLIKELY (start > end || end > file->size) - return NULL; - - return file->data + start; -} - -static gconstpointer -gvdb_table_dereference (GvdbTable *file, - const struct gvdb_pointer *pointer, - gint alignment, - gsize *size) -{ - guint32 start, end; - - start = guint32_from_le (pointer->start); - end = guint32_from_le (pointer->end); - - if G_UNLIKELY (start > end || end > file->size || start & (alignment - 1)) - return NULL; - - *size = end - start; - - return file->data + start; -} - -static void -gvdb_table_setup_root (GvdbTable *file, - const struct gvdb_pointer *pointer) -{ - const struct gvdb_hash_header *header; - guint32 n_bloom_words; - guint32 n_buckets; - gsize size; - - header = gvdb_table_dereference (file, pointer, 4, &size); - - if G_UNLIKELY (header == NULL || size < sizeof *header) - return; - - size -= sizeof *header; - - n_bloom_words = guint32_from_le (header->n_bloom_words); - n_buckets = guint32_from_le (header->n_buckets); - n_bloom_words &= (1u << 27) - 1; - - if G_UNLIKELY (n_bloom_words * sizeof (guint32_le) > size) - return; - - file->bloom_words = (gpointer) (header + 1); - size -= n_bloom_words * sizeof (guint32_le); - file->n_bloom_words = n_bloom_words; - - if G_UNLIKELY (n_buckets > G_MAXUINT / sizeof (guint32_le) || - n_buckets * sizeof (guint32_le) > size) - return; - - file->hash_buckets = file->bloom_words + file->n_bloom_words; - size -= n_buckets * sizeof (guint32_le); - file->n_buckets = n_buckets; - - if G_UNLIKELY (size % sizeof (struct gvdb_hash_item)) - return; - - file->hash_items = (gpointer) (file->hash_buckets + n_buckets); - file->n_hash_items = size / sizeof (struct gvdb_hash_item); -} - -/** - * gvdb_table_new: - * @filename: the path to the hash file - * @trusted: if the contents of @filename are trusted - * @error: %NULL, or a pointer to a %NULL #GError - * @returns: a new #GvdbTable - * - * Creates a new #GvdbTable from the contents of the file found at - * @filename. - * - * The only time this function fails is if the file can not be opened. - * In that case, the #GError that is returned will be an error from - * g_mapped_file_new(). - * - * An empty or otherwise corrupted file is considered to be a valid - * #GvdbTable with no entries. - * - * You should call gvdb_table_unref() on the return result when you no - * longer require it. - **/ -GvdbTable * -gvdb_table_new (const gchar *filename, - gboolean trusted, - GError **error) -{ - GMappedFile *mapped; - GvdbTable *file; - - if ((mapped = g_mapped_file_new (filename, FALSE, error)) == NULL) - return NULL; - - file = g_slice_new0 (GvdbTable); - file->data = g_mapped_file_get_contents (mapped); - file->size = g_mapped_file_get_length (mapped); - file->trusted = trusted; - file->mapped = mapped; - file->ref_count = 1; - - if (sizeof (struct gvdb_header) <= file->size) - { - const struct gvdb_header *header = (gpointer) file->data; - - if (header->signature[0] == GVDB_SIGNATURE0 && - header->signature[1] == GVDB_SIGNATURE1 && - guint32_from_le (header->version) == 0) - file->byteswapped = FALSE; - - else if (header->signature[0] == GVDB_SWAPPED_SIGNATURE0 && - header->signature[1] == GVDB_SWAPPED_SIGNATURE1 && - guint32_from_le (header->version) == 0) - file->byteswapped = TRUE; - - else - { - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, - "%s: invalid header", filename); - g_slice_free (GvdbTable, file); - g_mapped_file_unref (mapped); - - return NULL; - } - - gvdb_table_setup_root (file, &header->root); - } - - return file; -} - -static gboolean -gvdb_table_bloom_filter (GvdbTable *file, - guint32 hash_value) -{ - guint32 word, mask; - - if (file->n_bloom_words == 0) - return TRUE; - - word = (hash_value / 32) % file->n_bloom_words; - mask = 1 << (hash_value & 31); - mask |= 1 << ((hash_value >> file->bloom_shift) & 31); - - return (guint32_from_le (file->bloom_words[word]) & mask) == mask; -} - -static gboolean -gvdb_table_check_name (GvdbTable *file, - struct gvdb_hash_item *item, - const gchar *key, - guint key_length) -{ - const gchar *this_key; - gsize this_size; - guint32 parent; - - this_key = gvdb_table_item_get_key (file, item, &this_size); - - if G_UNLIKELY (this_key == NULL || this_size > key_length) - return FALSE; - - key_length -= this_size; - - if G_UNLIKELY (memcmp (this_key, key + key_length, this_size) != 0) - return FALSE; - - parent = guint32_from_le (item->parent); - if (key_length == 0 && parent == 0xffffffffu) - return TRUE; - - if G_LIKELY (parent < file->n_hash_items && this_size > 0) - return gvdb_table_check_name (file, - &file->hash_items[parent], - key, key_length); - - return FALSE; -} - -static const struct gvdb_hash_item * -gvdb_table_lookup (GvdbTable *file, - const gchar *key, - gchar type) -{ - guint32 hash_value = 5381; - guint key_length; - guint32 bucket; - guint32 lastno; - guint32 itemno; - - if G_UNLIKELY (file->n_buckets == 0 || file->n_hash_items == 0) - return NULL; - - for (key_length = 0; key[key_length]; key_length++) - hash_value = (hash_value * 33) + ((signed char *) key)[key_length]; - - if (!gvdb_table_bloom_filter (file, hash_value)) - return NULL; - - bucket = hash_value % file->n_buckets; - itemno = guint32_from_le (file->hash_buckets[bucket]); - - if (bucket == file->n_buckets - 1 || - (lastno = guint32_from_le(file->hash_buckets[bucket + 1])) > file->n_hash_items) - lastno = file->n_hash_items; - - while G_LIKELY (itemno < lastno) - { - struct gvdb_hash_item *item = &file->hash_items[itemno]; - - if (hash_value == guint32_from_le (item->hash_value)) - if G_LIKELY (gvdb_table_check_name (file, item, key, key_length)) - if G_LIKELY (item->type == type) - return item; - - itemno++; - } - - return NULL; -} - -static const struct gvdb_hash_item * -gvdb_table_get_item (GvdbTable *table, - guint32_le item_no) -{ - guint32 item_no_native = guint32_from_le (item_no); - - if G_LIKELY (item_no_native < table->n_hash_items) - return table->hash_items + item_no_native; - - return NULL; -} - -static gboolean -gvdb_table_list_from_item (GvdbTable *table, - const struct gvdb_hash_item *item, - const guint32_le **list, - guint *length) -{ - gsize size; - - *list = gvdb_table_dereference (table, &item->value.pointer, 4, &size); - - if G_LIKELY (*list == NULL || size % 4) - return FALSE; - - *length = size / 4; - - return TRUE; -} - - -/** - * gvdb_table_list: - * @file: a #GvdbTable - * @key: a string - * @returns: a %NULL-terminated string array - * - * List all of the keys that appear below @key. The nesting of keys - * within the hash file is defined by the program that created the hash - * file. One thing is constant: each item in the returned array can be - * concatenated to @key to obtain the full name of that key. - * - * It is not possible to tell from this function if a given key is - * itself a path, a value, or another hash table; you are expected to - * know this for yourself. - * - * You should call g_strfreev() on the return result when you no longer - * require it. - **/ -gchar ** -gvdb_table_list (GvdbTable *file, - const gchar *key) -{ - const struct gvdb_hash_item *item; - const guint32_le *list; - gchar **strv; - guint length; - guint i; - - if ((item = gvdb_table_lookup (file, key, 'L')) == NULL) - return NULL; - - if (!gvdb_table_list_from_item (file, item, &list, &length)) - return NULL; - - strv = g_new (gchar *, length + 1); - for (i = 0; i < length; i++) - { - guint32 itemno = guint32_from_le (list[i]); - - if (itemno < file->n_hash_items) - { - const struct gvdb_hash_item *item; - const gchar *string; - gsize strsize; - - item = file->hash_items + itemno; - - string = gvdb_table_item_get_key (file, item, &strsize); - - if (string != NULL) - strv[i] = g_strndup (string, strsize); - else - strv[i] = g_malloc0 (1); - } - else - strv[i] = g_malloc0 (1); - } - - strv[i] = NULL; - - return strv; -} - -/** - * gvdb_table_has_value: - * @file: a #GvdbTable - * @key: a string - * @returns: %TRUE if @key is in the table - * - * Checks for a value named @key in @file. - * - * Note: this function does not consider non-value nodes (other hash - * tables, for example). - **/ -gboolean -gvdb_table_has_value (GvdbTable *file, - const gchar *key) -{ - return gvdb_table_lookup (file, key, 'v') != NULL; -} - -static GVariant * -gvdb_table_value_from_item (GvdbTable *table, - const struct gvdb_hash_item *item) -{ - GVariant *variant, *value; - gconstpointer data; - gsize size; - - data = gvdb_table_dereference (table, &item->value.pointer, 8, &size); - - if G_UNLIKELY (data == NULL) - return NULL; - - variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, - data, size, table->trusted, - (GDestroyNotify) g_mapped_file_unref, - g_mapped_file_ref (table->mapped)); - value = g_variant_get_variant (variant); - g_variant_unref (variant); - - return value; -} - -/** - * gvdb_table_get_value: - * @file: a #GvdbTable - * @key: a string - * @returns: a #GVariant, or %NULL - * - * Looks up a value named @key in @file. - * - * If the value is not found then %NULL is returned. Otherwise, a new - * #GVariant instance is returned. The #GVariant does not depend on the - * continued existence of @file. - * - * You should call g_variant_unref() on the return result when you no - * longer require it. - **/ -GVariant * -gvdb_table_get_value (GvdbTable *file, - const gchar *key) -{ - const struct gvdb_hash_item *item; - GVariant *value; - - if ((item = gvdb_table_lookup (file, key, 'v')) == NULL) - return NULL; - - value = gvdb_table_value_from_item (file, item); - - if (value && file->byteswapped) - { - GVariant *tmp; - - tmp = g_variant_byteswap (value); - g_variant_unref (value); - value = tmp; - } - - return value; -} - -/** - * gvdb_table_get_raw_value: - * @table: a #GvdbTable - * @key: a string - * @returns: a #GVariant, or %NULL - * - * Looks up a value named @key in @file. - * - * This call is equivalent to gvdb_table_get_value() except that it - * never byteswaps the value. - **/ -GVariant * -gvdb_table_get_raw_value (GvdbTable *table, - const gchar *key) -{ - const struct gvdb_hash_item *item; - - if ((item = gvdb_table_lookup (table, key, 'v')) == NULL) - return NULL; - - return gvdb_table_value_from_item (table, item); -} - -/** - * gvdb_table_get_table: - * @file: a #GvdbTable - * @key: a string - * @returns: a new #GvdbTable, or %NULL - * - * Looks up the hash table named @key in @file. - * - * The toplevel hash table in a #GvdbTable can contain reference to - * child hash tables (and those can contain further references...). - * - * If @key is not found in @file then %NULL is returned. Otherwise, a - * new #GvdbTable is returned, referring to the child hashtable as - * contained in the file. This newly-created #GvdbTable does not depend - * on the continued existence of @file. - * - * You should call gvdb_table_unref() on the return result when you no - * longer require it. - **/ -GvdbTable * -gvdb_table_get_table (GvdbTable *file, - const gchar *key) -{ - const struct gvdb_hash_item *item; - GvdbTable *new; - - item = gvdb_table_lookup (file, key, 'H'); - - if (item == NULL) - return NULL; - - new = g_slice_new0 (GvdbTable); - new->mapped = g_mapped_file_ref (file->mapped); - new->byteswapped = file->byteswapped; - new->trusted = file->trusted; - new->data = file->data; - new->size = file->size; - new->ref_count = 1; - - gvdb_table_setup_root (new, &item->value.pointer); - - return new; -} - -/** - * gvdb_table_ref: - * @file: a #GvdbTable - * @returns: a new reference on @file - * - * Increases the reference count on @file. - **/ -GvdbTable * -gvdb_table_ref (GvdbTable *file) -{ - g_atomic_int_inc (&file->ref_count); - - return file; -} - -/** - * gvdb_table_unref: - * @file: a #GvdbTable - * - * Decreases the reference count on @file, possibly freeing it. - * - * Since: 2.26 - **/ -void -gvdb_table_unref (GvdbTable *file) -{ - if (g_atomic_int_dec_and_test (&file->ref_count)) - { - g_mapped_file_unref (file->mapped); - g_slice_free (GvdbTable, file); - } -} - -/** - * gvdb_table_is_valid: - * @table: a #GvdbTable - * @returns: %TRUE if @table is still valid - * - * Checks if the table is still valid. - * - * An on-disk GVDB can be marked as invalid. This happens when the file - * has been replaced. The appropriate action is typically to reopen the - * file. - **/ -gboolean -gvdb_table_is_valid (GvdbTable *table) -{ - return !!*table->data; -} - -/** - * gvdb_table_walk: - * @table: a #GvdbTable - * @key: a key corresponding to a list - * @open_func: the #GvdbWalkOpenFunc - * @value_func: the #GvdbWalkValueFunc - * @close_func: the #GvdbWalkCloseFunc - * @user_data: data to pass to the callbacks - * - * Looks up the list at @key and iterate over the items in it. - * - * First, @open_func is called to signal that we are starting to iterate over - * the list. Then the list is iterated. When all items in the list have been - * iterated over, the @close_func is called. - * - * When iterating, if a given item in the list is a value then @value_func is - * called. - * - * If a given item in the list is itself a list then @open_func is called. If - * that function returns %TRUE then the walk begins iterating the items in the - * sublist, until there are no more items, at which point a matching - * @close_func call is made. If @open_func returns %FALSE then no iteration of - * the sublist occurs and no corresponding @close_func call is made. - **/ -void -gvdb_table_walk (GvdbTable *table, - const gchar *key, - GvdbWalkOpenFunc open_func, - GvdbWalkValueFunc value_func, - GvdbWalkCloseFunc close_func, - gpointer user_data) -{ - const struct gvdb_hash_item *item; - const guint32_le *pointers[64]; - const guint32_le *enders[64]; - gsize name_lengths[64]; - gint index = 0; - - item = gvdb_table_lookup (table, key, 'L'); - name_lengths[0] = 0; - pointers[0] = NULL; - enders[0] = NULL; - goto start_here; - - while (index) - { - close_func (name_lengths[index], user_data); - index--; - - while (pointers[index] < enders[index]) - { - const gchar *name; - gsize name_len; - - item = gvdb_table_get_item (table, *pointers[index]++); - start_here: - - if (item != NULL && - (name = gvdb_table_item_get_key (table, item, &name_len))) - { - if (item->type == 'L') - { - if (open_func (name, name_len, user_data)) - { - guint length; - - index++; - g_assert (index < 64); - - gvdb_table_list_from_item (table, item, - &pointers[index], - &length); - enders[index] = pointers[index] + length; - name_lengths[index] = name_len; - } - } - else if (item->type == 'v') - { - GVariant *value; - - value = gvdb_table_value_from_item (table, item); - - if (value != NULL) - { - if (table->byteswapped) - { - GVariant *tmp; - - tmp = g_variant_byteswap (value); - g_variant_unref (value); - value = tmp; - } - - value_func (name, name_len, value, user_data); - g_variant_unref (value); - } - } - } - } - } -} diff --git a/src/gvdb/gvdb-reader.h b/src/gvdb/gvdb-reader.h deleted file mode 100644 index 8e718361a..000000000 --- a/src/gvdb/gvdb-reader.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright © 2010 Codethink Limited - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the licence, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - * Author: Ryan Lortie <desrt@desrt.ca> - */ - -#ifndef __gvdb_reader_h__ -#define __gvdb_reader_h__ - -#include <glib.h> - -typedef struct _GvdbTable GvdbTable; - -G_BEGIN_DECLS - -G_GNUC_INTERNAL -GvdbTable * gvdb_table_new (const gchar *filename, - gboolean trusted, - GError **error); -G_GNUC_INTERNAL -GvdbTable * gvdb_table_ref (GvdbTable *table); -G_GNUC_INTERNAL -void gvdb_table_unref (GvdbTable *table); - -G_GNUC_INTERNAL -gchar ** gvdb_table_list (GvdbTable *table, - const gchar *key); -G_GNUC_INTERNAL -GvdbTable * gvdb_table_get_table (GvdbTable *table, - const gchar *key); -G_GNUC_INTERNAL -GVariant * gvdb_table_get_raw_value (GvdbTable *table, - const gchar *key); -G_GNUC_INTERNAL -GVariant * gvdb_table_get_value (GvdbTable *table, - const gchar *key); - -G_GNUC_INTERNAL -gboolean gvdb_table_has_value (GvdbTable *table, - const gchar *key); - -G_GNUC_INTERNAL -gboolean gvdb_table_is_valid (GvdbTable *table); - -typedef void (*GvdbWalkValueFunc) (const gchar *name, - gsize name_len, - GVariant *value, - gpointer user_data); -typedef gboolean (*GvdbWalkOpenFunc) (const gchar *name, - gsize name_len, - gpointer user_data); -typedef void (*GvdbWalkCloseFunc) (gsize name_len, - gpointer user_data); - -G_GNUC_INTERNAL -void gvdb_table_walk (GvdbTable *table, - const gchar *key, - GvdbWalkOpenFunc open_func, - GvdbWalkValueFunc value_func, - GvdbWalkCloseFunc close_func, - gpointer user_data); - -G_END_DECLS - -#endif /* __gvdb_reader_h__ */ diff --git a/src/gvdb/meson.build b/src/gvdb/meson.build deleted file mode 100644 index 82177dd7f..000000000 --- a/src/gvdb/meson.build +++ /dev/null @@ -1,14 +0,0 @@ -gvdb_dependencies = [glib] - -libgvdb = static_library('gvdb', - 'gvdb-builder.c', - 'gvdb-reader.c', - dependencies: gvdb_dependencies, - pic: true, -) - -gvdb_dep = declare_dependency( - link_with: libgvdb, - dependencies: gvdb_dependencies, - include_directories: include_directories('..'), -) diff --git a/src/libtracker-sparql/core/meson.build b/src/libtracker-sparql/core/meson.build index c409f2684..299504245 100644 --- a/src/libtracker-sparql/core/meson.build +++ b/src/libtracker-sparql/core/meson.build @@ -5,7 +5,7 @@ tracker_data_enums = gnome.mkenums('tracker-data-enum-types', ) tracker_data_dependencies = [ - tracker_common_dep, gvdb_dep, sqlite, + tracker_common_dep, sqlite, ] core_files = files( diff --git a/src/libtracker-sparql/core/tracker-ontologies.c b/src/libtracker-sparql/core/tracker-ontologies.c index c54a42dba..064019b50 100644 --- a/src/libtracker-sparql/core/tracker-ontologies.c +++ b/src/libtracker-sparql/core/tracker-ontologies.c @@ -141,10 +141,10 @@ tracker_ontologies_finalize (GObject *object) g_clear_object (&priv->nrl_modified); if (priv->gvdb_table) { - gvdb_table_unref (priv->gvdb_properties_table); - gvdb_table_unref (priv->gvdb_classes_table); - gvdb_table_unref (priv->gvdb_namespaces_table); - gvdb_table_unref (priv->gvdb_table); + gvdb_table_free (priv->gvdb_properties_table); + gvdb_table_free (priv->gvdb_classes_table); + gvdb_table_free (priv->gvdb_namespaces_table); + gvdb_table_free (priv->gvdb_table); } G_OBJECT_CLASS (tracker_ontologies_parent_class)->finalize (object); diff --git a/src/libtracker-sparql/meson.build b/src/libtracker-sparql/meson.build index a109e036a..10140cff2 100644 --- a/src/libtracker-sparql/meson.build +++ b/src/libtracker-sparql/meson.build @@ -112,7 +112,7 @@ libtracker_sparql_private = static_library('tracker-sparql-private', '-DBUILDROOT="@0@"'.format(meson.build_root()), ] + tracker_c_args, - dependencies: [libtracker_sparql_dependencies], + dependencies: [libtracker_sparql_dependencies, gvdb_dep], gnu_symbol_visibility: 'hidden', ) diff --git a/src/meson.build b/src/meson.build index e3d330c6c..e1dba503a 100644 --- a/src/meson.build +++ b/src/meson.build @@ -4,8 +4,6 @@ subdir('libtracker-common') # Public ontologies subdir('ontologies') -subdir('gvdb') - # Intermediate library of RDF & SPARQL helper functions. # This gets used internally and also becomes part of the # public libtracker-sparql library. diff --git a/subprojects/gvdb b/subprojects/gvdb new file mode 160000 +Subproject 0854af0fdb6d527a8d1999835ac2c5059976c21 diff --git a/subprojects/gvdb.wrap b/subprojects/gvdb.wrap new file mode 100644 index 000000000..f01146056 --- /dev/null +++ b/subprojects/gvdb.wrap @@ -0,0 +1,8 @@ +[wrap-git] +directory = gvdb +url = https://gitlab.gnome.org/GNOME/gvdb.git +revision = 0854af0fdb6d527a8d1999835ac2c5059976c210 + +[provide] +gvdb = gvdb_dep + diff --git a/tests/gvdb/gvdb-test.c b/tests/gvdb/gvdb-test.c index ad91c7c6d..d32cc1dc1 100644 --- a/tests/gvdb/gvdb-test.c +++ b/tests/gvdb/gvdb-test.c @@ -14,72 +14,6 @@ remove_file (const gchar *filename) } static void -walk_value_cb (G_GNUC_UNUSED const gchar *name, - G_GNUC_UNUSED gsize name_len, - G_GNUC_UNUSED GVariant *value, - gpointer user_data) -{ - gint *counter = (gint *)user_data; - (*counter) += 1; -} - -static gboolean -walk_open_cb (G_GNUC_UNUSED const gchar *name, - G_GNUC_UNUSED gsize name_len, - G_GNUC_UNUSED gpointer user_data) -{ - return TRUE; -} - -static void -walk_close_cb (G_GNUC_UNUSED gsize name_len, - G_GNUC_UNUSED gpointer user_data) -{ -} - -static void -test_gvdb_walk (void) -{ - GHashTable *root_table, *ns_table; - GvdbItem *root, *item; - GvdbTable *root_level, *ns_level; - guint32 item_id; - gchar *key; - gint counter = 0; - - const gchar *DB_FILE = "./test_walk.gvdb"; - - root_table = gvdb_hash_table_new (NULL, NULL); - - ns_table = gvdb_hash_table_new (root_table, "namespaces"); - root = gvdb_hash_table_insert (ns_table, ""); - for (item_id = 0; item_id < 3; item_id++) { - key = g_strdup_printf ("ns%d", item_id); - item = gvdb_hash_table_insert (ns_table, key); - gvdb_item_set_parent (item, root); - gvdb_item_set_value (item, g_variant_new_string ("http://some.cool.ns")); - g_free (key); - } - - g_assert_true (gvdb_table_write_contents (root_table, DB_FILE, FALSE, NULL)); - - g_hash_table_unref (ns_table); - g_hash_table_unref (root_table); - - - root_level = gvdb_table_new (DB_FILE, TRUE, NULL); - ns_level = gvdb_table_get_table (root_level, "namespaces"); - - gvdb_table_walk (ns_level, "", walk_open_cb, walk_value_cb, walk_close_cb, &counter); - g_assert_cmpint (counter, ==, 3); - - gvdb_table_unref (root_level); - gvdb_table_unref (ns_level); - - remove_file (DB_FILE); -} - -static void test_gvdb_nested_keys (void) { GHashTable *root_table, *ns_table; @@ -127,8 +61,8 @@ test_gvdb_nested_keys (void) } g_strfreev (keys); - gvdb_table_unref (root_level); - gvdb_table_unref (ns_level); + gvdb_table_free (root_level); + gvdb_table_free (ns_level); remove_file (DB_FILE); } @@ -157,7 +91,7 @@ simple_test (const gchar *filename, gboolean use_byteswap) g_variant_unref (expected); g_variant_unref (value); - gvdb_table_unref (read); + gvdb_table_free (read); } static void @@ -182,42 +116,6 @@ test_gvdb_flat_strings (void) } static void -test_gvdb_ref_unref (void) -{ - GHashTable *table; - GvdbTable *read, *read_ref; - GVariant *value; - GVariant *expected; - - const gchar *DB_FILE = "./test_ref_unref.gvdb"; - - /* Create a table */ - table = gvdb_hash_table_new (NULL, "level1"); - gvdb_hash_table_insert_string (table, "key1", "whatever"); - g_assert_true (gvdb_table_write_contents (table, DB_FILE, FALSE, NULL)); - g_hash_table_unref (table); - - /* Read the table */ - read = gvdb_table_new (DB_FILE, TRUE, NULL); - g_assert_true (read && gvdb_table_is_valid (read)); - - /* Run the checks with a reference */ - read_ref = gvdb_table_ref (read); - g_assert_true (gvdb_table_has_value (read_ref, "key1")); - value = gvdb_table_get_value (read_ref, "key1"); - expected = g_variant_new_string ("whatever"); - g_assert_true (g_variant_equal (value, expected)); - - g_variant_unref (expected); - g_variant_unref (value); - - gvdb_table_unref (read); - gvdb_table_unref (read_ref); - - remove_file (DB_FILE); -} - -static void test_gvdb_corrupted_file (void) { GError *error = NULL; @@ -239,10 +137,8 @@ main (gint argc, gchar **argv) { g_test_init (&argc, &argv, NULL); - g_test_add_func ("/gvdb/ref_unref", test_gvdb_ref_unref); g_test_add_func ("/gvdb/flat_strings", test_gvdb_flat_strings); g_test_add_func ("/gvdb/nested_keys", test_gvdb_nested_keys); - g_test_add_func ("/gvdb/walk", test_gvdb_walk); g_test_add_func ("/gvdb/byteswapped", test_gvdb_byteswapped); g_test_add_func ("/gvdb/corrupted_file", test_gvdb_corrupted_file); diff --git a/tests/gvdb/meson.build b/tests/gvdb/meson.build index 558f0f4e2..5cdf4ac9a 100644 --- a/tests/gvdb/meson.build +++ b/tests/gvdb/meson.build @@ -1,6 +1,6 @@ gvdb_test = executable('gvdb-test', 'gvdb-test.c', - dependencies: gvdb_dep, + dependencies: [gio, gvdb_dep], include_directories: configinc, ) |