mirror of
https://git.savannah.gnu.org/git/make.git
synced 2024-12-27 23:06:53 +00:00
7670c84f77
Provides support for dynamically loadable objects in GNU make, as a "technology preview".
157 lines
4 KiB
C
157 lines
4 KiB
C
/* Loading dynamic objects for GNU Make.
|
|
Copyright (C) 2012 Free Software Foundation, Inc.
|
|
This file is part of GNU Make.
|
|
|
|
GNU Make 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 of the License, or (at your option) any later
|
|
version.
|
|
|
|
GNU Make 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 <http://www.gnu.org/licenses/>. */
|
|
|
|
#include "make.h"
|
|
|
|
#if MAKE_LOAD
|
|
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <stdlib.h>
|
|
#include <dlfcn.h>
|
|
#include <errno.h>
|
|
|
|
#define SYMBOL_EXTENSION "_gmake_setup"
|
|
|
|
static void *global_dl = NULL;
|
|
|
|
#include "debug.h"
|
|
#include "filedef.h"
|
|
#include "variable.h"
|
|
|
|
static int
|
|
init_symbol (const struct floc *flocp, const char *ldname, load_func_t symp)
|
|
{
|
|
int r;
|
|
const char *p;
|
|
int nmlen = strlen (ldname);
|
|
char *loaded = allocated_variable_expand("$(.LOADED)");
|
|
|
|
/* If it's already been loaded don't do it again. */
|
|
p = strstr (loaded, ldname);
|
|
r = p && (p==loaded || p[-1]==' ') && (p[nmlen]=='\0' || p[nmlen]==' ');
|
|
free (loaded);
|
|
if (r)
|
|
return 1;
|
|
|
|
/* Now invoke the symbol. */
|
|
r = (*symp) (flocp);
|
|
|
|
/* If it succeeded, add the symbol to the loaded variable. */
|
|
if (r > 0)
|
|
do_variable_definition (flocp, ".LOADED", ldname, o_default, f_append, 0);
|
|
|
|
return r;
|
|
}
|
|
|
|
int
|
|
load_file (const struct floc *flocp, const char *ldname, int noerror)
|
|
{
|
|
load_func_t symp;
|
|
const char *fp;
|
|
char *symname = NULL;
|
|
char *new = alloca (strlen (ldname) + CSTRLEN (SYMBOL_EXTENSION) + 1);
|
|
|
|
if (! global_dl)
|
|
{
|
|
global_dl = dlopen (NULL, RTLD_NOW|RTLD_GLOBAL);
|
|
if (! global_dl)
|
|
fatal (flocp, _("Failed to open global symbol table: %s"), dlerror());
|
|
}
|
|
|
|
/* If a symbol name was provided, use it. */
|
|
fp = strchr (ldname, '(');
|
|
if (fp)
|
|
{
|
|
const char *ep;
|
|
|
|
/* If there's an open paren, see if there's a close paren: if so use
|
|
that as the symbol name. We can't have whitespace: it would have
|
|
been chopped up before this function is called. */
|
|
ep = strchr (fp+1, ')');
|
|
if (ep && ep[1] == '\0')
|
|
{
|
|
int l = fp - ldname;;
|
|
|
|
++fp;
|
|
if (fp == ep)
|
|
fatal (flocp, _("Empty symbol name for load: %s"), ldname);
|
|
|
|
/* Make a copy of the ldname part. */
|
|
memcpy (new, ldname, l);
|
|
new[l] = '\0';
|
|
ldname = new;
|
|
|
|
/* Make a copy of the symbol name part. */
|
|
symname = new + l + 1;
|
|
memcpy (symname, fp, ep - fp);
|
|
symname[ep - fp] = '\0';
|
|
}
|
|
}
|
|
|
|
/* If we didn't find a symbol name yet, construct it from the ldname. */
|
|
if (! symname)
|
|
{
|
|
char *p = new;
|
|
|
|
fp = strrchr (ldname, '/');
|
|
if (!fp)
|
|
fp = ldname;
|
|
else
|
|
++fp;
|
|
while (isalnum (*fp) || *fp == '_')
|
|
*(p++) = *(fp++);
|
|
strcpy (p, SYMBOL_EXTENSION);
|
|
symname = new;
|
|
}
|
|
|
|
DB (DB_VERBOSE, (_("Loading symbol %s from %s\n"), symname, ldname));
|
|
|
|
/* See if it's already defined. */
|
|
symp = (load_func_t) dlsym (global_dl, symname);
|
|
if (! symp) {
|
|
void *dlp = dlopen (ldname, RTLD_LAZY|RTLD_GLOBAL);
|
|
if (! dlp)
|
|
{
|
|
if (noerror)
|
|
DB (DB_BASIC, ("%s", dlerror()));
|
|
else
|
|
error (flocp, "%s", dlerror());
|
|
return 0;
|
|
}
|
|
|
|
symp = dlsym (dlp, symname);
|
|
if (! symp)
|
|
fatal (flocp, _("Failed to load symbol %s from %s: %s"),
|
|
symname, ldname, dlerror());
|
|
}
|
|
|
|
/* Invoke the symbol to initialize the loaded object. */
|
|
return init_symbol(flocp, ldname, symp);
|
|
}
|
|
|
|
#else
|
|
|
|
int
|
|
load_file (const struct floc *flocp, const char *ldname, int noerror)
|
|
{
|
|
if (! noerror)
|
|
fatal (flocp, _("The 'load' operation is not supported on this platform."));
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* MAKE_LOAD */
|