0

I have an app that links to my static library.

I've just added Apple's Reachability Code to the library however this has caused the app to stop linking (even though app does not use the reachability code, nor is it including it indirectly, in addition Reachability.m is contained within the library's Compile Sources section).

So I added -ObjC to Other Linker Flags in the app and this solved the linking errors for Reachability. However the library is also using ZipArchive and adding the -ObjC linker flag caused linking errors related to that.

So what can I do? Leave -ObjC off and Reachability doesn't link, include it and ZipArchive doesn't link. Is there a solution?

Sample ZipArchiev linker error:

Undefined symbols for architecture arm64:
  "_deflate", referenced from:
      _zipWriteInFileInZip in libMyLibrary.a(zip.o)
      _zipCloseFileInZipRaw in libMyLibrary.a(zip.o)

Sample Reachability linker error:

Undefined symbols for architecture arm64:
  "_SCNetworkReachabilityGetFlags", referenced from:
      -[Reachability connectionRequired] in libMyLibrary.a(Reachability.o)
      -[Reachability currentReachabilityStatus] in libMyLibrary.a(Reachability.o)

The static library is being built with the -ObjC flag and it links with libz.1.2.5.dylib

I do actually have a solution which I found after initially posting this - I can add the -ObjC flag to the app and additionally link the app with libz.1.2.5.dylib. But IMO that is not good decoupling - my static library is going to be distributed and used by other people's apps and the fact it uses libz should be transparent to them and they should not have to link against it if they are already linking against my library. Is there a way I can solve the linking issue without the apps having to link both against my static library and the libz dynamic library?

Gruntcakes
  • 37,738
  • 44
  • 184
  • 378
  • Do you have Reachability linked with your binary in xcode? – evan.stoddard Jun 17 '14 at 20:13
  • Reachability isn't a library, its source code (supplied by Apple) – Gruntcakes Jun 17 '14 at 20:23
  • Yes but you still need to make sure the implementation file is linked to the app's source – evan.stoddard Jun 17 '14 at 20:28
  • The .m file is in the Compile Sources section if that's what you mean (as is mentioned above). If not then I don't know what you mean by linking against a source file. – Gruntcakes Jun 17 '14 at 20:30
  • @Even.stoddard Surely you can't "link" against a source file. You can *build* a source file and then *link* against the output of the build. How do you *link* against a *source* file? What do you mean by "implementation file is linked to the app's source"? – Gruntcakes Jun 17 '14 at 20:33

1 Answers1

0

I'm not sure why you need -ObjC for Reachability. That's usually needed when you're using categories from a static library. But I don't see any categories in Reachability.

Anyway, here is a solution I found for being able to get categories to work without -ObjC. Hopefully this might work for you too.

Remove the -ObjC linker flag. Since it can cause problems with lots of stuff, it's best to start there.

Now, from your static library code, you want to force the Reachability class to get compiled into the binary and loaded at runtime (that's my layman's description, probably not the real technical one). To do this, just add this function to the top of the Reachability class:

void loadReachability()
{
    // This is a trick to force the compiler to include this code.
}

I add this outside of the @implementation. I do have to put it in the .h to make it public.

I don't actually ever call it from my static library. The compiler just needs to think I'm going to call it. I call it after a return statement, so it doesn't happen at runtime. Just fakes out the compiler. I'm not actually using Reachability in my code, but I've changed the code below to use "Reachability" rather than the 10 or so categories I need to load.

+ (LPFSessionManager *)sharedManager
{
    static LPFSessionManager *sharedManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedManager = [[LPFSessionManager alloc] init];
    });
    return sharedManager;

    // Notice we don't really need to call this. We're faking out the compiler to include some code.
    loadReachability();
}

This could go in an -init method instead.

I found this solution here, and it's been working great for me: Objective-C categories in static library

Community
  • 1
  • 1
Dave Batton
  • 8,795
  • 1
  • 46
  • 50