Allow dynamically loaded objects to be rebuilt by make.

This commit is contained in:
Paul Smith 2013-01-20 00:55:57 -05:00
parent 8e0a5645b8
commit b70aa3709e
8 changed files with 1167 additions and 1061 deletions

View File

@ -1,5 +1,24 @@
2013-01-19 Paul Smith <psmith@gnu.org> 2013-01-19 Paul Smith <psmith@gnu.org>
* doc/make.texi (load Directive): Update to discuss location of
loaded object file.
(Remaking Loaded Objects): Document remaking of loaded objects.
* main.c (main): Rename READ_MAKEFILES to READ_FILES.
* read.c: Change READ_MAKEFILES to READ_FILES since it now
contains loaded object files as well.
(read_all_makefiles): Ditto.
(eval_makefile): Ditto.
(eval): Add any loaded file to the READ_FILES list, so that it
will be considered for re-build.
* load.c (load_file): Return the simple filename (no symbol) in
the LDNAME argument (now a const char **).
This filename should no longer have "./" prepended: modify the
function to always check the current directory if the name has no
"/", before using the normal methods.
* make.h: Change the load_file() prototype.
* README.git: Add a bit more documentation on Git workflow & rules. * README.git: Add a bit more documentation on Git workflow & rules.
2013-01-13 Paul Smith <psmith@gnu.org> 2013-01-13 Paul Smith <psmith@gnu.org>

View File

