From ccb397197360d6aa1b310b66ebf35575c4f6e2c7 Mon Sep 17 00:00:00 2001 From: bosk Date: Thu, 12 Nov 2009 16:42:36 +0000 Subject: [PATCH] Implement linker-compatible library search. --- ChangeLog | 20 +++++++++ NEWS | 9 ++++ doc/make.texi | 13 +++--- implicit.c | 2 +- make.h | 3 +- remake.c | 101 ++++++++++++++++++++++++++++-------------- tests/ChangeLog | 5 +++ tests/scripts/features/vpath3 | 50 +++++++++++++++++++++ vpath.c | 45 ++++++++++++++----- 9 files changed, 194 insertions(+), 54 deletions(-) create mode 100644 tests/scripts/features/vpath3 diff --git a/ChangeLog b/ChangeLog index 8ee33c4..e8c89d1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2009-11-12 Boris Kolpackov + + * vpath.c (vpath_search, selective_vpath_search): Add index arguments + which allows the caller to get the index of the matching directory. + + * make.h (vpath_search): Update prototype. + + * remake.c (library_search): Implement linker-compatible library + search. Use the new VPATH_SEARCH index functionality to keep track + of the directory index for each match. Select the match with the + lowest directory index. + + * implicit.c (pattern_search): Pass NULL for the index arguments in + the VPATH_SEARCH call. + + * doc/make.texi (Directory Search for Link Libraries): Describe the + new search behavior. + + * NEWS: Add a note about the new behavior. + 2009-10-25 Paul Smith * AUTHORS, et.al.: Update copyright years. diff --git a/NEWS b/NEWS index 661f87b..f452686 100644 --- a/NEWS +++ b/NEWS @@ -37,6 +37,15 @@ Version 3.81.90 patterns are preferred. To detect this feature search for 'shortest-stem' in the .FEATURES special variable. +* WARNING: Backward-incompatibility! + The library search behavior has changed to be compatible with the standard + linker behavior. Prior to this version for prerequisites specified using + the -lfoo syntax make fist searched for libfoo.so in the current directory, + vpath directories, and system directories. If that didn't yield a match, + make then searched for libfoo.a in these directories. Starting with this + version make searches first for libfoo.so and then for libfoo.a in each + of these directories in order. + * New command line option: --eval=STRING causes STRING to be evaluated as makefile syntax (akin to using the $(eval ...) function). The evaluation is performed after all default rules and variables are defined, but before any diff --git a/doc/make.texi b/doc/make.texi index ddf2c42..03212d5 100644 --- a/doc/make.texi +++ b/doc/make.texi @@ -4,7 +4,7 @@ @include version.texi @set EDITION 0.70 -@set RCSID $Id: make.texi,v 1.63 2009/10/25 00:46:52 psmith Exp $ +@set RCSID $Id: make.texi,v 1.64 2009/11/12 16:42:36 bosk Exp $ @settitle GNU @code{make} @setchapternewpage odd @@ -2425,17 +2425,15 @@ file, and the @emph{file name} of a library generally looks like @file{lib@var{name}.a}, not like @samp{-l@var{name}}.)@refill When a prerequisite's name has the form @samp{-l@var{name}}, @code{make} -handles it specially by searching for the file @file{lib@var{name}.so} in -the current directory, in directories specified by matching @code{vpath} +handles it specially by searching for the file @file{lib@var{name}.so}, +and, if it is not found, for the file @file{lib@var{name}.a} in the current +directory, in directories specified by matching @code{vpath} search paths and the @code{VPATH} search path, and then in the directories @file{/lib}, @file{/usr/lib}, and @file{@var{prefix}/lib} (normally @file{/usr/local/lib}, but MS-DOS/MS-Windows versions of @code{make} behave as if @var{prefix} is defined to be the root of the DJGPP installation tree). -If that file is not found, then the file @file{lib@var{name}.a} is -searched for, in the same directories as above. - For example, if there is a @file{/usr/lib/libcurses.a} library on your system (and no @file{/usr/lib/libcurses.so} file), then @@ -2457,8 +2455,7 @@ via the @code{.LIBPATTERNS} variable. Each word in the value of this variable is a pattern string. When a prerequisite like @samp{-l@var{name}} is seen, @code{make} will replace the percent in each pattern in the list with @var{name} and perform the above directory -searches using that library filename. If no library is found, the next -word in the list will be used. +searches using each library filename. The default value for @code{.LIBPATTERNS} is @samp{lib%.so lib%.a}, which provides the default behavior described above. diff --git a/implicit.c b/implicit.c index 492599f..6e67b71 100644 --- a/implicit.c +++ b/implicit.c @@ -721,7 +721,7 @@ pattern_search (struct file *file, int archive, "lib/foo.c", and VPATH=src, searches for "src/lib/foo.c". */ { - const char *vname = vpath_search (d->name, 0); + const char *vname = vpath_search (d->name, 0, NULL, NULL); if (vname) { DBS (DB_IMPLICIT, diff --git a/make.h b/make.h index c4b0c32..2841c7f 100644 --- a/make.h +++ b/make.h @@ -431,7 +431,8 @@ void install_default_implicit_rules (void); void build_vpath_lists (void); void construct_vpath_list (char *pattern, char *dirpath); -const char *vpath_search (const char *file, FILE_TIMESTAMP *mtime_ptr); +const char *vpath_search (const char *file, FILE_TIMESTAMP *mtime_ptr, + unsigned int* vpath_index, unsigned int* path_index); int gpath_search (const char *file, unsigned int len); void construct_include_path (const char **arg_dirs); diff --git a/remake.c b/remake.c index 0855ace..8bfd23b 100644 --- a/remake.c +++ b/remake.c @@ -1280,7 +1280,7 @@ f_mtime (struct file *file, int search) if (mtime == NONEXISTENT_MTIME && search && !file->ignore_vpath) { /* If name_mtime failed, search VPATH. */ - const char *name = vpath_search (file->name, &mtime); + const char *name = vpath_search (file->name, &mtime, NULL, NULL); if (name /* Last resort, is it a library (-lxxx)? */ || (file->name[0] == '-' && file->name[1] == 'l' @@ -1533,6 +1533,10 @@ library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr) unsigned int len; unsigned int liblen; + /* Information about the earliest (in the vpath sequence) match. */ + unsigned int best_vpath, best_path; + unsigned int std_dirs = 0; + char **dp; libpatterns = xstrdup (variable_expand ("$(.LIBPATTERNS)")); @@ -1541,7 +1545,9 @@ library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr) lib += 2; liblen = strlen (lib); - /* Loop through all the patterns in .LIBPATTERNS, and search on each one. */ + /* Loop through all the patterns in .LIBPATTERNS, and search on each one. + To implement the linker-compatible behavior we have to search through + all entries in .LIBPATTERNS and choose the "earliest" one. */ p2 = libpatterns; while ((p = find_next_token (&p2, &len)) != 0) { @@ -1577,51 +1583,80 @@ library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr) if (mtime_ptr != 0) *mtime_ptr = mtime; file = strcache_add (libbuf); - goto fini; + /* This by definition will have the best index, so stop now. */ + break; } /* Now try VPATH search on that. */ { - file = vpath_search (libbuf, mtime_ptr); - if (file) - goto fini; + unsigned int vpath_index, path_index; + const char* f = vpath_search (libbuf, mtime_ptr ? &mtime : NULL, + &vpath_index, &path_index); + if (f) + { + /* If we have a better match, record it. */ + if (file == 0 || + vpath_index < best_vpath || + (vpath_index == best_vpath && path_index < best_path)) + { + file = f; + best_vpath = vpath_index; + best_path = path_index; + + if (mtime_ptr != 0) + *mtime_ptr = mtime; + } + } } /* Now try the standard set of directories. */ if (!buflen) - { - for (dp = dirs; *dp != 0; ++dp) - { - int l = strlen (*dp); - if (l > libdir_maxlen) - libdir_maxlen = l; - } - buflen = strlen (libbuf); - buf = xmalloc(libdir_maxlen + buflen + 2); - } + { + for (dp = dirs; *dp != 0; ++dp) + { + int l = strlen (*dp); + if (l > libdir_maxlen) + libdir_maxlen = l; + std_dirs++; + } + buflen = strlen (libbuf); + buf = xmalloc(libdir_maxlen + buflen + 2); + } else if (buflen < strlen (libbuf)) - { - buflen = strlen (libbuf); - buf = xrealloc (buf, libdir_maxlen + buflen + 2); - } + { + buflen = strlen (libbuf); + buf = xrealloc (buf, libdir_maxlen + buflen + 2); + } + + { + /* Use the last std_dirs index for standard directories. This + was it will always be greater than the VPATH index. */ + unsigned int vpath_index = ~((unsigned int)0) - std_dirs; + + for (dp = dirs; *dp != 0; ++dp) + { + sprintf (buf, "%s/%s", *dp, libbuf); + mtime = name_mtime (buf); + if (mtime != NONEXISTENT_MTIME) + { + if (file == 0 || vpath_index < best_vpath) + { + file = strcache_add (buf); + best_vpath = vpath_index; + + if (mtime_ptr != 0) + *mtime_ptr = mtime; + } + } + + vpath_index++; + } + } - for (dp = dirs; *dp != 0; ++dp) - { - sprintf (buf, "%s/%s", *dp, libbuf); - mtime = name_mtime (buf); - if (mtime != NONEXISTENT_MTIME) - { - if (mtime_ptr != 0) - *mtime_ptr = mtime; - file = strcache_add (buf); - goto fini; - } - } } - fini: free (libpatterns); return file; } diff --git a/tests/ChangeLog b/tests/ChangeLog index f446dcb..eaacaec 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,8 @@ +2009-11-12 Boris Kolpackov + + * scripts/features/vpath3: Test for the new library search + behavior. + 2009-10-06 Boris Kolpackov * scripts/features/se_explicit: Enable the test for now fixed diff --git a/tests/scripts/features/vpath3 b/tests/scripts/features/vpath3 new file mode 100644 index 0000000..978c5ee --- /dev/null +++ b/tests/scripts/features/vpath3 @@ -0,0 +1,50 @@ +# -*-perl-*- + +$description = "Test the interaction of the -lfoo feature and vpath"; +$details = ""; + +open(MAKEFILE,"> $makefile"); + +# The Contents of the MAKEFILE ... + +print MAKEFILE "vpath %.a a1\n"; +print MAKEFILE "vpath %.so b1\n"; +print MAKEFILE "vpath % a2 b2\n"; +print MAKEFILE "vpath % b3\n"; +print MAKEFILE "all: -l1 -l2 -l3; \@echo \$^\n"; + +# END of Contents of MAKEFILE + +close(MAKEFILE); + +mkdir("a1", 0777); +mkdir("b1", 0777); +mkdir("a2", 0777); +mkdir("b2", 0777); +mkdir("b3", 0777); + +@files_to_touch = ("a1${pathsep}lib1.a", + "b1${pathsep}lib1.so", + "a2${pathsep}lib2.a", + "b2${pathsep}lib2.so", + "lib3.a", + "b3${pathsep}lib3.so"); + +&touch(@files_to_touch); + +&run_make_with_options($makefile,"",&get_logfile); + +# Create the answer to what should be produced by this Makefile +$answer = "a1${pathsep}lib1.a a2${pathsep}lib2.a lib3.a\n"; + +if (&compare_output($answer,&get_logfile(1))) +{ + unlink @files_to_touch; + rmdir("a1"); + rmdir("b1"); + rmdir("a2"); + rmdir("b2"); + rmdir("b3"); +} + +1; diff --git a/vpath.c b/vpath.c index 9685468..e9cd691 100644 --- a/vpath.c +++ b/vpath.c @@ -320,11 +320,12 @@ gpath_search (const char *file, unsigned int len) /* Search the given VPATH list for a directory where the name pointed to by FILE exists. If it is found, we return a cached name of the existing file and set *MTIME_PTR (if MTIME_PTR is not NULL) to its modtime (or zero if no - stat call was done). Otherwise we return NULL. */ + stat call was done). Also set the matching directory index in PATH_INDEX + if it is not NULL. Otherwise we return NULL. */ static const char * selective_vpath_search (struct vpath *path, const char *file, - FILE_TIMESTAMP *mtime_ptr) + FILE_TIMESTAMP *mtime_ptr, unsigned int* path_index) { int not_target; char *name; @@ -504,6 +505,9 @@ selective_vpath_search (struct vpath *path, const char *file, /* Store the name we found and return it. */ + if (path_index) + *path_index = i; + return strcache_add_len (name, (p + 1 - name) + flen); } } @@ -515,10 +519,12 @@ selective_vpath_search (struct vpath *path, const char *file, /* Search the VPATH list whose pattern matches FILE for a directory where FILE exists. If it is found, return the cached name of an existing file, and set *MTIME_PTR (if MTIME_PTR is not NULL) to its modtime (or zero if no - stat call was done). Otherwise we return 0. */ + stat call was done). Also set the matching directory index in VPATH_INDEX + and PATH_INDEX if they are not NULL. Otherwise we return 0. */ const char * -vpath_search (const char *file, FILE_TIMESTAMP *mtime_ptr) +vpath_search (const char *file, FILE_TIMESTAMP *mtime_ptr, + unsigned int* vpath_index, unsigned int* path_index) { struct vpath *v; @@ -532,23 +538,40 @@ vpath_search (const char *file, FILE_TIMESTAMP *mtime_ptr) || (vpaths == 0 && general_vpath == 0)) return 0; + if (vpath_index) + { + *vpath_index = 0; + *path_index = 0; + } + for (v = vpaths; v != 0; v = v->next) - if (pattern_matches (v->pattern, v->percent, file)) - { - const char *p = selective_vpath_search (v, file, mtime_ptr); - if (p) - return p; - } + { + if (pattern_matches (v->pattern, v->percent, file)) + { + const char *p = selective_vpath_search ( + v, file, mtime_ptr, path_index); + if (p) + return p; + } + + if (vpath_index) + ++*vpath_index; + } + if (general_vpath != 0) { - const char *p = selective_vpath_search (general_vpath, file, mtime_ptr); + const char *p = selective_vpath_search ( + general_vpath, file, mtime_ptr, path_index); if (p) return p; } return 0; } + + + /* Print the data base of VPATH search paths. */ -- 2.11.4.GIT