mirror of
https://github.com/mirror/make.git
synced 2025-01-27 21:00:22 +08:00
Implement linker-compatible library search.
This commit is contained in:
parent
5f188b39a4
commit
fe43fa9de3
20
ChangeLog
20
ChangeLog
@ -1,3 +1,23 @@
|
|||||||
|
2009-11-12 Boris Kolpackov <boris@codesynthesis.com>
|
||||||
|
|
||||||
|
* 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 <psmith@gnu.org>
|
2009-10-25 Paul Smith <psmith@gnu.org>
|
||||||
|
|
||||||
* AUTHORS, et.al.: Update copyright years.
|
* AUTHORS, et.al.: Update copyright years.
|
||||||
|
9
NEWS
9
NEWS
@ -37,6 +37,15 @@ Version 3.81.90
|
|||||||
patterns are preferred. To detect this feature search for 'shortest-stem'
|
patterns are preferred. To detect this feature search for 'shortest-stem'
|
||||||
in the .FEATURES special variable.
|
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
|
* New command line option: --eval=STRING causes STRING to be evaluated as
|
||||||
makefile syntax (akin to using the $(eval ...) function). The evaluation is
|
makefile syntax (akin to using the $(eval ...) function). The evaluation is
|
||||||
performed after all default rules and variables are defined, but before any
|
performed after all default rules and variables are defined, but before any
|
||||||
|
@ -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
|
@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}
|
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
|
handles it specially by searching for the file @file{lib@var{name}.so},
|
||||||
the current directory, in directories specified by matching @code{vpath}
|
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
|
search paths and the @code{VPATH} search path, and then in the
|
||||||
directories @file{/lib}, @file{/usr/lib}, and @file{@var{prefix}/lib}
|
directories @file{/lib}, @file{/usr/lib}, and @file{@var{prefix}/lib}
|
||||||
(normally @file{/usr/local/lib}, but MS-DOS/MS-Windows versions of
|
(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
|
@code{make} behave as if @var{prefix} is defined to be the root of the
|
||||||
DJGPP installation tree).
|
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
|
For example, if there is a @file{/usr/lib/libcurses.a} library on your
|
||||||
system (and no @file{/usr/lib/libcurses.so} file), then
|
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
|
variable is a pattern string. When a prerequisite like
|
||||||
@samp{-l@var{name}} is seen, @code{make} will replace the percent in
|
@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
|
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
|
searches using each library filename.
|
||||||
word in the list will be used.
|
|
||||||
|
|
||||||
The default value for @code{.LIBPATTERNS} is @samp{lib%.so lib%.a},
|
The default value for @code{.LIBPATTERNS} is @samp{lib%.so lib%.a},
|
||||||
which provides the default behavior described above.
|
which provides the default behavior described above.
|
||||||
|
@ -721,7 +721,7 @@ pattern_search (struct file *file, int archive,
|
|||||||
"lib/foo.c", and VPATH=src, searches for
|
"lib/foo.c", and VPATH=src, searches for
|
||||||
"src/lib/foo.c". */
|
"src/lib/foo.c". */
|
||||||
{
|
{
|
||||||
const char *vname = vpath_search (d->name, 0);
|
const char *vname = vpath_search (d->name, 0, NULL, NULL);
|
||||||
if (vname)
|
if (vname)
|
||||||
{
|
{
|
||||||
DBS (DB_IMPLICIT,
|
DBS (DB_IMPLICIT,
|
||||||
|
3
make.h
3
make.h
@ -431,7 +431,8 @@ void install_default_implicit_rules (void);
|
|||||||
|
|
||||||
void build_vpath_lists (void);
|
void build_vpath_lists (void);
|
||||||
void construct_vpath_list (char *pattern, char *dirpath);
|
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);
|
int gpath_search (const char *file, unsigned int len);
|
||||||
|
|
||||||
void construct_include_path (const char **arg_dirs);
|
void construct_include_path (const char **arg_dirs);
|
||||||
|
101
remake.c
101
remake.c
@ -1280,7 +1280,7 @@ f_mtime (struct file *file, int search)
|
|||||||
if (mtime == NONEXISTENT_MTIME && search && !file->ignore_vpath)
|
if (mtime == NONEXISTENT_MTIME && search && !file->ignore_vpath)
|
||||||
{
|
{
|
||||||
/* If name_mtime failed, search 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
|
if (name
|
||||||
/* Last resort, is it a library (-lxxx)? */
|
/* Last resort, is it a library (-lxxx)? */
|
||||||
|| (file->name[0] == '-' && file->name[1] == 'l'
|
|| (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 len;
|
||||||
unsigned int liblen;
|
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;
|
char **dp;
|
||||||
|
|
||||||
libpatterns = xstrdup (variable_expand ("$(.LIBPATTERNS)"));
|
libpatterns = xstrdup (variable_expand ("$(.LIBPATTERNS)"));
|
||||||
@ -1541,7 +1545,9 @@ library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr)
|
|||||||
lib += 2;
|
lib += 2;
|
||||||
liblen = strlen (lib);
|
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;
|
p2 = libpatterns;
|
||||||
while ((p = find_next_token (&p2, &len)) != 0)
|
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)
|
if (mtime_ptr != 0)
|
||||||
*mtime_ptr = mtime;
|
*mtime_ptr = mtime;
|
||||||
file = strcache_add (libbuf);
|
file = strcache_add (libbuf);
|
||||||
goto fini;
|
/* This by definition will have the best index, so stop now. */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now try VPATH search on that. */
|
/* Now try VPATH search on that. */
|
||||||
|
|
||||||
{
|
{
|
||||||
file = vpath_search (libbuf, mtime_ptr);
|
unsigned int vpath_index, path_index;
|
||||||
if (file)
|
const char* f = vpath_search (libbuf, mtime_ptr ? &mtime : NULL,
|
||||||
goto fini;
|
&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. */
|
/* Now try the standard set of directories. */
|
||||||
|
|
||||||
if (!buflen)
|
if (!buflen)
|
||||||
{
|
{
|
||||||
for (dp = dirs; *dp != 0; ++dp)
|
for (dp = dirs; *dp != 0; ++dp)
|
||||||
{
|
{
|
||||||
int l = strlen (*dp);
|
int l = strlen (*dp);
|
||||||
if (l > libdir_maxlen)
|
if (l > libdir_maxlen)
|
||||||
libdir_maxlen = l;
|
libdir_maxlen = l;
|
||||||
}
|
std_dirs++;
|
||||||
buflen = strlen (libbuf);
|
}
|
||||||
buf = xmalloc(libdir_maxlen + buflen + 2);
|
buflen = strlen (libbuf);
|
||||||
}
|
buf = xmalloc(libdir_maxlen + buflen + 2);
|
||||||
|
}
|
||||||
else if (buflen < strlen (libbuf))
|
else if (buflen < strlen (libbuf))
|
||||||
{
|
{
|
||||||
buflen = strlen (libbuf);
|
buflen = strlen (libbuf);
|
||||||
buf = xrealloc (buf, libdir_maxlen + buflen + 2);
|
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);
|
free (libpatterns);
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
2009-11-12 Boris Kolpackov <boris@codesynthesis.com>
|
||||||
|
|
||||||
|
* scripts/features/vpath3: Test for the new library search
|
||||||
|
behavior.
|
||||||
|
|
||||||
2009-10-06 Boris Kolpackov <boris@codesynthesis.com>
|
2009-10-06 Boris Kolpackov <boris@codesynthesis.com>
|
||||||
|
|
||||||
* scripts/features/se_explicit: Enable the test for now fixed
|
* scripts/features/se_explicit: Enable the test for now fixed
|
||||||
|
50
tests/scripts/features/vpath3
Normal file
50
tests/scripts/features/vpath3
Normal file
@ -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;
|
45
vpath.c
45
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
|
/* 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
|
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
|
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 *
|
static const char *
|
||||||
selective_vpath_search (struct vpath *path, const char *file,
|
selective_vpath_search (struct vpath *path, const char *file,
|
||||||
FILE_TIMESTAMP *mtime_ptr)
|
FILE_TIMESTAMP *mtime_ptr, unsigned int* path_index)
|
||||||
{
|
{
|
||||||
int not_target;
|
int not_target;
|
||||||
char *name;
|
char *name;
|
||||||
@ -504,6 +505,9 @@ selective_vpath_search (struct vpath *path, const char *file,
|
|||||||
|
|
||||||
/* Store the name we found and return it. */
|
/* Store the name we found and return it. */
|
||||||
|
|
||||||
|
if (path_index)
|
||||||
|
*path_index = i;
|
||||||
|
|
||||||
return strcache_add_len (name, (p + 1 - name) + flen);
|
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
|
/* 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
|
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
|
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 *
|
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;
|
struct vpath *v;
|
||||||
|
|
||||||
@ -532,23 +538,40 @@ vpath_search (const char *file, FILE_TIMESTAMP *mtime_ptr)
|
|||||||
|| (vpaths == 0 && general_vpath == 0))
|
|| (vpaths == 0 && general_vpath == 0))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (vpath_index)
|
||||||
|
{
|
||||||
|
*vpath_index = 0;
|
||||||
|
*path_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
for (v = vpaths; v != 0; v = v->next)
|
for (v = vpaths; v != 0; v = v->next)
|
||||||
if (pattern_matches (v->pattern, v->percent, file))
|
{
|
||||||
{
|
if (pattern_matches (v->pattern, v->percent, file))
|
||||||
const char *p = selective_vpath_search (v, file, mtime_ptr);
|
{
|
||||||
if (p)
|
const char *p = selective_vpath_search (
|
||||||
return p;
|
v, file, mtime_ptr, path_index);
|
||||||
}
|
if (p)
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vpath_index)
|
||||||
|
++*vpath_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (general_vpath != 0)
|
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)
|
if (p)
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Print the data base of VPATH search paths. */
|
/* Print the data base of VPATH search paths. */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user