3 Copyright (C) 1997, 2001, 2002 Free Software Foundation, Inc.
5 Author: Nicola Pero <nicola@brainstorm.co.uk>
8 Based on the original which_lib.c by Ovidiu Predescu,
9 Author: Ovidiu Predescu <ovidiu@net-community.com>
12 This file is part of the GNUstep Makefile Package.
14 This library is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License
16 as published by the Free Software Foundation; either version 2
17 of the License, or (at your option) any later version.
19 You should have received a copy of the GNU General Public
20 License along with this library; see the file COPYING.LIB.
21 If not, write to the Free Software Foundation,
22 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
26 Command line arguments are:
28 * a list of library search paths in the GCC notation, as in
30 -L/usr/GNUstep/Local/Library/Libraries/ix86/linux-gnu/gnu-gnu-gnu
31 -L/usr/GNUstep/System/Library/Libraries/ix86/linux-gnu/gnu-gnu-gnu
32 (order is important, paths are searched in the order they are listed);
34 * a list of libraries in the GCC notation, as in
35 -lgnustep-base -lgnustep-gui -lobjc
37 * flags specifying whether a debug, profile, static/shared library is
38 to be preferred, as in
39 debug=no profile=yes shared=yes
41 The tool outputs the same list of library search paths and the list
42 of libraries it received in input, with an important modification:
43 each library name is modified to match the available version of the
44 library (by appending nothing for a normal library, _d for a debug
45 version of the library, _p for a profile one, _s for a static one,
46 and the various combinations, _dp, _ds, _ps, _dps) -- giving
47 preference to libraries matching the specified debug, profile,
48 shared library flags. For example, if a debug=yes profile=no
49 shared=yes is specified, and libgnustep-base_d.so is in the library
50 search path, which_lib will replace -lgnustep-base with
51 -lgnustep-base_d in the output.
53 Here is exactly how the search is performed:
55 The tool first searches into the list of directories for a library
56 exactly matching the name and the type required. If found, it's
59 If none is found, the library looks for an approximate match, as
60 detailed in the following list. Each search in the following list
61 is performed on the list of directories, and uses the shared flags
64 If (debug=yes and profile=yes), the tool looks for a debug=yes
65 profile=no, then a debug=no profile=yes.
67 If (debug=yes and profile=no), the tool looks for a debug=no
70 If (debug=no and profile=yes), the tool looks for a debug=no
73 If (debug=no and profile=no), the tool looks for a debug=yes
76 If none is still found and shared=yes, the tool looks for any
77 available shared library with that name (regardless of wheter it's
78 debug/profile/nothing).
80 If none is still found, the tool looks for any available static
81 library with that name (regardless of any debug/profile/shared
84 If still not found, the tool outputs the unmodified library name (as
85 in -lgnustep-base) ... perhaps the library is somewhere else in the
86 linker path ... otherwise that will normally result in a linker
96 # include <sys/types.h>
108 # include <sys/stat.h>
116 # define dirent direct
118 # include <sys/ndir.h>
121 # include <sys/dir.h>
129 /* determine filesystem max path length */
131 # include <limits.h> /* for PATH_MAX */
133 #ifdef _POSIX_VERSION
136 # if HAVE_SYS_PARAM_H
137 # include <sys/param.h> /* for MAXPATHLEN */
142 # ifdef _POSIX_VERSION
143 # define PATH_MAX _POSIX_PATH_MAX
146 # define PATH_MAX MAXPATHLEN
148 # define PATH_MAX 1024
154 #include <sys/file.h>
157 /* Extension used for shared and non-shared libraries. */
159 char* shared_libext = ".so";
161 /* If set to 1, all code will print out information about what it
165 /* Strips off carriage returns, newlines and spaces at the end of the
166 string. (this removes some \r\n issues on Windows) */
167 static void stripstr (unsigned char *s)
176 len = strlen ((char *)s);
188 /* Normalize the directory, and checks that it exists on disk and is a
189 directory. Return the normalized path, or NULL if the path does
190 not exist on disk, or is not a valid directory. */
191 static char *normalize_and_check_dir (char *path)
193 int length = strlen (path);
194 char *normalized_path = NULL;
198 if (path[0] == '/' && path[1] == '/')
200 /* Convert //server/ to a format Windows functions understand. */
203 /* Convert //server/path/to/ --> server/path/to/ */
204 normalized_path = malloc (length * sizeof (char));
205 strcpy (normalized_path, &(path[2]));
207 /* Convert server/path/to/ --> server:/path/to/ */
208 s = strchr (normalized_path, '/');
211 /* The index of the '/' after 'server' in the original path. */
212 int index = 2 + (s - normalized_path);
215 strcpy (s + 1, &(path[index]));
221 normalized_path = malloc ((length + 1) * sizeof (char));
222 strcpy (normalized_path, path);
225 /* Now check that the path exists and is a directory. */
226 if (stat (normalized_path, &statbuf) < 0)
227 /* Error occured or dir doesn't exist */
231 fprintf (stderr, "Library path '%s' doesn't exist - ignored\n",
234 free (normalized_path);
237 else if ((statbuf.st_mode & S_IFMT) != S_IFDIR)
238 /* Not a directory */
242 fprintf (stderr, "Library path '%s' isn't a directory - ignored\n",
245 free (normalized_path);
249 stripstr ((unsigned char *)normalized_path);
250 return normalized_path;
253 /* Search for a library with library_name, suffix suffix and
256 library_name must not contain the suffix, so library_name should
257 be something like 'gnustep-base'.
259 suffix is the wanted suffix (valid suffixes are "", _d, _p, _s,
260 _ds, _dp, _ps, _dps). Must not be NULL.
262 ext is the wanted extension (normally, either .so or .a). Must
265 Return 0 if it doesn't find anything matching.
267 Return 1 if a library with the appropriate suffix/extension/type
268 matches in 'path' and print to stdout the name of the library. */
270 static int search_for_lib_with_suffix_and_ext (const char *library_name,
271 char **library_paths,
276 /* Iterate over the library_paths, looking for the library. */
279 for (i = 0; i < paths_no; i++)
281 char full_filename[PATH_MAX + 1];
284 strcpy (full_filename, library_paths[i]);
285 strcat (full_filename, "/lib");
286 strcat (full_filename, library_name);
287 strcat (full_filename, suffix);
288 strcat (full_filename, ext);
292 fprintf (stderr, " %s\n", full_filename);
295 if (stat (full_filename, &statbuf) < 0)
296 /* Error - likely that file doesn't exist. */
301 if ((statbuf.st_mode & S_IFMT) == S_IFREG)
306 fprintf (stderr, " Found!\n");
308 printf (" -l%s", library_name);
311 printf ("%s", suffix);
320 /* Search for a library with library_name, extension ext and any
323 The same comments as for 'search_for_lib_with_suffix_and_ext' apply,
324 except that any valid suffix is accepted (valid suffixes are: "",
325 _d, _p, _s, _ds, _dp, _ps, _dps).
328 static int search_for_lib_with_ext (const char *library_name,
329 int library_name_len,
330 char **library_paths,
334 /* Iterate over the library_paths, looking for the library. */
337 for (i = 0; i < paths_no; i++)
340 struct dirent* dirbuf;
345 fprintf (stderr, " %s/lib%s??%s\n", library_paths[i],
349 dir = opendir (library_paths[i]);
353 /* For some reasons, we can't read that path. Perhaps
354 someone removed the directory while we were running :-) */
358 while ((dirbuf = readdir (dir)))
360 /* Skip if it doesn't begin with 'lib'. This implicitly
361 skips "." and ".." in case they are returned. */
362 if (dirbuf->d_name[0] != 'l')
366 if (dirbuf->d_name[1] != 'i')
370 if (dirbuf->d_name[2] != 'b')
375 /* Skip if it does not match the library name. */
376 if (strncmp (dirbuf->d_name + 3, library_name, library_name_len))
384 filelen = strlen (dirbuf->d_name);
385 extlen = strlen (ext);
387 if (filelen - extlen <= 0)
389 /* Quite worrying this case. */
395 fprintf (stderr, " Considering %s\n", dirbuf->d_name);
398 /* First check if the extension matches */
399 if (strcmp (dirbuf->d_name + filelen - extlen, ext))
401 /* No luck, skip this file */
405 /* The extension matches. Check the last remaining bit
406 - that the remaining string we have not checked is
407 one of the allowed suffixes. The allowed suffixes
408 are: "", _d, _p, _s, _dp, _ds, _ps, _dps. */
412 int suffix_len = filelen - (3 /* 'lib' */
417 + extlen /* .so/.a */);
421 /* In the following cases, 'break' means found,
422 'continue' means not found. */
425 /* nothing - it's Ok. */
434 /* Must be one of _d, _p, _s */
437 if (dirbuf->d_name[3 + library_name_len] != '_')
442 c = dirbuf->d_name[3 + library_name_len + 1];
443 if (c != 'd' || c != 'p' || c != 's')
451 /* Must be one of _dp, _ds, _ps */
454 if (dirbuf->d_name[3 + library_name_len] != '_')
459 c = dirbuf->d_name[3 + library_name_len + 1];
460 d = dirbuf->d_name[3 + library_name_len + 2];
461 if ((c == 'd' && (d == 'p' || d == 's'))
462 || (c == 'p' && d == 's'))
470 if (dirbuf->d_name[3 + library_name_len] != '_')
474 if (dirbuf->d_name[3 + library_name_len] != 'd')
478 if (dirbuf->d_name[3 + library_name_len] != 'p')
482 if (dirbuf->d_name[3 + library_name_len] != 's')
494 /* If we're here, it's because it was found! */
497 fprintf (stderr, " Found!\n");
500 for (j = 0; j < suffix_len; j++)
502 f_suffix[j] = dirbuf->d_name[library_name_len + 3 + j];
505 printf (" -l%s%s", library_name, f_suffix);
521 /* Search for the library everywhere, and returns the library name. */
522 static void output_library_name (const char *library_name,
523 char** library_paths, int paths_no,
524 int debug, int profile, int shared,
525 char *libname_suffix)
527 char *extension = shared ? shared_libext : libext;
528 int library_name_len = strlen (library_name);
532 fprintf (stderr, "\n>>Library %s:\n", library_name);
535 /* We first perform the search of a matching library in all dirs. */
538 fprintf (stderr, "Scanning all paths for an exact match\n");
541 if (search_for_lib_with_suffix_and_ext (library_name,
542 library_paths, paths_no,
550 /* The library was not found. Try various approximations first,
551 slightly messing the original debug/profile requests, but still
552 honouring the shared=yes|no requirement. */
555 fprintf (stderr, "Scanning all paths for an approximate match\n");
558 /* _dp case: try _d, then _p */
559 if (debug && profile)
561 if (search_for_lib_with_suffix_and_ext (library_name,
562 library_paths, paths_no,
563 shared ? "_d" : "_ds",
569 if (search_for_lib_with_suffix_and_ext (library_name,
570 library_paths, paths_no,
571 shared ? "_p" : "_ps",
578 /* _d or _p: try nothing. */
579 if ((debug && !profile) || (!debug && profile))
581 if (search_for_lib_with_suffix_and_ext (library_name,
582 library_paths, paths_no,
590 /* nothing: try _d. */
591 if (!debug && !profile)
593 if (search_for_lib_with_suffix_and_ext (library_name,
594 library_paths, paths_no,
595 shared ? "_d" : "_ds",
602 /* The library was still not found. Try to get whatever library we
605 /* If a shared library is needed try to find a shared one first.
606 Any shared library is all right. */
612 "Scanning all paths for any shared lib with that name\n");
614 if (search_for_lib_with_ext (library_name, library_name_len,
615 library_paths, paths_no, shared_libext))
621 /* Last hope - return a static library with name 'library_name'.
622 Any static library is all right. */
626 "Scanning all paths for any static lib with that name\n");
628 if (search_for_lib_with_ext (library_name, library_name_len,
629 library_paths, paths_no, libext))
634 /* We couldn't locate the library. Output the library name we were
635 given, without any modification. Possibly it's somewhere else on
636 the linker path, otherwise (more likely) a linker error will
637 occur. Nothing we can do about it. */
640 fprintf (stderr, "Library not found, using unmodified library name\n");
642 printf (" -l%s", library_name);
646 int main (int argc, char** argv)
650 /* Type of libraries we prefer. */
655 /* Suffix of the libraries we prefer - something like "" or "_d" or
657 char libname_suffix[5];
659 /* Array of strings that are the library paths passed on the command
660 line. If we are on Windows, we convert library paths to a format
661 that Windows functions understand before we save the paths in
662 library_paths, so that you could pass them to Windows functions
663 accessing the filesystem. We also check that the paths actually
664 exist on disk, and are directories, before putting them in the
667 char** library_paths = NULL;
669 /* The list of libraries */
670 int libraries_no = 0;
671 char** all_libraries = NULL;
673 /* Other flags which are printed to the output as they are. */
674 int other_flags_no = 0;
675 char** other_flags = NULL;
680 setmode(1, O_BINARY);
681 setmode(2, O_BINARY);
686 printf ("usage: %s [-Lpath ...] -llibrary shared=yes|no debug=yes|no "
687 "profile=yes|no libext=string shared_libext=string "
688 "[show_all=yes]\n", argv[0]);
692 for (i = 1; i < argc; i++)
694 /* First switch basing on the first letter of each argument,
700 if (argv[i][1] == 'l')
704 all_libraries = realloc (all_libraries,
710 all_libraries = malloc ((libraries_no + 1)
713 all_libraries[libraries_no] = malloc (strlen (argv[i]) - 1);
714 strcpy (all_libraries[libraries_no], argv[i] + 2);
715 stripstr ((unsigned char *)all_libraries[libraries_no]);
719 else if (argv[i][1] == 'L')
721 char *lib_path = normalize_and_check_dir (argv[i] + 2);
723 /* Always print out the library search path flag,
725 printf (" %s", argv[i]);
727 if (lib_path != NULL)
731 library_paths = realloc (library_paths,
737 library_paths = malloc ((paths_no + 1)
740 library_paths[paths_no] = lib_path;
749 if (!strncmp (argv[i], "debug=", 6))
751 debug = !strncmp (argv[i] + 6, "yes", 3);
758 if (!strncmp (argv[i], "libext=", 7))
760 libext = malloc (strlen (argv[i] + 7) + 1);
761 strcpy (libext, argv[i] + 7);
768 if (!strncmp (argv[i], "profile=", 8))
770 profile = !strncmp (argv[i] + 8, "yes", 3);
777 if (!strncmp (argv[i], "shared=", 7))
779 shared = !strncmp (argv[i] + 7, "yes", 3);
782 else if (!strncmp (argv[i], "shared_libext=", 14))
784 shared_libext = malloc (strlen (argv[i] + 14) + 1);
785 strcpy (shared_libext, argv[i] + 14);
788 else if (!strncmp (argv[i], "show_all=", 9))
790 show_all = !strncmp (argv[i] + 9, "yes", 3);
799 /* The flag is something different; keep it in the `other_flags' */
802 other_flags = realloc (other_flags,
803 (other_flags_no + 1) * sizeof (char*));
807 other_flags = malloc ((other_flags_no + 1) * sizeof (char*));
809 other_flags[other_flags_no] = malloc (strlen (argv[i]) + 1);
810 strcpy (other_flags[other_flags_no], argv[i]);
814 /* Determine the exact libname_suffix of the libraries we are
816 libname_suffix[0] = '_';
817 libname_suffix[1] = '\0';
818 libname_suffix[2] = '\0';
819 libname_suffix[3] = '\0';
820 libname_suffix[4] = '\0';
826 libname_suffix[i] = 'd';
832 libname_suffix[i] = 'p';
838 libname_suffix[i] = 's';
844 libname_suffix[0] = '\0';
850 fprintf (stderr, ">>Input:\n");
851 fprintf (stderr, "shared = %d\n", shared);
852 fprintf (stderr, "debug = %d\n", debug);
853 fprintf (stderr, "profile = %d\n", profile);
854 fprintf (stderr, "libname_suffix = %s\n", libname_suffix);
855 fprintf (stderr, "libext = %s\n", libext);
856 fprintf (stderr, "shared_libext = %s\n", shared_libext);
858 fprintf (stderr, "library names:\n");
859 for (i = 0; i < libraries_no; i++)
861 fprintf (stderr, " %s\n", all_libraries[i]);
864 fprintf (stderr, "library paths:\n");
865 for (i = 0; i < paths_no; i++)
867 fprintf (stderr, " %s\n", library_paths[i]);
870 fprintf (stderr, "other flags:\n");
871 for (i = 0; i < other_flags_no; i++)
873 fprintf (stderr, " %s\n", other_flags[i]);
877 /* Now output the libraries. */
878 for (i = 0; i < libraries_no; i++)
880 /* Search for the library, and print (using -l%s) the library
881 name to standard output. */
882 output_library_name (all_libraries[i], library_paths,
883 paths_no, debug, profile, shared, libname_suffix);
886 /* Output the other flags */
887 for (i = 0; i < other_flags_no; i++)
889 printf (" %s", other_flags[i]);