diff options
author | Paul Smith <psmith@gnu.org> | 2013-05-04 17:38:53 -0400 |
---|---|---|
committer | Paul Smith <psmith@gnu.org> | 2013-05-04 17:38:53 -0400 |
commit | 3484c9675a8a09904e08e00bf6842d834cd0201d (patch) | |
tree | ac9c0c1179e567213ed25f3161b64fc0254e24c7 | |
parent | a0c5d0c63f6801ca16865d04faa223cea440d2c0 (diff) | |
download | gunmake-3484c9675a8a09904e08e00bf6842d834cd0201d.tar.gz |
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.
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | doc/make.texi | 121 | ||||
-rw-r--r-- | gnumake.h | 20 | ||||
-rw-r--r-- | loadapi.c | 16 | ||||
-rw-r--r-- | makeint.h | 7 | ||||
-rw-r--r-- | tests/ChangeLog | 2 | ||||
-rw-r--r-- | tests/scripts/features/loadapi | 6 |
7 files changed, 159 insertions, 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. diff --git a/doc/make.texi b/doc/make.texi index 3a11ffd..ea58d6e 100644 --- a/doc/make.texi +++ b/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} @@ -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_ */ @@ -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 diff --git a/tests/ChangeLog b/tests/ChangeLog index 991e96f..ade64f0 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -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. diff --git a/tests/scripts/features/loadapi b/tests/scripts/features/loadapi index cecb114..94a48a7 100644 --- a/tests/scripts/features/loadapi +++ b/tests/scripts/features/loadapi @@ -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 |