/* -*- c -*- */
/*
* Copyright 2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
* GNU Radio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* GNU Radio 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
/*
* This file is an attempt to work around a problem that appears on
* certain Ubuntu (and perhaps other) systems. On those systems
* (10.04 is known to have the problem, while 10.10 and later work OK
* without this kludge), we end up with a situation where exceptions
* are not caught by the swig code, even though the swig generated
* code "looks right" and "is right". Details of the issue can be
* found in swig bug 1863647,
* http://sourceforge.net/tracker/index.php?func=detail&aid=1863647&group_id=1645&atid=101645
*
* We work around the problem by loading swig generated guile modules
* using the equivalent of the dlopen's RTLD_GLOBAL flag. This is
* only possible on systems using libtool-2.*. Those systems contain
* the lt_dlavise_global function.
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
extern scm_t_bits scm_tc16_dynamic_obj;
#ifdef HAVE_LT_DLADVISE_GLOBAL
/*
* Load shared module using the equivalent of the RTLD_GLOBAL flag
*/
static lt_dlhandle
dlopenext_global (const char *filename)
{
lt_dlhandle handle = 0;
lt_dladvise advise;
if (!lt_dladvise_init (&advise)
&& !lt_dladvise_ext (&advise)
&& !lt_dladvise_global(&advise))
handle = lt_dlopenadvise (filename, advise);
lt_dladvise_destroy (&advise);
return handle;
}
#else
/*
* We don't have lt_dladvise_global. Fall back to lt_dlopenext.
*/
static lt_dlhandle
dlopenext_global (const char *filename)
{
return lt_dlopenext (filename);
}
#endif
static void *
sysdep_dynl_link_global (const char *fname, const char *subr)
{
lt_dlhandle handle;
handle = dlopenext_global (fname);
if (NULL == handle)
{
SCM fn;
SCM msg;
fn = scm_from_locale_string (fname);
msg = scm_from_locale_string (lt_dlerror ());
scm_misc_error (subr, "file: ~S, message: ~S", scm_list_2 (fn, msg));
}
return (void *) handle;
}
SCM_DEFINE (scm_dynamic_link_global, "dynamic-link-global", 1, 0, 0,
(SCM filename),
"Find the shared object (shared library) denoted by\n"
"@var{filename} and link it into the running Guile\n"
"application. The returned\n"
"scheme object is a ``handle'' for the library which can\n"
"be passed to @code{dynamic-func}, @code{dynamic-call} etc.\n\n"
"Searching for object files is system dependent. Normally,\n"
"if @var{filename} does have an explicit directory it will\n"
"be searched for in locations\n"
"such as @file{/usr/lib} and @file{/usr/local/lib}.")
#define FUNC_NAME s_scm_dynamic_link_global
{
void *handle;
char *file;
scm_dynwind_begin (0);
file = scm_to_locale_string (filename);
scm_dynwind_free (file);
handle = sysdep_dynl_link_global (file, FUNC_NAME);
scm_dynwind_end ();
SCM_RETURN_NEWSMOB2 (scm_tc16_dynamic_obj, SCM_UNPACK (filename), handle);
}
#undef FUNC_NAME
void
scm_init_gnuradio_dynl_global_module(void)
{
scm_c_define_gsubr (s_scm_dynamic_link_global, 1, 0, 0, (SCM (*)()) scm_dynamic_link_global);
}