// @(#)root/utils:$Id$ // Author: Fons Rademakers 05/12/2003 /************************************************************************* * Copyright (C) 1995-2002, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ // This program generates a map between class name and shared library. // Its output is in TEnv format. // Usage: rlibmap [-f] [-o ] -l -d // -c // -f: output full library path name (not needed when ROOT library // search path is used) // -o: write output to specified file, otherwise to stdout // -r: replace existing entries in the specified file // -l: library containing the classes in the specified linkdef files // -d: libraries on which the -l library depends // -c: linkdef files containing the list of classes defined in the -l library #include #include #include #include #include #include #include #include #include #ifndef WIN32 # include #else # define ssize_t int # include # include # include "cygpath.h" #endif #ifdef __APPLE__ #include #endif #if (defined(__FreeBSD__) && (__FreeBSD__ < 4)) || defined(__OpenBSD__) || \ (defined(__APPLE__) && (!defined(MAC_OS_X_VERSION_10_3) || \ (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_3))) #include #define lockf(fd, op, sz) flock((fd), (op)) #ifndef F_LOCK #define F_LOCK (LOCK_EX | LOCK_NB) #endif #ifndef F_ULOCK #define F_ULOCK LOCK_UN #endif #endif #if defined(__CYGWIN__) && defined(__GNUC__) #define F_LOCK F_WRLCK #define F_ULOCK F_UNLCK static int fcntl_lockf(int fd, int op, off_t off) { flock fl; fl.l_whence = SEEK_SET; fl.l_start = off; fl.l_len = 0; // whole file fl.l_pid = getpid(); fl.l_type = op; return fcntl(fd, F_SETLK, &fl); } #define lockf fcntl_lockf #endif const char *usage = "Usage: %s [-f] [<-r|-o> ] -l -d -c \n"; namespace std {} using namespace std; #ifdef WIN32 #include #include #define ftruncate(fd, size) win32_ftruncate(fd, size) //______________________________________________________________________________ int win32_ftruncate(int fd, ssize_t size) { HANDLE hfile; int curpos; if (fd < 0) return -1; hfile = (HANDLE) _get_osfhandle(fd); curpos = ::SetFilePointer(hfile, 0, 0, FILE_CURRENT); if (curpos == 0xFFFFFFFF || ::SetFilePointer(hfile, size, 0, FILE_BEGIN) == 0xFFFFFFFF || !::SetEndOfFile(hfile)) { int error = ::GetLastError(); switch (error) { case ERROR_INVALID_HANDLE: errno = EBADF; break; default: errno = EIO; break; } return -1; } return 0; } #endif // WIN32 //______________________________________________________________________________ char *Compress(const char *str) { // Remove all blanks from the string str. The returned string has to be // deleted by the user. static const char* composedTypes[] = {"const ", "signed ","unsigned "}; static unsigned int composedTypesLen[] = {6, 7, 9}; if (!str) return 0; const char *p = str; // allocate 20 extra characters in case of eg, vector> char *s, *s1 = new char[strlen(str)+20]; s = s1; while (*p) { if (*p != ' ') { for (unsigned int i = 0; i < sizeof(composedTypes) / sizeof(char*); ++i) { if (!strncmp(p, composedTypes[i], composedTypesLen[i]) && (p == str || !isalnum(p[-1]))) { // the last one will be copied after the for loop memcpy(s, composedTypes[i], composedTypesLen[i] - 1); p += composedTypesLen[i] - 1; s += composedTypesLen[i] - 1; continue; } } *s++ = *p; } p++; } *s = '\0'; return s1; } //______________________________________________________________________________ void UnCompressTemplate(char*& str) { // Replace ">>" by "> >" except for operator>>. // str might be changed; the old string gets deleted in here. // Even handles cases like "A>()>>::operator >>()". char* pos = strstr(str, ">>"); char* fixed = 0; int countgtgt = 0; while (pos) { // first run: just count, so we can allocate space for fixed ++countgtgt; pos = strstr(pos+1, ">>"); } if (!countgtgt) return; pos = strstr(str, ">>"); while (pos && pos > str) { bool isop = false; // check that it's not op>>: if (pos - str >= 8) { char* posop = pos - 1; // remove spaces in front of ">>": while (posop >= str && *posop == ' ') --posop; if (!strncmp("operator", posop - 7, 8)) { // it is an operator! isop = true; } } if (!isop) { // not an operator; we need to add a space. if (!fixed) { fixed = new char[strlen(str) + countgtgt + 1]; strcpy(fixed, str); } fixed[pos - str + 1] = ' '; strcpy(fixed + (pos - str) + 2, pos + 1); } pos = strstr(pos + 1, ">>"); } delete [] str; str = fixed; } //______________________________________________________________________________ int RemoveLib(const string &solib, bool fullpath, FILE *fp) { // Remove entries from the map file for the specified solib. fseek(fp, 0, SEEK_SET); // get file size struct stat sbuf; fstat(fileno(fp), &sbuf); size_t siz = sbuf.st_size; if (!siz) return 0; const char *libbase = solib.c_str(); if (!fullpath) { if ((libbase = strrchr(libbase, '/'))) libbase++; } // read file and remove lines matching specified libs char *fbuf = new char[siz+1]; char *fptr = fbuf; while (fgets(fptr, 1+siz - size_t(fptr-fbuf), fp)) { char *line = new char[strlen(fptr)+1]; strcpy(line, fptr); strtok(line, " "); char *lib = strtok(0, " \n"); if (lib && strcmp(lib, libbase)) { fptr += strlen(fptr); if (*(fptr-1) != '\n') { *fptr = '\n'; fptr++; } } delete [] line; // fgets() should return 0 in this case but doesn't if ( (siz - size_t(fptr - fbuf)) <= 0) break; } if (ftruncate(fileno(fp), 0)) {;} // write remaining lines back if (fptr != fbuf) { fseek(fp, 0, SEEK_SET); fwrite(fbuf, 1, size_t(fptr-fbuf), fp); } delete [] fbuf; fseek(fp, 0, SEEK_END); return 0; } //______________________________________________________________________________ int LibMap(const string &solib, const vector &solibdeps, const vector &linkdefs, bool fullpath, FILE *fp) { // Write libmap. Returns -1 in case of error. set classes; vector::const_iterator lk; for (lk = linkdefs.begin(); lk != linkdefs.end(); lk++) { const char *linkdef = lk->c_str(); FILE *lfp; char pragma[1024]; if ((lfp = fopen(linkdef, "r"))) { while (fgets(pragma, 1024, lfp)) { if (strcmp(strtok(pragma, " "), "#pragma")) continue; const char* linkOrCreate = strtok(0, " "); bool pragmaLink = (!strcmp(linkOrCreate, "link") && !strcmp(strtok(0, " "), "C++")); bool pragmaCreate = (!strcmp(linkOrCreate, "create") && !strcmp(strtok(0," "), "TClass")); if (pragmaLink || pragmaCreate) { const char *type = pragmaLink ? strtok(0, " ") : "class"; if (!strncmp(type, "option=", 7) || !strncmp(type, "options=", 8)) { if (strstr(type, "nomap")) continue; type = strtok(0, " "); } // handles class, class+protected and class+private, typedef if (!strncmp(type, "class", 5) || !strcmp(type, "typedef")) { char *cls = strtok(0, "-!+;"); // just in case remove trailing space and tab while (*cls == ' ') cls++; int len = strlen(cls) - 1; while (cls[len] == ' ' || cls[len] == '\t') cls[len--] = '\0'; //no space between tmpl arguments allowed cls = Compress(cls); // except for A >! UnCompressTemplate(cls); // don't include "vector" and "std::pair<" classes if (!strncmp(cls, "vector", 14) || !strncmp(cls, "std::pair<", 10)) continue; // replace "::" by "@@" since TEnv uses ":" as delimeter char *s = cls; while (*s) { if (*s == ':') *s = '@'; else if (*s == ' ') *s = '-'; s++; } classes.insert(cls); } } } fclose(lfp); } else { fprintf(stderr, "cannot open linkdef file %s\n", linkdef); } } const char *libbase = solib.c_str(); if (!fullpath) { if ((libbase = strrchr(libbase, '/'))) libbase++; else libbase = solib.c_str(); } set::const_iterator it; for (it = classes.begin(); it != classes.end(); it++) { fprintf(fp, "Library.%-35s %s", ((*it)+":").c_str(), libbase); if (solibdeps.size() > 0) { vector::const_iterator depit; for (depit = solibdeps.begin(); depit != solibdeps.end(); depit++) { #ifdef WIN32 string::size_type i = depit->find(".lib"); if (i != string::npos) continue; #endif const char *deplib = depit->c_str(); if (!fullpath) { if ((deplib = strrchr(deplib, '/'))) deplib++; else deplib = depit->c_str(); } fprintf(fp, " %s", deplib); } } fprintf(fp, "\n"); } return 0; } //______________________________________________________________________________ int main(int argc, char **argv) { string solib; vector solibdeps; vector linkdefs; bool fullpath = false; bool replace = false; FILE *fp = stdout; if (argc > 1) { int ic = 1; if (!strcmp(argv[ic], "-?") || !strcmp(argv[ic], "-h")) { fprintf(stderr, usage, argv[0]); return 1; } if (!strcmp(argv[ic], "-f")) { fullpath = true; ic++; } if (!strcmp(argv[ic], "-o")) { ic++; std::string outfile(argv[ic]); #ifdef WIN32 FromCygToNativePath(outfile); fp = fopen(outfile.c_str(), "w"); #else fp = fopen(argv[ic], "w"); #endif if (!fp) { fprintf(stderr, "cannot open output file %s\n", outfile.c_str()); return 1; } ic++; } if (!strcmp(argv[ic], "-r")) { replace = true; ic++; std::string outfile(argv[ic]); #ifdef WIN32 FromCygToNativePath(outfile); fp = fopen(outfile.c_str(), "a+"); #else fp = fopen(outfile.c_str(), "a+"); #endif if (!fp) { fprintf(stderr, "cannot open output file %s\n", outfile.c_str()); return 1; } ic++; } if (!strcmp(argv[ic], "-l")) { ic++; solib = argv[ic]; #ifdef WIN32 FromCygToNativePath(solib); #endif #ifdef __APPLE__ string::size_type i = solib.find(".dylib"); if (i != string::npos) solib.replace(i, 6, ".so"); #endif ic++; } if (!strcmp(argv[ic], "-d")) { ic++; for (int i = ic; i < argc && argv[i][0] != '-'; i++) { string dl = argv[i]; #ifdef WIN32 FromCygToNativePath(dl); #endif #ifdef __APPLE__ string::size_type j = dl.find(".dylib"); if (j != string::npos) dl.replace(j, 6, ".so"); #endif solibdeps.push_back(dl); ic++; } } if (!strcmp(argv[ic], "-c")) { ic++; for (int i = ic; i < argc; i++) { #ifdef WIN32 std::string linkdef(argv[i]); FromCygToNativePath(linkdef); linkdefs.push_back(linkdef); #else linkdefs.push_back(argv[i]); #endif ic++; } } } else { fprintf(stderr, usage, argv[0]); return 1; } if (replace) { #if !defined(WIN32) && !defined(__CYGWIN__) && !defined(__FreeBSD__) && \ !defined(__OpenBSD__) // lock file if (lockf(fileno(fp), F_LOCK, (off_t)1) == -1) { fprintf(stderr, "rlibmap: locking failed, don't use gmake -j\n"); } #endif // remove entries for solib to be processed RemoveLib(solib, fullpath, fp); } LibMap(solib, solibdeps, linkdefs, fullpath, fp); if (replace) { #if !defined(WIN32) && !defined(__CYGWIN__) && !defined(__FreeBSD__) && \ !defined(__OpenBSD__) // remove lock lseek(fileno(fp), 0, SEEK_SET); if (lockf(fileno(fp), F_ULOCK, (off_t)1) == -1) { //fprintf(stderr, "rlibmap: error unlocking output file\n"); } #endif } if (fp != stdout) fclose(fp); return 0; }