@ -4,7 +4,6 @@
@include version.texi @include version.texi
@set EDITION 0.72 @set EDITION 0.72
@set RCSID $Id$
@settitle GNU @code{make} @settitle GNU @code{make}
@setchapternewpage odd @setchapternewpage odd
@ -27,7 +26,7 @@ of @cite{The GNU Make Manual}, for GNU @code{make} version @value{VERSION}.
Copyright @copyright{} 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, Copyright @copyright{} 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
1996, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007, 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007,
2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
@quotation @quotation
Permission is granted to copy, distribute and/or modify this document Permission is granted to copy, distribute and/or modify this document
@ -348,6 +347,7 @@ GNU Guile Integration
Loading Dynamic Objects Loading Dynamic Objects
* load Directive:: Loading dynamic objects as extensions. * load Directive:: Loading dynamic objects as extensions.
* Remaking Loaded Objects:: How loaded objects get remade.
@end detailmenu @end detailmenu
@end menu @end menu
@ -1287,7 +1287,6 @@ in the makefiles. @xref{Include, , Including Other Makefiles}.
@node Remaking Makefiles, Overriding Makefiles, MAKEFILES Variable, Makefiles @node Remaking Makefiles, Overriding Makefiles, MAKEFILES Variable, Makefiles
@section How Makefiles Are Remade @section How Makefiles Are Remade
@cindex updating makefiles @cindex updating makefiles
@cindex remaking makefiles @cindex remaking makefiles
@cindex makefile, remaking of @cindex makefile, remaking of
@ -6295,7 +6294,6 @@ Has GNU Guile available as an embedded extension language.
@item load @item load
Supports dynamically loadable objects for creating custom extensions. Supports dynamically loadable objects for creating custom extensions.
@xref{Loading Objects, ,Loading Dynamic Objects}. @xref{Loading Objects, ,Loading Dynamic Objects}.
@end table @end table
@vindex .INCLUDE_DIRS @r{(list of include directories)} @vindex .INCLUDE_DIRS @r{(list of include directories)}
@ -10539,11 +10537,11 @@ program, although this can be inefficient.
In cases where the built-in capabilities of GNU @code{make} are In cases where the built-in capabilities of GNU @code{make} are
insufficient to your requirements there are two options for extending insufficient to your requirements there are two options for extending
@code{make}. On systems where it's provided, you can utilize GNU @code{make}. On systems where it's provided, you can utilize GNU
Guile as an embedded scripting language (@pxref{Guile Integration, Guile as an embedded scripting language (@pxref{Guile Integration,,GNU
,GNU Guile Integration}). On systems which support dynamically Guile Integration}). On systems which support dynamically loadable
loadable objects, you can write your own extension in any language objects, you can write your own extension in any language (which can
(which can be compiled into such an object) and load it to provide be compiled into such an object) and load it to provide extended
extended capabilities (@pxref{load Directive, ,The @code{load} Directive}). capabilities (@pxref{load Directive, ,The @code{load} Directive}).
@menu @menu
* Guile Integration:: Using Guile as an embedded scripting language. * Guile Integration:: Using Guile as an embedded scripting language.
@ -10786,15 +10784,16 @@ providing new capabilities which may then be invoked by your makefile.
The @code{load} directive is used to load a dynamic object. Once the The @code{load} directive is used to load a dynamic object. Once the
object is loaded, a ``setup'' function will be invoked to allow the object is loaded, a ``setup'' function will be invoked to allow the
object to initialize itself and register new facilities with GNU object to initialize itself and register new facilities with GNU
@code{make}. Typically a dynamic object would create new functions, @code{make}. A dynamic object might include new @code{make} functions,
for example, and the ``setup'' function would register them with GNU for example, and the ``setup'' function would register them with GNU
@code{make}'s function handling system. @code{make}'s function handling system.
@menu @menu
* load Directive:: Loading dynamic objects as extensions. * load Directive:: Loading dynamic objects as extensions.
* Remaking Loaded Objects:: How loaded objects get remade.
@end menu @end menu
@node load Directive, , Loading Objects, Loading Objects @node load Directive, Remaking Loaded Objects, Loading Objects, Loading Objects
@subsection The @code{load} Directive @subsection The @code{load} Directive
@cindex load directive @cindex load directive
@cindex extensions, load directive @cindex extensions, load directive
@ -10814,21 +10813,33 @@ or:
load @var{object-file}(@var{symbol-name}) @dots{} load @var{object-file}(@var{symbol-name}) @dots{}
@end example @end example
In the first form, the file @var{object-file} is dynamically loaded by The file @var{object-file} is dynamically loaded by GNU @code{make}.
GNU @code{make}. On failure, @code{make} will print a message and If @var{object-file} does not include a directory path then it is
exit. If the load succeeds @code{make} will invoke an initializing first looked for in the current directory. If it is not found there,
function whose name is created by taking the base file name of or a directory path is included, then system-specific paths will be
@var{object-file}, up to the first character which is not a valid searched. If the load fails for any reason, @code{make} will print a
symbol name character (alphanumerics and underscores are valid symbol message and exit.
name characters). To this prefix will be appended the suffix
@code{_gmake_setup}, then this symbol will be invoked.
In the second form, the function @var{symbol-name} will be invoked. If the load succeeds @code{make} will invoke an initializing function.
If @var{symbol-name} is provided, it will be used as the name of the
initializing function.
If no @var{symbol-name} is provided, the initializing function name is
created by taking the base file name of @var{object-file}, up to the
first character which is not a valid symbol name character
(alphanumerics and underscores are valid symbol name characters). To
this prefix will be appended the suffix @code{_gmake_setup}.
More than one object file may be loaded with a single @code{load} More than one object file may be loaded with a single @code{load}
directive, and both forms of @code{load} arguments may be used in the directive, and both forms of @code{load} arguments may be used in the
same directive. same directive.
The initializing function will be provided the file name and line
number of the invocation of the @code{load} operation. It should
return a value of type @code{int}, which must be @code{0} on failure
and non-@code{0} on success.
For example: For example:
@example @example
@ -10864,6 +10875,22 @@ generated if an object fails to load. The failed object is not added
to the @code{.LOADED} variable, which can then be consulted to to the @code{.LOADED} variable, which can then be consulted to
determine if the load was successful. determine if the load was successful.
@node Remaking Loaded Objects, , load Directive, Loading Objects
@subsection How Loaded Objects Are Remade
@cindex updating load objects
@cindex remaking load objects
@cindex load objects, remaking of
Loaded objects undergo the same re-make procedure as makefiles
(@pxref{Remaking Makefiles, ,How Makefiles Are Remade}). If any
loaded object is recreated, then @code{make} will start from scratch
and re-read all the makefiles, and reload the object files again. It
is not necessary for the loaded object to do anything special to
support this.@refill
It's up to the makefile author to provide the rules needed for
rebuilding the loaded object.
@node Features, Missing, Extending make, Top @node Features, Missing, Extending make, Top
@chapter Features of GNU @code{make} @chapter Features of GNU @code{make}
@cindex features of GNU @code{make} @cindex features of GNU @code{make}
@ -11007,6 +11034,12 @@ nonexistent file comes from SunOS 4 @code{make}. (But note that SunOS 4
The @code{!=} shell assignment operator exists in many BSD of The @code{!=} shell assignment operator exists in many BSD of
@code{make} and is purposefully implemented here to behave identically @code{make} and is purposefully implemented here to behave identically
to those implementations. to those implementations.
@item
Various build management tools are implemented using scripting
languages such as Perl or Python and thus provide a natural embedded
scripting language, similar to GNU @code{make}'s integration of GNU
Guile.
@end itemize @end itemize
The remaining features are inventions new in GNU @code{make}: The remaining features are inventions new in GNU @code{make}:
@ -11116,6 +11149,10 @@ Various new built-in implicit rules.
The built-in variable @samp{MAKE_VERSION} gives the version number of The built-in variable @samp{MAKE_VERSION} gives the version number of
@code{make}. @code{make}.
@vindex MAKE_VERSION @vindex MAKE_VERSION
@item
Load dynamic objects which can modify the behavior of @code{make}.
@xref{Loading Objects, ,Loading Dynamic Objects}.
@end itemize @end itemize
@node Missing, Makefile Conventions, Features, Top @node Missing, Makefile Conventions, Features, Top

43
load.c
View File

@ -58,12 +58,12 @@ init_symbol (const struct floc *flocp, const char *ldname, load_func_t symp)
} }
int int
load_file (const struct floc *flocp, const char *ldname, int noerror) load_file (const struct floc *flocp, const char **ldname, int noerror)
{ {
load_func_t symp; load_func_t symp;
const char *fp; const char *fp;
char *symname = NULL; char *symname = NULL;
char *new = alloca (strlen (ldname) + CSTRLEN (SYMBOL_EXTENSION) + 1); char *new = alloca (strlen (*ldname) + CSTRLEN (SYMBOL_EXTENSION) + 1);
if (! global_dl) if (! global_dl)
{ {
@ -73,27 +73,27 @@ load_file (const struct floc *flocp, const char *ldname, int noerror)
} }
/* If a symbol name was provided, use it. */ /* If a symbol name was provided, use it. */
fp = strchr (ldname, '('); fp = strchr (*ldname, '(');
if (fp) if (fp)
{ {
const char *ep; const char *ep;
/* If there's an open paren, see if there's a close paren: if so use /* There's an open paren, so see if there's a close paren: if so use
that as the symbol name. We can't have whitespace: it would have that as the symbol name. We can't have whitespace: it would have
been chopped up before this function is called. */ been chopped up before this function is called. */
ep = strchr (fp+1, ')'); ep = strchr (fp+1, ')');
if (ep && ep[1] == '\0') if (ep && ep[1] == '\0')
{ {
int l = fp - ldname;; int l = fp - *ldname;;
++fp; ++fp;
if (fp == ep) if (fp == ep)
fatal (flocp, _("Empty symbol name for load: %s"), ldname); fatal (flocp, _("Empty symbol name for load: %s"), *ldname);
/* Make a copy of the ldname part. */ /* Make a copy of the ldname part. */
memcpy (new, ldname, l); memcpy (new, *ldname, l);
new[l] = '\0'; new[l] = '\0';
ldname = new; *ldname = new;
/* Make a copy of the symbol name part. */ /* Make a copy of the symbol name part. */
symname = new + l + 1; symname = new + l + 1;
@ -102,14 +102,17 @@ load_file (const struct floc *flocp, const char *ldname, int noerror)
} }
} }
/* Add this name to the string cache so it can be reused later. */
*ldname = strcache_add (*ldname);
/* If we didn't find a symbol name yet, construct it from the ldname. */ /* If we didn't find a symbol name yet, construct it from the ldname. */
if (! symname) if (! symname)
{ {
char *p = new; char *p = new;
fp = strrchr (ldname, '/'); fp = strrchr (*ldname, '/');
if (!fp) if (!fp)
fp = ldname; fp = *ldname;
else else
++fp; ++fp;
while (isalnum (*fp) || *fp == '_') while (isalnum (*fp) || *fp == '_')
@ -118,12 +121,22 @@ load_file (const struct floc *flocp, const char *ldname, int noerror)
symname = new; symname = new;
} }
DB (DB_VERBOSE, (_("Loading symbol %s from %s\n"), symname, ldname)); DB (DB_VERBOSE, (_("Loading symbol %s from %s\n"), symname, *ldname));
/* See if it's already defined. */ /* See if it's already defined. */
symp = (load_func_t) dlsym (global_dl, symname); symp = (load_func_t) dlsym (global_dl, symname);
if (! symp) { if (! symp) {
void *dlp = dlopen (ldname, RTLD_LAZY|RTLD_GLOBAL); void *dlp = NULL;
/* If the path has no "/", try the current directory first. */
if (! strchr (*ldname, '/'))
dlp = dlopen (concat (2, "./", *ldname), RTLD_LAZY|RTLD_GLOBAL);
/* If we haven't opened it yet, try the default search path. */
if (! dlp)
dlp = dlopen (*ldname, RTLD_LAZY|RTLD_GLOBAL);
/* Still no? Then fail. */
if (! dlp) if (! dlp)
{ {
if (noerror) if (noerror)
@ -136,17 +149,17 @@ load_file (const struct floc *flocp, const char *ldname, int noerror)
symp = dlsym (dlp, symname); symp = dlsym (dlp, symname);
if (! symp) if (! symp)
fatal (flocp, _("Failed to load symbol %s from %s: %s"), fatal (flocp, _("Failed to load symbol %s from %s: %s"),
symname, ldname, dlerror()); symname, *ldname, dlerror());
} }
/* Invoke the symbol to initialize the loaded object. */ /* Invoke the symbol to initialize the loaded object. */
return init_symbol(flocp, ldname, symp); return init_symbol(flocp, *ldname, symp);
} }
#else #else
int int
load_file (const struct floc *flocp, const char *ldname, int noerror) load_file (const struct floc *flocp, const char **ldname, int noerror)
{ {
if (! noerror) if (! noerror)
fatal (flocp, _("The 'load' operation is not supported on this platform.")); fatal (flocp, _("The 'load' operation is not supported on this platform."));

1146
main.c

File diff suppressed because it is too large Load Diff

4
make.h
View File

@ -476,9 +476,9 @@ int strcache_setbufsize (unsigned int size);
int guile_gmake_setup (const struct floc *flocp); int guile_gmake_setup (const struct floc *flocp);
#endif #endif
/* Loadable object support */ /* Loadable object support. Sets to the strcached name of the loaded file. */
typedef int (*load_func_t)(const struct floc *flocp); typedef int (*load_func_t)(const struct floc *flocp);
int load_file (const struct floc *flocp, const char *filename, int noerror); int load_file (const struct floc *flocp, const char **filename, int noerror);
#ifdef HAVE_VFORK_H #ifdef HAVE_VFORK_H
# include <vfork.h> # include <vfork.h>

896
read.c

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,9 @@
2013-01-19 Paul Smith <psmith@gnu.org>
* scripts/features/load: Test loaded files with and without "./"
prefix. Add tests for automatically rebuilding loaded files if
they are out of date or non-existent.
2013-01-13 Paul Smith <psmith@gnu.org> 2013-01-13 Paul Smith <psmith@gnu.org>
* scripts/features/archives: Add a check targets that have parens, * scripts/features/archives: Add a check targets that have parens,

View File

@ -49,7 +49,7 @@ run_make_test('testload.so: testload.c ; @$(CC) -g -shared -fPIC -o $@ $<',
# TEST 1 # TEST 1
run_make_test(q! run_make_test(q!
all: ; @echo $(func-a foo) $(func-b bar) all: ; @echo $(func-a foo) $(func-b bar)
load ./testload.so load testload.so
!, !,
'', "func-a\n"); '', "func-a\n");
@ -64,19 +64,42 @@ load ./testload.so(explicit_setup)
# TEST 3 # TEST 3
# Verify the .LOADED variable # Verify the .LOADED variable
run_make_test(q! run_make_test(q!
all: ; @echo $(filter ./testload.so,$(.LOADED)) $(func-a foo) $(func-b bar) all: ; @echo $(filter testload.so,$(.LOADED)) $(func-a foo) $(func-b bar)
load ./testload.so(explicit_setup) load testload.so(explicit_setup)
!, !,
'', "./testload.so func-b\n"); '', "testload.so func-b\n");
# TEST 4 # TEST 4
# Check multiple loads # Check multiple loads
run_make_test(q! run_make_test(q!
all: ; @echo $(filter ./testload.so,$(.LOADED)) $(func-a foo) $(func-b bar) all: ; @echo $(filter testload.so,$(.LOADED)) $(func-a foo) $(func-b bar)
load ./testload.so load ./testload.so
load ./testload.so(explicit_setup) load testload.so(explicit_setup)
!, !,
'', "./testload.so func-a\n"); '', "testload.so func-a\n");
# TEST 5
# Check auto-rebuild of loaded file that's out of date
utouch(-10, 'testload.so');
touch('testload.c');
run_make_test(q!
all: ; @echo $(func-a foo) $(func-b bar)
load ./testload.so
testload.so: testload.c ; @echo "rebuilding $@"; $(CC) -g -shared -fPIC -o $@ $<
!,
'', "rebuilding testload.so\nfunc-a\n");
# TEST 5
# Check auto-rebuild of loaded file when it doesn't exist
unlink('testload.so');
run_make_test(q!
all: ; @echo $(func-a foo) $(func-b bar)
-load ./testload.so(explicit_setup)
%.so: %.c ; @echo "rebuilding $@"; $(CC) -g -shared -fPIC -o $@ $<
!,
'', "rebuilding testload.so\nfunc-b\n");
unlink(qw(testload.c testload.so)) unless $keep; unlink(qw(testload.c testload.so)) unless $keep;