Skip site navigation (1)Skip section navigation (2)
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(&regdir, 0, sizeof(regdir));
> +		r = regcomp(&regdir, envprocdir, REG_EXTENDED | REG_NOSUB);
> +		if (r != 0) {
> +			regerror(r, &regdir, regerr, sizeof(regerr));
> +			errx(1, "parsing regexp %s: %s", envprocdir, regerr);
> +		}
> +
> +		/* If curdir does not match, return w/o executing anything */
> +		r = regexec(&regdir, curdir, 0, NULL, 0);
> +		if (r == REG_NOMATCH)
> +			return;
> +		if (r != 0) {
> +			regerror(r, &regdir, 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-audit" 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>