How to make sure my reusable static library doesn't force my project to include multiple frameworks? - objective-c

I try to put some reusable functions into my own static library but i noticed one problem.
Let's say the static library has many functions and some requires quartz core framework, some requires messgeUI etc.
When I build a new project, I include this static library project into my code so that I can reuse those functions.
Now even if I only use a simple function that doesn't require any frameworks, I am forced to include all the quartzcore, message UI frameworks or I will face build errors because the static library requires them- but I do not need all of them!
How can I design a better general purpose static library that doesn't force people to include frameworks that is not used by them at all?

You can use weak linking - if weak linkage is used, unused symbols (functions, methods, global variables) don't have to be present at linking time.

Related

How to create a wrapper library without exposing the underlying library being used?

Using Cmake I would like to know how to create a wrapper library and let the users link their application with this library only. Users don't need to specify the original library in their linker flags.
For instance, I create a wrapper library for libwebsockets, named libcustomws.
add_library(customws main.c)
target_link_libraries(customws websockets)
I would like user (with no libwebsockets installed) to be able to do:
add_executable(user_app user_app.c)
target_link_libraries(user_app customws pthread)
Wrapper libraries without any additional code from within your project can best be implemented with small INTERFACE library targets with the IMPORTED tag. Example for your scenario:
add_library(customws INTERFACE IMPORTED)
target_include_directories(customws
INTERFACE
/some/include/path)
target_link_libraries(customws
INTERFACE
websockets)
This way, targets that use this library can just
add_executable(user_app user_app.c)
target_link_libraries(user_app customws pthread)
and get the usage requirements from the target customws, in this case an include directory and a linked library (websockets) are propagated through customws. This can be a good thing, as it might encapsulate implementation details of the dependency (different flags for different platforms etc.).
If you like to automatically link to compiled code (that is part of your project), this can be easily done by adding a small intermediate OBJECT library, e.g.
add_libraray(customwsenhanced
OBJECT
someCode.c)
target_link_library(customwsenhanced
PUBLIC
customws)
Depending on whether someCode.c depends on the usage requirements of customws, the target_link_library for customwsenhanced could also use INTERFACE propagation. Now, a client application can go with
add_executable(user_app user_app.c)
target_link_libraries(user_app customwsenhanced pthread)
and will get both the compiled object code of someCode.c as well as flags etc. from customws.

dllexport in headers confusion

I'm confused as to why __declspec(dllexport) or equivalent needs to go in the header file. Say I'm writing a library. Surely the users don't need to know or worry about whether symbols are exported or not, all they care about is that the function declarations are there and will presumably be linked against the shared or static library itself. So why can't all this boilerplate go into source files, for use only at build time?
The only use case I think of is a situation where someone is writing a wrapper of my library and needs to export all of my functions as well, but in general that is not the case - is it really worth the hassle of having all the export stuff inside public headers? Is there something I'm missing, is this a technical limitation of linkers..?
I'm asking because I like my headers and build system to be clean, and as dllexport stuff is generally set/not set based on whether we are building the library as a shared or static library, I find it strange that it should end up inside public headers since it's (to my understanding) fundamentally a build time concept. So can someone please enlighten me on what I am missing?
I'm not really sure I can provide a great answer. My impression is that it serves several purposes:
It speeds the loading of DLLs, particularly when lots of DLLs are used (because there are fewer exported symbols to search through)
It reduces the possibility of symbols colliding at run-time (because there are fewer exported symbols)
It allows the linker to complain about undefined symbols (instead of just assuming it might find them at run time.
I'm sure there are other reasons. I generally wrap my APIs in something like this:
#if defined(MY_LIB_CREATION)
#define MY_LIB_API __declspec(dllexport)
#else
#define MY_LIB_API __declspec(dllimport)
#endif
And then all of my API functions & classes are defined as MY_LIB_API:
class MY_LIB_API Foo {};
MY_LIB_API void bar();
And then in the project file defined MY_LIB_CREATION for the project implementing your library.

Xcode: define preprocessor macro in one project used by another project

I have multiple app projects which all link to the same static library project. Each app project needs to compile the static library project using different settings.
At the moment I have a conditional compilation header in the static library project, let's call it ViewType.h which adds more types, typedefs, macros, etc specific to each view.
#define VIEW_A 1
#define VIEW_B 2
#define VIEW_C 3
#ifndef VIEWTYPE
#define VIEWTYPE VIEW_A
#endif
#if VIEWTYPE == VIEW_A
// further typedefs and defines tailored to VIEW_A
#elif VIEWTYPE == VIEW_B
// further typedefs and defines tailored to VIEW_B
#elif VIEWTYPE == VIEW_C
// further typedefs and defines tailored to VIEW_C
#endif
The problem here is that each app project needs to change the VIEWTYPE in the static library project, and every time I switch app projects I have to change the VIEWTYPE again.
Unfortunately it seems I can not define VIEWTYPE=2 (for example) as preprocessor macro in the app target. And I can't define this in the static library project either because all 3 projects include the same static library project, because the .xcodeproj is shared between the 3 apps (ie the .xcodeproj is dragged & dropped onto the app project; I'm not using a workspace).
I understand one issue is that the static library being a dependent target it is built first before the app target is even considered. So perhaps there's some way to make that decision which app the library is built for based on other conditionals (ie checking for a file, or including an optional app-specific header).
Question: How I can create a macro or otherwise perform conditional compilation based on macros/settings defined by the app target which are then adhered to by the static library project?
The first, simplest approach, is to get rid of the static library, and just include the source files directly into the dependent projects. I often find that intermediate static libraries are much more trouble than they're worth. Their one big benefit comes when they provide a significant build-performance improvement, but they can't here since you're rebuilding the static library for every final target anyway.
I will say that the use of a type #defines almost always makes me cry, and may suggest a design flaw that could be better handled. For instance, you may want to implement methods that return the class required (the way UIView layerClass does). Pre-processor trickery that changes type definitions can lead to extremely subtle bugs. (I just chased down a case of this last year… it was a horrible, horrible crash to figure out.)
That said, another approach for certain versions of this problem can be solved with xcconfig files. For example, if there are actually multiple copies of the static library (i.e. this is a library that is commonly copied into other projects), then you can use an xcconfig file that has an #include "../SpecialTypeDefs.xcconfig". That file would be provided by each project to set special declarations. Failure to define that file would lead to a complier error, so it's easy to not have an error.
But personally, I'd just include the files into the actual project directly and skip the library unless they're really enormous.

