// Gestionnaire de lien dynamique - R. Ansari 12/98 // LAL (Orsay) / IN2P3-CNRS DAPNIA/SPP (Saclay) / CEA #include "pdlmgr.h" #include #include #include // Extension de noms de fichiers Shared libs static const char* sofext = ".so"; static const char* sofext_HPUX = ".sl"; // Variables et methodes static int PDynLinkMgr::numSO = 0; string* PDynLinkMgr::tmpDir = NULL; /*! \class SOPHYA::PDynLinkMgr \ingroup SysTools This classes handles the run-time operations related to using shared libraries. The present version has been adapted for different Unix flavours (Linux, Compaq/Digital Unix, SGI IRIX, IBM AIX, Sun Solaris). The example here the linking of shared library named "mylib.so" containing a function \c double \c myfunction(double x). \code #include "pdlmgr.h" typedef double (* AFunctionOfX) (double x); { // ... string soname = "mylib.so"; string funcname = "myfunction"; PDynLinkMgr dyl(son); AFunctionOfX f = (AFunctionOfX)dyl.GetFunction(funcname); double x = 3.1425; if (f != NULL) cout << " X= " << x << " myfunction(x)=" << f(x) << endl; // ... } \endcode */ /* --Methode-Static-- */ /*! Sets the path for a temporary space where shared libraries are copied. The path is appended to \b LD_LIBRARY_PATH */ void PDynLinkMgr::SetTmpDir(string const & path) { if ( (path.length() > 0) && (path[path.length()] != '/') ) GetTmpDir() = path + '/'; else GetTmpDir() = path; #if defined(OSF1) || defined(Linux) || defined(SunOS) string cmd = "LD_LIBRARY_PATH="; char* varenv=NULL; varenv=getenv("LD_LIBRARY_PATH"); #elif defined(IRIX64) string cmd = "LD_LIBRARYN32_PATH="; char* varenv=NULL; varenv=getenv("LD_LIBRARYN32_PATH"); if (varenv == NULL) { cmd += '.'; if (path.length() > 0) cmd += ':' + path; } else { if (varenv[0] != '.') cmd += ".:"; if (path.length() > 0) cmd += path + ':'; cmd += varenv; putenv(cmd.c_str()); } #elif defined(AIX) string cmd = "LIBPATH="; char* varenv=NULL; varenv=getenv("LIBPATH"); if (varenv == NULL) { cmd += '.'; if (path.length() > 0) cmd += ':' + path; cmd += ":/usr/lib:/lib"; } else { if (varenv[0] != '.') cmd += ".:"; if (path.length() > 0) cmd += path + ':'; cmd += varenv; putenv(const_cast(cmd.c_str())); } #endif return; } /* --Methode-Static-- */ /*! Returns the temporary space path */ string& PDynLinkMgr::GetTmpDir() { if (tmpDir == NULL) { tmpDir = new string(""); char* varenv; if ( (varenv=getenv("SOPHYA_TMP")) != NULL ) *tmpDir = varenv; else if ( (varenv=getenv("TMPDIR")) != NULL ) *tmpDir = varenv; } return(*tmpDir); } /* --Methode-Static-- */ /*! Compiles the C source file named \b fname and creates the corresponding shared library linking against the standard C library (-lc) and the math library (-lm). Returns a pointer to the created PDynLinkMgr object (by new). Returns the NULL pointer in case of errors. */ PDynLinkMgr* PDynLinkMgr::BuildFromCFile(string const & fname) { size_t l = fname.length(); if (l < 1) return(NULL); string fnameobj = GetTmpDir()+"tmp_pdl.o"; string cmd; int rc; // Compilation du fichier #ifndef __mac__ cmd = "cc -c -o " + fnameobj + " " + fname; #else cmd = "Il faut compiler !!!" + fnameobj + " " + fname; #endif rc = system(cmd.c_str()); if (rc != 0) { cerr << "PDynLinkMgr::BuildFromCFile() Error Rc(" << cmd <<")= "<< rc << endl; return(NULL); } char buff[32]; numSO++; #ifndef HPUX sprintf(buff,"pdlmgr%d%s", numSO,sofext); #endif string fnameso = GetTmpDir()+buff; // Creation du shared-lib #if defined(OSF1) cmd = "ld -shared -o " + fnameso + " -all " + fnameobj + " -none -lm -lc"; #elif defined(Linux) cmd = "ld -shared -o " + fnameso + " " + fnameobj + " -lm -lc"; #elif defined(SunOS) cmd = "ld -G -o " + fnameso + " " + fnameobj + " -lm -lc"; #elif defined(IRIX64) cmd = "ld -shared -o " + fnameso + " " + fnameobj + " -lm -lc"; #elif defined(AIX) cmd = "ld -G -bnogc -bexpall -bM:1L -o " + fnameso + " " + fnameobj; #elif defined(HPUX) cmd = "ld -b -o " + fnameso + " " + fnameobj + " -lm -lc"; #else cmd = "ld -o " + fnameso + " " + fnameobj + " -lm -lc"; #endif rc = system(cmd.c_str()); if (rc != 0) { cerr << "PDynLinkMgr::BuildFromCFile() Error Rc(" << cmd <<")= "<< rc << endl; return(NULL); } PDynLinkMgr* rdyn = new PDynLinkMgr(fnameso, false); rdyn->copy = true; return(rdyn); } /* --Methode-- */ /*! The constructor. \param soname : Name of the shared library. ".so" is appended to the name if no dot "." is found in the name. \param cp : if true, copies the shared library in the temporary space. */ PDynLinkMgr::PDynLinkMgr(string& soname, bool cp) { dlhandle = NULL; soName = ""; if (soname.find_last_of(".") > soname.length()) #ifdef HPUX soname += sofext_HPUX; #else soname += sofext; #endif string fnameso; if (cp) { numSO++; char buff[32]; #ifndef HPUX sprintf(buff,"pdlmgr%d%s", numSO,sofext); #else sprintf(buff,"pdlmgr%d%s", numSO,sofext_HPUX); #endif fnameso = GetTmpDir()+buff; string cmd = "cp " + soname + " " + fnameso; int rc = system(cmd.c_str()); if (rc != 0) { cerr << "PDynLinkMgr::PDynLinkMgr() Error Rc(" << cmd <<")= "<< rc << endl; return; } } else fnameso = soname; copy = cp; soName = fnameso; #if defined(HPUX) dlhandle = NULL; cerr << "PDynLinkMgr::PDynLinkMgr() Not yet available on HP-UX " << endl; return; #else dlhandle = dlopen(fnameso.c_str(), RTLD_NOW); if (dlhandle == NULL) { cerr << "PDynLinkMgr::PDynLinkMgr(): Error opening SO " << fnameso << " (" << soname << ")" << endl; string sn = dlerror(); cerr << "Loader Error (dlerror()) :" << sn << endl; return; } #endif } /* --Methode-- */ /*! Destructor. Closes the shared library. Removes the file if it had been copied in the temporary space, or generated by \b BuildFromCFile */ PDynLinkMgr::~PDynLinkMgr() { #if defined(HPUX) cerr << "PDynLinkMgr::~PDynLinkMgr() Not yet available on HP-UX " << endl; return; #else if (dlhandle) dlclose(dlhandle); dlhandle = NULL; if (copy) { string cmd = "rm -f " + soName; system(cmd.c_str()); } #endif } /* --Methode-- */ /*! Returns a handle to the function named \b funcname. Returns the NULL pointer in case of error */ DlFunction PDynLinkMgr::GetFunction(string const & funcname) { DlFunction f = NULL; #if defined(HPUX) cerr << "PDynLinkMgr::GetFunction() Not yet available on HP-UX " << endl; return f; #else if (dlhandle != NULL) f = (DlFunction)dlsym(dlhandle, funcname.c_str()); if (f == NULL) cerr << "PDynLinkMgr::GetFunction(): Error linking " << funcname << endl; return(f); #endif }