From: Paul Smith Date: Sun, 30 May 2021 22:47:50 +0000 (-0400) Subject: [SV 60412] Allow -I- to throw out the current directory path X-Git-Tag: 4.3.90~165 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b9c4fc441b2d66312a592bf4eab67ef7fbe4c645;p=thirdparty%2Fmake.git [SV 60412] Allow -I- to throw out the current directory path Accept a "-" directory value to the -I option to clear the set of directories to be searched up to that point, including the default directories. * NEWS: Announce the change. * doc/make.texi (Summary of Options): Add documentation. * src/read.c (construct_include_path): Check for '-' and if found, clear the list of directories to be searched. * tests/scripts/options/dash-I: Add tests for -I-. * tests/scripts/variables/INCLUDE_DIRS: Add tests for -I-. --- diff --git a/NEWS b/NEWS index c45ef741..26a272e3 100644 --- a/NEWS +++ b/NEWS @@ -50,6 +50,10 @@ https://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=109&se user-defined function and they will not impact global variable assignments. Implementation provided by Jouke Witteveen +* The -I option accepts an argument "-" (e.g., "-I-") which means "reset the + list of search directories to empty". Among other things this can be used + to prevent GNU make from searching in its default list of directories. + * New debug option "print" will show the recipe to be run, even when silent mode is set, and new debug option "why" will show why a target is rebuilt (which prerequisites caused the target to be considered out of date). diff --git a/doc/make.texi b/doc/make.texi index db4d7e7a..411fb692 100644 --- a/doc/make.texi +++ b/doc/make.texi @@ -1281,6 +1281,16 @@ hierarchy.}) @file{/usr/gnu/include}, @file{/usr/local/include}, @file{/usr/include}. +The @code{.INCLUDE_DIRS} variable will contain the current list of +directories that make will search for included files. @xref{Special +Variables, ,Other Special Variables}. + +You can avoid searching in these default directories by adding the +command line option @code{-I} with the special value @code{-} (e.g., +@code{-I-}) to the command line. This will cause @code{make} to +forget any already-set include directories, including the default +directories. + If an included makefile cannot be found in any of these directories it is not an immediately fatal error; processing of the makefile containing the @code{include} continues. Once it has finished reading @@ -6676,6 +6686,8 @@ Supports dynamically loadable objects for creating custom extensions. @item .INCLUDE_DIRS Expands to a list of directories that @code{make} searches for included makefiles (@pxref{Include, , Including Other Makefiles}). +Note that modifying this variable's value does not change the list of +directories which are searched. @vindex .EXTRA_PREREQS @r{(prerequisites not added to automatic variables)} @item .EXTRA_PREREQS @@ -9058,7 +9070,11 @@ Ignore all errors in recipes executed to remake files. Specifies a directory @var{dir} to search for included makefiles. @xref{Include, ,Including Other Makefiles}. If several @samp{-I} options are used to specify several directories, the directories are -searched in the order specified. +searched in the order specified. If the directory @var{dir} is a +single dash (@code{-}) then any already-specified directories up to +that point (including the default directory paths) will be discarded. +You can examine the current list of directories to be searched via the +@code{.INCLUDE_DIRS} variable. @item -j [@var{jobs}] @cindex @code{-j} diff --git a/src/read.c b/src/read.c index 4b285c57..5cdb5139 100644 --- a/src/read.c +++ b/src/read.c @@ -2926,6 +2926,7 @@ construct_include_path (const char **arg_dirs) const char **dirs; const char **cpp; size_t idx; + int disable = 0; /* Compute the number of pointers we need in the table. */ idx = sizeof (default_include_directories) / sizeof (const char *); @@ -2944,7 +2945,8 @@ construct_include_path (const char **arg_dirs) max_incl_len = 0; /* First consider any dirs specified with -I switches. - Ignore any that don't exist. Remember the maximum string length. */ + Ignore any that don't exist. Restart if we find "-". + Remember the maximum string length. */ if (arg_dirs) while (*arg_dirs != 0) @@ -2953,6 +2955,14 @@ construct_include_path (const char **arg_dirs) char *expanded = 0; int e; + if (dir[0] == '-' && dir[1] == '\0') + { + disable = 1; + idx = 0; + max_incl_len = 0; + continue; + } + if (dir[0] == '~') { expanded = tilde_expand (dir); @@ -2976,41 +2986,40 @@ construct_include_path (const char **arg_dirs) } /* Now add the standard default dirs at the end. */ - + if (!disable) + { #ifdef __MSDOS__ - { - /* The environment variable $DJDIR holds the root of the DJGPP directory - tree; add ${DJDIR}/include. */ - struct variable *djdir = lookup_variable ("DJDIR", 5); - - if (djdir) - { - size_t len = strlen (djdir->value) + 8; - char *defdir = alloca (len + 1); + /* The environment variable $DJDIR holds the root of the DJGPP directory + tree; add ${DJDIR}/include. */ + struct variable *djdir = lookup_variable ("DJDIR", 5); - strcat (strcpy (defdir, djdir->value), "/include"); - dirs[idx++] = strcache_add (defdir); - - if (len > max_incl_len) - max_incl_len = len; - } - } -#endif + if (djdir) + { + size_t len = strlen (djdir->value) + 8; + char *defdir = alloca (len + 1); - for (cpp = default_include_directories; *cpp != 0; ++cpp) - { - int e; + strcat (strcpy (defdir, djdir->value), "/include"); + dirs[idx++] = strcache_add (defdir); - EINTRLOOP (e, stat (*cpp, &stbuf)); - if (e == 0 && S_ISDIR (stbuf.st_mode)) - { - size_t len = strlen (*cpp); - /* If dir name is written with trailing slashes, discard them. */ - while (len > 1 && (*cpp)[len - 1] == '/') - --len; if (len > max_incl_len) max_incl_len = len; - dirs[idx++] = strcache_add_len (*cpp, len); + } +#endif + for (cpp = default_include_directories; *cpp != 0; ++cpp) + { + int e; + + EINTRLOOP (e, stat (*cpp, &stbuf)); + if (e == 0 && S_ISDIR (stbuf.st_mode)) + { + size_t len = strlen (*cpp); + /* If dir name is written with trailing slashes, discard them. */ + while (len > 1 && (*cpp)[len - 1] == '/') + --len; + if (len > max_incl_len) + max_incl_len = len; + dirs[idx++] = strcache_add_len (*cpp, len); + } } } diff --git a/tests/scripts/options/dash-I b/tests/scripts/options/dash-I index 5d2df389..e4646014 100644 --- a/tests/scripts/options/dash-I +++ b/tests/scripts/options/dash-I @@ -1,6 +1,6 @@ # -*-perl-*- -$description ="The following test creates a makefile to test the -I option."; +$description = "The following test creates a makefile to test the -I option."; $details = "\ This test tests the -I option by including a filename in @@ -9,53 +9,108 @@ under -I in the command line. Without this option, the make would fail to find the included file. It also checks to make sure that the -I option gets passed to recursive makes."; -$makefile2 = &get_tmpfile; +use File::Spec; -open(MAKEFILE,"> $makefile"); +# Create a directory and put a makefile in it. +# We can't put it in the current directory since that's automatically searched +# anyway. +my $subdir = 'idir'; +mkdir($subdir, 0777); -# The Contents of the MAKEFILE ... - -$mf2 = substr ($makefile2, index ($makefile2, $pathsep) + 1); -print MAKEFILE < $makefile2"); - -print MAKEFILE <catfile($subdir, $included); +create_file($ipath, " ANOTHER: \t\@echo This is another included makefile recurse: -\t\$(MAKE) ANOTHER -f $makefile -EOF +\t\@\$(MAKE) ANOTHER -f \$(main_makefile)\n"); + +my $nosuch = "#MAKEFILE#:5: $included: $ERR_no_such_file +#MAKE#: *** No rule to make target '$included'. Stop.\n"; + -close(MAKEFILE); +# Verify that we get an error if we don't have -I +run_make_test(qq! +main_makefile := \$(firstword \$(MAKEFILE_LIST)) +all: +\t\@echo There should be no errors for this makefile +include $included +!, + '', $nosuch, 512); + +# Check basic -I works +run_make_test(undef, "-I $subdir all", + "There should be no errors for this makefile\n"); + +# Check that the included target works +run_make_test(undef, "-I $subdir ANOTHER", + "This is another included makefile\n"); + +# Check that -I is passed down through MAKEFLAGS +run_make_test(undef, "-I $subdir recurse", + "#MAKE#[1]: Entering directory '#PWD#' +This is another included makefile +#MAKE#[1]: Leaving directory '#PWD#'\n"); -&run_make_with_options($makefile,"-I $workdir all",&get_logfile); +# Verify that we get an error if we add -I- to delete previous includes +run_make_test(undef, "-I $subdir -I- all", $nosuch, 512); -# Create the answer to what should be produced by this Makefile -$answer = "There should be no errors for this makefile.\n"; -&compare_output($answer,&get_logfile(1)); +# Make another directory with the same name and make sure the right one is +# chosen if -I- stops the path. +mkdir('idir2', 0777); +my $ipath2 = File::Spec->catfile('idir2', $included); +create_file($ipath2, "This is a bad makefile!!\n"); -$answer = "This is another included makefile\n"; -&run_make_with_options($makefile,"-I $workdir ANOTHER",&get_logfile); -&compare_output($answer,&get_logfile(1)); +run_make_test(undef, "-I idir2 -I $subdir ANOTHER", + "$included:1: *** missing separator. Stop.\n", 512); +run_make_test(undef, "-I idir2 -I - -I $subdir ANOTHER", + "This is another included makefile\n"); -$answer = subst_make_string("$mkpath ANOTHER -f $makefile -#MAKE#[1]: Entering directory '#PWD#' +# Check that -I- is passed down through MAKEFLAGS +run_make_test(undef, "-I idir2 -I - -I $subdir recurse", + "#MAKE#[1]: Entering directory '#PWD#' This is another included makefile #MAKE#[1]: Leaving directory '#PWD#'\n"); -&run_make_with_options($makefile,"-I $workdir recurse",&get_logfile); -&compare_output($answer,&get_logfile(1)); +unlink($ipath2); +rmdir('idir2'); + +# The only way to check if -I- voids included directories is to see if a file +# exists in one and try to include it. We very likely can't add our own files +# to the default directories since they're probably write-protected. This +# won't work if none of the default directories contain any files :-/ + +create_file('defaultdirs.mk', "\$(info \$(.INCLUDE_DIRS))\nall:;\@:\n"); +my $cmd = subst_make_string("#MAKEPATH# -f defaultdirs.mk"); +my @dirs = `$cmd`; +my $dirs = $dirs[0]; +chomp $dirs; +unlink('defaultdirs.mk'); + +my $fn = undef; +foreach my $dn (split ' ', $dirs) { + # On Windows the default is "." which is bogus! + if ($dn != '.') { + my @files = glob(File::Spec->catfile($dn, "*")); + if (@files) { + (undef, undef, $fn) = File::Spec->splitpath($files[0]); + last; + } + } +} + +if ($fn) { + run_make_test(" +all:; +include $fn +", + '-I-', "#MAKEFILE#:3: $fn: $ERR_no_such_file +#MAKE#: *** No rule to make target '$fn'. Stop.\n", 512); +} + +unlink($ipath); +rmdir($subdir); 1; diff --git a/tests/scripts/variables/INCLUDE_DIRS b/tests/scripts/variables/INCLUDE_DIRS index c9662e94..e00b06ee 100644 --- a/tests/scripts/variables/INCLUDE_DIRS +++ b/tests/scripts/variables/INCLUDE_DIRS @@ -20,8 +20,7 @@ endif .PHONY: all all:;@: ', -'', -''); + '', ''); # Test #2: Make sure -I paths end up in .INCLUDE_DIRS. @@ -38,9 +37,56 @@ endif .PHONY: all all:;@: ', -"-I$dir dir=$dir", -''); + "-I$dir dir=$dir", ''); +# Find the default .INCLUDE_DIRS +create_file('defaultdirs.mk', "\$(info \$(.INCLUDE_DIRS))\nall:;\@:\n"); +my $cmd = subst_make_string("#MAKEPATH# -f defaultdirs.mk"); +my @dirs = `$cmd`; +my $dirs = $dirs[0]; +chomp $dirs; +unlink('defaultdirs.mk'); + +run_make_test(" +ifneq (\$(.INCLUDE_DIRS),$dirs) +\$(warning Mismatched \$(.INCLUDE_DIRS) != $dirs) +endif +all:;\@: +", + '', ''); + +# Verify that -I- disables content from .INCLUDE_DIRS + +run_make_test(" +ifneq (\$(.INCLUDE_DIRS),) +\$(warning Mismatched \$(.INCLUDE_DIRS) != ) +endif +all:;\@: +", + '-I-', ''); + +# Prefix -I dirs to the front +mkdir('somedir', 0777); + +run_make_test(" +ifneq (\$(.INCLUDE_DIRS),somedir $dirs) +\$(warning Mismatched \$(.INCLUDE_DIRS) != somedir $dirs) +endif +all:;\@: +", + '-I somedir', ''); + +# Verify .INCLUDE_DIRS contains files after -I- + +run_make_test(" +ifneq (\$(.INCLUDE_DIRS),somedir) +\$(warning Mismatched \$(.INCLUDE_DIRS) != somedir) +endif +all:;\@: +", + '-I - -I somedir', ''); + +rmdir('somedir'); # This tells the test driver that the perl test script executed properly. 1;