Date: Sun, 6 Jan 2002 22:20:02 +0200 From: Peter Pentchev <roam@ringlet.net> To: arch@FreeBSD.org Cc: audit@FreeBSD.org Subject: Re: make(1) enhancement - an 'environment processor' option Message-ID: <20020106222002.E314@straylight.oblivion.bg> In-Reply-To: <20011225202925.F304@straylight.oblivion.bg>; from roam@ringlet.net on Tue, Dec 25, 2001 at 08:29:25PM %2B0200 References: <20011225202925.F304@straylight.oblivion.bg>
next in thread | previous in thread | raw e-mail | index | archive | help
Hi,
No feedback on this proposed change to make(1)? :)
If this means that there are no objections, I'm CC'ing this to -audit
to let the folks there take a look at it too. FWIW, I've been running
three machines with the -stable version of this patch since I posted it,
and builds of both the OS and ports all go just fine, using the appropriate
environment settings for the matched directories.
Or was the introduction a bit too long to read and review? :) If so,
one could safely skip the background and go to the explanations and
the patch itself :)
G'luck,
Peter
--
You have, of course, just begun reading the sentence that you have just finished reading.
On Tue, Dec 25, 2001 at 08:29:25PM +0200, Peter Pentchev wrote:
> Hi,
>
> <BACKGROUND STYLE="shameless plug">
> As some of you may have noticed, I maintain a little utility that
> keeps environment variables on a per-directory basis - the sysutils/penv
> port. Basically, what it does is remember what variables you want set
> for a specific directory and then hand them in the environment of any
> program you want to run. This may be quite useful for ports, especially
> those with lots of tweakable knobs, like vpopmail or MySQL, since it won't
> let you miss one of those knobs the next time you rebuild the port.
>
> However, there is one little problem with penv - it only sets
> the environment based on the data for the current directory. If a port
> has dependencies, and some of them also have knobs, you either have to
> set them for the port you want to build, or you have to build
> the dependency separately. For example, I want Ghostscript to build
> with an A4 output format, but then I want to build Ghostscript as part
> of the textproc/docproj build. If I set 'A4=yes' in the print/ghostscript-gnu
> directory and then I do a 'make' in the textproc/docproj directory,
> penv and make(1) will only pick up the textproc/docproj settings, and
> this A4=yes will be lost. If only there was a way to let make(1) read
> per-directory information for every single directory it recursed into..
> </BACKGROUND>
>
> Here is a little patch to make make(1) do just that - invoke an external
> 'environment processor', read its output and modify its own environment
> before doing anything else. This way, I can keep the A4=yes in the penv
> settings for the print/ghostscript-gnu directory and rest assured that
> a docproj build will pick it right up.
>
> This, incidentally, removes the need for the 'penv' invocation to be
> visible at all. Whereas before one had to run 'penv make all install',
> now all one has to do is run 'make all install', and make(1) will run
> penv all by itself.
>
> For those worried about the overhead of a program invocation, there is
> the MAKEENVDIR environment variable, which, if specified, is treated
> as an extended regular expression for the directory names to run
> the environment processor in. Thus, if MAKEENVDIR is set to something
> like, say, "^(/usr|/home/roam/fbsd)/ports/", then the environment
> processor will only be run in the Ports collection and not at all during
> a buildworld.
>
> Comments? Flames? Instant shootdowns? :)
>
> G'luck,
> Peter
>
> --
> .siht ekil ti gnidaer eb d'uoy ,werbeH ni erew ecnetnes siht fI
>
> Index: src/usr.bin/make/main.c
> ===================================================================
> RCS file: /home/ncvs/src/usr.bin/make/main.c,v
> retrieving revision 1.49
> diff -u -r1.49 main.c
> --- src/usr.bin/make/main.c 25 Apr 2001 14:44:41 -0000 1.49
> +++ src/usr.bin/make/main.c 25 Dec 2001 17:37:25 -0000
> @@ -88,6 +88,7 @@
> #include <stdlib.h>
> #include <errno.h>
> #include <fcntl.h>
> +#include <regex.h>
> #include <stdio.h>
> #include <sysexits.h>
> #ifdef __STDC__
> @@ -139,6 +140,8 @@
> static void MainParseArgs __P((int, char **));
> char * chdir_verify_path __P((char *, char *));
> static int ReadMakefile __P((void *, void *));
> +static void ReadEnvProc __P((const char *, const char *,
> + const char *));
> static void usage __P((void));
>
> static char *curdir; /* startup directory */
> @@ -428,6 +431,81 @@
> return 0;
> }
>
> +/*-
> + * ReadEnvProc --
> + * Read the output of an environment processor program and
> + * set or unset environment variables accordingly.
> + *
> + * Results:
> + * none
> + *
> + * Side effects:
> + * Executes the program specified by the envproc argument and
> + * sets or unsets environment variables according to the program output.
> + */
> +
> +static void
> +ReadEnvProc(const char *envproc, const char *envprocdir, const char *curdir) {
> + regex_t regdir;
> + int r;
> + char regerr[128];
> + FILE *envout;
> + char *s, *new;
> + size_t len;
> +
> + /* First check if the env processor needs to run at all here */
> + if ((envprocdir != NULL) && (envprocdir[0] != '\0')) {
> + memset(®dir, 0, sizeof(regdir));
> + r = regcomp(®dir, envprocdir, REG_EXTENDED | REG_NOSUB);
> + if (r != 0) {
> + regerror(r, ®dir, regerr, sizeof(regerr));
> + errx(1, "parsing regexp %s: %s", envprocdir, regerr);
> + }
> +
> + /* If curdir does not match, return w/o executing anything */
> + r = regexec(®dir, curdir, 0, NULL, 0);
> + if (r == REG_NOMATCH)
> + return;
> + if (r != 0) {
> + regerror(r, ®dir, regerr, sizeof(regerr));
> + errx(1, "matching regexp %s against %s: %s",
> + envprocdir, curdir, regerr);
> + }
> + }
> +
> + if ((envout = popen(envproc, "r")) == NULL)
> + err(1, "invoking environment processor '%s'", envproc);
> +
> + while ((s = fgetln(envout, &len)) != NULL) {
> + /* Null-terminate as needed */
> + if (s[len - 1] == '\n') {
> + s[len - 1] = '\0';
> + new = NULL;
> + } else {
> + if ((new = realloc(s, len + 1)) == NULL)
> + err(1, "reading env processor output");
> + memcpy(new, s, len);
> + new[len] = '\0';
> + s = new;
> + }
> +
> + /*
> + * A 'var=value' specification sets the variable, while
> + * a mere variable name unsets it.
> + */
> + if (strchr(s, '=') != NULL)
> + putenv(s);
> + else
> + unsetenv(s);
> +
> + if (new != NULL)
> + free(new);
> + }
> + if (ferror(envout))
> + err(1, "reading env processor output");
> +
> + pclose(envout);
> +}
>
> /*-
> * main --
> @@ -465,6 +543,8 @@
> char *cp = NULL, *start;
> /* avoid faults on read-only strings */
> static char syspath[] = _PATH_DEFSYSPATH;
> + char *envproc = getenv("MAKEENVPROC");
> + char *envprocdir = getenv("MAKEENVDIR");
>
> #if DEFSHELL == 2
> /*
> @@ -497,6 +577,12 @@
>
> if (stat(curdir, &sa) == -1)
> err(2, "%s", curdir);
> +
> + /*
> + * Look for an environment processor as early as possible
> + */
> + if ((envproc != NULL) && (envproc[0] != '\0'))
> + ReadEnvProc(envproc, envprocdir, curdir);
>
> #if defined(__i386__) && defined(__FreeBSD_version) && \
> __FreeBSD_version > 300003
> Index: src/usr.bin/make/make.1
> ===================================================================
> RCS file: /home/ncvs/src/usr.bin/make/make.1,v
> retrieving revision 1.48
> diff -u -r1.48 make.1
> --- src/usr.bin/make/make.1 10 Aug 2001 13:45:27 -0000 1.48
> +++ src/usr.bin/make/make.1 25 Dec 2001 17:40:39 -0000
> @@ -32,7 +32,7 @@
> .\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
> .\" $FreeBSD$
> .\"
> -.Dd March 19, 1994
> +.Dd December 25, 2001
> .Dt MAKE 1
> .Os
> .Sh NAME
> @@ -373,7 +373,9 @@
> .It Environment variables
> Variables defined as part of
> .Nm Ns 's
> -environment.
> +environment or in the output of the
> +.Ev MAKEENVPROC
> +program, if specified (see the ENVIRONMENT PROCESSORS section below).
> .It Global variables
> Variables defined in the makefile or in included makefiles.
> .It Command line variables
> @@ -716,6 +718,47 @@
> .It Cm U
> Converts variable to upper-case letters.
> .El
> +.Sh ENVIRONMENT PROCESSORS
> +External programs, called
> +.Dq environment processors ,
> +may provide
> +additional environment data before any Makefile parsing is done.
> +If the
> +.Ev MAKEENVPROC
> +environment variable is set before
> +.Nm
> +is invoked, it is interpreted as a command to obtain additional environment
> +variables from.
> +.Nm
> +executes the command using the
> +.Xr popen 3
> +function and examines each line of its output.
> +If the line contains a
> +.Sq =
> +character, it is treated as a
> +.Ar variable Ns No = Ns Ar value
> +assignment operator and
> +.Nm
> +sets the respective variable in its environment to the specified value.
> +If the line does not contain a
> +.Sq =
> +character, it is treated as the name of a variable to be removed from the
> +.Nm
> +environment.
> +.Pp
> +If the
> +.Ev MAKEENVDIR
> +environment variable is also set,
> +.Nm
> +treats it as an extended regular expression (see
> +.Xr re_format 7 )
> +and matches the current directory against it.
> +If there is no match, the environment processor is not executed at all.
> +This allows for running the processor only in certain directory trees, e.g.
> +.Pa /usr/ports ,
> +without the burden of the additional command execution when running
> +.Nm
> +in other directories.
> .Sh DIRECTIVES, CONDITIONALS, AND FOR LOOPS
> Directives, conditionals, and for loops reminiscent
> of the C programming language are provided in
> @@ -1174,6 +1217,8 @@
> uses the following environment variables, if they exist:
> .Ev MACHINE ,
> .Ev MAKE ,
> +.Ev MAKEENVDIR ,
> +.Ev MAKEENVPROC ,
> .Ev MAKEFLAGS ,
> .Ev MAKEOBJDIR ,
> and
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-arch" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020106222002.E314>
