|
|
@@ -76,6 +76,79 @@ upcase_string(const string &str) {
|
|
|
}
|
|
|
*/
|
|
|
|
|
|
+/**
|
|
|
+ * Finds a dependency cycle between the given dependency mapping, starting at
|
|
|
+ * the node that is already placed in the given cycle vector.
|
|
|
+ */
|
|
|
+static bool find_dependency_cycle(vector_string &cycle, map<string, set<string> > &dependencies) {
|
|
|
+ assert(!cycle.empty());
|
|
|
+
|
|
|
+ const set<string> &deps = dependencies[cycle.back()];
|
|
|
+ for (auto it = deps.begin(); it != deps.end(); ++it) {
|
|
|
+ auto it2 = std::find(cycle.begin(), cycle.end(), *it);
|
|
|
+ if (it2 != cycle.end()) {
|
|
|
+ // Chop off the part of the chain that is not relevant.
|
|
|
+ cycle.erase(cycle.begin(), it2);
|
|
|
+ cycle.push_back(*it);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Recurse.
|
|
|
+ cycle.push_back(*it);
|
|
|
+ if (find_dependency_cycle(cycle, dependencies)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ cycle.pop_back();
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Given that a direct link has been established between the two libraries,
|
|
|
+ * finds the two types that make up this relationship and prints out the
|
|
|
+ * nature of their dependency.
|
|
|
+ */
|
|
|
+static bool print_dependent_types(const string &lib1, const string &lib2) {
|
|
|
+ for (int ti = 0; ti < interrogate_number_of_global_types(); ti++) {
|
|
|
+ TypeIndex thetype = interrogate_get_global_type(ti);
|
|
|
+ if (interrogate_type_has_module_name(thetype) &&
|
|
|
+ interrogate_type_has_library_name(thetype) &&
|
|
|
+ lib1 == interrogate_type_library_name(thetype) &&
|
|
|
+ module_name == interrogate_type_module_name(thetype)) {
|
|
|
+
|
|
|
+ // Get the dependencies for this library.
|
|
|
+ int num_derivations = interrogate_type_number_of_derivations(thetype);
|
|
|
+ for (int di = 0; di < num_derivations; ++di) {
|
|
|
+ TypeIndex basetype = interrogate_type_get_derivation(thetype, di);
|
|
|
+ if (interrogate_type_is_global(basetype) &&
|
|
|
+ interrogate_type_has_library_name(basetype) &&
|
|
|
+ interrogate_type_library_name(basetype) == lib2) {
|
|
|
+ cerr
|
|
|
+ << " " << interrogate_type_scoped_name(thetype) << " ("
|
|
|
+ << lib1 << ") inherits from "
|
|
|
+ << interrogate_type_scoped_name(basetype) << " (" << lib2 << ")\n";
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // It also counts if this is a typedef pointing to another type.
|
|
|
+ if (interrogate_type_is_typedef(thetype)) {
|
|
|
+ TypeIndex wrapped = interrogate_type_wrapped_type(thetype);
|
|
|
+ if (interrogate_type_is_global(wrapped) &&
|
|
|
+ interrogate_type_has_library_name(wrapped) &&
|
|
|
+ interrogate_type_library_name(wrapped) == lib2) {
|
|
|
+ cerr
|
|
|
+ << " " << interrogate_type_scoped_name(thetype) << " ("
|
|
|
+ << lib1 << ") is a typedef to "
|
|
|
+ << interrogate_type_scoped_name(wrapped) << " (" << lib2 << ")\n";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
int write_python_table_native(ostream &out) {
|
|
|
out << "\n#include \"dtoolbase.h\"\n"
|
|
|
<< "#include \"interrogate_request.h\"\n\n"
|
|
|
@@ -83,7 +156,7 @@ int write_python_table_native(ostream &out) {
|
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
- vector_string libraries;
|
|
|
+ map<string, set<string> > dependencies;
|
|
|
|
|
|
// out << "extern \"C\" {\n";
|
|
|
|
|
|
@@ -99,21 +172,110 @@ int write_python_table_native(ostream &out) {
|
|
|
// name add it to set of libraries
|
|
|
if (interrogate_function_has_library_name(function_index)) {
|
|
|
string library_name = interrogate_function_library_name(function_index);
|
|
|
- if (std::find(libraries.begin(), libraries.end(), library_name) == libraries.end()) {
|
|
|
- libraries.push_back(library_name);
|
|
|
- }
|
|
|
+ dependencies[library_name];
|
|
|
}
|
|
|
// }
|
|
|
}
|
|
|
|
|
|
- for (int ti = 0; ti < interrogate_number_of_types(); ti++) {
|
|
|
- TypeIndex thetype = interrogate_get_type(ti);
|
|
|
+ for (int ti = 0; ti < interrogate_number_of_global_types(); ti++) {
|
|
|
+ TypeIndex thetype = interrogate_get_global_type(ti);
|
|
|
if (interrogate_type_has_module_name(thetype) && module_name == interrogate_type_module_name(thetype)) {
|
|
|
if (interrogate_type_has_library_name(thetype)) {
|
|
|
string library_name = interrogate_type_library_name(thetype);
|
|
|
+ set<string> &deps = dependencies[library_name];
|
|
|
+
|
|
|
+ // Get the dependencies for this library.
|
|
|
+ int num_derivations = interrogate_type_number_of_derivations(thetype);
|
|
|
+ for (int di = 0; di < num_derivations; ++di) {
|
|
|
+ TypeIndex basetype = interrogate_type_get_derivation(thetype, di);
|
|
|
+ if (interrogate_type_is_global(basetype) &&
|
|
|
+ interrogate_type_has_library_name(basetype)) {
|
|
|
+ string baselib = interrogate_type_library_name(basetype);
|
|
|
+ if (baselib != library_name) {
|
|
|
+ deps.insert(move(baselib));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (interrogate_type_is_typedef(thetype)) {
|
|
|
+ TypeIndex wrapped = interrogate_type_wrapped_type(thetype);
|
|
|
+ if (interrogate_type_is_global(wrapped) &&
|
|
|
+ interrogate_type_has_library_name(wrapped)) {
|
|
|
+ string wrappedlib = interrogate_type_library_name(wrapped);
|
|
|
+ if (wrappedlib != library_name) {
|
|
|
+ deps.insert(move(wrappedlib));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Now add the libraries in their proper ordering, based on dependencies.
|
|
|
+ vector_string libraries;
|
|
|
+ while (libraries.size() < dependencies.size()) {
|
|
|
+ // We have this check to make sure we don't enter an infinite loop.
|
|
|
+ bool added_any = false;
|
|
|
+
|
|
|
+ for (auto it = dependencies.begin(); it != dependencies.end(); ++it) {
|
|
|
+ const string &library_name = it->first;
|
|
|
+ set<string> &deps = dependencies[library_name];
|
|
|
+
|
|
|
+ // Remove the dependencies that have already been added from the deps.
|
|
|
+ if (!deps.empty()) {
|
|
|
+ for (auto li = libraries.begin(); li != libraries.end(); ++li) {
|
|
|
+ deps.erase(*li);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (deps.empty()) {
|
|
|
+ // OK, no remaining dependencies, so we can add this.
|
|
|
if (std::find(libraries.begin(), libraries.end(), library_name) == libraries.end()) {
|
|
|
libraries.push_back(library_name);
|
|
|
+ added_any = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!added_any) {
|
|
|
+ // Oh dear, we must have hit a circular dependency. Go through the
|
|
|
+ // remaining libraries to figure it out and print it.
|
|
|
+ cerr << "Circular dependency between libraries detected:\n";
|
|
|
+ for (auto it = dependencies.begin(); it != dependencies.end(); ++it) {
|
|
|
+ const string &library_name = it->first;
|
|
|
+ set<string> &deps = dependencies[library_name];
|
|
|
+ if (deps.empty()) {
|
|
|
+ continue;
|
|
|
}
|
|
|
+
|
|
|
+ // But since it does indicate a potential architectural flaw, we do
|
|
|
+ // want to let the user know about this.
|
|
|
+ vector_string cycle;
|
|
|
+ cycle.push_back(library_name);
|
|
|
+ if (!find_dependency_cycle(cycle, dependencies)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ assert(cycle.size() >= 2);
|
|
|
+
|
|
|
+ // Show the cycle of library dependencies.
|
|
|
+ auto ci = cycle.begin();
|
|
|
+ cerr << " " << *ci;
|
|
|
+ for (++ci; ci != cycle.end(); ++ci) {
|
|
|
+ cerr << " -> " << *ci;
|
|
|
+ }
|
|
|
+ cerr << "\n";
|
|
|
+
|
|
|
+ // Now print out the actual types that make up the cycle.
|
|
|
+ ci = cycle.begin();
|
|
|
+ string prev = *ci;
|
|
|
+ for (++ci; ci != cycle.end(); ++ci) {
|
|
|
+ print_dependent_types(prev, *ci);
|
|
|
+ prev = *ci;
|
|
|
+ }
|
|
|
+
|
|
|
+ // We have to arbitrarily break one of the dependencies in order to be
|
|
|
+ // able to proceed. Break the first dependency.
|
|
|
+ dependencies[cycle[0]].erase(cycle[1]);
|
|
|
}
|
|
|
}
|
|
|
}
|