diff --git a/src/db/db/dbLibrary.cc b/src/db/db/dbLibrary.cc index d62136018..d590fef3a 100644 --- a/src/db/db/dbLibrary.cc +++ b/src/db/db/dbLibrary.cc @@ -145,9 +145,25 @@ Library::is_retired (const db::cell_index_type library_cell_index) const return (i != m_refcount.end () && j != m_retired_count.end () && i->second == j->second); } +void +Library::rename (const std::string &name) +{ + if (name != get_name () && db::LibraryManager::initialized ()) { + + // if the name changed, reregister the library under the new name + db::LibraryManager::instance ().unregister_lib (this); + set_name (name); + db::LibraryManager::instance ().register_lib (this); + + } +} + void Library::refresh () { + std::string name = reload (); + rename (name); + layout ().refresh (); remap_to (this); } diff --git a/src/db/db/dbLibrary.h b/src/db/db/dbLibrary.h index af8e71c50..6da00df3c 100644 --- a/src/db/db/dbLibrary.h +++ b/src/db/db/dbLibrary.h @@ -65,6 +65,20 @@ public: */ virtual ~Library (); + /** + * @brief Called to reload the library + * + * If the library is a file-based one, this method can be reimplemented to reload + * the file. This method must not change the name of the library, but return a new + * name in case it has changed. + * + * @return The new name of the library + */ + virtual std::string reload () + { + return get_name (); + } + /** * @brief The layout object * @@ -211,6 +225,14 @@ public: */ void refresh (); + /** + * @brief Renames the library + * + * Unlike "set_name", this method will take care of properly re-registering the library + * under the new name. + */ + void rename (const std::string &name); + /** * @brief Remap the library proxies to a different library * diff --git a/src/db/db/dbLibraryManager.cc b/src/db/db/dbLibraryManager.cc index a10430e2f..c03cf602a 100644 --- a/src/db/db/dbLibraryManager.cc +++ b/src/db/db/dbLibraryManager.cc @@ -126,6 +126,9 @@ LibraryManager::unregister_lib (Library *library) library->remap_to (0); library->set_id (std::numeric_limits::max ()); + + // issue the change notification + changed_event (); } void diff --git a/src/db/db/gsiDeclDbLibrary.cc b/src/db/db/gsiDeclDbLibrary.cc index 6e40c00e2..c7c749065 100644 --- a/src/db/db/gsiDeclDbLibrary.cc +++ b/src/db/db/gsiDeclDbLibrary.cc @@ -79,6 +79,11 @@ static void register_lib (db::Library *lib, const std::string &name) db::LibraryManager::instance ().register_lib (lib); } +static void unregister_lib (db::Library *lib) +{ + db::LibraryManager::instance ().unregister_lib (lib); +} + static void delete_lib (db::Library *lib) { db::LibraryManager::instance ().delete_lib (lib); @@ -97,7 +102,7 @@ static std::string get_technology (db::Library *lib) static void destroy_lib (db::Library *lib) { if (db::LibraryManager::instance ().lib_ptr_by_name (lib->get_name ()) == lib) { - // Library is registered -> do not delete + delete_lib (lib); } else { delete lib; } @@ -105,31 +110,51 @@ static void destroy_lib (db::Library *lib) namespace { +template class LibraryClass - : public Class + : public gsi::Class { public: LibraryClass (const char *module, const char *name, const gsi::Methods &methods, const char *description) - : Class (module, name, methods, description) + : gsi::Class (module, name, methods, description) + { } + + template + LibraryClass (const gsi::Class &base, const char *module, const char *name, const gsi::Methods &methods, const char *description) + : gsi::Class (base, module, name, methods, description) { } virtual void destroy (void *p) const { - db::Library *lib = reinterpret_cast (p); + Base *lib = reinterpret_cast (p); destroy_lib (lib); } }; +class LibraryImpl + : public db::Library +{ +public: + LibraryImpl () : db::Library () { } + + virtual std::string reload () + { + if (cb_reload.can_issue ()) { + return cb_reload.issue (&db::Library::reload); + } else { + return db::Library::reload (); + } + } + + gsi::Callback cb_reload; +}; + } -LibraryClass decl_Library ("db", "Library", - gsi::constructor ("new", &new_lib, - "@brief Creates a new, empty library" - ) + +LibraryClass decl_Library ("db", "LibraryBase", gsi::method ("library_by_name", &library_by_name, gsi::arg ("name"), gsi::arg ("for_technology", std::string (), "unspecific"), "@brief Gets a library by name\n" - "Returns the library object for the given name. If the name is not a valid\n" - "library name, nil is returned.\n" + "Returns the library object for the given name. If the name is not a valid library name, nil is returned.\n" "\n" "Different libraries can be registered under the same names for different technologies. When a technology name is given in 'for_technologies', " "the first library matching this technology is returned. If no technology is given, the first library is returned.\n" @@ -166,6 +191,22 @@ LibraryClass decl_Library ("db", "Library", "\n" "The technology specific behaviour has been introduced in version 0.27." ) + + gsi::method_ext ("unregister", &unregister_lib, + "@brief Unregisters the library\n" + "\n" + "Unregisters the library from the system. This will break all references of cells " + "using this library and make them 'defunct'.\n" + "\n" + "This method has been introduced in version 0.30.5." + ) + + gsi::method ("rename", &db::Library::rename, gsi::arg ("name"), + "@brief Renames the library\n" + "\n" + "Re-registers the library under a new name. Note that this will not change library references - " + "i.e. references to the old name will become invalid after calling this method.\n" + "\n" + "This method has been introduced in version 0.30.5." + ) + gsi::method_ext ("delete", &delete_lib, "@brief Deletes the library\n" "\n" @@ -176,7 +217,7 @@ LibraryClass decl_Library ("db", "Library", ) + gsi::method ("name", &db::Library::get_name, "@brief Returns the libraries' name\n" - "The name is set when the library is registered and cannot be changed\n" + "The name is set when the library is registered. To change it use \\rename.\n" ) + gsi::method ("id", &db::Library::get_id, "@brief Returns the library's ID\n" @@ -240,9 +281,27 @@ LibraryClass decl_Library ("db", "Library", "@brief Updates all layouts using this library.\n" "This method will retire cells or update layouts in the attached clients.\n" "It will also recompute the PCells inside the library. " + "Starting with version 0.30.5, this method will also call 'reload' on all libraries to " + "refresh cells located in external files.\n" "\n" "This method has been introduced in version 0.27.8." ), + "@hide" +); + +LibraryClass decl_LibraryImpl (decl_Library, "db", "Library", + gsi::constructor ("new", &new_lib, + "@brief Creates a new, empty library" + ) + + gsi::callback ("reload", &LibraryImpl::reload, &LibraryImpl::cb_reload, + "@brief Reloads resources for the library.\n" + "Reimplement this method if you like to reload resources the library was created from - " + "for example layout files.\n" + "\n" + "@return The new name of the library or the original name if it did not change.\n" + "\n" + "This method is called on \\refresh. It was introduced in version 0.30.5.\n" + ), "@brief A Library \n" "\n" "A library is basically a wrapper around a layout object. The layout object\n" diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index b258f5aad..9ec4ccae4 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -1034,7 +1034,7 @@ Class decl_dbEqualDeviceParameters ("db", "EqualDevic Class decl_GenericDeviceParameterCompare (decl_dbEqualDeviceParameters, "db", "GenericDeviceParameterCompare", gsi::callback ("less", &GenericDeviceParameterCompare::less, &GenericDeviceParameterCompare::cb_less, gsi::arg ("device_a"), gsi::arg ("device_b"), - "@brief Compares the parameters of two devices for a begin less than b. " + "@brief Compares the parameters of two devices for a begin less than b.\n" "Returns true, if the parameters of device a are considered less than those of device b." "The 'less' implementation needs to ensure strict weak ordering. Specifically, less(a,b) == false and less(b,a) implies that a is equal to b and " "less(a,b) == true implies that less(b,a) is false and vice versa. If not, an internal error " diff --git a/src/lay/lay/layLibraryController.cc b/src/lay/lay/layLibraryController.cc index fd5607520..0f47743ca 100644 --- a/src/lay/lay/layLibraryController.cc +++ b/src/lay/lay/layLibraryController.cc @@ -32,12 +32,53 @@ #include "dbReader.h" #include "tlLog.h" #include "tlStream.h" +#include "tlFileUtils.h" #include namespace lay { +// ------------------------------------------------------------------------------------------- + +class FileBasedLibrary + : public db::Library +{ +public: + FileBasedLibrary (const std::string &path) + : db::Library (), m_path (path) + { + set_description (tl::filename (path)); + } + + virtual std::string reload () + { + std::string name = tl::basename (m_path); + + layout ().clear (); + + tl::InputStream stream (m_path); + db::Reader reader (stream); + reader.read (layout ()); + + // Use the libname if there is one + db::Layout::meta_info_name_id_type libname_name_id = layout ().meta_info_name_id ("libname"); + for (db::Layout::meta_info_iterator m = layout ().begin_meta (); m != layout ().end_meta (); ++m) { + if (m->first == libname_name_id && ! m->second.value.is_nil ()) { + name = m->second.value.to_string (); + break; + } + } + + return name; + } + +private: + std::string m_path; +}; + +// ------------------------------------------------------------------------------------------- + LibraryController::LibraryController () : m_file_watcher (0), dm_sync_files (this, &LibraryController::sync_files) @@ -166,7 +207,6 @@ LibraryController::sync_files () QStringList libs = lp.entryList (name_filters, QDir::Files); for (QStringList::const_iterator im = libs.begin (); im != libs.end (); ++im) { - std::string filename = tl::to_string (*im); std::string lib_path = tl::to_string (lp.absoluteFilePath (*im)); try { @@ -187,26 +227,13 @@ LibraryController::sync_files () if (needs_load) { - std::unique_ptr lib (new db::Library ()); - lib->set_description (filename); + std::unique_ptr lib (new FileBasedLibrary (lib_path)); if (! p->second.empty ()) { lib->set_technology (p->second); } - lib->set_name (tl::to_string (QFileInfo (*im).baseName ())); tl::log << "Reading library '" << lib_path << "'"; - tl::InputStream stream (lib_path); - db::Reader reader (stream); - reader.read (lib->layout ()); - - // Use the libname if there is one - db::Layout::meta_info_name_id_type libname_name_id = lib->layout ().meta_info_name_id ("libname"); - for (db::Layout::meta_info_iterator m = lib->layout ().begin_meta (); m != lib->layout ().end_meta (); ++m) { - if (m->first == libname_name_id && ! m->second.value.is_nil ()) { - lib->set_name (m->second.value.to_string ()); - break; - } - } + lib->set_name (lib->reload ()); if (! p->second.empty ()) { tl::log << "Registering as '" << lib->get_name () << "' for tech '" << p->second << "'";