mirror of
https://github.com/mirror/make.git
synced 2025-03-28 04:50:10 +08:00
Add memory allocation cleanup to loadable objects.
Add gmk_alloc() and gmk_free() functions so loadable objects can access our memory model. Also provide a more extensive example in the manual.
This commit is contained in:
parent
a0c5d0c63f
commit
3484c9675a
@ -1,5 +1,12 @@
|
|||||||
2013-05-04 Paul Smith <psmith@gnu.org>
|
2013-05-04 Paul Smith <psmith@gnu.org>
|
||||||
|
|
||||||
|
* loadapi.c (gmk_alloc): New function.
|
||||||
|
* gnumake.h: Add gmk_alloc(). Clean GMK_EXPORT a bit to avoid MAIN.
|
||||||
|
* makeint.h (GMK_EXPORT): New handling, vs. MAIN.
|
||||||
|
* doc/make.texi (Loaded Object API): Add information on the memory
|
||||||
|
handling functions.
|
||||||
|
(Loaded Object Example): Create an example.
|
||||||
|
|
||||||
* job.c (pump_from_tmp): (Rename) Write to stdout/stderr using
|
* job.c (pump_from_tmp): (Rename) Write to stdout/stderr using
|
||||||
FILE* rather than fd. It's not a good idea to mix and match.
|
FILE* rather than fd. It's not a good idea to mix and match.
|
||||||
|
|
||||||
|
121
doc/make.texi
121
doc/make.texi
@ -354,6 +354,7 @@ Loading Dynamic Objects
|
|||||||
* load Directive:: Loading dynamic objects as extensions.
|
* load Directive:: Loading dynamic objects as extensions.
|
||||||
* Remaking Loaded Objects:: How loaded objects get remade.
|
* 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
|
||||||
|
|
||||||
@end detailmenu
|
@end detailmenu
|
||||||
@end menu
|
@end menu
|
||||||
@ -10892,6 +10893,7 @@ for example, and the ``setup'' function would register them with GNU
|
|||||||
* load Directive:: Loading dynamic objects as extensions.
|
* load Directive:: Loading dynamic objects as extensions.
|
||||||
* 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
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@node load Directive, Remaking Loaded Objects, Loading Objects, Loading Objects
|
@node load Directive, Remaking Loaded Objects, Loading Objects, Loading Objects
|
||||||
@ -10992,7 +10994,7 @@ support this.@refill
|
|||||||
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 loaded object.
|
rebuilding the loaded object.
|
||||||
|
|
||||||
@node Loaded Object API, , 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
|
||||||
@ -11009,8 +11011,8 @@ implementations in future versions of GNU @code{make}.
|
|||||||
|
|
||||||
To be useful, loaded objects must be able to interact with GNU
|
To be useful, loaded objects must be able to interact with GNU
|
||||||
@code{make}. This interaction includes both interfaces the loaded
|
@code{make}. This interaction includes both interfaces the loaded
|
||||||
object provides to makefiles and also interfaces the loaded object can
|
object provides to makefiles and also interfaces @code{make} provides
|
||||||
use to manipulate @code{make}'s operation.
|
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
|
||||||
@ -11021,7 +11023,8 @@ Typically, a loaded object will register one or more new GNU
|
|||||||
@code{make} functions using the @code{gmk_add_function} routine from
|
@code{make} functions using the @code{gmk_add_function} routine from
|
||||||
within its setup function. The implementations of these @code{make}
|
within its setup function. The implementations of these @code{make}
|
||||||
functions may make use of the @code{gmk_expand} and @code{gmk_eval}
|
functions may make use of the @code{gmk_expand} and @code{gmk_eval}
|
||||||
routines to perform their tasks.
|
routines to perform their tasks, then optionally return a string as
|
||||||
|
the result of the function expansion.
|
||||||
|
|
||||||
@subsubheading Data Structures
|
@subsubheading Data Structures
|
||||||
|
|
||||||
@ -11033,6 +11036,7 @@ where the definition occurred if necessary.
|
|||||||
@end table
|
@end table
|
||||||
|
|
||||||
@subsubheading Registering Functions
|
@subsubheading Registering Functions
|
||||||
|
@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 loaded object: through the @code{make} function call
|
by the loaded object: through the @code{make} function call
|
||||||
@ -11087,15 +11091,18 @@ works with.
|
|||||||
|
|
||||||
@table @code
|
@table @code
|
||||||
@item gmk_expand
|
@item 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. The result of the expansion is returned in a string
|
expansion rules. The result of the expansion is returned in a
|
||||||
that has been allocated using @code{malloc}. The caller is
|
nil-terminated string buffer. The caller is responsible for calling
|
||||||
responsible for calling @code{free} on the string when done.
|
@code{gmk_free} with a pointer to the returned buffer when done.
|
||||||
|
|
||||||
@item gmk_eval
|
@item 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. This function can be used to define new variables, new rules,
|
syntax. This function can be used to define new variables, new rules,
|
||||||
etc. It is equivalent to using the @code{eval} @code{make} function.
|
etc. It is equivalent to using the @code{eval} @code{make} function.
|
||||||
|
@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
|
||||||
@ -11103,8 +11110,108 @@ the latter case the string will be expanded @emph{twice}; once by
|
|||||||
@code{gmk_expand} and then again by the @code{eval} function. Using
|
@code{gmk_expand} and then again by the @code{eval} function. Using
|
||||||
@code{gmk_eval} the buffer is only expanded once, at most (as it's
|
@code{gmk_eval} the buffer is only expanded once, at most (as it's
|
||||||
read by the @code{make} parser).
|
read by the @code{make} parser).
|
||||||
|
|
||||||
|
@subsubheading Memory Management
|
||||||
|
|
||||||
|
Some systems allow for different memory management schemes. Thus you
|
||||||
|
should never pass memory that you've allocated directly to any
|
||||||
|
@code{make} function, nor should you attempt to directly free any
|
||||||
|
memory returned to you by any @code{make} function. Instead, use the
|
||||||
|
@code{gmk_alloc} and @code{gmk_free} functions.
|
||||||
|
|
||||||
|
@table @code
|
||||||
|
@item gmk_alloc
|
||||||
|
@findex gmk_alloc
|
||||||
|
Return a pointer to a newly-allocated buffer. This function will
|
||||||
|
always return a valid pointer; if not enough memory is available
|
||||||
|
@code{make} will exit.
|
||||||
|
|
||||||
|
@item gmk_free
|
||||||
|
@findex gmk_free
|
||||||
|
Free a buffer returned to you by @code{make}. Once the
|
||||||
|
@code{gmk_free} function returns the string will no longer be valid.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
|
@node Loaded Object Example, , Loaded Object API, Loading Objects
|
||||||
|
@subsection Example Loaded Object
|
||||||
|
@cindex loaded object example
|
||||||
|
@cindex example of loaded objects
|
||||||
|
|
||||||
|
Let's suppose we wanted to write a new GNU @code{make} function that
|
||||||
|
would create a temporary file and return its name. We would like our
|
||||||
|
function to take a prefix as an argument. First we can write the
|
||||||
|
function in a file @file{mk_temp.c}:
|
||||||
|
|
||||||
|
@example
|
||||||
|
@group
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <gnumake.h>
|
||||||
|
|
||||||
|
char *
|
||||||
|
gen_tmpfile(const char *nm, int argc, char **argv)
|
||||||
|
@{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
/* Compute the size of the filename and allocate space for it. */
|
||||||
|
int len = strlen (argv[0]) + 6 + 1;
|
||||||
|
char *buf = gmk_alloc (len);
|
||||||
|
|
||||||
|
strcpy (buf, argv[0]);
|
||||||
|
strcat (buf, "XXXXXX");
|
||||||
|
|
||||||
|
fd = mkstemp(buf);
|
||||||
|
if (fd >= 0)
|
||||||
|
@{
|
||||||
|
/* Don't leak the file descriptor. */
|
||||||
|
close (fd);
|
||||||
|
return buf;
|
||||||
|
@}
|
||||||
|
|
||||||
|
/* Failure. */
|
||||||
|
fprintf (stderr, "mkstemp(%s) failed: %s\n", buf, strerror (errno));
|
||||||
|
gmk_free (buf);
|
||||||
|
return NULL;
|
||||||
|
@}
|
||||||
|
|
||||||
|
int
|
||||||
|
mk_temp_gmk_setup ()
|
||||||
|
@{
|
||||||
|
/* Register the function with make name "mk-temp". */
|
||||||
|
gmk_add_function ("mk-temp", gen_tmpfile, 1, 1, 1);
|
||||||
|
return 1;
|
||||||
|
@}
|
||||||
|
@end group
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Next, we will write a makefile that can build this shared object, load
|
||||||
|
it, and use it:
|
||||||
|
|
||||||
|
@example
|
||||||
|
@group
|
||||||
|
all:
|
||||||
|
@@echo Temporary file: $(mk-temp tmpfile.)
|
||||||
|
|
||||||
|
load mk_temp.so
|
||||||
|
|
||||||
|
mk_temp.so: mk_temp.c
|
||||||
|
$(CC) -shared -fPIC -o $@ $<
|
||||||
|
@end group
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Now when you run @code{make} you'll see something like:
|
||||||
|
|
||||||
|
@example
|
||||||
|
$ make
|
||||||
|
cc -shared -fPIC -o mk_temp.so mk_temp.c
|
||||||
|
Temporary filename: tmpfile.A7JEwd
|
||||||
|
@end example
|
||||||
|
|
||||||
@node Features, Missing, Extending make, Top
|
@node Features, Missing, Extending make, Top
|
||||||
@chapter Features of GNU @code{make}
|
@chapter Features of GNU @code{make}
|
||||||
@cindex features of GNU @code{make}
|
@cindex features of GNU @code{make}
|
||||||
|
14
gnumake.h
14
gnumake.h
@ -26,22 +26,26 @@ typedef struct
|
|||||||
unsigned long lineno;
|
unsigned long lineno;
|
||||||
} gmk_floc;
|
} gmk_floc;
|
||||||
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# ifdef MAIN
|
# ifndef GMK_EXPORT
|
||||||
# define GMK_EXPORT __declspec(dllexport)
|
|
||||||
# else
|
|
||||||
# define GMK_EXPORT __declspec(dllimport)
|
# define GMK_EXPORT __declspec(dllimport)
|
||||||
# endif
|
# endif
|
||||||
#else
|
#else
|
||||||
# define GMK_EXPORT
|
# define GMK_EXPORT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Free memory returned by the gmk_expand() function. */
|
||||||
|
void GMK_EXPORT gmk_free (char *str);
|
||||||
|
|
||||||
|
/* Allocate memory in GNU make's context. */
|
||||||
|
char * GMK_EXPORT gmk_alloc (unsigned int len);
|
||||||
|
|
||||||
/* Run $(eval ...) on the provided string BUFFER. */
|
/* Run $(eval ...) on the provided string BUFFER. */
|
||||||
void GMK_EXPORT gmk_eval (const char *buffer, const gmk_floc *floc);
|
void GMK_EXPORT gmk_eval (const char *buffer, const gmk_floc *floc);
|
||||||
|
|
||||||
/* Run GNU make expansion on the provided string STR.
|
/* Run GNU make expansion on the provided string STR.
|
||||||
Returns an allocated buffer that the caller must free. */
|
Returns an allocated buffer that the caller must free with gmk_free(). */
|
||||||
char * GMK_EXPORT gmk_expand (const char *str);
|
char * GMK_EXPORT gmk_expand (const char *str);
|
||||||
|
|
||||||
/* Register a new GNU make function NAME (maximum of 255 chars long).
|
/* Register a new GNU make function NAME (maximum of 255 chars long).
|
||||||
@ -50,7 +54,7 @@ char * GMK_EXPORT gmk_expand (const char *str);
|
|||||||
|
|
||||||
The return value of FUNC must be either NULL, in which case it expands to
|
The return value of FUNC must be either NULL, in which case it expands to
|
||||||
the empty string, or a pointer to the result of the expansion in a string
|
the empty string, or a pointer to the result of the expansion in a string
|
||||||
created by malloc(). GNU make will free() the memory when it's done.
|
created by gmk_alloc(). GNU make will free the memory when it's done.
|
||||||
|
|
||||||
MIN_ARGS is the minimum number of arguments the function requires.
|
MIN_ARGS is the minimum number of arguments the function requires.
|
||||||
MAX_ARGS is the maximum number of arguments (or 0 if there's no maximum).
|
MAX_ARGS is the maximum number of arguments (or 0 if there's no maximum).
|
||||||
|
16
loadapi.c
16
loadapi.c
@ -20,6 +20,20 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
|||||||
#include "variable.h"
|
#include "variable.h"
|
||||||
#include "dep.h"
|
#include "dep.h"
|
||||||
|
|
||||||
|
/* Allocate a buffer in our context, so we can free it. */
|
||||||
|
char *
|
||||||
|
gmk_alloc (unsigned int len)
|
||||||
|
{
|
||||||
|
return xmalloc (len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free a buffer returned by gmk_expand(). */
|
||||||
|
void
|
||||||
|
gmk_free (char *s)
|
||||||
|
{
|
||||||
|
free (s);
|
||||||
|
}
|
||||||
|
|
||||||
/* Evaluate a buffer as make syntax.
|
/* Evaluate a buffer as make syntax.
|
||||||
Ideally eval_buffer() will take const char *, but not yet. */
|
Ideally eval_buffer() will take const char *, but not yet. */
|
||||||
void
|
void
|
||||||
@ -31,7 +45,7 @@ gmk_eval (const char *buffer, const gmk_floc *floc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Expand a string and return an allocated buffer.
|
/* Expand a string and return an allocated buffer.
|
||||||
Caller must free() this buffer. */
|
Caller must call gmk_free() with this buffer. */
|
||||||
char *
|
char *
|
||||||
gmk_expand (const char *ref)
|
gmk_expand (const char *ref)
|
||||||
{
|
{
|
||||||
|
@ -49,11 +49,12 @@ char *alloca ();
|
|||||||
|
|
||||||
/* Include the externally-visible content.
|
/* Include the externally-visible content.
|
||||||
Be sure to use the local one, and not one installed on the system.
|
Be sure to use the local one, and not one installed on the system.
|
||||||
Define MAIN for proper selection of dllexport/dllimport declarations
|
Define GMK_EXPORT for proper selection of dllexport/dllimport declarations
|
||||||
for MS-Windows. */
|
for MS-Windows. */
|
||||||
#define MAIN
|
#ifdef WINDOWS32
|
||||||
|
# define GMK_EXPORT __declspec(dllexport)
|
||||||
|
#endif
|
||||||
#include "gnumake.h"
|
#include "gnumake.h"
|
||||||
#undef MAIN
|
|
||||||
|
|
||||||
#ifdef CRAY
|
#ifdef CRAY
|
||||||
/* This must happen before #include <signal.h> so
|
/* This must happen before #include <signal.h> so
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
2013-05-04 Paul Smith <psmith@gnu.org>
|
2013-05-04 Paul Smith <psmith@gnu.org>
|
||||||
|
|
||||||
|
* scripts/features/loadapi: Use the new alloc functions.
|
||||||
|
|
||||||
* scripts/features/output-sync (output_sync_set): New test for
|
* scripts/features/output-sync (output_sync_set): New test for
|
||||||
ordered recursive output for -Ojob / -Otarget.
|
ordered recursive output for -Ojob / -Otarget.
|
||||||
|
|
||||||
|
@ -36,13 +36,17 @@ test_expand (const char *val)
|
|||||||
static char *
|
static char *
|
||||||
func_test (const char *funcname, int argc, char **argv)
|
func_test (const char *funcname, int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
char *mem;
|
||||||
|
|
||||||
if (strcmp (funcname, "test-expand") == 0)
|
if (strcmp (funcname, "test-expand") == 0)
|
||||||
return test_expand (argv[0]);
|
return test_expand (argv[0]);
|
||||||
|
|
||||||
if (strcmp (funcname, "test-eval") == 0)
|
if (strcmp (funcname, "test-eval") == 0)
|
||||||
return test_eval (argv[0]);
|
return test_eval (argv[0]);
|
||||||
|
|
||||||
return strdup ("unknown");
|
mem = gmk_alloc (strlen ("unknown") + 1);
|
||||||
|
strcpy (mem, "unknown");
|
||||||
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
Loading…
Reference in New Issue
Block a user