Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static Library using frameworks in specific projects

Tags:

I have created a static library containing all my generic classes. Some of these classes use frameworks.

Now I have two projects, one that uses some classes that use frameworks, and one that doesn't use any of the classes that use frameworks.

Because Static Libraries don't support including frameworks (if I am correct). I have to include the frameworks in the project that uses them. But when I compile the project that doesn't use any of the framework-classes the compiler breaks because it still requires the frameworks. Now I know it tries to compile all the (unused) classes from the library because I use the Linker Flag '-ObjC' to prevent 'unrecognized selector' errors.

Does anyone know how to compile only the required source files per project? And prevent from all frameworks having to be included in all projects that use my static library?

like image 304
Thizzer Avatar asked May 15 '11 14:05

Thizzer


People also ask

What is the difference between static library and framework?

Static frameworks contain a static library packaged with its resources. Dynamic frameworks contain the dynamic library with its resources. In addition to that, dynamic frameworks may conveniently include different versions of the same dynamic library in the same framework!

When should I use static library?

If you have a lot of files, multiple copies of a static library means an increase in the executable file's size. If, however, the benefits of execution time outweigh the need to save space, the static library is the way to go.

What is difference between framework and static library iOS?

Libraries and frameworks are basic building blocks for creating iOS and macOS programs. Libraries are collections of code and data, while frameworks are hierarchial directories with different kinds of files, including other libraries and frameworks. Based on how libraries are linked, they can be static or dynamic.

Is XCFramework static or dynamic?

An XCFramework can be either static or dynamic and can include headers.


2 Answers

First of all, you are right in that a static library cannot include any framework nor other static libraries, it is just the collection of all object files (*.obj) that make up that specific static library.

Does anyone know how to compile only the required source files per project?

The linker will by default only link in object files from the static library that contain symbols referenced by the application. So, if you have two files a.m and b.m in your static library and you only use symbols from a.m in your main program, then b.o (the object file generated from b.c) will not appear in your final executable. As a sub-case, if b.m uses a function/class c which is only declared (not implemented), then you will not get any linker errors. As soon as you include some symbols from b.m in your program, b.o will also be linked and you will get linker errors due to the missing implementation of c.

If you want this kind of selection to happen at symbol rather than at object level granularity, enable dead code stripping in Xcode. This corresponds to the gcc option -Wl,-dead_strip (= linker option -dead_strip in the Build settings Info pane for your project). This would ensure further optimization.

In your case, though, as you correctly say, it is the use of the "-ObjC" linker flag that defeats this mechanism. So this actually depends on you. If you remove the -Objc flag, you get the behavior you like for free, while losing the stricter check on selectors.

And prevent from all frameworks having to be included in all projects that use my static library?

Xcode/GCC support an linking option which is called "weak linking", which allows to lazily load a framework or static library, i.e., only when one of its symbols is actually used. "weak linking" can be enabled either through a linker flag (see Apple doc above), or through Xcode UI (Target -> Info -> General -> Linked Libraries).

Anyhow, the framework or library must be available in all cases at compile/link time: the "weak" option only affects the moment when the framework is first loaded at runtime. Thus, I don't think this is useful for you, since you would need anyway to include the framework in all of your projects, which is what you do not want.

As a side note, weak_linking is an option that mostly make sense when using features only available on newer SDK version (say, 4.3.2) while also supporting deployment on older SDK versions (say, 3.1.3). In this case, you rely on the fact that the newer SDK frameworks will be actually available on the newer deployment devices, and you conditionally compile in the features requiring it, so that on older devices they will not be required (and will not produce thus the attempt at loading the newer version of the framework and the crash).


To make things worse, GCC does not support a feature known as "auto-linking" with Microsoft compilers, which allow to specify which library to link by means of a #pragma comment in your source file. This could offer a workaround, but is not there.


So, I am really sorry to have to say that you should use a different approach that could equally satisfy your needs:

  1. remove the -ObjC flag;

  2. split your static library in two or more parts according to their dependencies from external frameworks;

  3. resort to including the source files directly.

like image 162
sergio Avatar answered Oct 20 '22 00:10

sergio


Abour second part of your question, you can mark a linked framework as Optional : Optional framework

About first part, it is not clear to me what you intend to do:

  • A library being declared in a project
  • A project declaring which files are compiled (via Target > Build phases > Compile sources)
  • Unless setting complex build rules to include or not files, which if I remember well can be done using .xcconfig files, I don't see any other solutions than splitting your Library. Which I would recommend, for its ease. You should even do several targets in the same project... You could also just use precompiler MACROS (#ifdef...) but that depends on what you want to do.
like image 24
Vincent Guerci Avatar answered Oct 20 '22 00:10

Vincent Guerci