summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Smith <psmith@gnu.org>2013-05-04 17:38:53 -0400
committerPaul Smith <psmith@gnu.org>2013-05-04 17:38:53 -0400
commit3e67695034a1e235cbcf2c70d283fe0cd6c77427 (patch)
treeac9c0c1179e567213ed25f3161b64fc0254e24c7
parent54eddcc711207137cbace67d1f922a7690bb90e8 (diff)
downloadmake-3e67695034a1e235cbcf2c70d283fe0cd6c77427.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--ChangeLog7
-rw-r--r--doc/make.texi121
-rw-r--r--gnumake.h20
-rw-r--r--loadapi.c16
-rw-r--r--makeint.h7
-rw-r--r--tests/ChangeLog2
-rw-r--r--tests/scripts/features/loadapi6
7 files changed, 159 insertions, 20 deletions
diff --git a/ChangeLog b/ChangeLog
index ea207538..9f30bf78 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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 3a11ffd4..ea58d6e7 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}
diff --git a/gnumake.h b/gnumake.h
index a6308fe0..168f3708 100644
--- a/gnumake.h
+++ b/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_ */
diff --git a/loadapi.c b/loadapi.c
index d79c41c6..e314390b 100644
--- a/loadapi.c
+++ b/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)
{
diff --git a/makeint.h b/makeint.h
index 9f0d1b81..6cce8484 100644
--- a/makeint.h
+++ b/makeint.h
@@ -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 991e96f4..ade64f0b 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 cecb114f..94a48a71 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