mirror of
https://github.com/mirror/make.git
synced 2025-03-09 17:20:59 +08: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
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>
|
2012-09-29 Paul Smith <psmith@gnu.org>
|
||||||
|
|
||||||
* configure.in: Require a new version of gettext (1.18.1).
|
* configure.in: Require a new version of gettext (1.18.1).
|
||||||
|
@ -39,7 +39,7 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
make_SOURCES = ar.c arscan.c commands.c default.c dir.c expand.c file.c \
|
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 \
|
misc.c read.c remake.c rule.c signame.c \
|
||||||
strcache.c variable.c version.c vpath.c hash.c \
|
strcache.c variable.c version.c vpath.c hash.c \
|
||||||
$(remote)
|
$(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
|
See the README file and the GNU make manual for instructions for
|
||||||
reporting bugs.
|
reporting bugs.
|
||||||
|
|
||||||
Version 3.82.90
|
Version 3.99.90
|
||||||
|
|
||||||
A complete list of bugs fixed in this version is available here:
|
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.
|
GNU Guile serves as an embedded extension language for make.
|
||||||
See the "Guile Function" section in the GNU Make manual for details.
|
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.
|
* New function: $(file ...) writes to a file.
|
||||||
|
|
||||||
* On failure, the makefile name and linenumber of the recipe that failed are
|
* 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.])
|
[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
|
# See if the user wants to use pmake's "customs" distributed build capability
|
||||||
|
|
||||||
AC_SUBST([REMOTE]) REMOTE=stub
|
AC_SUBST([REMOTE]) REMOTE=stub
|
||||||
use_customs=false
|
use_customs=false
|
||||||
AC_ARG_WITH([customs],
|
AC_ARG_WITH([customs],
|
||||||
@ -280,7 +278,6 @@ AC_ARG_WITH([customs],
|
|||||||
AM_CONDITIONAL([USE_CUSTOMS], [test "$use_customs" = true])
|
AM_CONDITIONAL([USE_CUSTOMS], [test "$use_customs" = true])
|
||||||
|
|
||||||
# See if the user asked to handle case insensitive file systems.
|
# See if the user asked to handle case insensitive file systems.
|
||||||
|
|
||||||
AH_TEMPLATE([HAVE_CASE_INSENSITIVE_FS], [Use case insensitive file names])
|
AH_TEMPLATE([HAVE_CASE_INSENSITIVE_FS], [Use case insensitive file names])
|
||||||
AC_ARG_ENABLE([case-insensitive-file-system],
|
AC_ARG_ENABLE([case-insensitive-file-system],
|
||||||
AC_HELP_STRING([--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])])])
|
[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.
|
# See if we can handle the job server feature, and if the user wants it.
|
||||||
|
|
||||||
AC_ARG_ENABLE([job-server],
|
AC_ARG_ENABLE([job-server],
|
||||||
AC_HELP_STRING([--disable-job-server],
|
AC_HELP_STRING([--disable-job-server],
|
||||||
[disallow recursive make communication during -jN]),
|
[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.])
|
[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
|
# if we have both lstat() and readlink() then we can support symlink
|
||||||
# timechecks.
|
# timechecks.
|
||||||
AS_IF([test "$ac_cv_func_lstat" = yes && test "$ac_cv_func_readlink" = yes],
|
AS_IF([test "$ac_cv_func_lstat" = yes && test "$ac_cv_func_readlink" = yes],
|
||||||
[ AC_DEFINE([MAKE_SYMLINKS], [1],
|
[ AC_DEFINE([MAKE_SYMLINKS], [1],
|
||||||
[Define to 1 to enable symbolic link timestamp checking.])
|
[Define to 1 to enable symbolic link timestamp checking.])
|
||||||
])
|
])
|
||||||
|
|
||||||
# Find the SCCS commands, so we can include them in our default rules.
|
# 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
|
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.
|
# Specify what files are to be created.
|
||||||
AC_CONFIG_FILES([Makefile glob/Makefile po/Makefile.in config/Makefile \
|
AC_CONFIG_FILES([Makefile glob/Makefile po/Makefile.in config/Makefile \
|
||||||
doc/Makefile w32/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,
|
* Implicit Rules:: Use implicit rules to treat many files alike,
|
||||||
based on their file names.
|
based on their file names.
|
||||||
* Archives:: How @code{make} can update library archives.
|
* 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.
|
* Features:: Features GNU @code{make} has over other @code{make}s.
|
||||||
* Missing:: What GNU @code{make} lacks from other @code{make}s.
|
* Missing:: What GNU @code{make} lacks from other @code{make}s.
|
||||||
* Makefile Conventions:: Conventions for writing makefiles for
|
* Makefile Conventions:: Conventions for writing makefiles for
|
||||||
@ -277,13 +278,7 @@ Functions for Transforming Text
|
|||||||
* Flavor Function:: Find out the flavor of a variable.
|
* Flavor Function:: Find out the flavor of a variable.
|
||||||
* Make Control Functions:: Functions that control how make runs.
|
* Make Control Functions:: Functions that control how make runs.
|
||||||
* Shell Function:: Substitute the output of a shell command.
|
* 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.
|
||||||
|
|
||||||
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}.
|
|
||||||
|
|
||||||
How to Run @code{make}
|
How to Run @code{make}
|
||||||
|
|
||||||
@ -339,6 +334,21 @@ Implicit Rule for Archive Member Targets
|
|||||||
|
|
||||||
* Archive Symbols:: How to update archive symbol directories.
|
* 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 detailmenu
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@ -6280,7 +6290,11 @@ Supports the @code{undefine} directive. @xref{Undefine Directive}.
|
|||||||
|
|
||||||
@item guile
|
@item guile
|
||||||
Has GNU Guile available as an embedded extension language.
|
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
|
@end table
|
||||||
|
|
||||||
@ -6422,12 +6436,12 @@ endif
|
|||||||
or:
|
or:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
@var{conditional-directive}
|
@var{conditional-directive-one}
|
||||||
@var{text-if-one-is-true}
|
@var{text-if-one-is-true}
|
||||||
else @var{conditional-directive}
|
else @var{conditional-directive-two}
|
||||||
@var{text-if-true}
|
@var{text-if-two-is-true}
|
||||||
else
|
else
|
||||||
@var{text-if-false}
|
@var{text-if-one-and-two-are-false}
|
||||||
endif
|
endif
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
@ -6631,7 +6645,7 @@ be substituted.
|
|||||||
* Flavor Function:: Find out the flavor of a variable.
|
* Flavor Function:: Find out the flavor of a variable.
|
||||||
* Make Control Functions:: Functions that control how make runs.
|
* Make Control Functions:: Functions that control how make runs.
|
||||||
* Shell Function:: Substitute the output of a shell command.
|
* 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
|
@end menu
|
||||||
|
|
||||||
@node Syntax of Functions, Text Functions, Functions, Functions
|
@node Syntax of Functions, Text Functions, Functions, Functions
|
||||||
@ -7896,208 +7910,17 @@ exists).@refill
|
|||||||
@findex guile
|
@findex guile
|
||||||
@cindex Guile
|
@cindex Guile
|
||||||
|
|
||||||
GNU make may be built with support for GNU Guile as an embedded
|
If GNU @code{make} is built with support for GNU Guile as an embedded
|
||||||
extension language. You can check the @code{.FEATURES} variable for
|
extension language then the @code{guile} function will be available.
|
||||||
the word @samp{guile} to determine if your version of GNU make
|
The @code{guile} function takes one argument which is first expanded
|
||||||
provides this capability.
|
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
|
||||||
GNU Guile implements the Scheme language. A review of GNU Guile and
|
used as the expansion of the @code{guile} function in the makefile.
|
||||||
the Scheme language and its features is beyond the scope of this
|
See @ref{Guile Integration, ,GNU Guile Integration} for details on
|
||||||
manual: see the documentation for GNU Guile and Scheme.
|
writing extensions to @code{make} in Guile.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
|
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
|
@node Running, Implicit Rules, Functions, Top
|
||||||
@chapter How to Run @code{make}
|
@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
|
automatic variables are set corresponding to the target and
|
||||||
prerequisites. @xref{Automatic Variables}.
|
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
|
@chapter Using @code{make} to Update Archive Files
|
||||||
@cindex archive
|
@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{@samp{.@var{x}.a}} produces two pattern rules: @samp{@w{(%.o):}
|
||||||
@w{%.@var{x}}} and @samp{@w{%.a}: @w{%.@var{x}}}.@refill
|
@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}
|
@chapter Features of GNU @code{make}
|
||||||
@cindex features of GNU @code{make}
|
@cindex features of GNU @code{make}
|
||||||
@cindex portability
|
@cindex portability
|
||||||
|
7
guile.c
7
guile.c
@ -104,8 +104,10 @@ func_guile (char *o, char **argv, const char *funcname UNUSED)
|
|||||||
|
|
||||||
/* ----- Public interface ----- */
|
/* ----- 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
|
int
|
||||||
setup_guile ()
|
guile_gmake_setup (const struct floc *flocp UNUSED)
|
||||||
{
|
{
|
||||||
/* Initialize the Guile interpreter. */
|
/* Initialize the Guile interpreter. */
|
||||||
scm_with_guile (guile_init, NULL);
|
scm_with_guile (guile_init, NULL);
|
||||||
@ -113,8 +115,5 @@ setup_guile ()
|
|||||||
/* Create a make function "guile". */
|
/* Create a make function "guile". */
|
||||||
define_new_function (NILF, "guile", 0, 1, 1, func_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;
|
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
|
#endif
|
||||||
#ifdef MAKE_SYMLINKS
|
#ifdef MAKE_SYMLINKS
|
||||||
" check-symlink"
|
" check-symlink"
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_GUILE
|
||||||
|
" guile"
|
||||||
|
#endif
|
||||||
|
#ifdef MAKE_LOAD
|
||||||
|
" load"
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -1156,7 +1162,7 @@ main (int argc, char **argv, char **envp)
|
|||||||
|
|
||||||
#ifdef HAVE_GUILE
|
#ifdef HAVE_GUILE
|
||||||
/* Configure GNU Guile support */
|
/* Configure GNU Guile support */
|
||||||
setup_guile ();
|
guile_gmake_setup (NILF);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Read in variables from the environment. It is important that this be
|
/* 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 all the makefiles. */
|
||||||
|
|
||||||
read_makefiles
|
read_makefiles = read_all_makefiles (makefiles == 0 ? 0 : makefiles->list);
|
||||||
= read_all_makefiles (makefiles == 0 ? 0 : makefiles->list);
|
|
||||||
|
|
||||||
#ifdef WINDOWS32
|
#ifdef WINDOWS32
|
||||||
/* look one last time after reading all Makefiles */
|
/* look one last time after reading all Makefiles */
|
||||||
@ -3271,7 +3276,7 @@ die (int status)
|
|||||||
if (directory_before_chdir != 0)
|
if (directory_before_chdir != 0)
|
||||||
{
|
{
|
||||||
/* If it fails we don't care: shut up GCC. */
|
/* If it fails we don't care: shut up GCC. */
|
||||||
int _x;
|
int _x UNUSED;
|
||||||
_x = chdir (directory_before_chdir);
|
_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);
|
int strcache_setbufsize (unsigned int size);
|
||||||
|
|
||||||
/* Guile support */
|
/* 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
|
#ifdef HAVE_VFORK_H
|
||||||
# include <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 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
|
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
|
to the next line. If you see record_waiting_files(), then the statement
|
||||||
with at the moment. If you see a "goto rule_complete", then the
|
we are parsing also finishes the previous rule. */
|
||||||
statement we just parsed also finishes the previous rule. */
|
|
||||||
|
|
||||||
commands = xmalloc (200);
|
commands = xmalloc (200);
|
||||||
|
|
||||||
@ -707,6 +706,9 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||||||
struct variable *v;
|
struct variable *v;
|
||||||
enum variable_origin origin = vmod.override_v ? o_override : o_file;
|
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 we're ignoring then we're done now. */
|
||||||
if (ignoring)
|
if (ignoring)
|
||||||
{
|
{
|
||||||
@ -718,9 +720,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||||||
if (vmod.undefine_v)
|
if (vmod.undefine_v)
|
||||||
{
|
{
|
||||||
do_undefine (p, origin, ebuf);
|
do_undefine (p, origin, ebuf);
|
||||||
|
continue;
|
||||||
/* This line has been dealt with. */
|
|
||||||
goto rule_complete;
|
|
||||||
}
|
}
|
||||||
else if (vmod.define_v)
|
else if (vmod.define_v)
|
||||||
v = do_define (p, origin, ebuf);
|
v = do_define (p, origin, ebuf);
|
||||||
@ -735,7 +735,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||||||
v->private_var = 1;
|
v->private_var = 1;
|
||||||
|
|
||||||
/* This line has been dealt with. */
|
/* This line has been dealt with. */
|
||||||
goto rule_complete;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If this line is completely empty, ignore it. */
|
/* 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;
|
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. */
|
/* (un)export by itself causes everything to be (un)exported. */
|
||||||
if (*p2 == '\0')
|
if (*p2 == '\0')
|
||||||
export_all_variables = exporting;
|
export_all_variables = exporting;
|
||||||
@ -803,7 +806,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||||||
|
|
||||||
free (ap);
|
free (ap);
|
||||||
}
|
}
|
||||||
goto rule_complete;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle the special syntax for vpath. */
|
/* Handle the special syntax for vpath. */
|
||||||
@ -812,6 +815,10 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||||||
const char *cp;
|
const char *cp;
|
||||||
char *vpat;
|
char *vpat;
|
||||||
unsigned int l;
|
unsigned int l;
|
||||||
|
|
||||||
|
/* vpath ends the previous rule. */
|
||||||
|
record_waiting_files ();
|
||||||
|
|
||||||
cp = variable_expand (p2);
|
cp = variable_expand (p2);
|
||||||
p = find_next_token (&cp, &l);
|
p = find_next_token (&cp, &l);
|
||||||
if (p != 0)
|
if (p != 0)
|
||||||
@ -828,7 +835,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||||||
if (vpat != 0)
|
if (vpat != 0)
|
||||||
free (vpat);
|
free (vpat);
|
||||||
|
|
||||||
goto rule_complete;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle include and variants. */
|
/* Handle include and variants. */
|
||||||
@ -843,6 +850,9 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||||||
exist. "sinclude" is an alias for this from SGI. */
|
exist. "sinclude" is an alias for this from SGI. */
|
||||||
int noerror = (p[0] != 'i');
|
int noerror = (p[0] != 'i');
|
||||||
|
|
||||||
|
/* Include ends the previous rule. */
|
||||||
|
record_waiting_files ();
|
||||||
|
|
||||||
p = allocated_variable_expand (p2);
|
p = allocated_variable_expand (p2);
|
||||||
|
|
||||||
/* If no filenames, it's a no-op. */
|
/* If no filenames, it's a no-op. */
|
||||||
@ -887,9 +897,51 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||||||
/* Restore conditional state. */
|
/* Restore conditional state. */
|
||||||
restore_conditionals (save);
|
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
|
/* 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
|
was no preceding target, and the line might have been usable as a
|
||||||
variable definition. But now we know it is definitely lossage. */
|
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.
|
/* We get here except in the case that we just read a rule line.
|
||||||
Record now the last rule we read, so following spurious
|
Record now the last rule we read, so following spurious
|
||||||
commands are properly diagnosed. */
|
commands are properly diagnosed. */
|
||||||
rule_complete:
|
|
||||||
record_waiting_files ();
|
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>
|
2012-09-09 Paul Smith <psmith@gnu.org>
|
||||||
|
|
||||||
* scripts/functions/file: Get errors in the C locale, not the
|
* scripts/functions/file: Get errors in the C locale, not the
|
||||||
|
@ -97,6 +97,17 @@ sub valid_option
|
|||||||
|
|
||||||
$old_makefile = undef;
|
$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
|
sub run_make_test
|
||||||
{
|
{
|
||||||
local ($makestring, $options, $answer, $err_code, $timeout) = @_;
|
local ($makestring, $options, $answer, $err_code, $timeout) = @_;
|
||||||
@ -114,16 +125,9 @@ sub run_make_test
|
|||||||
$makefile = &get_tmpfile();
|
$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";
|
$makestring && $makestring !~ /\n$/s and $makestring .= "\n";
|
||||||
|
$makestring = subst_make_string($makestring);
|
||||||
# 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;
|
|
||||||
|
|
||||||
# Populate the makefile!
|
# Populate the makefile!
|
||||||
open(MAKEFILE, "> $makefile") || die "Failed to open $makefile: $!\n";
|
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.
|
# Do the same processing on $answer as we did on $makestring.
|
||||||
|
|
||||||
$answer && $answer !~ /\n$/s and $answer .= "\n";
|
$answer && $answer !~ /\n$/s and $answer .= "\n";
|
||||||
$answer =~ s/#MAKEFILE#/$makefile/g;
|
$answer = subst_make_string($answer);
|
||||||
$answer =~ s/#MAKEPATH#/$mkpath/g;
|
|
||||||
$answer =~ s/#MAKE#/$make_name/g;
|
|
||||||
$answer =~ s/#PERL#/$perl_name/g;
|
|
||||||
$answer =~ s/#PWD#/$pwd/g;
|
|
||||||
|
|
||||||
run_make_with_options($makefile, $options, &get_logfile(0),
|
run_make_with_options($makefile, $options, &get_logfile(0),
|
||||||
$err_code, $timeout);
|
$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");
|
'--no-print-directory -j2', "touch file3");
|
||||||
|
|
||||||
#rmfiles('file1', 'file2', 'file3', 'file4');
|
rmfiles('file1', 'file2', 'file3', 'file4');
|
||||||
|
|
||||||
if ($all_tests) {
|
if ($all_tests) {
|
||||||
# Jobserver FD handling is messed up in some way.
|
# 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.';
|
$details = 'This only works on systems that support it.';
|
||||||
|
|
||||||
# If this instance of make doesn't support GNU Guile, skip 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;
|
exists $FEATURES{guile} or return -1;
|
||||||
|
|
||||||
# Verify simple data type conversions
|
# Verify simple data type conversions
|
||||||
|
Loading…
Reference in New Issue
Block a user