#include "caffe2/core/module.h" #include "caffe2/core/logging.h" #ifndef _WIN32 #include #endif namespace caffe2 { static std::mutex& gModuleChangeMutex() { static std::mutex m_; return m_; } static CaffeMap& MutableCurrentModules() { static CaffeMap 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 CurrentModuleHandles() { static CaffeMap module_handle_map_; return module_handle_map_; } const CaffeMap& CurrentModules() { return MutableCurrentModules(); } ModuleSchema::ModuleSchema(const char* name, const char* description) { std::lock_guard 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 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 guard(gModuleChangeMutex()); CurrentModuleHandles()[filename] = handle; } #endif // _WIN32 } } // namespace caffe2