Linux: use generated library loader for gsettings.

BUG=162733
TEST=Test proxy settings on a system with GNOME3.

Review URL: https://codereview.chromium.org/11348279

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@170544 0039d316-1c4b-4281-b951-d872f2087c98
parent c5926242
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BUILD_LINUX_GSETTINGS_H_
#define BUILD_LINUX_GSETTINGS_H_
#include <gio/gio.h>
// The GSettings API was not part of GIO until GIO version 2.26,
// while Ubuntu 10.04 Lucid ships with version 2.24.
//
// To allow compiling on Lucid those forward declarations are provided.
//
// If compiling with GIO version 2.26, these won't conflict,
// because they're identical to the types defined.
//
// TODO(phajdan.jr): This will no longer be needed after switch to Precise,
// see http://crbug.com/158577 .
struct _GSettings;
typedef struct _GSettings GSettings;
GSettings* g_settings_new(const gchar* schema);
GSettings* g_settings_get_child(GSettings* settings, const gchar* name);
gboolean g_settings_get_boolean(GSettings* settings, const gchar* key);
gchar* g_settings_get_string(GSettings* settings, const gchar* key);
gint g_settings_get_int(GSettings* settings, const gchar* key);
gchar** g_settings_get_strv(GSettings* settings, const gchar* key);
const gchar* const* g_settings_list_schemas();
#endif // BUILD_LINUX_GSETTINGS_H_
...@@ -242,9 +242,15 @@ ...@@ -242,9 +242,15 @@
}, },
{ {
'target_name': 'gio', 'target_name': 'gio',
'type': 'none', 'type': 'static_library',
'conditions': [ 'conditions': [
['use_gio==1 and _toolset=="target"', { ['use_gio==1 and _toolset=="target"', {
'dependencies': [
'../../base/base.gyp:base',
],
'cflags': [
'<!@(<(pkg-config) --cflags gio-2.0)',
],
'direct_dependent_settings': { 'direct_dependent_settings': {
'cflags': [ 'cflags': [
'<!@(<(pkg-config) --cflags gio-2.0)', '<!@(<(pkg-config) --cflags gio-2.0)',
...@@ -252,10 +258,8 @@ ...@@ -252,10 +258,8 @@
'defines': [ 'defines': [
'USE_GIO', 'USE_GIO',
], ],
'conditions': [ 'include_dirs': [
['linux_link_gsettings==0', { '<(SHARED_INTERMEDIATE_DIR)',
'defines': ['DLOPEN_GSETTINGS'],
}],
], ],
}, },
'link_settings': { 'link_settings': {
...@@ -273,6 +277,44 @@ ...@@ -273,6 +277,44 @@
}], }],
], ],
}, },
'hard_dependency': 1,
'actions': [
{
'variables': {
'output_h': '<(SHARED_INTERMEDIATE_DIR)/library_loaders/libgio.h',
'output_cc': '<(INTERMEDIATE_DIR)/libgio_loader.cc',
'generator': '../../tools/generate_library_loader/generate_library_loader.py',
},
'action_name': 'generate_libgio_loader',
'inputs': [
'<(generator)',
],
'outputs': [
'<(output_h)',
'<(output_cc)',
],
'action': ['python',
'<(generator)',
'--name', 'LibGioLoader',
'--output-h', '<(output_h)',
'--output-cc', '<(output_cc)',
'--header', '<gio/gio.h>',
# TODO(phajdan.jr): This will no longer be needed
# after switch to Precise, http://crbug.com/158577 .
'--bundled-header', '"build/linux/gsettings.h"',
'--link-directly=<(linux_link_gsettings)',
'g_settings_new',
'g_settings_get_child',
'g_settings_get_string',
'g_settings_get_boolean',
'g_settings_get_int',
'g_settings_get_strv',
'g_settings_list_schemas',
],
'message': 'Generating libgio library loader.',
'process_outputs_as_sources': 1,
},
],
}], }],
], ],
}, },
...@@ -282,8 +324,8 @@ ...@@ -282,8 +324,8 @@
'cflags': [ 'cflags': [
'<!@(<(pkg-config) --cflags libpci)', '<!@(<(pkg-config) --cflags libpci)',
], ],
'include_dirs': [ 'dependencies': [
'../..', '../../base/base.gyp:base',
], ],
'direct_dependent_settings': { 'direct_dependent_settings': {
'include_dirs': [ 'include_dirs': [
......
...@@ -9,12 +9,6 @@ ...@@ -9,12 +9,6 @@
#if defined(USE_GCONF) #if defined(USE_GCONF)
#include <gconf/gconf-client.h> #include <gconf/gconf-client.h>
#endif // defined(USE_GCONF) #endif // defined(USE_GCONF)
#if defined(USE_GIO)
#include <gio/gio.h>
#if defined(DLOPEN_GSETTINGS)
#include <dlfcn.h>
#endif // defined(DLOPEN_GSETTINGS)
#endif // defined(USE_GIO)
#include <limits.h> #include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
...@@ -43,6 +37,10 @@ ...@@ -43,6 +37,10 @@
#include "net/proxy/proxy_config.h" #include "net/proxy/proxy_config.h"
#include "net/proxy/proxy_server.h" #include "net/proxy/proxy_server.h"
#if defined(USE_GIO)
#include "library_loaders/libgio.h"
#endif // defined(USE_GIO)
namespace net { namespace net {
namespace { namespace {
...@@ -515,16 +513,6 @@ class SettingGetterImplGSettings ...@@ -515,16 +513,6 @@ class SettingGetterImplGSettings
: public ProxyConfigServiceLinux::SettingGetter { : public ProxyConfigServiceLinux::SettingGetter {
public: public:
SettingGetterImplGSettings() : SettingGetterImplGSettings() :
#if defined(DLOPEN_GSETTINGS)
g_settings_new(NULL),
g_settings_get_child(NULL),
g_settings_get_boolean(NULL),
g_settings_get_string(NULL),
g_settings_get_int(NULL),
g_settings_get_strv(NULL),
g_settings_list_schemas(NULL),
gio_handle_(NULL),
#endif
client_(NULL), client_(NULL),
http_client_(NULL), http_client_(NULL),
https_client_(NULL), https_client_(NULL),
...@@ -554,16 +542,10 @@ class SettingGetterImplGSettings ...@@ -554,16 +542,10 @@ class SettingGetterImplGSettings
} }
} }
DCHECK(!client_); DCHECK(!client_);
#if defined(DLOPEN_GSETTINGS)
if (gio_handle_) {
dlclose(gio_handle_);
gio_handle_ = NULL;
}
#endif
} }
bool SchemaExists(const char* schema_name) { bool SchemaExists(const char* schema_name) {
const gchar* const* schemas = g_settings_list_schemas(); const gchar* const* schemas = libgio_loader_.g_settings_list_schemas();
while (*schemas) { while (*schemas) {
if (strcmp(schema_name, static_cast<const char*>(*schemas)) == 0) if (strcmp(schema_name, static_cast<const char*>(*schemas)) == 0)
return true; return true;
...@@ -582,17 +564,17 @@ class SettingGetterImplGSettings ...@@ -582,17 +564,17 @@ class SettingGetterImplGSettings
DCHECK(!task_runner_); DCHECK(!task_runner_);
if (!SchemaExists("org.gnome.system.proxy") || if (!SchemaExists("org.gnome.system.proxy") ||
!(client_ = g_settings_new("org.gnome.system.proxy"))) { !(client_ = libgio_loader_.g_settings_new("org.gnome.system.proxy"))) {
// It's not clear whether/when this can return NULL. // It's not clear whether/when this can return NULL.
LOG(ERROR) << "Unable to create a gsettings client"; LOG(ERROR) << "Unable to create a gsettings client";
return false; return false;
} }
task_runner_ = glib_thread_task_runner; task_runner_ = glib_thread_task_runner;
// We assume these all work if the above call worked. // We assume these all work if the above call worked.
http_client_ = g_settings_get_child(client_, "http"); http_client_ = libgio_loader_.g_settings_get_child(client_, "http");
https_client_ = g_settings_get_child(client_, "https"); https_client_ = libgio_loader_.g_settings_get_child(client_, "https");
ftp_client_ = g_settings_get_child(client_, "ftp"); ftp_client_ = libgio_loader_.g_settings_get_child(client_, "ftp");
socks_client_ = g_settings_get_child(client_, "socks"); socks_client_ = libgio_loader_.g_settings_get_child(client_, "socks");
DCHECK(http_client_ && https_client_ && ftp_client_ && socks_client_); DCHECK(http_client_ && https_client_ && ftp_client_ && socks_client_);
return true; return true;
} }
...@@ -713,41 +695,10 @@ class SettingGetterImplGSettings ...@@ -713,41 +695,10 @@ class SettingGetterImplGSettings
} }
private: private:
#if defined(DLOPEN_GSETTINGS)
// We replicate the prototypes for the g_settings APIs we need. We may not
// even be compiling on a system that has them. If we are, these won't
// conflict both because they are identical and also due to scoping. The
// scoping will also ensure that these get used instead of the global ones.
struct _GSettings;
typedef struct _GSettings GSettings;
GSettings* (*g_settings_new)(const gchar* schema);
GSettings* (*g_settings_get_child)(GSettings* settings, const gchar* name);
gboolean (*g_settings_get_boolean)(GSettings* settings, const gchar* key);
gchar* (*g_settings_get_string)(GSettings* settings, const gchar* key);
gint (*g_settings_get_int)(GSettings* settings, const gchar* key);
gchar** (*g_settings_get_strv)(GSettings* settings, const gchar* key);
const gchar* const* (*g_settings_list_schemas)();
// The library handle.
void* gio_handle_;
// Load a symbol from |gio_handle_| and store it into |*func_ptr|.
bool LoadSymbol(const char* name, void** func_ptr) {
dlerror();
*func_ptr = dlsym(gio_handle_, name);
const char* error = dlerror();
if (error) {
VLOG(1) << "Unable to load symbol " << name << ": " << error;
return false;
}
return true;
}
#endif // defined(DLOPEN_GSETTINGS)
bool GetStringByPath(GSettings* client, const char* key, bool GetStringByPath(GSettings* client, const char* key,
std::string* result) { std::string* result) {
DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(task_runner_->BelongsToCurrentThread());
gchar* value = g_settings_get_string(client, key); gchar* value = libgio_loader_.g_settings_get_string(client, key);
if (!value) if (!value)
return false; return false;
*result = value; *result = value;
...@@ -756,18 +707,19 @@ class SettingGetterImplGSettings ...@@ -756,18 +707,19 @@ class SettingGetterImplGSettings
} }
bool GetBoolByPath(GSettings* client, const char* key, bool* result) { bool GetBoolByPath(GSettings* client, const char* key, bool* result) {
DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(task_runner_->BelongsToCurrentThread());
*result = static_cast<bool>(g_settings_get_boolean(client, key)); *result = static_cast<bool>(
libgio_loader_.g_settings_get_boolean(client, key));
return true; return true;
} }
bool GetIntByPath(GSettings* client, const char* key, int* result) { bool GetIntByPath(GSettings* client, const char* key, int* result) {
DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(task_runner_->BelongsToCurrentThread());
*result = g_settings_get_int(client, key); *result = libgio_loader_.g_settings_get_int(client, key);
return true; return true;
} }
bool GetStringListByPath(GSettings* client, const char* key, bool GetStringListByPath(GSettings* client, const char* key,
std::vector<std::string>* result) { std::vector<std::string>* result) {
DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(task_runner_->BelongsToCurrentThread());
gchar** list = g_settings_get_strv(client, key); gchar** list = libgio_loader_.g_settings_get_strv(client, key);
if (!list) if (!list)
return false; return false;
for (size_t i = 0; list[i]; ++i) { for (size_t i = 0; list[i]; ++i) {
...@@ -818,6 +770,8 @@ class SettingGetterImplGSettings ...@@ -818,6 +770,8 @@ class SettingGetterImplGSettings
// thread. Only for assertions. // thread. Only for assertions.
scoped_refptr<base::SingleThreadTaskRunner> task_runner_; scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
LibGioLoader libgio_loader_;
DISALLOW_COPY_AND_ASSIGN(SettingGetterImplGSettings); DISALLOW_COPY_AND_ASSIGN(SettingGetterImplGSettings);
}; };
...@@ -838,40 +792,16 @@ bool SettingGetterImplGSettings::LoadAndCheckVersion( ...@@ -838,40 +792,16 @@ bool SettingGetterImplGSettings::LoadAndCheckVersion(
// but don't use gsettings for proxy settings, but they do have the old // but don't use gsettings for proxy settings, but they do have the old
// binary, so we detect these systems that way. // binary, so we detect these systems that way.
#ifdef DLOPEN_GSETTINGS // Try also without .0 at the end; on some systems this may be required.
gio_handle_ = dlopen("libgio-2.0.so.0", RTLD_NOW | RTLD_GLOBAL); if (!libgio_loader_.Load("libgio-2.0.so.0") &&
if (!gio_handle_) { !libgio_loader_.Load("libgio-2.0.so")) {
// Try again without .0 at the end; on some systems this may be required. VLOG(1) << "Cannot load gio library. Will fall back to gconf.";
gio_handle_ = dlopen("libgio-2.0.so", RTLD_NOW | RTLD_GLOBAL);
if (!gio_handle_) {
VLOG(1) << "Cannot load gio library. Will fall back to gconf.";
return false;
}
}
if (!LoadSymbol("g_settings_new",
reinterpret_cast<void**>(&g_settings_new)) ||
!LoadSymbol("g_settings_get_child",
reinterpret_cast<void**>(&g_settings_get_child)) ||
!LoadSymbol("g_settings_get_string",
reinterpret_cast<void**>(&g_settings_get_string)) ||
!LoadSymbol("g_settings_get_boolean",
reinterpret_cast<void**>(&g_settings_get_boolean)) ||
!LoadSymbol("g_settings_get_int",
reinterpret_cast<void**>(&g_settings_get_int)) ||
!LoadSymbol("g_settings_get_strv",
reinterpret_cast<void**>(&g_settings_get_strv)) ||
!LoadSymbol("g_settings_list_schemas",
reinterpret_cast<void**>(&g_settings_list_schemas))) {
VLOG(1) << "Cannot load gsettings API. Will fall back to gconf.";
dlclose(gio_handle_);
gio_handle_ = NULL;
return false; return false;
} }
#endif
GSettings* client; GSettings* client;
if (!SchemaExists("org.gnome.system.proxy") || if (!SchemaExists("org.gnome.system.proxy") ||
!(client = g_settings_new("org.gnome.system.proxy"))) { !(client = libgio_loader_.g_settings_new("org.gnome.system.proxy"))) {
VLOG(1) << "Cannot create gsettings client. Will fall back to gconf."; VLOG(1) << "Cannot create gsettings client. Will fall back to gconf.";
return false; return false;
} }
......
...@@ -146,6 +146,7 @@ def main(): ...@@ -146,6 +146,7 @@ def main():
parser.add_option('--output-h') parser.add_option('--output-h')
parser.add_option('--header') parser.add_option('--header')
parser.add_option('--bundled-header')
parser.add_option('--use-extern-c', action='store_true', default=False) parser.add_option('--use-extern-c', action='store_true', default=False)
parser.add_option('--link-directly', type=int, default=0) parser.add_option('--link-directly', type=int, default=0)
...@@ -190,7 +191,10 @@ def main(): ...@@ -190,7 +191,10 @@ def main():
'unique_prefix': unique_prefix 'unique_prefix': unique_prefix
}) })
wrapped_header_include = '#include %s' % options.header header = options.header
if options.link_directly == 0 and options.bundled_header:
header = options.bundled_header
wrapped_header_include = '#include %s\n' % header
# Some libraries (e.g. libpci) have headers that cannot be included # Some libraries (e.g. libpci) have headers that cannot be included
# without extern "C", otherwise they cause the link to fail. # without extern "C", otherwise they cause the link to fail.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment