mirror of
https://salsa.debian.org/srivasta/make-dfsg.git
synced 2025-01-30 08:21:56 +00:00
Implement new "load" directive.
Provides support for dynamically loadable objects in GNU make, as a "technology preview".
This commit is contained in:
parent
2efd6b47bf
commit
7670c84f77
15 changed files with 807 additions and 260 deletions
12
ChangeLog
12
ChangeLog
|
@ -1,3 +1,15 @@
|
|||
2012-10-29 Paul Smith <psmith@gnu.org>
|
||||
|
||||
New feature: "load" directive for dynamically-loaded objects.
|
||||
|
||||
* NEWS: Document new "load" directive.
|
||||
* doc/make.texi (Extending make): New chapter on extensions to make.
|
||||
* configure.in: Check for dlopen/dlsym/dlerror and -ldl.
|
||||
* Makefile.am (make_SOURCES): Add new file load.c.
|
||||
* make.h: Prototype for load_file().
|
||||
* main.c (main): Add "load" to .FEATURES if it's available.
|
||||
* read.c (eval): Parse "load" and "-load" directives.
|
||||
|
||||
2012-09-29 Paul Smith <psmith@gnu.org>
|
||||
|
||||
* configure.in: Require a new version of gettext (1.18.1).
|
||||
|
|
|
@ -39,7 +39,7 @@ else
|
|||
endif
|
||||
|
||||
make_SOURCES = ar.c arscan.c commands.c default.c dir.c expand.c file.c \
|
||||
function.c getopt.c getopt1.c implicit.c job.c main.c \
|
||||
function.c getopt.c getopt1.c implicit.c job.c load.c main.c \
|
||||
misc.c read.c remake.c rule.c signame.c \
|
||||
strcache.c variable.c version.c vpath.c hash.c \
|
||||
$(remote)
|
||||
|
|
7
NEWS
7
NEWS
|
@ -9,7 +9,7 @@ manual, which is contained in this distribution as the file doc/make.texi.
|
|||
See the README file and the GNU make manual for instructions for
|
||||
reporting bugs.
|
||||
|
||||
Version 3.82.90
|
||||
Version 3.99.90
|
||||
|
||||
A complete list of bugs fixed in this version is available here:
|
||||
|
||||
|
@ -50,6 +50,11 @@ http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=101&set
|
|||
GNU Guile serves as an embedded extension language for make.
|
||||
See the "Guile Function" section in the GNU Make manual for details.
|
||||
|
||||
* New feature: Loadable objects
|
||||
This version of GNU make contains a "technology preview": the ability to
|
||||
load dynamic objects into the make runtime. These objects can be created by
|
||||
the user and can add extended functionality, usable by makefiles.
|
||||
|
||||
* New function: $(file ...) writes to a file.
|
||||
|
||||
* On failure, the makefile name and linenumber of the recipe that failed are
|
||||
|
|
63
configure.in
63
configure.in
|
@ -252,9 +252,7 @@ AS_IF([test "$PATH_SEPARATOR" = ';'],
|
|||
[Define to 1 if your system requires backslashes or drive specs in pathnames.])
|
||||
])
|
||||
|
||||
|
||||
# See if the user wants to use pmake's "customs" distributed build capability
|
||||
|
||||
AC_SUBST([REMOTE]) REMOTE=stub
|
||||
use_customs=false
|
||||
AC_ARG_WITH([customs],
|
||||
|
@ -280,7 +278,6 @@ AC_ARG_WITH([customs],
|
|||
AM_CONDITIONAL([USE_CUSTOMS], [test "$use_customs" = true])
|
||||
|
||||
# See if the user asked to handle case insensitive file systems.
|
||||
|
||||
AH_TEMPLATE([HAVE_CASE_INSENSITIVE_FS], [Use case insensitive file names])
|
||||
AC_ARG_ENABLE([case-insensitive-file-system],
|
||||
AC_HELP_STRING([--enable-case-insensitive-file-system],
|
||||
|
@ -288,7 +285,6 @@ AC_ARG_ENABLE([case-insensitive-file-system],
|
|||
[AS_IF([test "$enableval" = yes], [AC_DEFINE([HAVE_CASE_INSENSITIVE_FS])])])
|
||||
|
||||
# See if we can handle the job server feature, and if the user wants it.
|
||||
|
||||
AC_ARG_ENABLE([job-server],
|
||||
AC_HELP_STRING([--disable-job-server],
|
||||
[disallow recursive make communication during -jN]),
|
||||
|
@ -324,11 +320,57 @@ AS_CASE([/$make_cv_job_server/$user_job_server/],
|
|||
[Define to 1 to enable job server support in GNU make.])
|
||||
])
|
||||
|
||||
# If dl*() functions are supported we can enable the load operation
|
||||
AC_CHECK_DECLS([dlopen, dlsym, dlerror], [], [],
|
||||
[[#include <dlfcn.h>]])
|
||||
|
||||
AC_ARG_ENABLE([load],
|
||||
AC_HELP_STRING([--disable-load],
|
||||
[disable support for the 'load' operation]),
|
||||
[make_cv_load="$enableval" user_load="$enableval"],
|
||||
[make_cv_load="yes"])
|
||||
|
||||
AS_CASE([/$ac_cv_func_dlopen/$ac_cv_func_dlsym/$ac_cv_func_dlerror/],
|
||||
[*/no/*], [make_cv_load=no])
|
||||
|
||||
AS_CASE([/$make_cv_load/$user_load/],
|
||||
[*/no/*], [make_cv_load=no],
|
||||
[AC_DEFINE(MAKE_LOAD, 1,
|
||||
[Define to 1 to enable 'load' support in GNU make.])
|
||||
])
|
||||
|
||||
# We might need -ldl
|
||||
AS_IF([test "$make_cv_load" = yes], [
|
||||
AC_SEARCH_LIBS([dlopen], [dl], [], [make_cv_load=])
|
||||
])
|
||||
|
||||
# If we want load support, we might need to link with export-dynamic.
|
||||
# See if we can figure it out. Unfortunately this is very difficult.
|
||||
# For example passing -rdynamic to the SunPRO linker gives a warning
|
||||
# but succeeds and creates a shared object, not an executable!
|
||||
AS_IF([test "$make_cv_load" = yes], [
|
||||
AC_MSG_CHECKING([If the linker accepts -Wl,--export-dynamic])
|
||||
old_LDFLAGS="$LDFLAGS"
|
||||
LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
|
||||
AC_LINK_IFELSE([int main(){}],
|
||||
[AC_MSG_RESULT([yes])
|
||||
AC_SUBST([AM_LDFLAGS], [-Wl,--export-dynamic])],
|
||||
[AC_MSG_RESULT([no])
|
||||
AC_MSG_CHECKING([If the linker accepts -rdynamic])
|
||||
LDFLAGS="$old_LDFLAGS -rdynamic"
|
||||
AC_LINK_IFELSE([int main(){}],
|
||||
[AC_MSG_RESULT([yes])
|
||||
AC_SUBST([AM_LDFLAGS], [-rdynamic])],
|
||||
[AC_MSG_RESULT([no])])
|
||||
])
|
||||
LDFLAGS="$old_LDFLAGS"
|
||||
])
|
||||
|
||||
# if we have both lstat() and readlink() then we can support symlink
|
||||
# timechecks.
|
||||
AS_IF([test "$ac_cv_func_lstat" = yes && test "$ac_cv_func_readlink" = yes],
|
||||
[ AC_DEFINE([MAKE_SYMLINKS], [1],
|
||||
[Define to 1 to enable symbolic link timestamp checking.])
|
||||
[ AC_DEFINE([MAKE_SYMLINKS], [1],
|
||||
[Define to 1 to enable symbolic link timestamp checking.])
|
||||
])
|
||||
|
||||
# Find the SCCS commands, so we can include them in our default rules.
|
||||
|
@ -458,6 +500,15 @@ AS_IF([test "x$make_cv_job_server" = xno && test "x$user_job_server" = xyes],
|
|||
echo
|
||||
])
|
||||
|
||||
AS_IF([test "x$make_cv_load" = xno && test "x$user_load" = xyes],
|
||||
[ echo
|
||||
echo "WARNING: 'load' support requires a POSIX-ish system that"
|
||||
echo " supports the dlopen(), dlsym(), and dlerror() functions."
|
||||
echo " Your system doesn't appear to provide one or more of these."
|
||||
echo " Disabling 'load' support."
|
||||
echo
|
||||
])
|
||||
|
||||
# Specify what files are to be created.
|
||||
AC_CONFIG_FILES([Makefile glob/Makefile po/Makefile.in config/Makefile \
|
||||
doc/Makefile w32/Makefile])
|
||||
|
|
593
doc/make.texi
593
doc/make.texi
|
@ -100,6 +100,7 @@ Cover art by Etienne Suvasa.
|
|||
* Implicit Rules:: Use implicit rules to treat many files alike,
|
||||
based on their file names.
|
||||
* Archives:: How @code{make} can update library archives.
|
||||
* Extending make:: Using extensions to @code{make}.
|
||||
* Features:: Features GNU @code{make} has over other @code{make}s.
|
||||
* Missing:: What GNU @code{make} lacks from other @code{make}s.
|
||||
* Makefile Conventions:: Conventions for writing makefiles for
|
||||
|
@ -277,13 +278,7 @@ Functions for Transforming Text
|
|||
* Flavor Function:: Find out the flavor of a variable.
|
||||
* Make Control Functions:: Functions that control how make runs.
|
||||
* Shell Function:: Substitute the output of a shell command.
|
||||
* Guile Function:: Call the GNU Guile embedded scripting language.
|
||||
|
||||
The @code{guile} Function
|
||||
|
||||
* Guile Types:: Converting Guile types to @code{make} strings.
|
||||
* Guile Interface:: Invoking @code{make} functions from Guile.
|
||||
* Guile Example:: Example using Guile in @code{make}.
|
||||
* Guile Function:: Use GNU Guile embedded scripting language.
|
||||
|
||||
How to Run @code{make}
|
||||
|
||||
|
@ -339,6 +334,21 @@ Implicit Rule for Archive Member Targets
|
|||
|
||||
* Archive Symbols:: How to update archive symbol directories.
|
||||
|
||||
Extending GNU @code{make}
|
||||
|
||||
* Guile Integration:: Using Guile as an embedded scripting language.
|
||||
* Loading Objects:: Loading dynamic objects as extensions.
|
||||
|
||||
GNU Guile Integration
|
||||
|
||||
* Guile Types:: Converting Guile types to @code{make} strings.
|
||||
* Guile Interface:: Invoking @code{make} functions from Guile.
|
||||
* Guile Example:: Example using Guile in @code{make}.
|
||||
|
||||
Loading Dynamic Objects
|
||||
|
||||
* load Directive:: Loading dynamic objects as extensions.
|
||||
|
||||
@end detailmenu
|
||||
@end menu
|
||||
|
||||
|
@ -6280,7 +6290,11 @@ Supports the @code{undefine} directive. @xref{Undefine Directive}.
|
|||
|
||||
@item guile
|
||||
Has GNU Guile available as an embedded extension language.
|
||||
@xref{Guile Function}.
|
||||
@xref{Guile Integration, ,GNU Guile Integration}.
|
||||
|
||||
@item load
|
||||
Supports dynamically loadable objects for creating custom extensions.
|
||||
@xref{Loading Objects, ,Loading Dynamic Objects}.
|
||||
|
||||
@end table
|
||||
|
||||
|
@ -6422,12 +6436,12 @@ endif
|
|||
or:
|
||||
|
||||
@example
|
||||
@var{conditional-directive}
|
||||
@var{conditional-directive-one}
|
||||
@var{text-if-one-is-true}
|
||||
else @var{conditional-directive}
|
||||
@var{text-if-true}
|
||||
else @var{conditional-directive-two}
|
||||
@var{text-if-two-is-true}
|
||||
else
|
||||
@var{text-if-false}
|
||||
@var{text-if-one-and-two-are-false}
|
||||
endif
|
||||
@end example
|
||||
|
||||
|
@ -6631,7 +6645,7 @@ be substituted.
|
|||
* Flavor Function:: Find out the flavor of a variable.
|
||||
* Make Control Functions:: Functions that control how make runs.
|
||||
* Shell Function:: Substitute the output of a shell command.
|
||||
* Guile Function:: Call the GNU Guile embedded scripting language.
|
||||
* Guile Function:: Use GNU Guile embedded scripting language.
|
||||
@end menu
|
||||
|
||||
@node Syntax of Functions, Text Functions, Functions, Functions
|
||||
|
@ -7896,208 +7910,17 @@ exists).@refill
|
|||
@findex guile
|
||||
@cindex Guile
|
||||
|
||||
GNU make may be built with support for GNU Guile as an embedded
|
||||
extension language. You can check the @code{.FEATURES} variable for
|
||||
the word @samp{guile} to determine if your version of GNU make
|
||||
provides this capability.
|
||||
|
||||
GNU Guile implements the Scheme language. A review of GNU Guile and
|
||||
the Scheme language and its features is beyond the scope of this
|
||||
manual: see the documentation for GNU Guile and Scheme.
|
||||
|
||||
If GNU Guile is available as an extension language, there will be one
|
||||
new @code{make} function available: @code{guile}. The @code{guile}
|
||||
function takes one argument which is first expanded by @code{make} in
|
||||
the normal fashion, then passed to the GNU Guile evaluator. The
|
||||
result of the evaluator is converted into a string and used as the
|
||||
expansion of the @code{guile} function in the makefile.
|
||||
|
||||
Similarly, there are Guile procedures exposed by @code{make} for use
|
||||
in Guile scripts.
|
||||
|
||||
@menu
|
||||
* Guile Types:: Converting Guile types to @code{make} strings.
|
||||
* Guile Interface:: Invoking @code{make} functions from Guile.
|
||||
* Guile Example:: Example using Guile in @code{make}.
|
||||
@end menu
|
||||
|
||||
@node Guile Types, Guile Interface, Guile Function, Guile Function
|
||||
@subsection Conversion of Guile Types
|
||||
@cindex convert guile types
|
||||
@cindex guile, conversion of types
|
||||
@cindex types, conversion of
|
||||
|
||||
There is only one ``data type'' in @code{make}: a string. GNU Guile,
|
||||
on the other hand, provides a rich variety of different data types.
|
||||
An important aspect of the interface between @code{make} and GNU Guile
|
||||
is the conversion of Guile data types into @code{make} strings.
|
||||
|
||||
This conversion is relevant in two places: when a makefile invokes the
|
||||
@code{guile} function to evaluate a Guile expression, the result of
|
||||
that evaluation must be converted into a make string so it can be
|
||||
further evaluated by @code{make}. And secondly, when a Guile script
|
||||
invokes one of the procedures exported by @code{make} the argument
|
||||
provided to the procedure must be converted into a string.
|
||||
|
||||
The conversion of Guile types into @code{make} strings is as below:
|
||||
|
||||
@table @code
|
||||
@item #f
|
||||
False is converted into the empty string: in @code{make} conditionals
|
||||
the empty string is considered false.
|
||||
|
||||
@item #t
|
||||
True is converted to the string @samp{#t}: in @code{make} conditionals
|
||||
any non-empty string is considered true.
|
||||
|
||||
@item symbol
|
||||
@item number
|
||||
A symbol or number is converted into the string representation of that
|
||||
symbol or number.
|
||||
|
||||
@item character
|
||||
A printable character is converted to the same character.
|
||||
|
||||
@item string
|
||||
A string containing only printable characters is converted to the same
|
||||
string.
|
||||
|
||||
@item list
|
||||
A list is converted recursively according to the above rules. This
|
||||
implies that any structured list will be flattened (that is, a result
|
||||
of @samp{'(a b (c d) e)} will be converted to the @code{make} string
|
||||
@samp{a b c d e}).
|
||||
|
||||
@item other
|
||||
Any other Guile type results in an error. In future versions of
|
||||
@code{make}, other Guile types may be converted.
|
||||
|
||||
@end table
|
||||
|
||||
The translation of @samp{#f} (to the empty string) and @samp{#t} (to
|
||||
the non-empty string @samp{#t}) is designed to allow you to use Guile
|
||||
boolean results directly as @code{make} boolean conditions. For
|
||||
example:
|
||||
|
||||
@example
|
||||
$(if $(guile (access? "myfile" R_OK)),$(info myfile exists))
|
||||
@end example
|
||||
|
||||
As a consequence of these conversion rules you must consider the
|
||||
result of your Guile script, as that result will be converted into a
|
||||
string and parsed by @code{make}. If there is no natural result for
|
||||
the script (that is, the script exists solely for its side-effects),
|
||||
you should add @samp{#f} as the final expression in order to avoid
|
||||
syntax errors in your makefile.
|
||||
|
||||
@node Guile Interface, Guile Example, Guile Types, Guile Function
|
||||
@subsection Interfaces from Guile to @code{make}
|
||||
@cindex make interface to guile
|
||||
@cindex make procedures in guile
|
||||
|
||||
In addition to the @code{guile} function available in makefiles,
|
||||
@code{make} exposes some procedures for use in your Guile scripts. At
|
||||
startup @code{make} creates a new Guile module, @code{gnu make}, and
|
||||
exports these procedures as public interfaces from that module:
|
||||
|
||||
@table @code
|
||||
@item gmk-expand
|
||||
This procedure takes a single argument which is converted into a
|
||||
string. The string is expanded by @code{make} using normal
|
||||
@code{make} expansion rules. The result of the expansion is converted
|
||||
into a Guile string and provided as the result of the procedure.
|
||||
|
||||
@item gmk-eval
|
||||
This procedure takes a single argument which is converted into a
|
||||
string. The string is evaluated by @code{make} as if it were a
|
||||
makefile. This is the same capability available via the @code{eval}
|
||||
function (@pxref{Eval Function}). The result of the @code{gmk-eval}
|
||||
procedure is always the empty string.
|
||||
|
||||
@item gmk-var
|
||||
This procedure takes a single argument which is converted into a
|
||||
string. The string is assumed to be the name of a @code{make}
|
||||
variable, which is then expanded. The expansion is converted into a
|
||||
string and provided as the result of the procedure.
|
||||
|
||||
@end table
|
||||
|
||||
@node Guile Example, , Guile Interface, Guile Function
|
||||
@subsection Example Using Guile in @code{make}
|
||||
@cindex Guile example
|
||||
@cindex example using Guile
|
||||
|
||||
Here is a very simple example using GNU Guile to manage writing to a
|
||||
file. These Guile procedures simply open a file, allow writing to the
|
||||
file (one string per line), and close the file. Note that because we
|
||||
cannot store complex values such as Guile ports in @code{make}
|
||||
variables, we'll keep the port as a global variable in the Guile
|
||||
interpreter.
|
||||
|
||||
You can create Guile functions easily using @code{define}/@code{endef}
|
||||
to create a Guile script, then use the @code{guile} function to
|
||||
internalize it:
|
||||
|
||||
@example
|
||||
@group
|
||||
define GUILEIO
|
||||
;; A simple Guile IO library for GNU make
|
||||
|
||||
(define MKPORT #f)
|
||||
|
||||
(define (mkopen name mode)
|
||||
(set! MKPORT (open-file name mode))
|
||||
#f)
|
||||
|
||||
(define (mkwrite s)
|
||||
(display s MKPORT)
|
||||
(newline MKPORT)
|
||||
#f)
|
||||
|
||||
(define (mkclose)
|
||||
(close-port MKPORT)
|
||||
#f)
|
||||
|
||||
#f
|
||||
endef
|
||||
|
||||
# Internalize the Guile IO functions
|
||||
$(guile $(GUILEIO))
|
||||
@end group
|
||||
@end example
|
||||
|
||||
If you have a significant amount of Guile support code, you might
|
||||
consider keeping it in a different file (e.g., @file{guileio.scm}) and
|
||||
then loading it in your makefile using the @code{guile} function:
|
||||
|
||||
@example
|
||||
$(guile (load "guileio.scm"))
|
||||
@end example
|
||||
|
||||
An advantage to this method is that when editing @file{guileio.scm},
|
||||
your editor will understand that this file contains Scheme syntax
|
||||
rather than makefile syntax.
|
||||
|
||||
Now you can use these Guile functions to create files. Suppose you
|
||||
need to operate on a very large list, which cannot fit on the command
|
||||
line, but the utility you're using accepts the list as input as well:
|
||||
|
||||
@example
|
||||
@group
|
||||
prog: $(PREREQS)
|
||||
@@$(guile (mkopen "tmp.out" "w")) \
|
||||
$(foreach X,$^,$(guile (mkwrite "$(X)"))) \
|
||||
$(guile (mkclose))
|
||||
$(LINK) < tmp.out
|
||||
@end group
|
||||
@end example
|
||||
|
||||
A more comprehensive suite of file manipulation procedures is possible
|
||||
of course. You could, for example, maintain multiple output files at
|
||||
the same time by choosing a symbol for each one and using it as the
|
||||
key to a hash table, where the value is a port, then returning the
|
||||
symbol to be stored in a @code{make} variable.
|
||||
If GNU @code{make} is built with support for GNU Guile as an embedded
|
||||
extension language then the @code{guile} function will be available.
|
||||
The @code{guile} function takes one argument which is first expanded
|
||||
by @code{make} in the normal fashion, then passed to the GNU Guile
|
||||
evaluator. The result of the evaluator is converted into a string and
|
||||
used as the expansion of the @code{guile} function in the makefile.
|
||||
See @ref{Guile Integration, ,GNU Guile Integration} for details on
|
||||
writing extensions to @code{make} in Guile.
|
||||
|
||||
You can determine whether GNU Guile support is available by checking
|
||||
the @code{.FEATURES} variable for the word @var{guile}.
|
||||
|
||||
@node Running, Implicit Rules, Functions, Top
|
||||
@chapter How to Run @code{make}
|
||||
|
@ -10476,7 +10299,7 @@ When the recipe of a pattern rule is executed for @var{t}, the
|
|||
automatic variables are set corresponding to the target and
|
||||
prerequisites. @xref{Automatic Variables}.
|
||||
|
||||
@node Archives, Features, Implicit Rules, Top
|
||||
@node Archives, Extending make, Implicit Rules, Top
|
||||
@chapter Using @code{make} to Update Archive Files
|
||||
@cindex archive
|
||||
|
||||
|
@ -10703,7 +10526,345 @@ in the normal way (@pxref{Suffix Rules}). Thus a double-suffix rule
|
|||
@w{@samp{.@var{x}.a}} produces two pattern rules: @samp{@w{(%.o):}
|
||||
@w{%.@var{x}}} and @samp{@w{%.a}: @w{%.@var{x}}}.@refill
|
||||
|
||||
@node Features, Missing, Archives, Top
|
||||
@node Extending make, Features, Archives, Top
|
||||
@chapter Extending GNU @code{make}
|
||||
@cindex make extensions
|
||||
|
||||
GNU @code{make} provides many advanced capabilities, including many
|
||||
useful functions. However, it does not contain a complete programming
|
||||
language and so it has limitations. Sometimes these limitations can be
|
||||
overcome through use of the @code{shell} function to invoke a separate
|
||||
program, although this can be inefficient.
|
||||
|
||||
In cases where the built-in capabilities of GNU @code{make} are
|
||||
insufficient to your requirements there are two options for extending
|
||||
@code{make}. On systems where it's provided, you can utilize GNU
|
||||
Guile as an embedded scripting language (@pxref{Guile Integration,
|
||||
,GNU Guile Integration}). On systems which support dynamically
|
||||
loadable objects, you can write your own extension in any language
|
||||
(which can be compiled into such an object) and load it to provide
|
||||
extended capabilities (@pxref{load Directive, ,The @code{load} Directive}).
|
||||
|
||||
@menu
|
||||
* Guile Integration:: Using Guile as an embedded scripting language.
|
||||
* Loading Objects:: Loading dynamic objects as extensions.
|
||||
@end menu
|
||||
|
||||
@node Guile Integration, Loading Objects, Extending make, Extending make
|
||||
@section GNU Guile Integration
|
||||
@cindex Guile
|
||||
@cindex extensions, Guile
|
||||
|
||||
GNU @code{make} may be built with support for GNU Guile as an embedded
|
||||
extension language. Guile implements the Scheme language. A review
|
||||
of GNU Guile and the Scheme language and its features is beyond the
|
||||
scope of this manual: see the documentation for GNU Guile and Scheme.
|
||||
|
||||
You can determine if @code{make} contains support for Guile by
|
||||
examining the @code{.FEATURES} variable; it will contain the word
|
||||
@var{guile} if Guile support is available.
|
||||
|
||||
The Guile integration provides one new @code{make} function: @code{guile}.
|
||||
The @code{guile} function takes one argument which is first expanded
|
||||
by @code{make} in the normal fashion, then passed to the GNU Guile
|
||||
evaluator. The result of the evaluator is converted into a string and
|
||||
used as the expansion of the @code{guile} function in the makefile.
|
||||
|
||||
In addition, GNU @code{make} exposes Guile procedures for use in Guile
|
||||
scripts.
|
||||
|
||||
@menu
|
||||
* Guile Types:: Converting Guile types to @code{make} strings.
|
||||
* Guile Interface:: Invoking @code{make} functions from Guile.
|
||||
* Guile Example:: Example using Guile in @code{make}.
|
||||
@end menu
|
||||
|
||||
@node Guile Types, Guile Interface, Guile Integration, Guile Integration
|
||||
@subsection Conversion of Guile Types
|
||||
@cindex convert guile types
|
||||
@cindex guile, conversion of types
|
||||
@cindex types, conversion of
|
||||
|
||||
There is only one ``data type'' in @code{make}: a string. GNU Guile,
|
||||
on the other hand, provides a rich variety of different data types.
|
||||
An important aspect of the interface between @code{make} and GNU Guile
|
||||
is the conversion of Guile data types into @code{make} strings.
|
||||
|
||||
This conversion is relevant in two places: when a makefile invokes the
|
||||
@code{guile} function to evaluate a Guile expression, the result of
|
||||
that evaluation must be converted into a make string so it can be
|
||||
further evaluated by @code{make}. And secondly, when a Guile script
|
||||
invokes one of the procedures exported by @code{make} the argument
|
||||
provided to the procedure must be converted into a string.
|
||||
|
||||
The conversion of Guile types into @code{make} strings is as below:
|
||||
|
||||
@table @code
|
||||
@item #f
|
||||
False is converted into the empty string: in @code{make} conditionals
|
||||
the empty string is considered false.
|
||||
|
||||
@item #t
|
||||
True is converted to the string @samp{#t}: in @code{make} conditionals
|
||||
any non-empty string is considered true.
|
||||
|
||||
@item symbol
|
||||
@item number
|
||||
A symbol or number is converted into the string representation of that
|
||||
symbol or number.
|
||||
|
||||
@item character
|
||||
A printable character is converted to the same character.
|
||||
|
||||
@item string
|
||||
A string containing only printable characters is converted to the same
|
||||
string.
|
||||
|
||||
@item list
|
||||
A list is converted recursively according to the above rules. This
|
||||
implies that any structured list will be flattened (that is, a result
|
||||
of @samp{'(a b (c d) e)} will be converted to the @code{make} string
|
||||
@samp{a b c d e}).
|
||||
|
||||
@item other
|
||||
Any other Guile type results in an error. In future versions of
|
||||
@code{make}, other Guile types may be converted.
|
||||
|
||||
@end table
|
||||
|
||||
The translation of @samp{#f} (to the empty string) and @samp{#t} (to
|
||||
the non-empty string @samp{#t}) is designed to allow you to use Guile
|
||||
boolean results directly as @code{make} boolean conditions. For
|
||||
example:
|
||||
|
||||
@example
|
||||
$(if $(guile (access? "myfile" R_OK)),$(info myfile exists))
|
||||
@end example
|
||||
|
||||
As a consequence of these conversion rules you must consider the
|
||||
result of your Guile script, as that result will be converted into a
|
||||
string and parsed by @code{make}. If there is no natural result for
|
||||
the script (that is, the script exists solely for its side-effects),
|
||||
you should add @samp{#f} as the final expression in order to avoid
|
||||
syntax errors in your makefile.
|
||||
|
||||
@node Guile Interface, Guile Example, Guile Types, Guile Integration
|
||||
@subsection Interfaces from Guile to @code{make}
|
||||
@cindex make interface to guile
|
||||
@cindex make procedures in guile
|
||||
|
||||
In addition to the @code{guile} function available in makefiles,
|
||||
@code{make} exposes some procedures for use in your Guile scripts. At
|
||||
startup @code{make} creates a new Guile module, @code{gnu make}, and
|
||||
exports these procedures as public interfaces from that module:
|
||||
|
||||
@table @code
|
||||
@item gmk-expand
|
||||
This procedure takes a single argument which is converted into a
|
||||
string. The string is expanded by @code{make} using normal
|
||||
@code{make} expansion rules. The result of the expansion is converted
|
||||
into a Guile string and provided as the result of the procedure.
|
||||
|
||||
@item gmk-eval
|
||||
This procedure takes a single argument which is converted into a
|
||||
string. The string is evaluated by @code{make} as if it were a
|
||||
makefile. This is the same capability available via the @code{eval}
|
||||
function (@pxref{Eval Function}). The result of the @code{gmk-eval}
|
||||
procedure is always the empty string.
|
||||
|
||||
@item gmk-var
|
||||
This procedure takes a single argument which is converted into a
|
||||
string. The string is assumed to be the name of a @code{make}
|
||||
variable, which is then expanded. The expansion is converted into a
|
||||
string and provided as the result of the procedure.
|
||||
|
||||
@end table
|
||||
|
||||
@node Guile Example, , Guile Interface, Guile Integration
|
||||
@subsection Example Using Guile in @code{make}
|
||||
@cindex Guile example
|
||||
@cindex example using Guile
|
||||
|
||||
Here is a very simple example using GNU Guile to manage writing to a
|
||||
file. These Guile procedures simply open a file, allow writing to the
|
||||
file (one string per line), and close the file. Note that because we
|
||||
cannot store complex values such as Guile ports in @code{make}
|
||||
variables, we'll keep the port as a global variable in the Guile
|
||||
interpreter.
|
||||
|
||||
You can create Guile functions easily using @code{define}/@code{endef}
|
||||
to create a Guile script, then use the @code{guile} function to
|
||||
internalize it:
|
||||
|
||||
@example
|
||||
@group
|
||||
define GUILEIO
|
||||
;; A simple Guile IO library for GNU make
|
||||
|
||||
(define MKPORT #f)
|
||||
|
||||
(define (mkopen name mode)
|
||||
(set! MKPORT (open-file name mode))
|
||||
#f)
|
||||
|
||||
(define (mkwrite s)
|
||||
(display s MKPORT)
|
||||
(newline MKPORT)
|
||||
#f)
|
||||
|
||||
(define (mkclose)
|
||||
(close-port MKPORT)
|
||||
#f)
|
||||
|
||||
#f
|
||||
endef
|
||||
|
||||
# Internalize the Guile IO functions
|
||||
$(guile $(GUILEIO))
|
||||
@end group
|
||||
@end example
|
||||
|
||||
If you have a significant amount of Guile support code, you might
|
||||
consider keeping it in a different file (e.g., @file{guileio.scm}) and
|
||||
then loading it in your makefile using the @code{guile} function:
|
||||
|
||||
@example
|
||||
$(guile (load "guileio.scm"))
|
||||
@end example
|
||||
|
||||
An advantage to this method is that when editing @file{guileio.scm},
|
||||
your editor will understand that this file contains Scheme syntax
|
||||
rather than makefile syntax.
|
||||
|
||||
Now you can use these Guile functions to create files. Suppose you
|
||||
need to operate on a very large list, which cannot fit on the command
|
||||
line, but the utility you're using accepts the list as input as well:
|
||||
|
||||
@example
|
||||
@group
|
||||
prog: $(PREREQS)
|
||||
@@$(guile (mkopen "tmp.out" "w")) \
|
||||
$(foreach X,$^,$(guile (mkwrite "$(X)"))) \
|
||||
$(guile (mkclose))
|
||||
$(LINK) < tmp.out
|
||||
@end group
|
||||
@end example
|
||||
|
||||
A more comprehensive suite of file manipulation procedures is possible
|
||||
of course. You could, for example, maintain multiple output files at
|
||||
the same time by choosing a symbol for each one and using it as the
|
||||
key to a hash table, where the value is a port, then returning the
|
||||
symbol to be stored in a @code{make} variable.
|
||||
|
||||
@node Loading Objects, , Guile Integration, Extending make
|
||||
@section Loading Dynamic Objects
|
||||
@cindex loading objects
|
||||
@cindex objects, loading
|
||||
@cindex extensions, loading
|
||||
|
||||
@cartouche
|
||||
@quotation Warning
|
||||
The @code{load} directive and extension capability is considered a
|
||||
``technology preview'' in this release of GNU make. We encourage you
|
||||
to experiment with this feature and we appreciate any feedback on it.
|
||||
However we cannot guarantee to maintain backward-compatibility in the
|
||||
next release.
|
||||
|
||||
In particular, for this feature to be useful your extensions will need
|
||||
to invoke various functions internal to GNU @code{make}. In this
|
||||
release there is no stable programming interface defined for
|
||||
@code{make}: any internal function may change or even disappear in
|
||||
future releases.
|
||||
@end quotation
|
||||
@end cartouche
|
||||
|
||||
Many operating systems provide a facility for dynamically loading
|
||||
compiled objects. If your system provides this facility, GNU
|
||||
@code{make} can make use of it to load dynamic objects at runtime,
|
||||
providing new capabilities which may then be invoked by your makefile.
|
||||
|
||||
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 to initialize itself and register new facilities with GNU
|
||||
@code{make}. Typically a dynamic object would create new functions,
|
||||
for example, and the ``setup'' function would register them with GNU
|
||||
@code{make}'s function handling system.
|
||||
|
||||
@menu
|
||||
* load Directive:: Loading dynamic objects as extensions.
|
||||
@end menu
|
||||
|
||||
@node load Directive, , Loading Objects, Loading Objects
|
||||
@subsection The @code{load} Directive
|
||||
@cindex load directive
|
||||
@cindex extensions, load directive
|
||||
|
||||
Objects are loaded into GNU @code{make} by placing the @code{load}
|
||||
directive into your makefile. The syntax of the @code{load} directive
|
||||
is as follows:
|
||||
|
||||
@findex load
|
||||
@example
|
||||
load @var{object-file} @dots{}
|
||||
@end example
|
||||
|
||||
or:
|
||||
|
||||
@example
|
||||
load @var{object-file}(@var{symbol-name}) @dots{}
|
||||
@end example
|
||||
|
||||
In the first form, the file @var{object-file} is dynamically loaded by
|
||||
GNU @code{make}. On failure, @code{make} will print a message and
|
||||
exit. If the load succeeds @code{make} will invoke an initializing
|
||||
function whose 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}, then this symbol will be invoked.
|
||||
|
||||
In the second form, the function @var{symbol-name} will be invoked.
|
||||
|
||||
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
|
||||
same directive.
|
||||
|
||||
For example:
|
||||
|
||||
@example
|
||||
load ../mk_funcs.so
|
||||
@end example
|
||||
|
||||
will load the dynamic object @file{../mk_funcs.so}. After the object
|
||||
is loaded, @code{make} will invoke the function (assumed to be defined
|
||||
by the shared object) @code{mk_funcs_gmake_setup}.
|
||||
|
||||
On the other hand:
|
||||
|
||||
@example
|
||||
load ../mk_funcs.so(init_mk_func)
|
||||
@end example
|
||||
|
||||
will load the dynamic object @file{../mk_funcs.so}. After the object
|
||||
is loaded, @code{make} will invoke the function @code{init_mk_func}.
|
||||
|
||||
Regardless of how many times an object file appears in a @code{load}
|
||||
directive, it will only be loaded (and it's setup function will only
|
||||
be invoked) once.
|
||||
|
||||
@vindex .LOADED
|
||||
After an object has been successfully loaded, its file name is
|
||||
appended to the @code{.LOADED} variable.
|
||||
|
||||
@findex -load
|
||||
If you would prefer that failure to load a dynamic object not be
|
||||
reported as an error, you can use the @code{-load} directive instead
|
||||
of @code{load}. GNU @code{make} will not fail and no message will be
|
||||
generated if an object fails to load. The failed object is not added
|
||||
to the @code{.LOADED} variable, which can then be consulted to
|
||||
determine if the load was successful.
|
||||
|
||||
@node Features, Missing, Extending make, Top
|
||||
@chapter Features of GNU @code{make}
|
||||
@cindex features of GNU @code{make}
|
||||
@cindex portability
|
||||
|
|
7
guile.c
7
guile.c
|
@ -104,8 +104,10 @@ func_guile (char *o, char **argv, const char *funcname UNUSED)
|
|||
|
||||
/* ----- Public interface ----- */
|
||||
|
||||
/* We could send the flocp to define_new_function(), but since guile is
|
||||
"kind of" built-in, that didn't seem so useful. */
|
||||
int
|
||||
setup_guile ()
|
||||
guile_gmake_setup (const struct floc *flocp UNUSED)
|
||||
{
|
||||
/* Initialize the Guile interpreter. */
|
||||
scm_with_guile (guile_init, NULL);
|
||||
|
@ -113,8 +115,5 @@ setup_guile ()
|
|||
/* Create a make function "guile". */
|
||||
define_new_function (NILF, "guile", 0, 1, 1, func_guile);
|
||||
|
||||
/* Add 'guile' to the list of features. */
|
||||
do_variable_definition (NILF, ".FEATURES", "guile", o_default, f_append, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
157
load.c
Normal file
157
load.c
Normal file
|
@ -0,0 +1,157 @@
|
|||
/* 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 */
|
13
main.c
13
main.c
|
@ -1148,6 +1148,12 @@ main (int argc, char **argv, char **envp)
|
|||
#endif
|
||||
#ifdef MAKE_SYMLINKS
|
||||
" check-symlink"
|
||||
#endif
|
||||
#ifdef HAVE_GUILE
|
||||
" guile"
|
||||
#endif
|
||||
#ifdef MAKE_LOAD
|
||||
" load"
|
||||
#endif
|
||||
;
|
||||
|
||||
|
@ -1156,7 +1162,7 @@ main (int argc, char **argv, char **envp)
|
|||
|
||||
#ifdef HAVE_GUILE
|
||||
/* Configure GNU Guile support */
|
||||
setup_guile ();
|
||||
guile_gmake_setup (NILF);
|
||||
#endif
|
||||
|
||||
/* Read in variables from the environment. It is important that this be
|
||||
|
@ -1661,8 +1667,7 @@ main (int argc, char **argv, char **envp)
|
|||
|
||||
/* Read all the makefiles. */
|
||||
|
||||
read_makefiles
|
||||
= read_all_makefiles (makefiles == 0 ? 0 : makefiles->list);
|
||||
read_makefiles = read_all_makefiles (makefiles == 0 ? 0 : makefiles->list);
|
||||
|
||||
#ifdef WINDOWS32
|
||||
/* look one last time after reading all Makefiles */
|
||||
|
@ -3271,7 +3276,7 @@ die (int status)
|
|||
if (directory_before_chdir != 0)
|
||||
{
|
||||
/* If it fails we don't care: shut up GCC. */
|
||||
int _x;
|
||||
int _x UNUSED;
|
||||
_x = chdir (directory_before_chdir);
|
||||
}
|
||||
|
||||
|
|
7
make.h
7
make.h
|
@ -472,8 +472,13 @@ const char *strcache_add_len (const char *str, unsigned int len);
|
|||
int strcache_setbufsize (unsigned int size);
|
||||
|
||||
/* Guile support */
|
||||
int setup_guile (void);
|
||||
#ifdef HAVE_GUILE
|
||||
int guile_gmake_setup (const struct floc *flocp);
|
||||
#endif
|
||||
|
||||
/* Loadable object support */
|
||||
typedef int (*load_func_t)(const struct floc *flocp);
|
||||
int load_file (const struct floc *flocp, const char *filename, int noerror);
|
||||
|
||||
#ifdef HAVE_VFORK_H
|
||||
# include <vfork.h>
|
||||
|
|
73
read.c
73
read.c
|
@ -595,9 +595,8 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||
when the start of the next rule (or eof) is encountered.
|
||||
|
||||
When you see a "continue" in the loop below, that means we are moving on
|
||||
to the next line _without_ ending any rule that we happen to be working
|
||||
with at the moment. If you see a "goto rule_complete", then the
|
||||
statement we just parsed also finishes the previous rule. */
|
||||
to the next line. If you see record_waiting_files(), then the statement
|
||||
we are parsing also finishes the previous rule. */
|
||||
|
||||
commands = xmalloc (200);
|
||||
|
||||
|
@ -707,6 +706,9 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||
struct variable *v;
|
||||
enum variable_origin origin = vmod.override_v ? o_override : o_file;
|
||||
|
||||
/* Variable assignment ends the previous rule. */
|
||||
record_waiting_files ();
|
||||
|
||||
/* If we're ignoring then we're done now. */
|
||||
if (ignoring)
|
||||
{
|
||||
|
@ -718,9 +720,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||
if (vmod.undefine_v)
|
||||
{
|
||||
do_undefine (p, origin, ebuf);
|
||||
|
||||
/* This line has been dealt with. */
|
||||
goto rule_complete;
|
||||
continue;
|
||||
}
|
||||
else if (vmod.define_v)
|
||||
v = do_define (p, origin, ebuf);
|
||||
|
@ -735,7 +735,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||
v->private_var = 1;
|
||||
|
||||
/* This line has been dealt with. */
|
||||
goto rule_complete;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If this line is completely empty, ignore it. */
|
||||
|
@ -779,6 +779,9 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||
{
|
||||
int exporting = *p == 'u' ? 0 : 1;
|
||||
|
||||
/* Export/unexport ends the previous rule. */
|
||||
record_waiting_files ();
|
||||
|
||||
/* (un)export by itself causes everything to be (un)exported. */
|
||||
if (*p2 == '\0')
|
||||
export_all_variables = exporting;
|
||||
|
@ -803,7 +806,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||
|
||||
free (ap);
|
||||
}
|
||||
goto rule_complete;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Handle the special syntax for vpath. */
|
||||
|
@ -812,6 +815,10 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||
const char *cp;
|
||||
char *vpat;
|
||||
unsigned int l;
|
||||
|
||||
/* vpath ends the previous rule. */
|
||||
record_waiting_files ();
|
||||
|
||||
cp = variable_expand (p2);
|
||||
p = find_next_token (&cp, &l);
|
||||
if (p != 0)
|
||||
|
@ -828,7 +835,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||
if (vpat != 0)
|
||||
free (vpat);
|
||||
|
||||
goto rule_complete;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Handle include and variants. */
|
||||
|
@ -843,6 +850,9 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||
exist. "sinclude" is an alias for this from SGI. */
|
||||
int noerror = (p[0] != 'i');
|
||||
|
||||
/* Include ends the previous rule. */
|
||||
record_waiting_files ();
|
||||
|
||||
p = allocated_variable_expand (p2);
|
||||
|
||||
/* If no filenames, it's a no-op. */
|
||||
|
@ -887,9 +897,51 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||
/* Restore conditional state. */
|
||||
restore_conditionals (save);
|
||||
|
||||
goto rule_complete;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Handle the load operations. */
|
||||
if (word1eq ("load") || word1eq ("-load"))
|
||||
{
|
||||
/* A 'load' line specifies a dynamic object to load. */
|
||||
struct nameseq *files;
|
||||
int noerror = (p[0] == '-');
|
||||
|
||||
/* Load ends the previous rule. */
|
||||
record_waiting_files ();
|
||||
|
||||
p = allocated_variable_expand (p2);
|
||||
|
||||
/* If no filenames, it's a no-op. */
|
||||
if (*p == '\0')
|
||||
{
|
||||
free (p);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Parse the list of file names.
|
||||
Don't expand archive references or strip "./" */
|
||||
p2 = p;
|
||||
files = PARSE_FILE_SEQ (&p2, struct nameseq, '\0', NULL,
|
||||
PARSEFS_NOAR|PARSEFS_NOSTRIP);
|
||||
free (p);
|
||||
|
||||
/* Load each file. */
|
||||
while (files != 0)
|
||||
{
|
||||
struct nameseq *next = files->next;
|
||||
const char *name = files->name;
|
||||
|
||||
free_ns (files);
|
||||
files = next;
|
||||
|
||||
if (! load_file (&ebuf->floc, name, noerror) && ! noerror)
|
||||
fatal (&ebuf->floc, _("%s: failed to load"), name);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* This line starts with a tab but was not caught above because there
|
||||
was no preceding target, and the line might have been usable as a
|
||||
variable definition. But now we know it is definitely lossage. */
|
||||
|
@ -1293,7 +1345,6 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||
/* We get here except in the case that we just read a rule line.
|
||||
Record now the last rule we read, so following spurious
|
||||
commands are properly diagnosed. */
|
||||
rule_complete:
|
||||
record_waiting_files ();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
2012-10-29 Paul Smith <psmith@gnu.org>
|
||||
|
||||
* scripts/features/load: New test suite for the "load" directive.
|
||||
|
||||
2012-09-09 Paul Smith <psmith@gnu.org>
|
||||
|
||||
* scripts/functions/file: Get errors in the C locale, not the
|
||||
|
|
|
@ -97,6 +97,17 @@ sub valid_option
|
|||
|
||||
$old_makefile = undef;
|
||||
|
||||
sub subst_make_string
|
||||
{
|
||||
local $_ = shift;
|
||||
$makefile and s/#MAKEFILE#/$makefile/g;
|
||||
s/#MAKEPATH#/$mkpath/g;
|
||||
s/#MAKE#/$make_name/g;
|
||||
s/#PERL#/$perl_name/g;
|
||||
s/#PWD#/$pwd/g;
|
||||
return $_;
|
||||
}
|
||||
|
||||
sub run_make_test
|
||||
{
|
||||
local ($makestring, $options, $answer, $err_code, $timeout) = @_;
|
||||
|
@ -114,16 +125,9 @@ sub run_make_test
|
|||
$makefile = &get_tmpfile();
|
||||
}
|
||||
|
||||
# Make sure it ends in a newline.
|
||||
# Make sure it ends in a newline and substitute any special tokens.
|
||||
$makestring && $makestring !~ /\n$/s and $makestring .= "\n";
|
||||
|
||||
# Replace @MAKEFILE@ with the makefile name and @MAKE@ with the path to
|
||||
# make
|
||||
$makestring =~ s/#MAKEFILE#/$makefile/g;
|
||||
$makestring =~ s/#MAKEPATH#/$mkpath/g;
|
||||
$makestring =~ s/#MAKE#/$make_name/g;
|
||||
$makestring =~ s/#PERL#/$perl_name/g;
|
||||
$makestring =~ s/#PWD#/$pwd/g;
|
||||
$makestring = subst_make_string($makestring);
|
||||
|
||||
# Populate the makefile!
|
||||
open(MAKEFILE, "> $makefile") || die "Failed to open $makefile: $!\n";
|
||||
|
@ -132,13 +136,8 @@ sub run_make_test
|
|||
}
|
||||
|
||||
# Do the same processing on $answer as we did on $makestring.
|
||||
|
||||
$answer && $answer !~ /\n$/s and $answer .= "\n";
|
||||
$answer =~ s/#MAKEFILE#/$makefile/g;
|
||||
$answer =~ s/#MAKEPATH#/$mkpath/g;
|
||||
$answer =~ s/#MAKE#/$make_name/g;
|
||||
$answer =~ s/#PERL#/$perl_name/g;
|
||||
$answer =~ s/#PWD#/$pwd/g;
|
||||
$answer = subst_make_string($answer);
|
||||
|
||||
run_make_with_options($makefile, $options, &get_logfile(0),
|
||||
$err_code, $timeout);
|
||||
|
|
84
tests/scripts/features/load
Normal file
84
tests/scripts/features/load
Normal file
|
@ -0,0 +1,84 @@
|
|||
# -*-perl-*-
|
||||
$description = "Test the load operator.";
|
||||
|
||||
$details = "Test dynamic loading of modules.";
|
||||
|
||||
# Don't do anything if this system doesn't support "load"
|
||||
exists $FEATURES{load} or return -1;
|
||||
|
||||
# First build a shared object
|
||||
# Provide both a default and non-default load symbol
|
||||
|
||||
unlink(qw(testload.c testload.so));
|
||||
|
||||
open(my $F, '> testload.c') or die "open: testload.c: $!\n";
|
||||
print $F <<'EOF' ;
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void define_new_function (void *, const char *, int, int, int,
|
||||
char *(*)(char *, char **, const char *));
|
||||
|
||||
char *variable_buffer_output (char *, const char *, unsigned int);
|
||||
|
||||
static char *
|
||||
func_test(char *o, char **argv, const char *funcname)
|
||||
{
|
||||
return variable_buffer_output (o, funcname, strlen (funcname));
|
||||
}
|
||||
|
||||
int
|
||||
testload_gmake_setup ()
|
||||
{
|
||||
define_new_function (0, "func-a", 1, 1, 1, func_test);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
explicit_setup ()
|
||||
{
|
||||
define_new_function (0, "func-b", 1, 1, 1, func_test);
|
||||
return 1;
|
||||
}
|
||||
EOF
|
||||
close($F) or die "close: testload.c: $!\n";
|
||||
|
||||
run_make_test('testload.so: testload.c ; @$(CC) -g -shared -fPIC -o $@ $<',
|
||||
'', '');
|
||||
|
||||
# TEST 1
|
||||
run_make_test(q!
|
||||
all: ; @echo $(func-a foo) $(func-b bar)
|
||||
load ./testload.so
|
||||
!,
|
||||
'', "func-a\n");
|
||||
|
||||
# TEST 2
|
||||
# Load a different function
|
||||
run_make_test(q!
|
||||
all: ; @echo $(func-a foo) $(func-b bar)
|
||||
load ./testload.so(explicit_setup)
|
||||
!,
|
||||
'', "func-b\n");
|
||||
|
||||
# TEST 3
|
||||
# Verify the .LOADED variable
|
||||
run_make_test(q!
|
||||
all: ; @echo $(filter ./testload.so,$(.LOADED)) $(func-a foo) $(func-b bar)
|
||||
load ./testload.so(explicit_setup)
|
||||
!,
|
||||
'', "./testload.so func-b\n");
|
||||
|
||||
# TEST 4
|
||||
# Check multiple loads
|
||||
run_make_test(q!
|
||||
all: ; @echo $(filter ./testload.so,$(.LOADED)) $(func-a foo) $(func-b bar)
|
||||
load ./testload.so
|
||||
load ./testload.so(explicit_setup)
|
||||
!,
|
||||
'', "./testload.so func-a\n");
|
||||
|
||||
unlink(qw(testload.c testload.so)) unless $keep;
|
||||
|
||||
# This tells the test driver that the perl test script executed properly.
|
||||
1;
|
|
@ -229,7 +229,7 @@ file2: file1 ; @touch $@
|
|||
!,
|
||||
'--no-print-directory -j2', "touch file3");
|
||||
|
||||
#rmfiles('file1', 'file2', 'file3', 'file4');
|
||||
rmfiles('file1', 'file2', 'file3', 'file4');
|
||||
|
||||
if ($all_tests) {
|
||||
# Jobserver FD handling is messed up in some way.
|
||||
|
|
|
@ -5,6 +5,20 @@ $description = 'Test the $(guile ...) function.';
|
|||
$details = 'This only works on systems that support it.';
|
||||
|
||||
# If this instance of make doesn't support GNU Guile, skip it
|
||||
# This detects if guile is loaded using the "load" directive
|
||||
# $makefile = get_tmpfile();
|
||||
# open(MAKEFILE, "> $makefile") || die "Failed to open $makefile: $!\n";
|
||||
# print MAKEFILE q!
|
||||
# -load guile
|
||||
# all: ; @echo $(filter guile,$(.LOADED))
|
||||
# !;
|
||||
# close(MAKEFILE) || die "Failed to write $makefile: $!\n";
|
||||
# $cmd = subst_make_string("#MAKEPATH# -f $makefile");
|
||||
# $log = get_logfile(0);
|
||||
# $code = run_command_with_output($log, $cmd);
|
||||
# read_file_into_string ($log) eq "guile\n" and $FEATURES{guile} = 1;
|
||||
|
||||
# If we don't have Guile support, never mind.
|
||||
exists $FEATURES{guile} or return -1;
|
||||
|
||||
# Verify simple data type conversions
|
||||
|
|
Loading…
Reference in a new issue