+ // -no_implicit_dylibs disables this optimization
+ if ( ! fImplicitlyLinkPublicDylibs )
+ return false;
+
+ // /usr/lib is a public location
+ if ( (strncmp(path, "/usr/lib/", 9) == 0) && (strchr(&path[9], '/') == NULL) )
+ return true;
+
+ // /System/Library/Frameworks/ is a public location
+ if ( strncmp(path, "/System/Library/Frameworks/", 27) == 0 ) {
+ const char* frameworkDot = strchr(&path[27], '.');
+ // but only top level framework
+ // /System/Library/Frameworks/Foo.framework/Versions/A/Foo ==> true
+ // /System/Library/Frameworks/Foo.framework/Resources/libBar.dylib ==> false
+ // /System/Library/Frameworks/Foo.framework/Frameworks/Bar.framework/Bar ==> false
+ // /System/Library/Frameworks/Foo.framework/Frameworks/Xfoo.framework/XFoo ==> false
+ if ( frameworkDot != NULL ) {
+ int frameworkNameLen = frameworkDot - &path[27];
+ if ( strncmp(&path[strlen(path)-frameworkNameLen-1], &path[26], frameworkNameLen+1) == 0 )
+ return true;
+ }
+ }
+
+ return false;
+}
+
+template <typename A>
+void Reader<A>::processIndirectLibraries(DylibHander* handler)
+{
+ if ( fLinkingFlat ) {
+ for (typename std::vector<PathAndFlag>::iterator it = fDependentLibraryPaths.begin(); it != fDependentLibraryPaths.end(); it++) {
+ handler->findDylib(it->path, this->getPath());
+ }
+ }
+ else if ( fNoRexports ) {
+ // MH_NO_REEXPORTED_DYLIBS bit set, then nothing to do
+ }
+ else {
+ // two-level, might have re-exports
+ for (typename std::vector<PathAndFlag>::iterator it = fDependentLibraryPaths.begin(); it != fDependentLibraryPaths.end(); it++) {
+ if ( it->reExport ) {
+ //fprintf(stderr, "processIndirectLibraries() parent=%s, child=%s\n", this->getInstallPath(), it->path);
+ // a LC_REEXPORT_DYLIB, LC_SUB_UMBRELLA or LC_SUB_LIBRARY says we re-export this child
+ ObjectFile::Reader* child = handler->findDylib(it->path, this->getPath());
+ if ( isPublicLocation(child->getInstallPath()) ) {
+ // promote this child to be automatically added as a direct dependent if this already is
+ if ( this->explicitlyLinked() || this->implicitlyLinked() ) {
+ //fprintf(stderr, "processIndirectLibraries() implicitly linking %s\n", child->getInstallPath());
+ ((Reader<A>*)child)->setImplicitlyLinked();
+ }
+ else
+ fReExportedChildren.push_back(child);
+ }
+ else {
+ // add all child's symbols to me
+ fReExportedChildren.push_back(child);
+ //fprintf(stderr, "processIndirectLibraries() parent=%s will re-export child=%s\n", this->getInstallPath(), it->path);
+ }
+ }
+ else if ( !fExplictReExportFound ) {
+ // see if child contains LC_SUB_FRAMEWORK with my name
+ ObjectFile::Reader* child = handler->findDylib(it->path, this->getPath());
+ const char* parentUmbrellaName = ((Reader<A>*)child)->parentUmbrella();
+ if ( parentUmbrellaName != NULL ) {
+ const char* parentName = this->getPath();
+ const char* lastSlash = strrchr(parentName, '/');
+ if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], parentUmbrellaName) == 0) ) {
+ // add all child's symbols to me
+ fReExportedChildren.push_back(child);
+ //fprintf(stderr, "processIndirectLibraries() umbrella=%s will re-export child=%s\n", this->getInstallPath(), it->path);
+ }
+ }
+ }
+ }
+ }
+
+ // check for re-export cycles
+ ReExportChain chain;
+ chain.prev = NULL;
+ chain.reader = this;
+ this->assertNoReExportCycles(&chain);
+}
+
+template <typename A>
+void Reader<A>::assertNoReExportCycles(ReExportChain* prev)
+{
+ // recursively check my re-exported dylibs
+ ReExportChain chain;
+ chain.prev = prev;
+ chain.reader = this;
+ for (std::vector<ObjectFile::Reader*>::iterator it = fReExportedChildren.begin(); it != fReExportedChildren.end(); it++) {
+ ObjectFile::Reader* child = *it;
+ // check child is not already in chain
+ for (ReExportChain* p = prev; p != NULL; p = p->prev) {
+ if ( p->reader == child ) {
+ throwf("cycle in dylib re-exports with %s", child->getPath());
+ }
+ }
+ ((Reader<A>*)(*it))->assertNoReExportCycles(&chain);