Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2011-2023 The plumed team 3 : (see the PEOPLE file at the root of the distribution for a list of names) 4 : 5 : See http://www.plumed.org for more information. 6 : 7 : This file is part of plumed, version 2. 8 : 9 : plumed is free software: you can redistribute it and/or modify 10 : it under the terms of the GNU Lesser General Public License as published by 11 : the Free Software Foundation, either version 3 of the License, or 12 : (at your option) any later version. 13 : 14 : plumed is distributed in the hope that it will be useful, 15 : but WITHOUT ANY WARRANTY; without even the implied warranty of 16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 : GNU Lesser General Public License for more details. 18 : 19 : You should have received a copy of the GNU Lesser General Public License 20 : along with plumed. If not, see <http://www.gnu.org/licenses/>. 21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ 22 : #include "DLLoader.h" 23 : 24 : #include "Exception.h" 25 : #include <cstdlib> 26 : #include <iostream> 27 : #include "core/ActionRegister.h" 28 : #include "core/CLToolRegister.h" 29 : 30 : #ifdef __PLUMED_HAS_DLOPEN 31 : #include <dlfcn.h> 32 : #endif 33 : 34 : namespace PLMD { 35 : 36 42 : bool DLLoader::installed() { 37 : #ifdef __PLUMED_HAS_DLOPEN 38 42 : return true; 39 : #else 40 : return false; 41 : #endif 42 : } 43 : 44 : 45 51 : void* DLLoader::load(const std::string&s) { 46 : #ifdef __PLUMED_HAS_DLOPEN 47 51 : auto lockerAction=Register::registrationLock(s); 48 51 : void* p=dlopen(s.c_str(),RTLD_NOW|RTLD_LOCAL); 49 51 : if(!p) plumed_error()<<"Could not load library "<<s<<"\n"<<dlerror(); 50 51 : handles.push_back(p); 51 51 : Register::completeAllRegistrations(p); 52 51 : return p; 53 : #else 54 : plumed_error()<<"you are trying to use dlopen but it's not configured on your system"; 55 : #endif 56 51 : } 57 : 58 812061 : DLLoader::~DLLoader() { 59 812061 : auto debug=std::getenv("PLUMED_LOAD_DEBUG"); 60 : #ifdef __PLUMED_HAS_DLOPEN 61 812061 : if(debug) std::fprintf(stderr,"delete dlloader\n"); 62 812112 : while(!handles.empty()) { 63 51 : int ret=dlclose(handles.back()); 64 51 : if(ret) { 65 0 : std::fprintf(stderr,"+++ error reported by dlclose: %s\n",dlerror()); 66 : } 67 : handles.pop_back(); 68 : } 69 812061 : if(debug) std::fprintf(stderr,"end delete dlloader\n"); 70 : #endif 71 812061 : } 72 : 73 812061 : DLLoader::DLLoader() { 74 : // do nothing 75 812061 : } 76 : 77 55163 : const std::vector<void*> & DLLoader::getHandles() const noexcept { 78 55163 : return handles; 79 : } 80 : 81 0 : DLLoader::EnsureGlobalDLOpen::EnsureGlobalDLOpen(const void *symbol) noexcept { 82 : #ifdef __PLUMED_HAS_DLOPEN 83 : #ifdef __PLUMED_HAS_DLADDR 84 : Dl_info info; 85 : // from the manual: 86 : // If the address specified in addr could not be matched to a shared 87 : // object, then these functions return 0. In this case, an error 88 : // message is not available via dlerror(3). 89 0 : int zeroIsError=dladdr(symbol, &info); 90 0 : if(zeroIsError!=0) { 91 : //This "promotes" to GLOBAL the object with the symbol pointed by ptr 92 0 : handle_ = dlopen(info.dli_fname, RTLD_GLOBAL | RTLD_NOW); 93 : } else { 94 0 : std::fprintf(stderr, 95 : "+++WARNING+++" 96 : "Failure in finding any object that contains the symbol %p.\n", 97 : symbol); 98 : } 99 : #else 100 : std::fprintf(stderr, 101 : "+++WARNING+++" 102 : "I can't use dladdr for promoting the library containing the symbol %p.\n" 103 : "This system seems not to support dladdr", 104 : symbol); 105 : #endif //__PLUMED_HAS_DLADDR 106 : #endif //__PLUMED_HAS_DLOPEN 107 0 : } 108 : 109 0 : DLLoader::EnsureGlobalDLOpen::~EnsureGlobalDLOpen() { 110 : #ifdef __PLUMED_HAS_DLOPEN 111 0 : if (handle_) { 112 0 : dlclose(handle_); 113 : } 114 : #endif //__PLUMED_HAS_DLOPEN 115 0 : } 116 : 117 0 : bool DLLoader::isPlumedGlobal() { 118 : #if defined(__APPLE__) 119 : bool result; 120 : #ifdef __PLUMED_HAS_DLOPEN 121 : void* handle; 122 : #if defined(__PLUMED_HAS_RTLD_DEFAULT) 123 : handle=RTLD_DEFAULT; 124 : #else 125 : handle=dlopen(NULL,RTLD_LOCAL); 126 : #endif 127 : // we check for two variants, see wrapper/Plumed.h for an explanation: 128 : result=dlsym(handle,"plumed_plumedmain_create") || dlsym(handle,"plumedmain_create"); 129 : if(handle) dlclose(handle); 130 : #else 131 : // if a system cannot use dlopen, we assume plumed is globally available 132 : result=true; 133 : #endif //__PLUMED_HAS_DLOPEN 134 : return result; 135 : #else 136 0 : plumed_error()<<"DLLoader::isPlumedGlobal() is only functional with APPLE dlsym"; 137 : #endif 138 : } 139 : 140 : } // namespace PLMD