/* Beware - some guesswork in here */ #include #include #include #include #include "mkmk.h" /* * Global hints are those needed by every file, even if it doesn't * include config.h, and thus they are passed on the command line. * Local hints are also passed on the command line, unless we are * in Autoconf mode, in which case they go into the config.h file. */ List *Glbhints = nil; List *Lochints = nil; typedef struct { char *name; char *macro; } Macdef; /* * any attempt to include these files requires the definition * of the given macro name or plan9's APE system will cause * a compilation error. This list is complete at the time or writing * but will become inaccurate with time. */ Macdef Filehints[] = { { "bsd.h", "_BSD_EXTENSION" }, { "netdb.h", "_BSD_EXTENSION" }, { "select.h", "_BSD_EXTENSION" }, { "sys/ioctl.h", "_BSD_EXTENSION" }, { "sys/resource.h", "_BSD_EXTENSION" }, { "sys/time.h", "_BSD_EXTENSION" }, { "sys/select.h", "_BSD_EXTENSION" }, { "sys/socket.h", "_BSD_EXTENSION" }, { "sys/systime.h", "_BSD_EXTENSION" }, { "sys/uio.h", "_BSD_EXTENSION" }, { "regexp.h", "_REGEXP_EXTENSION" }, { "u.h", "_PLAN9_EXTENSION" }, { "cursor.h", "_PLAN9_EXTENSION" }, { "draw.h", "_PLAN9_EXTENSION" }, { "event.h", "_PLAN9_EXTENSION" }, { "fmt.h", "_PLAN9_EXTENSION" }, { "keyboard.h", "_PLAN9_EXTENSION" }, { "lib9.h", "_PLAN9_EXTENSION" }, { "lock.h", "_PLAN9_EXTENSION" }, { "mouse.h", "_PLAN9_EXTENSION" }, { "qlock.h", "_PLAN9_EXTENSION" }, { "ar.h", "_RESEARCH_SOURCE" }, { "libv.h", "_RESEARCH_SOURCE" }, { "libl.h", "_RESEARCH_SOURCE" }, { "error.h", "_RESEARCH_SOURCE" }, { "inttypes.h", "_SUSV2_SOURCE" }, { "fcntl.h", "_POSIX_SOURCE" }, { "grp.h", "_POSIX_SOURCE" }, { "pwd.h", "_POSIX_SOURCE" }, { "unistd.h", "_POSIX_SOURCE" }, }; /* * Arbitary defines that GNU Autoconf wants and we support. */ char *Wellknown[] = { { "HAVE_WORKING_FORK" }, // yes our fork does work { "STDC_HEADERS" }, // unistd, stdlib and some friends { "TIME_WITH_SYS_TIME" }, // we have both time.h and sys/time.h { "GETPGRP_VOID" }, // getgrp() returns a void { "HAVE_UTIME_NULL" }, // utime() accepts nil for times { "SELECT_TYPE_ARG234=fd_set" }, // the type of args for select() { "_POSIX_SOURCE" }, // yes, we are POSIX compliant { "HAVE_ANSI_COMPILER" }, // yes, we are ANSI compiliant too }; static void addhint(List **lp, char *macro, char *value) { if(looksym(macro, nil) != nil) return; addlist(lp, macro); setsym(macro, value); } static char * looktab(List **lp, char *macro, char **first, char **last) { char **t; for(t = first; t < last; t++) if(strcmp(macro, *t) == 0){ addhint(lp, macro, "1"); return "1"; } return nil; } /* * This could cause problems. we only realise we need _LIMITS_EXTENSION when * its already too late, we have included limits.h, without this macro active * and missed the extra info. If the extension macros are only used in the C code * all is well but if their value is test in #if statements then we are stuffed * we I only guess at "1" for each limit. I should probably parse the sys/limits.h * file when I detect the first preprocessor use of any of the #defines in it but * I have not been bitten by this yet. */ #include "syslimits.h" static char * extendedlimits(char *macro) { char **t; for(t = Syslimits; t < &Syslimits[nelem(Syslimits)]; t++) if(strcmp(macro, *t) == 0){ addhint(&Glbhints, "_LIMITS_EXTENSION", "1"); return "1"; } return nil; } /* * Found a HAVE_funcname or FUNC_funcname test, lookup funcname * in all the system libraries I expect to link with. */ static char * function_name(char *macro, char *func) { if(inlibrary(func) == 0) return nil; /* * people tend to assume strdup() is part of POSIX */ if(strcmp(func, "strdup") == 0) addhint(&Glbhints, "_BSD_EXTENSION", "1"); addhint(&Lochints, macro, "1"); return "1"; } /* * Found HAVE_file_H so we check the system include "file" exists */ static char * incfile_exists(char *macro, char *str, List *incdirs) { int rc; char *s; List *l; for (l = incdirs; l; l = l->next){ s = emallocz(strlen(l->name)+strlen(str)+2, 0); strcpy(s, l->name); strcat(s, "/"); strcat(s, str); rc = access(s, 4); free(s); if(rc != -1){ addhint(&Lochints, macro, "1"); return "1"; } } return nil; } /* * I found an #if #elif or #ifdef referencing a macro which doesn't exist, * so I check to see if I think it "should" exist and define it if so. */ char * macrohint(char *macro, List *incdirs) { char *val, *s, *name; if((val = looktab(&Lochints, macro, Wellknown, &Wellknown[nelem(Wellknown)])) != nil) return val; if((val = extendedlimits(macro)) != nil) return val; if(strncmp(macro, "FUNC_", 5) == 0){ name = estrdup(macro+5); for(s = name; *s; s++) *s = tolower(*s); val = function_name(macro, name); free(name); return val; } if(strncmp(macro, "HAVE_", 5) == 0){ name = estrdup(macro+5); for(s = name; *s; s++) *s = tolower(*s); if((s = strrchr(name, '_')) != nil && strcmp(s, "_h") == 0){ *s = '.'; for(s = name; *s; s++) if(*s == '_') *s = '/'; val = incfile_exists(macro, name, incdirs); free(name); return val; } val = function_name(macro, name); free(name); return val; } return nil; } /* * this inclide file has been used, check if we can * infer any macros that need to be #define as a result. * * This is mainly for plan9 headers which raise an error if * the apropriate _XXXX_EXTENSION macro is not set when they are used. */ void includehint(char *file) { Macdef *nv; for(nv = Filehints; nv < &Filehints[nelem(Filehints)]; nv++) if(strcmp(file, nv->name) == 0){ if(looksym(nv->name, nil) == nil) addhint(&Glbhints, nv->macro, "1"); break; } } /* * assumes the GNU practice of naming * packages directories e.g. make-3.78 */ void gnu_pkgvers(void) { char buf[128], str[128], *ver, *pkg; getwd(buf, sizeof(buf)); ver = nil; if((pkg = strrchr(buf, '/')) != nil){ pkg++; if((ver = strchr(pkg, '-')) != nil) *ver++ = 0; } if(pkg) snprint(str, sizeof(str), "\"%s\"", pkg); else snprint(str, sizeof(str), "\"unknown\""); addhint(&Lochints, "PACKAGE", str); if(ver) snprint(str, sizeof(str), "\"%s\"", ver); else snprint(str, sizeof(str), "\"unknown\""); addhint(&Lochints, "VERSION", str); }