| #include "caffe2/core/module.h" | |
| #include "caffe2/core/logging.h" | |
| #ifndef _WIN32 | |
| #include <dlfcn.h> | |
| #endif | |
| namespace caffe2 { | |
| static std::mutex& gModuleChangeMutex() { | |
| static std::mutex m_; | |
| return m_; | |
| } | |
| static CaffeMap<string, const ModuleSchema*>& MutableCurrentModules() { | |
| static CaffeMap<string, const ModuleSchema*> module_schema_map_; | |
| return module_schema_map_; | |
| } | |
| // Note(jiayq): I am not sure whether the module handles are going to be used | |
| // as C2 uses modules via registration, but let's keep the handles at least. | |
| static CaffeMap<string, void*> CurrentModuleHandles() { | |
| static CaffeMap<string, void*> module_handle_map_; | |
| return module_handle_map_; | |
| } | |
| const CaffeMap<string, const ModuleSchema*>& CurrentModules() { | |
| return MutableCurrentModules(); | |
| } | |
| ModuleSchema::ModuleSchema(const char* name, const char* description) { | |
| std::lock_guard<std::mutex> guard(gModuleChangeMutex()); | |
| MutableCurrentModules().emplace(name, this); | |
| } | |
| bool HasModule(const string& name) { | |
| auto& modules = CurrentModules(); | |
| return (modules.find(name) != modules.end()); | |
| } | |
| void LoadModule(const string& name, const string& filename) { | |
| CAFFE_ENFORCE( | |
| name.size() > 0 || filename.size() > 0, | |
| "You must provide at least one of name and filename."); | |
| if (name.size() && HasModule(name)) { | |
| VLOG(1) << "Module " << name << " already present. Skip loading."; | |
| return; | |
| } | |
| #ifdef _WIN32 | |
| CAFFE_ENFORCE( | |
| !HasModule(name), | |
| "On Windows, LoadModule is currently not supported yet and you should " | |
| "use static linking for any module that you intend to use."); | |
| #else | |
| void* handle = nullptr; | |
| if (filename.size()) { | |
| handle = dlopen(filename.c_str(), RTLD_NOW | RTLD_GLOBAL); | |
| CAFFE_ENFORCE( | |
| handle != nullptr, | |
| "Cannot load module ", | |
| name, | |
| " (with given filename ", | |
| filename, | |
| "), are you sure it is correct?"); | |
| } else { | |
| string inferred_name = string("lib") + name + ".so"; | |
| handle = dlopen(inferred_name.c_str(), RTLD_NOW | RTLD_GLOBAL); | |
| #ifdef __APPLE__ | |
| // For apple, we will also try the dylib extension. | |
| if (!handle) { | |
| string inferred_name = string("lib") + name + ".dylib"; | |
| handle = | |
| dlopen(inferred_name.c_str(), RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE); | |
| } | |
| #endif | |
| CAFFE_ENFORCE( | |
| handle != nullptr, | |
| "Cannot load module ", | |
| name, | |
| " (with inferred filename ", | |
| inferred_name, | |
| "), are you sure it is in the dynamic linker search path?"); | |
| } | |
| // After the module is loaded, we should check if it actually has the | |
| // intended module name. If not, it might be that the module file name | |
| // and the module name are inconsistent. | |
| if (name.size()) { | |
| string module_name_check = "gCaffe2ModuleSanityCheck" + name; | |
| CAFFE_ENFORCE( | |
| dlsym(handle, module_name_check.c_str()), | |
| "The loaded module ", | |
| name, | |
| " did not pass the module name sanity check. Is it built with the " | |
| "right configs? Make sure the file name and the CAFFE2_MODULE name " | |
| "are consistent."); | |
| // After it passes the dlopen and dlsym check, we should add it to the | |
| // current handles. | |
| std::lock_guard<std::mutex> guard(gModuleChangeMutex()); | |
| CurrentModuleHandles()[name] = handle; | |
| } else { | |
| // If not, we issue a warning that one is recommended to use explicit | |
| // module name. | |
| LOG(WARNING) | |
| << "Module file " << filename | |
| << " was loaded without a proper module name. It is recommended " | |
| "that one load a model with an explicit module name in addition " | |
| "to the filename."; | |
| // As a contingency, we will store the current module handle with the | |
| // filename. | |
| std::lock_guard<std::mutex> guard(gModuleChangeMutex()); | |
| CurrentModuleHandles()[filename] = handle; | |
| } | |
| #endif // _WIN32 | |
| } | |
| } // namespace caffe2 |