mirror of
https://github.com/mirror/make.git
synced 2025-01-29 05:40:52 +08:00
Remove the "preview" status from the loaded object feature
Add an ABI version both to the header file and passed to the setup function. Unfortunately this itself is an ABI break and I couldn't find a good way to avoid it. * NEWS: Announce the ABI is not a preview and the incompatibility. * doc/make.texi: Remove the preview warnings for object loading. Document the new ABI version argument. * src/gnumake.h (GMK_ABI_VERSION): Set the ABI version to 1. Add comments documenting the format of the setup function. * src/load.c (setup_func_t): Rename from load_func_t. (load_file): Pass the ABI version to the setup function. * tests/scripts/features/load: Rework the setup function. * tests/scripts/features/loadapi: Ditto.
This commit is contained in:
parent
3f28ec2f58
commit
8e0e6c678f
9
NEWS
9
NEWS
@ -20,6 +20,15 @@ https://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=111&se
|
|||||||
This version of GNU Make no longer supports AmigaOS. If you need support
|
This version of GNU Make no longer supports AmigaOS. If you need support
|
||||||
for AmigaOS please use one of the older versions of GNU Make.
|
for AmigaOS please use one of the older versions of GNU Make.
|
||||||
|
|
||||||
|
* WARNING: Loaded Object ABI incompatibility!
|
||||||
|
This release changes the loaded object feature from "technology preview" to
|
||||||
|
fully-supported feature. However, it introduces an ABI incompatibility with
|
||||||
|
previous releases: the setup function now takes an ABI version as its first
|
||||||
|
argument. When compiling your loaded object you can test the GMK_ABI_VERSION
|
||||||
|
constant at compile time to detect which ABI should be used. At runtime
|
||||||
|
your initialization function can check the provided ABI version to verify
|
||||||
|
it's being loaded correctly.
|
||||||
|
|
||||||
* New feature: Makefile warning reporting control
|
* New feature: Makefile warning reporting control
|
||||||
A new option "--warn" controls reporting of warnings for makefiles. Actions
|
A new option "--warn" controls reporting of warnings for makefiles. Actions
|
||||||
can be set to "ignore", "warn", or "error". Two new warnings are reported:
|
can be set to "ignore", "warn", or "error". Two new warnings are reported:
|
||||||
|
381
doc/make.texi
381
doc/make.texi
@ -366,6 +366,7 @@ GNU Guile Integration
|
|||||||
Loading Dynamic Objects
|
Loading Dynamic Objects
|
||||||
|
|
||||||
* load Directive:: Loading dynamic objects as extensions.
|
* load Directive:: Loading dynamic objects as extensions.
|
||||||
|
* Initializing Functions:: How initializing functions are called.
|
||||||
* Remaking Loaded Objects:: How loaded objects get remade.
|
* Remaking Loaded Objects:: How loaded objects get remade.
|
||||||
* Loaded Object API:: Programmatic interface for loaded objects.
|
* Loaded Object API:: Programmatic interface for loaded objects.
|
||||||
* Loaded Object Example:: Example of a loaded object
|
* Loaded Object Example:: Example of a loaded object
|
||||||
@ -11936,37 +11937,27 @@ symbol to be stored in a @code{make} variable.
|
|||||||
@cindex objects, loaded
|
@cindex objects, loaded
|
||||||
@cindex extensions, loading
|
@cindex extensions, loading
|
||||||
|
|
||||||
@cartouche
|
Many operating systems provide a facility for dynamically loading compiled
|
||||||
@quotation Warning
|
objects. If your system provides this facility, GNU @code{make} can make use
|
||||||
The @code{load} directive and extension capability is considered a
|
of it to load dynamic objects at runtime, providing new capabilities which may
|
||||||
``technology preview'' in this release of GNU Make. We encourage you
|
then be invoked by your makefile.
|
||||||
to experiment with this feature and we appreciate any feedback on it.
|
|
||||||
However we cannot guarantee to maintain backward-compatibility in the
|
|
||||||
next release. Consider using GNU Guile instead for extending GNU Make
|
|
||||||
(@pxref{Guile Function, ,The @code{guile} Function}).
|
|
||||||
@end quotation
|
|
||||||
@end cartouche
|
|
||||||
|
|
||||||
Many operating systems provide a facility for dynamically loading
|
The @code{load} makefile directive is used to load a dynamic object. Once the
|
||||||
compiled objects. If your system provides this facility, GNU
|
object is loaded, an initializing function will be invoked to allow the object
|
||||||
@code{make} can make use of it to load dynamic objects at runtime,
|
to initialize itself and register new facilities with GNU @code{make}. A
|
||||||
providing new capabilities which may then be invoked by your makefile.
|
dynamic object might include new @code{make} functions, for example, and the
|
||||||
|
initializing function would register them with GNU @code{make}'s function
|
||||||
The @code{load} directive is used to load a dynamic object. Once the
|
handling system.
|
||||||
object is loaded, a ``setup'' function will be invoked to allow the
|
|
||||||
object to initialize itself and register new facilities with GNU
|
|
||||||
@code{make}. A dynamic object might include new @code{make} functions,
|
|
||||||
for example, and the ``setup'' function would register them with GNU
|
|
||||||
@code{make}'s function handling system.
|
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
* load Directive:: Loading dynamic objects as extensions.
|
* load Directive:: Loading dynamic objects as extensions.
|
||||||
|
* Initializing Functions:: How initializing functions are called.
|
||||||
* Remaking Loaded Objects:: How loaded objects get remade.
|
* Remaking Loaded Objects:: How loaded objects get remade.
|
||||||
* Loaded Object API:: Programmatic interface for loaded objects.
|
* Loaded Object API:: Programmatic interface for loaded objects.
|
||||||
* Loaded Object Example:: Example of a loaded object
|
* Loaded Object Example:: Example of a loaded object
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@node load Directive, Remaking Loaded Objects, Loading Objects, Loading Objects
|
@node load Directive, Initializing Functions, Loading Objects, Loading Objects
|
||||||
@subsection The @code{load} Directive
|
@subsection The @code{load} Directive
|
||||||
@cindex load directive
|
@cindex load directive
|
||||||
@cindex extensions, load directive
|
@cindex extensions, load directive
|
||||||
@ -11986,34 +11977,24 @@ or:
|
|||||||
load @var{object-file}(@var{symbol-name}) @dots{}
|
load @var{object-file}(@var{symbol-name}) @dots{}
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
The file @var{object-file} is dynamically loaded by GNU @code{make}.
|
More than one object file may be loaded with a single @code{load} directive,
|
||||||
If @var{object-file} does not include a directory path then it is
|
and both forms of @code{load} arguments may be used in the same directive.
|
||||||
first looked for in the current directory. If it is not found there,
|
|
||||||
or a directory path is included, then system-specific paths will be
|
|
||||||
searched. If the load fails for any reason, @code{make} will print a
|
|
||||||
message and exit.
|
|
||||||
|
|
||||||
If the load succeeds @code{make} will invoke an initializing function.
|
The file @var{object-file} is dynamically loaded by GNU @code{make}. If
|
||||||
|
@var{object-file} does not include a directory path then it is first looked
|
||||||
|
for in the current directory. If it is not found there, or a directory path
|
||||||
|
is included, then system-specific paths will be searched. If the load fails
|
||||||
|
for any reason, @code{make} will print a message and exit.
|
||||||
|
|
||||||
If @var{symbol-name} is provided, it will be used as the name of the
|
If the load succeeds @code{make} will invoke an initializing function. If
|
||||||
initializing function.
|
@var{symbol-name} is provided, it will be used as the name of the initializing
|
||||||
|
function.
|
||||||
|
|
||||||
If no @var{symbol-name} is provided, the initializing function name is
|
If no @var{symbol-name} is provided, the initializing function name is created
|
||||||
created by taking the base file name of @var{object-file}, up to the
|
by taking the base file name of @var{object-file}, up to the first character
|
||||||
first character which is not a valid symbol name character
|
which is not a valid symbol name character (alphanumerics and underscores are
|
||||||
(alphanumerics and underscores are valid symbol name characters). To
|
valid symbol name characters). To this prefix will be appended the suffix
|
||||||
this prefix will be appended the suffix @code{_gmk_setup}.
|
@code{_gmk_setup}.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
The initializing function will be provided the file name and line
|
|
||||||
number of the invocation of the @code{load} operation. It should
|
|
||||||
return a value of type @code{int}, which must be @code{0} on failure
|
|
||||||
and non-@code{0} on success. If the return value is @code{-1}, then
|
|
||||||
GNU Make will @emph{not} attempt to rebuild the object file
|
|
||||||
(@pxref{Remaking Loaded Objects, ,How Loaded Objects Are Remade}).
|
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
@ -12021,9 +12002,9 @@ For example:
|
|||||||
load ../mk_funcs.so
|
load ../mk_funcs.so
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
will load the dynamic object @file{../mk_funcs.so}. After the object
|
will load the dynamic object @file{../mk_funcs.so}. After the object is
|
||||||
is loaded, @code{make} will invoke the function (assumed to be defined
|
loaded, @code{make} will invoke the initializing function (assumed to be
|
||||||
by the shared object) @code{mk_funcs_gmk_setup}.
|
defined by the shared object) @code{mk_funcs_gmk_setup}.
|
||||||
|
|
||||||
On the other hand:
|
On the other hand:
|
||||||
|
|
||||||
@ -12031,86 +12012,96 @@ On the other hand:
|
|||||||
load ../mk_funcs.so(init_mk_func)
|
load ../mk_funcs.so(init_mk_func)
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
will load the dynamic object @file{../mk_funcs.so}. After the object
|
will load the dynamic object @file{../mk_funcs.so}. After the object is
|
||||||
is loaded, @code{make} will invoke the function @code{init_mk_func}.
|
loaded, @code{make} will invoke the initializing function @code{init_mk_func}.
|
||||||
|
|
||||||
Regardless of how many times an object file appears in a @code{load}
|
Regardless of how many times an object file appears in a @code{load}
|
||||||
directive, it will only be loaded (and its setup function will only
|
directive, it will only be loaded (and its setup function will only be
|
||||||
be invoked) once.
|
invoked) once.
|
||||||
|
|
||||||
@vindex .LOADED
|
@vindex .LOADED
|
||||||
After an object has been successfully loaded, its file name is
|
After an object has been successfully loaded, its file name is appended to the
|
||||||
appended to the @code{.LOADED} variable.
|
@code{.LOADED} variable.
|
||||||
|
|
||||||
@findex -load
|
@findex -load
|
||||||
If you would prefer that failure to load a dynamic object not be
|
If you would prefer that failure to load a dynamic object not be reported as
|
||||||
reported as an error, you can use the @code{-load} directive instead
|
an error, you can use the @code{-load} directive instead of @code{load}. GNU
|
||||||
of @code{load}. GNU @code{make} will not fail and no message will be
|
@code{make} will not fail and no message will be generated if an object fails
|
||||||
generated if an object fails to load. The failed object is not added
|
to load. The failed object is not added to the @code{.LOADED} variable, which
|
||||||
to the @code{.LOADED} variable, which can then be consulted to
|
can then be consulted to determine if the load was successful.
|
||||||
determine if the load was successful.
|
|
||||||
|
|
||||||
@node Remaking Loaded Objects, Loaded Object API, load Directive, Loading Objects
|
@node Initializing Functions, Remaking Loaded Objects, load Directive, Loading Objects
|
||||||
|
@subsection Initializing Functions
|
||||||
|
@cindex loaded object initializing function
|
||||||
|
@cindex initializing function, for loaded objects
|
||||||
|
|
||||||
|
The initializing function defined by the loaded object must have this
|
||||||
|
signature:
|
||||||
|
|
||||||
|
@example
|
||||||
|
int <name> (unsigned int abi_version, const gmk_floc *floc);
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Where @emph{<name>} is described in the previous section.
|
||||||
|
|
||||||
|
The @code{abi_version} value will be the value of the @code{GMK_ABI_VERSION}
|
||||||
|
constant (see the @file{gnumake.h} file) for this GNU Make release. The
|
||||||
|
@code{floc} pointer provides the file name and line number of the invocation
|
||||||
|
of the @code{load} operation.
|
||||||
|
|
||||||
|
The initializing function should return an @code{int}, which must be @code{0}
|
||||||
|
on failure and non-@code{0} on success. If the return value is @code{-1},
|
||||||
|
then GNU Make will @emph{not} attempt to rebuild the object file
|
||||||
|
(@pxref{Remaking Loaded Objects, ,How Loaded Objects Are Remade}).
|
||||||
|
|
||||||
|
@node Remaking Loaded Objects, Loaded Object API, Initializing Functions, Loading Objects
|
||||||
@subsection How Loaded Objects Are Remade
|
@subsection How Loaded Objects Are Remade
|
||||||
@cindex updating loaded objects
|
@cindex updating loaded objects
|
||||||
@cindex remaking loaded objects
|
@cindex remaking loaded objects
|
||||||
@cindex loaded objects, remaking of
|
@cindex loaded objects, remaking of
|
||||||
|
|
||||||
Loaded objects undergo the same re-make procedure as makefiles
|
Loaded objects undergo the same re-make procedure as makefiles
|
||||||
(@pxref{Remaking Makefiles, ,How Makefiles Are Remade}). If any
|
(@pxref{Remaking Makefiles, ,How Makefiles Are Remade}). If any loaded object
|
||||||
loaded object is recreated, then @code{make} will start from scratch
|
is recreated, then @code{make} will start from scratch and re-read all the
|
||||||
and re-read all the makefiles, and reload the object files again. It
|
makefiles, and reload the object files again. It is not necessary for the
|
||||||
is not necessary for the loaded object to do anything special to
|
loaded object to do anything special to support this.
|
||||||
support this.
|
|
||||||
|
|
||||||
It's up to the makefile author to provide the rules needed for
|
It's up to the makefile author to provide the rules needed for rebuilding the
|
||||||
rebuilding the loaded object.
|
loaded object.
|
||||||
|
|
||||||
@node Loaded Object API, Loaded Object Example, Remaking Loaded Objects, Loading Objects
|
@node Loaded Object API, Loaded Object Example, Remaking Loaded Objects, Loading Objects
|
||||||
@subsection Loaded Object Interface
|
@subsection Loaded Object Interface
|
||||||
@cindex loaded object API
|
@cindex loaded object API
|
||||||
@cindex interface for loaded objects
|
@cindex interface for loaded objects
|
||||||
|
|
||||||
@cartouche
|
To be useful, loaded objects must be able to interact with GNU @code{make}.
|
||||||
@quotation Warning
|
This interaction includes both interfaces the loaded object provides to
|
||||||
For this feature to be useful your extensions will need to invoke
|
makefiles and also interfaces @code{make} provides to the loaded object to
|
||||||
various functions internal to GNU @code{make}. The programming
|
manipulate @code{make}'s operation.
|
||||||
interfaces provided in this release should not be considered stable:
|
|
||||||
functions may be added, removed, or change calling signatures or
|
|
||||||
implementations in future versions of GNU @code{make}.
|
|
||||||
@end quotation
|
|
||||||
@end cartouche
|
|
||||||
|
|
||||||
To be useful, loaded objects must be able to interact with GNU
|
|
||||||
@code{make}. This interaction includes both interfaces the loaded
|
|
||||||
object provides to makefiles and also interfaces @code{make} provides
|
|
||||||
to the loaded object to manipulate @code{make}'s operation.
|
|
||||||
|
|
||||||
The interface between loaded objects and @code{make} is defined by the
|
The interface between loaded objects and @code{make} is defined by the
|
||||||
@file{gnumake.h} C header file. All loaded objects written in C
|
@file{gnumake.h} C header file. All loaded objects written in C should
|
||||||
should include this header file. Any loaded object not written in C
|
include this header file. Any loaded object not written in C will need to
|
||||||
will need to implement the interface defined in this header file.
|
implement the interface defined in this header file.
|
||||||
|
|
||||||
Typically, a loaded object will register one or more new GNU
|
Typically, a loaded object will register one or more new GNU @code{make}
|
||||||
@code{make} functions using the @code{gmk_add_function} routine from
|
functions using the @code{gmk_add_function} routine from within its setup
|
||||||
within its setup function. The implementations of these @code{make}
|
function. The implementations of these @code{make} functions may make use of
|
||||||
functions may make use of the @code{gmk_expand} and @code{gmk_eval}
|
the @code{gmk_expand} and @code{gmk_eval} routines to perform their tasks,
|
||||||
routines to perform their tasks, then optionally return a string as
|
then optionally return a string as the result of the function expansion.
|
||||||
the result of the function expansion.
|
|
||||||
|
|
||||||
@subsubheading Loaded Object Licensing
|
@subsubheading Loaded Object Licensing
|
||||||
@cindex loaded object licensing
|
@cindex loaded object licensing
|
||||||
@cindex plugin_is_GPL_compatible
|
@cindex plugin_is_GPL_compatible
|
||||||
|
|
||||||
Every dynamic extension should define the global symbol
|
Every dynamic extension should define the global symbol
|
||||||
@code{plugin_is_GPL_compatible} to assert that it has been licensed
|
@code{plugin_is_GPL_compatible} to assert that it has been licensed under a
|
||||||
under a GPL-compatible license. If this symbol does not exist,
|
GPL-compatible license. If this symbol does not exist, @code{make} emits a
|
||||||
@code{make} emits a fatal error and exits when it tries to load your
|
fatal error and exits when it tries to load your extension.
|
||||||
extension.
|
|
||||||
|
|
||||||
The declared type of the symbol should be @code{int}. It does not need
|
The declared type of the symbol should be @code{int}. It does not need to be
|
||||||
to be in any allocated section, though. The code merely asserts that
|
in any allocated section, though. The code merely asserts that the symbol
|
||||||
the symbol exists in the global scope. Something like this is enough:
|
exists in the global scope. Something like this is enough:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
int plugin_is_GPL_compatible;
|
int plugin_is_GPL_compatible;
|
||||||
@ -12120,19 +12111,44 @@ int plugin_is_GPL_compatible;
|
|||||||
|
|
||||||
@table @code
|
@table @code
|
||||||
@item gmk_floc
|
@item gmk_floc
|
||||||
This structure represents a filename/location pair. It is provided
|
This structure represents a filename/location pair. It is provided when
|
||||||
when defining items, so GNU @code{make} can inform the user later
|
defining items, so GNU @code{make} can inform the user where the definition
|
||||||
where the definition occurred if necessary.
|
occurred if necessary.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
|
@subsubheading Checking Versions
|
||||||
|
@findex gmk_get_version
|
||||||
|
|
||||||
|
The @code{gmk_get_version} allows loaded objects to check which loaded object
|
||||||
|
API version is supported by GNU Make. The API version is specified as two
|
||||||
|
values: the @emph{major} version and the @emph{minor} version. Note, these
|
||||||
|
two values are not the same as the version of GNU Make!
|
||||||
|
|
||||||
|
The @emph{major} version is incremented when there is a change to the loaded
|
||||||
|
object ABI, which might cause .
|
||||||
|
|
||||||
|
It is called as:
|
||||||
|
|
||||||
|
@example
|
||||||
|
void gmk_get_version (unsigned int *major, unsigned int *minor);
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@table @code
|
||||||
|
@item major
|
||||||
|
If not NULL, the major version number is placed here.
|
||||||
|
|
||||||
|
@item minor
|
||||||
|
If not NULL, the minor version number is placed here.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
|
||||||
@subsubheading Registering Functions
|
@subsubheading Registering Functions
|
||||||
@findex gmk_add_function
|
@findex gmk_add_function
|
||||||
|
|
||||||
There is currently one way for makefiles to invoke operations provided
|
There is currently one way for makefiles to invoke operations provided by the
|
||||||
by the loaded object: through the @code{make} function call
|
loaded object: through the @code{make} function call interface. A loaded
|
||||||
interface. A loaded object can register one or more new functions
|
object can register one or more new functions which may then be invoked from
|
||||||
which may then be invoked from within the makefile in the same way as
|
within the makefile in the same way as any other function.
|
||||||
any other function.
|
|
||||||
|
|
||||||
Use @code{gmk_add_function} to create a new @code{make} function. Its
|
Use @code{gmk_add_function} to create a new @code{make} function. Its
|
||||||
arguments are as follows:
|
arguments are as follows:
|
||||||
@ -12140,109 +12156,101 @@ arguments are as follows:
|
|||||||
@table @code
|
@table @code
|
||||||
@item name
|
@item name
|
||||||
The function name. This is what the makefile should use to invoke the
|
The function name. This is what the makefile should use to invoke the
|
||||||
function. The name must be between 1 and 255 characters long and it
|
function. The name must be between 1 and 255 characters long and it may only
|
||||||
may only contain alphanumeric, period (@samp{.}), dash (@samp{-}), and
|
contain alphanumeric, period (@samp{.}), dash (@samp{-}), and underscore
|
||||||
underscore (@samp{_}) characters. It may not begin with a period.
|
(@samp{_}) characters. It may not begin with a period.
|
||||||
|
|
||||||
@item func_ptr
|
@item func_ptr
|
||||||
A pointer to a function that @code{make} will invoke when it expands
|
A pointer to a function that @code{make} will invoke when it expands the
|
||||||
the function in a makefile. This function must be defined by the
|
function in a makefile. This function must be defined by the loaded object.
|
||||||
loaded object.
|
|
||||||
|
|
||||||
@item min_args
|
@item min_args
|
||||||
The minimum number of arguments the function will accept. Must be
|
The minimum number of arguments the function will accept. Must be between 0
|
||||||
between 0 and 255. GNU @code{make} will check this and fail before
|
and 255. GNU @code{make} will check this and fail before invoking
|
||||||
invoking @code{func_ptr} if the function was invoked with too few
|
@code{func_ptr} if the function was invoked with too few arguments.
|
||||||
arguments.
|
|
||||||
|
|
||||||
@item max_args
|
@item max_args
|
||||||
The maximum number of arguments the function will accept. Must be
|
The maximum number of arguments the function will accept. Must be between 0
|
||||||
between 0 and 255. GNU @code{make} will check this and fail before
|
and 255. GNU @code{make} will check this and fail before invoking
|
||||||
invoking @code{func_ptr} if the function was invoked with too many
|
@code{func_ptr} if the function was invoked with too many arguments. If the
|
||||||
arguments. If the value is 0, then any number of arguments is
|
value is 0, then any number of arguments is accepted. If the value is greater
|
||||||
accepted. If the value is greater than 0, then it must be greater
|
than 0, then it must be greater than or equal to @code{min_args}.
|
||||||
than or equal to @code{min_args}.
|
|
||||||
|
|
||||||
@item flags
|
@item flags
|
||||||
Flags that specify how this function will operate; the desired flags
|
Flags that specify how this function will operate; the desired flags should be
|
||||||
should be OR'd together. If the @code{GMK_FUNC_NOEXPAND} flag is
|
OR'd together. If the @code{GMK_FUNC_NOEXPAND} flag is given then the
|
||||||
given then the function arguments will not be expanded before the
|
function arguments will not be expanded before the function is called;
|
||||||
function is called; otherwise they will be expanded first.
|
otherwise they will be expanded first.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@subsubheading Registered Function Interface
|
@subsubheading Registered Function Interface
|
||||||
@findex gmk_func_ptr
|
@findex gmk_func_ptr
|
||||||
|
|
||||||
A function registered with @code{make} must match the
|
A function registered with @code{make} must match the @code{gmk_func_ptr}
|
||||||
@code{gmk_func_ptr} type. It will be invoked with three parameters:
|
type. It will be invoked with three parameters: @code{name} (the name of the
|
||||||
@code{name} (the name of the function), @code{argc} (the number of
|
function), @code{argc} (the number of arguments to the function), and
|
||||||
arguments to the function), and @code{argv} (an array of pointers to
|
@code{argv} (an array of pointers to arguments to the function). The last
|
||||||
arguments to the function). The last pointer (that is,
|
pointer (that is, @code{argv[argc]}) will be null (@code{0}).
|
||||||
@code{argv[argc]}) will be null (@code{0}).
|
|
||||||
|
|
||||||
The return value of the function is the result of expanding the
|
The return value of the function is the result of expanding the function. If
|
||||||
function. If the function expands to nothing the return value may be
|
the function expands to nothing the return value may be null. Otherwise, it
|
||||||
null. Otherwise, it must be a pointer to a string created with
|
must be a pointer to a string created with @code{gmk_alloc}. Once the
|
||||||
@code{gmk_alloc}. Once the function returns, @code{make} owns this
|
function returns, @code{make} owns this string and will free it when
|
||||||
string and will free it when appropriate; it cannot be accessed by the
|
appropriate; it cannot be accessed by the loaded object.
|
||||||
loaded object.
|
|
||||||
|
|
||||||
@subsubheading GNU @code{make} Facilities
|
@subsubheading GNU @code{make} Facilities
|
||||||
|
|
||||||
There are some facilities exported by GNU @code{make} for use by
|
There are some facilities exported by GNU @code{make} for use by loaded
|
||||||
loaded objects. Typically these would be run from within the
|
objects. Typically these would be run from within the setup function and/or
|
||||||
setup function and/or the functions registered via
|
the functions registered via @code{gmk_add_function}, to retrieve or modify
|
||||||
@code{gmk_add_function}, to retrieve or modify the data @code{make}
|
the data @code{make} works with.
|
||||||
works with.
|
|
||||||
|
|
||||||
@table @code
|
@table @code
|
||||||
@item gmk_expand
|
@item gmk_expand
|
||||||
@findex gmk_expand
|
@findex gmk_expand
|
||||||
This function takes a string and expands it using @code{make}
|
This function takes a string and expands it using @code{make} expansion rules.
|
||||||
expansion rules. The result of the expansion is returned in a
|
The result of the expansion is returned in a nil-terminated string buffer.
|
||||||
nil-terminated string buffer. The caller is responsible for calling
|
The caller is responsible for calling @code{gmk_free} with a pointer to the
|
||||||
@code{gmk_free} with a pointer to the returned buffer when done.
|
returned buffer when done.
|
||||||
|
|
||||||
@item gmk_eval
|
@item gmk_eval
|
||||||
@findex gmk_eval
|
@findex gmk_eval
|
||||||
This function takes a buffer and evaluates it as a segment of makefile
|
This function takes a buffer and evaluates it as a segment of makefile syntax.
|
||||||
syntax. This function can be used to define new variables, new rules,
|
This function can be used to define new variables, new rules, etc. It is
|
||||||
etc. It is equivalent to using the @code{eval} @code{make} function.
|
equivalent to using the @code{eval} @code{make} function.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
Note that there is a difference between @code{gmk_eval} and calling
|
Note that there is a difference between @code{gmk_eval} and calling
|
||||||
@code{gmk_expand} with a string using the @code{eval} function: in
|
@code{gmk_expand} with a string using the @code{eval} function: in the latter
|
||||||
the latter case the string will be expanded @emph{twice}; once by
|
case the string will be expanded @emph{twice}; once by @code{gmk_expand} and
|
||||||
@code{gmk_expand} and then again by the @code{eval} function. Using
|
then again by the @code{eval} function. Using @code{gmk_eval} the buffer is
|
||||||
@code{gmk_eval} the buffer is only expanded once, at most (as it's
|
only expanded once, at most (as it's read by the @code{make} parser).
|
||||||
read by the @code{make} parser).
|
|
||||||
|
|
||||||
@subsubheading Memory Management
|
@subsubheading Memory Management
|
||||||
|
|
||||||
Some systems allow for different memory management schemes. Thus you
|
Some systems allow for different memory management schemes. Thus you should
|
||||||
should never pass memory that you've allocated directly to any
|
never pass memory that you've allocated directly to any @code{make} function,
|
||||||
@code{make} function, nor should you attempt to directly free any
|
nor should you attempt to directly free any memory returned to you by any
|
||||||
memory returned to you by any @code{make} function. Instead, use the
|
@code{make} function. Instead, use the @code{gmk_alloc} and @code{gmk_free}
|
||||||
@code{gmk_alloc} and @code{gmk_free} functions.
|
functions.
|
||||||
|
|
||||||
In particular, the string returned to @code{make} by a function
|
In particular, the string returned to @code{make} by a function registered
|
||||||
registered using @code{gmk_add_function} @emph{must} be allocated
|
using @code{gmk_add_function} @emph{must} be allocated using @code{gmk_alloc},
|
||||||
using @code{gmk_alloc}, and the string returned from the @code{make}
|
and the string returned from the @code{make} @code{gmk_expand} function
|
||||||
@code{gmk_expand} function @emph{must} be freed (when no longer
|
@emph{must} be freed (when no longer needed) using @code{gmk_free}.
|
||||||
needed) using @code{gmk_free}.
|
|
||||||
|
|
||||||
@table @code
|
@table @code
|
||||||
@item gmk_alloc
|
@item gmk_alloc
|
||||||
@findex gmk_alloc
|
@findex gmk_alloc
|
||||||
Return a pointer to a newly-allocated buffer. This function will
|
Return a pointer to a newly-allocated buffer. This function will always
|
||||||
always return a valid pointer; if not enough memory is available
|
return a valid pointer; if not enough memory is available @code{make} will
|
||||||
@code{make} will exit. @code{gmk_alloc} does not initialize allocated memory.
|
exit. @code{gmk_alloc} does not initialize allocated memory.
|
||||||
|
|
||||||
@item gmk_free
|
@item gmk_free
|
||||||
@findex gmk_free
|
@findex gmk_free
|
||||||
Free a buffer returned to you by @code{make}. Once the
|
Free a buffer returned to you by @code{make}. Once the @code{gmk_free}
|
||||||
@code{gmk_free} function returns the string will no longer be valid.
|
function returns the string will no longer be valid. If NULL is passed to
|
||||||
If NULL is passed to @code{gmk_free}, no operation is performed.
|
@code{gmk_free}, no operation is performed.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@node Loaded Object Example, , Loaded Object API, Loading Objects
|
@node Loaded Object Example, , Loaded Object API, Loading Objects
|
||||||
@ -12250,10 +12258,10 @@ If NULL is passed to @code{gmk_free}, no operation is performed.
|
|||||||
@cindex loaded object example
|
@cindex loaded object example
|
||||||
@cindex example of loaded objects
|
@cindex example of loaded objects
|
||||||
|
|
||||||
Let's suppose we wanted to write a new GNU @code{make} function that
|
Let's suppose we wanted to write a new GNU @code{make} function that would
|
||||||
would create a temporary file and return its name. We would like our
|
create a temporary file and return its name. We would like our function to
|
||||||
function to take a prefix as an argument. First we can write the
|
take a prefix as an argument. First we can write the function in a file
|
||||||
function in a file @file{mk_temp.c}:
|
@file{mk_temp.c}:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
@group
|
@group
|
||||||
@ -12294,9 +12302,10 @@ gen_tmpfile(const char *nm, int argc, char **argv)
|
|||||||
@}
|
@}
|
||||||
|
|
||||||
int
|
int
|
||||||
mk_temp_gmk_setup (const gmk_floc *floc)
|
mk_temp_gmk_setup (unsigned int abi, const gmk_floc *floc)
|
||||||
@{
|
@{
|
||||||
printf ("mk_temp plugin loaded from %s:%lu\n", floc->filenm, floc->lineno);
|
printf ("mk_temp abi %u plugin loaded from %s:%lu\n",
|
||||||
|
abi, floc->filenm, floc->lineno);
|
||||||
/* Register the function with make name "mk-temp". */
|
/* Register the function with make name "mk-temp". */
|
||||||
gmk_add_function ("mk-temp", gen_tmpfile, 1, 1, 1);
|
gmk_add_function ("mk-temp", gen_tmpfile, 1, 1, 1);
|
||||||
return 1;
|
return 1;
|
||||||
@ -12319,12 +12328,12 @@ mk_temp.so: mk_temp.c
|
|||||||
@end group
|
@end group
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
On MS-Windows, due to peculiarities of how shared objects are
|
On MS-Windows, due to peculiarities of how shared objects are produced, the
|
||||||
produced, the compiler needs to scan the @dfn{import library} produced
|
compiler needs to scan the @dfn{import library} produced when building
|
||||||
when building @code{make}, typically called
|
@code{make}, typically called @file{libgnumake-@var{version}.dll.a}, where
|
||||||
@file{libgnumake-@var{version}.dll.a}, where @var{version} is the
|
@var{version} is the version of the load object API. So the recipe to produce
|
||||||
version of the load object API. So the recipe to produce a shared
|
a shared object will look on Windows like this (assuming the API version is
|
||||||
object will look on Windows like this (assuming the API version is 1):
|
1):
|
||||||
|
|
||||||
@example
|
@example
|
||||||
@group
|
@group
|
||||||
@ -12337,7 +12346,7 @@ Now when you run @code{make} you'll see something like:
|
|||||||
|
|
||||||
@example
|
@example
|
||||||
$ make
|
$ make
|
||||||
mk_temp plugin loaded from Makefile:4
|
mk_temp abi 1 plugin loaded from Makefile:4
|
||||||
cc -shared -fPIC -o mk_temp.so mk_temp.c
|
cc -shared -fPIC -o mk_temp.so mk_temp.c
|
||||||
Temporary filename: tmpfile.A7JEwd
|
Temporary filename: tmpfile.A7JEwd
|
||||||
@end example
|
@end example
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
/* External interfaces usable by dynamic objects loaded into GNU Make.
|
/* External interfaces usable by dynamic objects loaded into GNU Make.
|
||||||
--THIS API IS A "TECHNOLOGY PREVIEW" ONLY. IT IS NOT A STABLE INTERFACE--
|
|
||||||
|
|
||||||
Copyright (C) 2013-2023 Free Software Foundation, Inc.
|
Copyright (C) 2013-2023 Free Software Foundation, Inc.
|
||||||
This file is part of GNU Make.
|
This file is part of GNU Make.
|
||||||
@ -19,6 +18,8 @@ this program. If not, see <https://www.gnu.org/licenses/>. */
|
|||||||
#ifndef _GNUMAKE_H_
|
#ifndef _GNUMAKE_H_
|
||||||
#define _GNUMAKE_H_
|
#define _GNUMAKE_H_
|
||||||
|
|
||||||
|
#define GMK_ABI_VERSION 1
|
||||||
|
|
||||||
/* Specify the location of elements read from makefiles. */
|
/* Specify the location of elements read from makefiles. */
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -28,6 +29,14 @@ typedef struct
|
|||||||
|
|
||||||
typedef char *(*gmk_func_ptr)(const char *nm, unsigned int argc, char **argv);
|
typedef char *(*gmk_func_ptr)(const char *nm, unsigned int argc, char **argv);
|
||||||
|
|
||||||
|
/* When an object is loaded by GNU Make, a setup method will be invoked.
|
||||||
|
The name of the method is either derived from the filename of the object,
|
||||||
|
or specified explicitly in the makefile. It has the signature:
|
||||||
|
|
||||||
|
int <setup_fn> (unsigned int abi_version, const gmk_floc *flocp);
|
||||||
|
|
||||||
|
The abi_version will be set to GMK_ABI_VERSION. */
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# ifdef GMK_BUILDING_MAKE
|
# ifdef GMK_BUILDING_MAKE
|
||||||
# define GMK_EXPORT __declspec(dllexport)
|
# define GMK_EXPORT __declspec(dllexport)
|
||||||
@ -38,7 +47,7 @@ typedef char *(*gmk_func_ptr)(const char *nm, unsigned int argc, char **argv);
|
|||||||
# define GMK_EXPORT
|
# define GMK_EXPORT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Free memory returned by the gmk_expand() function. */
|
/* Free memory returned by the gmk_expand() and gmk_free() functions. */
|
||||||
GMK_EXPORT void gmk_free (char *str);
|
GMK_EXPORT void gmk_free (char *str);
|
||||||
|
|
||||||
/* Allocate memory in GNU Make's context. */
|
/* Allocate memory in GNU Make's context. */
|
||||||
|
21
src/load.c
21
src/load.c
@ -44,12 +44,14 @@ struct load_list
|
|||||||
|
|
||||||
static struct load_list *loaded_syms = NULL;
|
static struct load_list *loaded_syms = NULL;
|
||||||
|
|
||||||
static load_func_t
|
typedef int (*setup_func_t)(unsigned int abi, const floc *flocp);
|
||||||
|
|
||||||
|
static setup_func_t
|
||||||
load_object (const floc *flocp, int noerror, const char *ldname,
|
load_object (const floc *flocp, int noerror, const char *ldname,
|
||||||
const char *symname)
|
const char *symname)
|
||||||
{
|
{
|
||||||
static void *global_dl = NULL;
|
static void *global_dl = NULL;
|
||||||
load_func_t symp;
|
setup_func_t symp;
|
||||||
|
|
||||||
if (! global_dl)
|
if (! global_dl)
|
||||||
{
|
{
|
||||||
@ -61,7 +63,7 @@ load_object (const floc *flocp, int noerror, const char *ldname,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
symp = (load_func_t) dlsym (global_dl, symname);
|
symp = (setup_func_t) dlsym (global_dl, symname);
|
||||||
if (! symp)
|
if (! symp)
|
||||||
{
|
{
|
||||||
struct load_list *new;
|
struct load_list *new;
|
||||||
@ -93,13 +95,13 @@ load_object (const floc *flocp, int noerror, const char *ldname,
|
|||||||
DB (DB_VERBOSE, (_("Loaded shared object %s\n"), ldname));
|
DB (DB_VERBOSE, (_("Loaded shared object %s\n"), ldname));
|
||||||
|
|
||||||
/* Assert that the GPL license symbol is defined. */
|
/* Assert that the GPL license symbol is defined. */
|
||||||
symp = (load_func_t) dlsym (dlp, "plugin_is_GPL_compatible");
|
symp = (setup_func_t) dlsym (dlp, "plugin_is_GPL_compatible");
|
||||||
if (! symp)
|
if (! symp)
|
||||||
OS (fatal, flocp,
|
OS (fatal, flocp,
|
||||||
_("loaded object %s is not declared to be GPL compatible"),
|
_("loaded object %s is not declared to be GPL compatible"),
|
||||||
ldname);
|
ldname);
|
||||||
|
|
||||||
symp = (load_func_t) dlsym (dlp, symname);
|
symp = (setup_func_t) dlsym (dlp, symname);
|
||||||
if (! symp)
|
if (! symp)
|
||||||
{
|
{
|
||||||
const char *err = dlerror ();
|
const char *err = dlerror ();
|
||||||
@ -129,7 +131,7 @@ load_file (const floc *flocp, struct file *file, int noerror)
|
|||||||
char *symname = NULL;
|
char *symname = NULL;
|
||||||
const char *fp;
|
const char *fp;
|
||||||
int r;
|
int r;
|
||||||
load_func_t symp;
|
setup_func_t symp;
|
||||||
|
|
||||||
/* Break the input into an object file name and a symbol name. If no symbol
|
/* Break the input into an object file name and a symbol name. If no symbol
|
||||||
name was provided, compute one from the object file name. */
|
name was provided, compute one from the object file name. */
|
||||||
@ -210,8 +212,11 @@ load_file (const floc *flocp, struct file *file, int noerror)
|
|||||||
if (! symp)
|
if (! symp)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Invoke the symbol. */
|
/* Invoke the setup function. */
|
||||||
r = (*symp) (flocp);
|
{
|
||||||
|
unsigned int abi = GMK_ABI_VERSION;
|
||||||
|
r = (*symp) (abi, flocp);
|
||||||
|
}
|
||||||
|
|
||||||
/* If the load didn't fail, add the file to the .LOADED variable. */
|
/* If the load didn't fail, add the file to the .LOADED variable. */
|
||||||
if (r)
|
if (r)
|
||||||
|
@ -672,7 +672,6 @@ const char *strcache_add_len (const char *str, size_t len);
|
|||||||
int guile_gmake_setup (const floc *flocp);
|
int guile_gmake_setup (const floc *flocp);
|
||||||
|
|
||||||
/* Loadable object support. Sets to the strcached name of the loaded file. */
|
/* Loadable object support. Sets to the strcached name of the loaded file. */
|
||||||
typedef int (*load_func_t)(const floc *flocp);
|
|
||||||
int load_file (const floc *flocp, struct file *file, int noerror);
|
int load_file (const floc *flocp, struct file *file, int noerror);
|
||||||
int unload_file (const char *name);
|
int unload_file (const char *name);
|
||||||
|
|
||||||
|
@ -25,11 +25,11 @@ char* getenv (const char*);
|
|||||||
|
|
||||||
int plugin_is_GPL_compatible;
|
int plugin_is_GPL_compatible;
|
||||||
|
|
||||||
int testload_gmk_setup (gmk_floc *);
|
int testload_gmk_setup (unsigned int, gmk_floc *);
|
||||||
int explicit_setup (gmk_floc *);
|
int explicit_setup (unsigned int, gmk_floc *);
|
||||||
|
|
||||||
int
|
int
|
||||||
testload_gmk_setup (gmk_floc *pos)
|
testload_gmk_setup (unsigned int abi, gmk_floc *pos)
|
||||||
{
|
{
|
||||||
(void)pos;
|
(void)pos;
|
||||||
gmk_eval ("TESTLOAD = implicit", 0);
|
gmk_eval ("TESTLOAD = implicit", 0);
|
||||||
@ -39,7 +39,7 @@ testload_gmk_setup (gmk_floc *pos)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
explicit_setup (gmk_floc *pos)
|
explicit_setup (unsigned int abi, gmk_floc *pos)
|
||||||
{
|
{
|
||||||
(void)pos;
|
(void)pos;
|
||||||
gmk_eval ("TESTLOAD = explicit", 0);
|
gmk_eval ("TESTLOAD = explicit", 0);
|
||||||
|
@ -28,7 +28,7 @@ char *getenv (const char*);
|
|||||||
|
|
||||||
int plugin_is_GPL_compatible;
|
int plugin_is_GPL_compatible;
|
||||||
|
|
||||||
int testapi_gmk_setup ();
|
int testapi_gmk_setup (unsigned int abi, const gmk_floc *floc);
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
test_eval (const char *buf)
|
test_eval (const char *buf)
|
||||||
@ -71,7 +71,7 @@ func_test (const char *funcname, unsigned int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
testapi_gmk_setup (const gmk_floc *floc)
|
testapi_gmk_setup (unsigned int abi, const gmk_floc *floc)
|
||||||
{
|
{
|
||||||
const char *verbose = getenv ("TESTAPI_VERBOSE");
|
const char *verbose = getenv ("TESTAPI_VERBOSE");
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user