preface
Review the past to learn new, review the compilation principle knowledge, can gain new understanding.
This article is from a problem encountered in the past, the export of ipA error as follows:
This article is the result of a review of some of the gains made during the settlement process.
Key words:Preprocess, compile, assemble, link, dynamic link library, static link library.
The body of the
Compilation and linking process
When we compile, we will go through the process of preprocessing, compiling, assembling and linking. This is plain C code:
#include <stdio.h>
int main()
{
puts("It's OK.");
return 0;
}
Copy the code
Use GCC to compile the above code, the whole compilation process is as follows:
This process requires several GCC instructions to handle:
- 1. Pretreatment
gcc -E test.c -o test.i
Copy the code
- 2, compile,
gcc -S test.i -o test.s
Copy the code
- 3, assembly
gcc -c test.s -o test.o
Copy the code
- 4, links,
gcc test.o -o test
Copy the code
Instructions to explain
-E Only run the preprocessor
-S Only run preprocess and compilation steps
-c Only run preprocess, compile, and assemble steps
-o <file> Write output to <file>
Static and dynamic links
1. Static links
Static linking is linking files in the static linking library (.a file) to executable files.
A file is a combination of multiple. O files. .o files are object files that contain machine instructions; Links are multiple. O files packaged into executable files;
2. Dynamic linking
Dynamic linking refers to adding related description files into the executable file and dynamically loading the corresponding dynamic link library during execution.
3. Link process
The linking process, symbol relocation. The compilation of C/C ++ programs is carried out in the unit of files, so each C/CPP file is also called a translation unit. The source file is first compiled into one object file, and then the linker combines these object files into an executable file or library. Its core work is to solve the problem of mutual reference of various symbols (variables, functions) between modules. The essence of symbol reference is to reference its specific address in memory, so determining symbol address is an indispensable work in the process of compilation, linking and loading, which is the so-called symbol relocation. Essentially, symbol relocation addresses the problem of how the current compilation unit accesses “external” symbols.
This section refers to the implementation principle of dynamic linking in Linux, and has a more detailed introduction of the principle.
IOS related
The following figure shows the setup of Xcode project. Next, step by step, analyze each key configuration.
The first isEmbedded BinariesTwo libraries of,GPUImage.framework
andlib.framework
.
These two are dynamic libraries, and the framework content format is as follows
Next is the Linked Frameworks and Libraries dependency, libstdc++.6.tbd. TBD is an optimized version of Dylib. The official explanation is as follows:
the .tbd files are new “text-based stub libraries”, that provide a much more compact version of the stub libraries for use in the SDK, and help to significantly reduce its download size
Libxg-sdk. a is a static link library provided by CocoaPods, libxxx. framework and gpuimage. framework are the framework and gpuimage. libPods-live. a is a static link library generated and managed by CocoaPods.
In Build Phases, the Check Pods manifest. lock script checks podfile. lock and manifest. lock for differences. Deciding whether to re-pod install Embed Pods Frameworks and Copy Pods Resources are the other two scripts
Troubleshoot problems
After understanding the basic setup of the project, let’s locate the problem mentioned earlier.
Archive -> Export -> Ad HocFound an unexpected Mach-O header code
.
Click show Logs, then select standard.log
The log description isdid not contain a "archived-expanded-entitlements.xcent" resource
.
This question has also been asked on StackOverflow, but not in my case. Stackoverflow suggests this: Go to BUILD PHASES -> COPY BUNDLE RESOURCES, you will find there some framework. Remove from this section and add it to LINK BINARY WITH LIBRARIES. It will work..
A review of the project’s Settings shows that a colleague has added a static library to the Embedded Binaries TAB. Static libraries cannot be packaged into the IPA. (The code in the static library is compiled and linked to the executable, and the resource files need to be repackaged into a bundle and put into the IPA package)
🤔 : CocoaPods third-party libraries include UI resources, but we know that. A file does not include resources, so how to handle third-party library resources?
Static and dynamic libraries
Use several test samples and test projects to better understand dynamic and static libraries. This paper introduces the test project and how to test it: Project P is the main project, and there are four sub-projects A, B, C and D. The libraries packed by the sub-projects are dynamic libraries or static libraries, and there are dependencies between the sub-projects. Test the dependence of dynamic library on static library, static library on dynamic library, static library on static library by modifying the dependency library of the main project, and the dependency relationship and packaging type of the sub-project.
Before testing, let’s briefly explain the packaging methods of static and dynamic libraries, as shown below
-
When Cocoa Touch Framework is selected, if Mach -o Type is Static, the Framework file is a Static library. If mach-o Type is Dynamic, the packaged. Framework file is a Dynamic library.
-
When Cocoa Touch Static Library is selected, the packaged.a file is the Static Library.
Static libraries depend on static libraries
The test environment static libraries A, B, and C are all packaged using Cocoa Touch Framework.
- Static library A: provides function foo();
- Static library B: provides call_foo_b(); Rely on static library A to call foo() in call_foo_b;
- Static library C: provides function foo();
The test code is as follows
#include "BLib.h"
#include "CLib.h"
- (void)testLib {
NSLog(@"Test A.");
call_foo_b();
NSLog(@"Test B.");
foo();
}
Copy the code
Test result output:
2016-12-20 09:54:12.931731 testLib[7671:4787567] Test A.
call_foo in BLib.
foo in ALib.
2016-12-20 09:54:12.931925 testLib[7671:4787567] Test B.
foo in ALib.
Copy the code
For TestA, we call call_foo_B of B and then foo of A from call_foo_B, printing the order of calls B->A as expected. For TestB, we import C’s header file, and then call C’s foo, printing the order of the calls to A, and the result is abnormal;
Results 🤔 static library generation only compile, no link; When the project exists in libraries A and C, the function symbols in foo are first introduced when linking. The verification method is to change the project dependency order from ABC to CBA, and the output becomes:
2016-12-20 10:19:28.613791 testLib[7691:4795943] Test a. call_foo in blib.foo in clib.2016-12-20 10:19:28.613871 testLib[7691:4795943] Test B. foo in CLib.Copy the code
Static libraries depend on dynamic libraries
The test environment
Libraries A, B, C, and D are all packaged as Cocoa Touch Framework.
* Dynamic library A: provides function foo();
* Static library B: provides call_foo_b(); Rely on dynamic library A to call foo() in call_foo_b;
* Dynamic library C: provides function foo();
Static library D: provides call_foo_d(); Rely on dynamic library C to call foo() in call_foo_d;
The test code
#include "BLib.h"
#include "DLib.h"
- (void)testLib {
NSLog(@"Test lib.");
call_foo_b();
call_foo_d();
}
Copy the code
The test results
[777:4799800] Test lib [777:4799800] Test lib
call_foo in BLib. foo in ALib. call_foo in DLib. foo in ALib.
- For the first set of tests, we call call_foo_B from static library B and call dynamic library A from call_foo_B, fine.
- For the second set of tests, we call call_foo_d from static library D and call dynamic library A from call_foo_d, exception; (Supposedly calling dynamic library C functions)
Results 🤔 static library generation only compile, no link; So in the process of generating static library D, it only confirms that static library D needs to use function foo in dynamic library; When run, dynamic libraries A and C are loaded, two of which contain foo functions. The dynamic linker fetchers function foo from dynamic library A in the order it was loaded; So the foo function called by static library B and D is the foo function in dynamic library A.
Verify: Switch the Link Binary With Libraries where A and C are located
TestLib [7705:4799491] Test lib.call_foo in blib.foo in clib.call_foo in lib.foo in CLib.Copy the code
Dynamic libraries depend on static libraries
The test environment libraries A, B, C, and D are all packaged using Cocoa Touch Framework.
- Static library A: provides function foo();
- Dynamic library B: provides call_foo_b(); Rely on static library A to call foo() in call_foo_b;
- Static library C: provides function foo();
- Dynamic library D: provides call_foo_d(); Rely on static library C to call foo() in call_foo_d;
The test code
#include "BLib.h"
#include "DLib.h"
- (void)testLib {
NSLog(@"Test lib.");
call_foo_b();
call_foo_d();
}
Copy the code
The test results
2016-12-20 11:08:52.715415 testLib[7746:4810080] Test lib.call_foo in blib.foo in alib.call_foo in lib.foo in CLib.Copy the code
- For the first set of tests, we call call_foo_B from dynamic library B and call_foo_B from static library A, fine;
- For the second set of tests, we call call_foo_d from dynamic library D and call_foo_d from static library C, normal;
Results: there are only dynamic libraries B and D in 🤔 project dependency, but no static libraries A and C. Static library A and C functions with the same name foo do not conflict; The reason for these two phenomena is that in the process of dynamic library generation, in addition to compilation, there is also a linking process. If the dynamic library depends on the static library, the static library code is merged into the dynamic library when the dynamic library is generated.
If the function names of dynamic Libraries B and D are the same as call_foo, the order of calls is the same as Link Binary With Libraries, not the order of embeded calls. (Embeded simply puts dynamic libraries into bundles; the key is the order of the linkers.)
Dynamic libraries depend on dynamic libraries
The test environment dynamic libraries A, B, C, and D are all packaged using Cocoa Touch Framework.
- Dynamic library A: provides function foo();
- Dynamic library B: provides call_foo_b(); Rely on dynamic library A to call foo() in call_foo_b;
- Dynamic library C: provides function foo();
- Dynamic library D: provides call_foo_d(); Rely on dynamic library C to call foo() in call_foo_d;
The test code
#include "BLib.h"
#include "DLib.h"
- (void)testLib {
NSLog(@"Test lib.");
call_foo_b();
call_foo_d();
}
Copy the code
The test results
2016-12-20 11:08:52.715415 testLib[7746:4810080] Test lib
call_foo in BLib. foo in ALib. call_foo in DLib. foo in CLib.
- For the first set of tests, we call call_foo_B from dynamic library B and foo from dynamic library A from call_foo_B, fine.
- For the second set of tests, we call call_foo_d from dynamic library D and foo from dynamic library C from call_foo_d, fine.
Results 🤔 all four dynamic libraries need Link and Embeded; Unlike the test example where static libraries depend on dynamic libraries, this time the dynamic libraries A and C have functions with the same name, foo, but are called without conflict. Dynamic libraries depend on dynamic libraries and are not merged into dynamic libraries when generating dynamic libraries.
Dependencies between static and dynamic libraries
Static library generation is only compiled, not linked; Dynamic library generation in addition to compilation and link process; If the dynamic library depends on the static library, the static library code will be merged into the dynamic library when the dynamic library is generated.
- Static library A depends on static library B. When using static Libraries, you need to import static Libraries A and B into Link Binary With Libraries.
- Static library A depends on dynamic library B. When using static library A and dynamic library B, we need to introduce static library A and dynamic library Bin Link Binary With Libraries and dynamic library Bin Embeded Binaries.
- Dynamic library A depends on static library B and needs to be imported into Link Binary With Libraries and Embeded Binaries.
- Dynamic library A depends on dynamic library B. When using dynamic library A and B, we need to import dynamic Libraries A and Bin Link Binary With Libraries and in Embeded Binaries.
All the code can be found here.
Extension -Cocoa Touch Static Library packaging
Cocoa Touch Static Library Cocoa Touch Static Library Cocoa Touch Static Library Cocoa Touch Static Library Cocoa Touch Static Library Cocoa Touch Static Library
How do I package a static library without including its dependent library files?
Simply introduce a dependency library header file, because static libraries are compiled and not linked. (But if Cocoa Touch Static Library is filled with third-party Static libraries, it will be automatically packaged.)
Both. A and. Framework are static library formats, but the. Framework format includes static library files, header files, and resource files, so it is easier to use.
How to use the.a static library directly, without the static library header file?
Link Binary With Libraries add a static library.
Add declarations before functions that use static libraries, but do not define implementations; At compile time, the definition is looked up globally based on the declaration;
conclusion
In the process of writing the article, I briefly reviewed the compilation principle, and felt that the programmer’s skill tree is too large, just one branch is enough to learn for a lifetime. When I encounter problems in development, I am used to asking questions. This time, I will simply connect these knowledge and combine them with the project to deepen my memory. Please point out any omissions in the article.