mirror of
https://salsa.debian.org/srivasta/make-dfsg.git
synced 2024-12-26 14:00:56 +00: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
7 changed files with 159 additions and 20 deletions
|
@ -1,5 +1,12 @@
|
|||
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
|
||||
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.
|
||||
* Remaking Loaded Objects:: How loaded objects get remade.
|
||||
* Loaded Object API:: Programmatic interface for loaded objects.
|
||||
* Loaded Object Example:: Example of a loaded object
|
||||
|
||||
@end detailmenu
|
||||
@end menu
|
||||
|
@ -10892,6 +10893,7 @@ for example, and the ``setup'' function would register them with GNU
|
|||
* load Directive:: Loading dynamic objects as extensions.
|
||||
* Remaking Loaded Objects:: How loaded objects get remade.
|
||||
* Loaded Object API:: Programmatic interface for loaded objects.
|
||||
* Loaded Object Example:: Example of a loaded object
|
||||
@end menu
|
||||
|
||||
@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
|
||||
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
|
||||
@cindex loaded object API
|
||||
@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
|
||||
@code{make}. This interaction includes both interfaces the loaded
|
||||
object provides to makefiles and also interfaces the loaded object can
|
||||
use to manipulate @code{make}'s operation.
|
||||
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
|
||||
@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
|
||||
within its setup function. The implementations of these @code{make}
|
||||
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
|
||||
|
||||
|
@ -11033,6 +11036,7 @@ where the definition occurred if necessary.
|
|||
@end table
|
||||
|
||||
@subsubheading Registering Functions
|
||||
@findex gmk_add_function
|
||||
|
||||
There is currently one way for makefiles to invoke operations provided
|
||||
by the loaded object: through the @code{make} function call
|
||||
|
@ -11087,15 +11091,18 @@ works with.
|
|||
|
||||
@table @code
|
||||
@item gmk_expand
|
||||
@findex gmk_expand
|
||||
This function takes a string and expands it using @code{make}
|
||||
expansion rules. The result of the expansion is returned in a string
|
||||
that has been allocated using @code{malloc}. The caller is
|
||||
responsible for calling @code{free} on the string when done.
|
||||
expansion rules. The result of the expansion is returned in a
|
||||
nil-terminated string buffer. The caller is responsible for calling
|
||||
@code{gmk_free} with a pointer to the returned buffer when done.
|
||||
|
||||
@item gmk_eval
|
||||
@findex gmk_eval
|
||||
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,
|
||||
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
|
||||
@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_eval} the buffer is only expanded once, at most (as it's
|
||||
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
|
||||
|
||||
@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
|
||||
@chapter Features of GNU @code{make}
|
||||
@cindex features of GNU @code{make}
|
||||
|
|
20
gnumake.h
20
gnumake.h
|
@ -26,22 +26,26 @@ typedef struct
|
|||
unsigned long lineno;
|
||||
} gmk_floc;
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef MAIN
|
||||
# define GMK_EXPORT __declspec(dllexport)
|
||||
# else
|
||||
# ifndef GMK_EXPORT
|
||||
# define GMK_EXPORT __declspec(dllimport)
|
||||
# endif
|
||||
#else
|
||||
# define GMK_EXPORT
|
||||
#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. */
|
||||
void GMK_EXPORT gmk_eval (const char *buffer, const gmk_floc *floc);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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 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.
|
||||
MAX_ARGS is the maximum number of arguments (or 0 if there's no maximum).
|
||||
|
@ -60,8 +64,8 @@ char * GMK_EXPORT gmk_expand (const char *str);
|
|||
before FUNC is called. If EXPAND_ARGS is non-0, they will be expanded.
|
||||
*/
|
||||
void GMK_EXPORT gmk_add_function (const char *name,
|
||||
char *(*func)(const char *nm,
|
||||
int argc, char **argv),
|
||||
int min_args, int max_args, int expand_args);
|
||||
char *(*func)(const char *nm,
|
||||
int argc, char **argv),
|
||||
int min_args, int max_args, int expand_args);
|
||||
|
||||
#endif /* _GNUMAKE_H_ */
|
||||
|
|
16
loadapi.c
16
loadapi.c
|
@ -20,6 +20,20 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
|||
#include "variable.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.
|
||||
Ideally eval_buffer() will take const char *, but not yet. */
|
||||
void
|
||||
|
@ -31,7 +45,7 @@ gmk_eval (const char *buffer, const gmk_floc *floc)
|
|||
}
|
||||
|
||||
/* Expand a string and return an allocated buffer.
|
||||
Caller must free() this buffer. */
|
||||
Caller must call gmk_free() with this buffer. */
|
||||
char *
|
||||
gmk_expand (const char *ref)
|
||||
{
|
||||
|
|
|
@ -49,11 +49,12 @@ char *alloca ();
|
|||
|
||||
/* Include the externally-visible content.
|
||||
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. */
|
||||
#define MAIN
|
||||
#ifdef WINDOWS32
|
||||
# define GMK_EXPORT __declspec(dllexport)
|
||||
#endif
|
||||
#include "gnumake.h"
|
||||
#undef MAIN
|
||||
|
||||
#ifdef CRAY
|
||||
/* This must happen before #include <signal.h> so
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
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
|
||||
ordered recursive output for -Ojob / -Otarget.
|
||||
|
||||
|
|
|
@ -36,13 +36,17 @@ test_expand (const char *val)
|
|||
static char *
|
||||
func_test (const char *funcname, int argc, char **argv)
|
||||
{
|
||||
char *mem;
|
||||
|
||||
if (strcmp (funcname, "test-expand") == 0)
|
||||
return test_expand (argv[0]);
|
||||
|
||||
if (strcmp (funcname, "test-eval") == 0)
|
||||
return test_eval (argv[0]);
|
||||
|
||||
return strdup ("unknown");
|
||||
mem = gmk_alloc (strlen ("unknown") + 1);
|
||||
strcpy (mem, "unknown");
|
||||
return mem;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
Loading…
Reference in a new issue