tools-make/which_lib.c
Adam Fedor f3c6cfa062 Support for DLLs, etc
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/tools/make/trunk@6671 72102866-910b-0410-8b05-ffd578937521
2000-06-13 15:14:23 +00:00

469 lines
12 KiB
C

/*
which_lib.c
Copyright (C) 1997 Free Software Foundation, Inc.
Author: Ovidiu Predescu <ovidiu@net-community.com>
Date: October 1997
This file is part of the GNUstep Makefile Package.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
You should have received a copy of the GNU General Public
License along with this library; see the file COPYING.LIB.
If not, write to the Free Software Foundation,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Takes the name of the library, a list of search paths in the gcc notation
(using -Lpath) and the type of the library needed using the debug, profile,
static and shared variables.
It searches into the list of directories for a library matching the name and
the type required. If a library of that type is not found in a directory,
a similar one is tried. If no library is found at all then the next directory
will be searched. If no library is found in the list of libraries passed as
arguments, the user, then the local and finally the system GNUstep libraries
are searched.
*/
#include "config.h"
#include <stdio.h>
#include <errno.h>
#if HAVE_SYS_ERRNO_H
# include <sys/errno.h>
#endif
#if HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#if HAVE_STDLIB_H
# include <stdlib.h>
#endif
#if HAVE_STRING_H
# include <string.h>
#endif
#if HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#include <fcntl.h>
#if HAVE_DIRENT_H
# include <dirent.h>
# define NAMLEN(dirent) strlen((dirent)->d_name)
#else
# define dirent direct
# define NAMLEN(dirent) (dirent)->d_namlen
# if HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif
# if HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif
# if HAVE_NDIR_H
# include <ndir.h>
# endif
#endif
#if !defined(_POSIX_VERSION)
# if defined(NeXT)
# define DIR_enum_item struct direct
# endif
#endif
#if !defined(DIR_enum_item)
# define DIR_enum_item struct dirent
#endif
#define DIR_enum_state DIR
/* determine filesystem max path length */
# include <limits.h> /* for PATH_MAX */
#ifdef _POSIX_VERSION
# include <utime.h>
#else
# if HAVE_SYS_PARAM_H
# include <sys/param.h> /* for MAXPATHLEN */
# endif
#endif
#ifndef PATH_MAX
# ifdef _POSIX_VERSION
# define PATH_MAX _POSIX_PATH_MAX
# else
# ifdef MAXPATHLEN
# define PATH_MAX MAXPATHLEN
# else
# define PATH_MAX 1024
# endif
# endif
#endif
#if HAVE_SYS_FILE_H
#include <sys/file.h>
#endif
#define PATH_SEP "/"
/* Array of strings that are the library paths passed to compiler */
int paths_no = 0;
char** library_paths = NULL;
/* The list of libraries */
int libraries_no = 0;
char** all_libraries = NULL;
int other_flags_no = 0;
char** other_flags = NULL;
int library_name_len;
char* library_name = NULL;
char *libname_suffix;
int debug = 0;
int profile = 0;
int shared = 1;
char* libext = ".a";
char* shared_libext = ".so";
char* extension;
static void stripstr(unsigned char *s)
{
/*
Strips off carriage returns, newlines and spaces
at the end of the string. (this removes some \r\n issues on Windows)
*/
unsigned len;
if (s == NULL) return;
if ((len = strlen(s)) == 0) return;
while (len > 0) {
len--;
if (s[len] < 33) s[len] = '\0';
}
}
void get_arguments (int argc, char** argv)
{
int i;
for (i = 1; i < argc; i++) {
if (!strncmp (argv[i], "-l", 2)) {
if (all_libraries)
all_libraries = realloc (all_libraries,
(libraries_no + 1) * sizeof (char*));
else
all_libraries = malloc ((libraries_no + 1) * sizeof (char*));
all_libraries[libraries_no] = malloc (strlen (argv[i]) - 1);
strcpy (all_libraries[libraries_no], argv[i] + 2);
stripstr(all_libraries[libraries_no]);
libraries_no++;
}
else if (!strncmp (argv[i], "-L", 2)) {
if (library_paths)
library_paths = realloc (library_paths, (paths_no + 1) * sizeof(char*));
else
library_paths = malloc ((paths_no + 1) * sizeof(char*));
library_paths[paths_no] = malloc (strlen (argv[i]) - 1);
strcpy (library_paths[paths_no], argv[i] + 2);
stripstr(library_paths[paths_no]);
paths_no++;
}
else if (!strncmp (argv[i], "shared=", 7)) {
shared = !strncmp (argv[i] + 7, "yes", 3);
}
else if (!strncmp (argv[i], "debug=", 6)) {
debug = !strncmp (argv[i] + 6, "yes", 3);
}
else if (!strncmp (argv[i], "profile=", 8)) {
profile = !strncmp (argv[i] + 8, "yes", 3);
}
else if (!strncmp (argv[i], "libext=", 7)) {
libext = malloc (strlen (argv[i] + 7) + 1);
strcpy (libext, argv[i] + 7);
}
else if (!strncmp (argv[i], "shared_libext=", 14)) {
shared_libext = malloc (strlen (argv[i] + 14) + 1);
strcpy (shared_libext, argv[i] + 14);
}
else {
/* The flag is something different; keep it in the `other_flags' */
if (other_flags)
other_flags = realloc (other_flags,
(other_flags_no + 1) * sizeof (char*));
else
other_flags = malloc ((other_flags_no + 1) * sizeof (char*));
other_flags[other_flags_no] = malloc (strlen (argv[i]) + 1);
strcpy (other_flags[other_flags_no], argv[i]);
other_flags_no++;
}
}
/* Setup the exact prefix of the library we are looking for */
libname_suffix = malloc (5);
*libname_suffix = 0;
if (debug)
strcat (libname_suffix, "d");
if (profile)
strcat (libname_suffix, "p");
if (!shared)
strcat (libname_suffix, "s");
if (*libname_suffix) {
char tmp[5];
strcpy (tmp, libname_suffix);
strcpy (libname_suffix, "_");
strcat (libname_suffix, tmp);
}
/* Setup the extension */
extension = shared ? shared_libext : libext;
}
void show_all (void)
{
int i;
printf ("shared = %d\n", shared);
printf ("debug = %d\n", debug);
printf ("profile = %d\n", profile);
printf ("libext = %s\n", libext);
printf ("shared_libext = %s\n", shared_libext);
printf ("library name = %s\n", library_name);
puts ("library paths:");
for (i = 0; i < paths_no; i++)
printf (" %s\n", library_paths[i]);
}
/* Search for a library whose type is defined in 'type' as
'd' for debug
'p' for profile
's' for static
0 for the first library that matches library_name
Return 1 if a library with this type matches in 'path' and print to stdout
the name of the library. */
int search_for_library_with_type_in_directory(char type, char* path, char* ext)
{
DIR_enum_state* dir;
DIR_enum_item* dirbuf;
int i, found = 0;
dir = opendir (path);
while ((dirbuf = readdir (dir))) {
int filelen, extlen;
/* Skip "." and ".." directory entries */
if (strcmp(dirbuf->d_name, ".") == 0
|| strcmp(dirbuf->d_name, "..") == 0)
continue;
/* Skip it if the prefix does not match the library name. */
if (strncmp (dirbuf->d_name + 3, library_name, library_name_len))
continue;
filelen = strlen (dirbuf->d_name);
/* Now check if the extension matches */
if (ext && (extlen = strlen (ext)) && filelen - extlen > 0) {
int dfound = 0, sfound = 0, pfound = 0, dash = 0;
if (strcmp (dirbuf->d_name + filelen - extlen, ext))
/* No luck, skip this file */
continue;
/* The extension matches. Do a check to see if the suffix of the
library matches the library type we are looking for. */
for (i = library_name_len + 3; i < filelen - extlen; i++) {
/* Possibly a match */
if (type == dirbuf->d_name[i])
found = 1;
if (dirbuf->d_name[i] == '_') { /* Only one dash allowed */
/* Found another dash or one of the letters first */
if (dash || dfound || sfound || pfound) {
found = 0;
break;
}
else {
dash = 1;
continue;
}
}
else if (dirbuf->d_name[i] == 'd') { /* Only one d allowed */
/* We must have found the dash already */
if (!dash || dfound) {
found = 0;
break;
}
else {
dfound = 1;
continue;
}
}
else if (dirbuf->d_name[i] == 'p') { /* Only one p allowed */
/* We must have found the dash already */
if (!dash || pfound) {
found = 0;
break;
}
else {
pfound = 1;
continue;
}
}
else if (dirbuf->d_name[i] == 's') { /* Only one s allowed */
/* We must have found the dash already */
if (!dash || sfound) {
found = 0;
break;
}
else {
sfound = 1;
continue;
}
}
else {
/* Skip the libraries that begin with the same name but have
different suffix, eg libobjc.a libobjc-test.a. */
found = 0;
break;
}
}
if (found) {
char filename[PATH_MAX + 1];
/* Copy the name of the library without the "lib" prefix and the
extension. */
strncpy (filename, dirbuf->d_name + 3, filelen - extlen - 3);
filename[filelen - extlen - 3] = 0;
printf (" -l%s", filename);
break;
}
}
}
closedir (dir);
return found;
}
/* Returns 1 if found the library in path and prints to stdout the name of the
library. */
int search_for_library_in_directory (char* path)
{
struct stat statbuf;
char full_filename[PATH_MAX + 1];
if (stat (path, &statbuf) < 0) /* An error occured or the dir doesn't exist */
return 0;
else if ((statbuf.st_mode & S_IFMT) != S_IFDIR) /* Not a directory */
return 0;
strcpy (full_filename, path);
strcat (full_filename, PATH_SEP);
strcat (full_filename, "lib");
strcat (full_filename, library_name);
strcat (full_filename, libname_suffix);
strcat (full_filename, extension);
if (stat (full_filename, &statbuf) < 0 && errno != ENOENT) /* Error */
return 0;
if ((statbuf.st_mode & S_IFMT) == S_IFREG) { /* Found it! */
printf (" -l%s", library_name);
if (*libname_suffix)
printf ("%s", libname_suffix);
return 1;
}
/* The library was not found. If the library needed is a debug version try
to find a library with debugging info. */
if (debug && search_for_library_with_type_in_directory('d', path, extension))
return 1;
/* The library was still not found. If the library needed is a profile
version try to find one that has profile info in it. */
if (profile && search_for_library_with_type_in_directory('p',path,extension))
return 1;
/* The library was still not found. Try to get whatever library we have
there. */
/* If a shared library is needed try to find a shared one first. */
if (shared
&& search_for_library_with_type_in_directory (0, path, shared_libext))
return 1;
/* Return a static library that matches the 'library_name' */
if (search_for_library_with_type_in_directory (0, path, libext))
return 1;
return 0;
}
int main(int argc, char** argv)
{
int i, j, found;
#ifdef __WIN32__
setmode(1, O_BINARY);
setmode(2, O_BINARY);
#endif
if (argc == 1) {
printf ("usage: %s [-Lpath ...] -llibrary shared=yes|no debug=yes|no "
"profile=yes|no libext=string shared_libext=string\n", argv[0]);
exit (1);
}
get_arguments (argc, argv);
if (!libraries_no)
exit (0);
// show_all ();
for (i = 0; i < libraries_no; i++) {
library_name = all_libraries[i];
library_name_len = strlen (library_name);
found = 0;
for (j = 0; j < paths_no; j++)
if (search_for_library_in_directory (library_paths[j])) {
found = 1;
break;
}
if (!found) {
/* The library was not found. Assume there is somewhere else in the
linker library path and it will find the library. Otherwise a linking
error will happen but this is not our fault ;-). */
printf (" -l%s", library_name);
}
}
/* Output the other flags */
for (i = 0; i < other_flags_no; i++)
printf (" %s", other_flags[i]);
puts ("");
exit (0);
return 0;
}