isMemberOfClass with static library linked twice

I'm working on few plugins for Quartz Composer, that all link to the same custom static library copied for each of them in the bundles frameworks folder. The plugins could be used separately, so I have to distribute the library in each plugin.
Everything goes well, apart from the isMemberOfClass and isKindOfClass methods. I read here that importing twice the same classes could be the origin of the problem.
I have no error at compilation.
Let's say that I have 2 plugins (NSBundles) that contains the lib XCode project and compile it before linking to it.
They both copy the lib in their resources folder.
Then, they both instantiate a custom hOzPolygon2D class from that library.
The first plugin return true to the test of the hOzPolygon2D object with isMemberOfClass method.
The second return false.
isKindOfCLass method returns the same "error".
I can't imagine a solution in my case. I'm really not a compilation professional and would really appreciate some help.
You should distribute the static library separately (possibly as its own framework). From the question title I assume you're seeing duplicate symbol errors from the linker. If you statically link the same static library into multiple other libraries and then try to link an application to more than one of those libraries you're bound to see these duplicate symbol issues. I haven't actually tried this with frameworks, but I know of this issue from linking iOS apps against interdependent static libraries.
You shouldn't worry about the fact that the modules can be used separately. Just make sure your users can also get the base library. This is a normal situation. For example AppKit and UIKit depend on Foundation, but neither of them actually contains a copy of Foundation.

ObjC: How to compile static library that includes optional classes that depend on a third party library

I'm trying to find the best way to package a static library(lets call it Lib1) that includes an optional class(say, ClassA), which itself requires a second static library(Lib2). In other words, Lib2 is only needed if ClassA is referenced in the project's code. Things seem to work fine, unless Lib1 is used in a project that doesn't use ClassA(and hence does not include Lib2), but requires the -ObjC linker flag(because of other project dependencies, not mine).
I'm trying to come up with a an easy solution for the following three scenarios:
1) project includes my static lib, does NOT use the optional class, does not specify the -ObjC flag
2) project includes my static lib, does NOT use the optional class, but requires -ObjC flag
3) project includes my static lib + second static library, and DOES use the optional class (we don't care about the -ObjC flag at this point)
Is there a linker flag out there to strip my optional class out of the final project app so that it doesn't require the second static lib? I guess my other alternatives are to release multiple versions of my static lib, one that includes the option class(the standard choice), one that does not(the alternate, for projects with -ObjC requirements), or maybe supply a stub file, that supplies empty implementations of all the classes needed from the second static library? This seems like it could be a common problem in the static library world... is there a best practice for this scenario?
Thanks!
Solution:
1) Suggest to my -ObjC users that they use -force_load instead. (thanks Rob!)
2) For users that can't do 1, I'll have a alternate build that does not include ClassA
The best practice is always to have the final binary link all the static libs required. You should never bundle one static library into another. You should absolutely never bundle a well-known (i.e. open-source) static library into a static library you ship. This can create incredible headaches for the final consumer because they can wind up with multiple versions of the same code. Tracking down the bugs that can come from this is insanely difficult. If they're lucky, they'll just get confusing compiler errors. If they're unlucky, their code will behave in unpredictable ways and randomly crash.
Ship all the static libraries separately. Tell your clients which ones they need to link for various configurations. Trying to avoid this just makes their lives difficult.
Some other discussions that may be useful:
Duplicate Symbol Error: SBJsonParser.o? (Example of a customer who ran into a vendor doing this to him)
Linking static libraries, that share another static library
Why don't iOS framework dependencies need to be explicitly linked to a static library project or framework project when they do for an app project?
The -ObjC flag should be preventing the automatic stripping of ClassA entirely, whether its used or not (see TN1490 for more details).
If ClassA is never used except in certain circumstances and you want to save space, you should probably move ClassA into its own static library. Or use #ifdef to conditionally compile it.
Alternately, you can remove the -ObjC flag and use -force_load to individually load any category-only compile units (which is the problem -ObjC is used to address).