pod install installation process
Let's take a look at the install portal first
Enter which pod on the command line to find the directory where the pod command is located
➜ [/Users] ✗ open /usr/local/bin/pod ➜ [/Users] ✗ open /usr/local/bin
According to the path, we open the script of pod. We can see that this script is used to evoke CocoaPods. The process is to use gem activate_ bin_ Path find the installation directory of CocoaPods cocoapods/bin, and then use gem bin_ Path to load the / pod file in the directory. Then we open the pod file and see Pod:: command Run (argv), and finally enter install through the run method under pod.
#!/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/bin/ruby # # This file was generated by RubyGems. # # The application 'cocoapods' is installed as part of a gem, and # this file is here to facilitate running it. # require 'rubygems' version = ">= 0.a" str = ARGV.first if str str = str.b[/\A_(.*)_\z/, 1] if str and Gem::Version.correct?(str) version = str ARGV.shift end end if Gem.respond_to?(:activate_bin_path) load Gem.activate_bin_path('cocoapods', 'pod', version) else gem "cocoapods", version load Gem.bin_path("cocoapods", "pod", version) end //Part of the code below the Pod file require 'cocoapods' if profile_filename = ENV['COCOAPODS_PROFILE'] require 'ruby-prof' reporter = case (profile_extname = File.extname(profile_filename)) when '.txt' RubyProf::FlatPrinterWithLineNumbers when '.html' RubyProf::GraphHtmlPrinter when '.callgrind' RubyProf::CallTreePrinter else raise "Unknown profiler format indicated by extension: #{profile_extname}" end File.open(profile_filename, 'w') do |io| reporter.new(RubyProf.profile { Pod::Command.run(ARGV) }).print(io) end else Pod::Command.run(ARGV) end
(1) Preparation for install – prepare
Complete the environment preparation of pod install, including version consistency, directory structure, and take out all pre install plug-in loading scripts, and execute the corresponding pre_install hook.
def prepare # If it is detected that the current directory is Pods, raise terminates directly if Dir.pwd.start_with?(sandbox.root.to_path) message = 'Command should be run from a directory outside Pods directory.' message << "\n\n\tCurrent directory is #{UI.path(Pathname.pwd)}\n" raise Informative, message end UI.message 'Preparing' do # If the CocoaPods major version of the lock file is different from the current version, the xcodeproj project file will be updated with the configuration of the new version deintegrate_if_different_major_version # Create a subdirectory structure for the sandbox(Pods) directory sandbox.prepare # Check whether the PluginManager has a pre install plugin ensure_plugins_are_installed! # Execute all hooks methods of pre install in the plug-in run_plugins_pre_install_hooks end end
(2) resolve_dependencies
The dependency resolution process is through Podfile and Podfile Lock and the manifest in the sandbox generate analyzer objects. Analyzer will use Molinillo (specifically Molinillo::DependencyGraph algorithm) to parse a dependency table.
(1) Many dependency information can be obtained through Analyzer, such as the dependency analysis results of Podfile files, or from specs_by_target to view specs related to each target.
(2) There is a pre in the analyze process_ The download phase, that is, the Fetching external sources process seen under – verbose. This pre_ The download phase is not a dependency download process, but in the current dependency analysis phase.
def resolve_dependencies # Get Sources plugin_sources = run_source_provider_hooks # Create an Analyzer analyzer = create_analyzer(plugin_sources) # If with repo_update tag UI.section 'Updating local specs repositories' do # Perform the update Repo operation of Analyzer analyzer.update_repositories end if repo_update? UI.section 'Analyzing dependencies' do # Get the latest analysis results from analyzer, @ analysis_result,@aggregate_targets,@pod_targets analyze(analyzer) # Spelling errors, degradation recognition, white list filtering validate_build_configurations end # If deployment? If it is true, it will verify whether the podfile & lockfile needs to be updated UI.section 'Verifying no changes' do verify_no_podfile_changes! verify_no_lockfile_changes! end if deployment? analyzer end
(3) Download dependencies – download_dependencies
Execute install first_ Pod_ Sources procedure, which will call the install of the corresponding Pod! Method to download resources; Then execute the pre install hooks defined by podfile, and finally clean up the pod sources information according to the configuration, mainly the useless platform related content
def download_dependencies UI.section 'Downloading dependencies' do # Download and install the documentation and clean up the source code of the Pod that needs to be installed install_pod_sources # Run pre with specs and Podfile installed_ Install hook. run_podfile_pre_install_hooks #Clean up pod source clean_pod_sources end end
(4) Validate targets – validate_targets
Verify the legitimacy of the products (targets generated by pod) in the previous process
def validate_targets #Construct TargetValidator validator = Xcode::TargetValidator.new(aggregate_targets, pod_targets, installation_options) #It is used to verify whether the provided aggregation and pod are correct. Otherwise, an error will be reported validator.validate! end def validate! verify_no_duplicate_framework_and_library_names verify_no_static_framework_transitive_dependencies verify_swift_pods_swift_version verify_swift_pods_have_module_dependencies verify_no_multiple_project_names if installation_options.generate_multiple_pod_projects? end
The validate method is used to verify whether the provided aggregation and pod are correct. Otherwise, an error is reported. The following is an introduction to the five functions in the method
- verify_no_duplicate_framework_and_library_names
Verify whether there is a framework with the same name. If there is a conflict, the framework with conflicting names exception will be thrown directly.
- verify_no_static_framework_transitive_dependencies
Verify whether there are static link library (. a or. framework) dependencies in the dynamic library. If they exist, transitional dependencies that include static binaries will be triggered Wrong. Suppose the following scenarios exist:
-
-
Both component A and component B depend on component C, which is a static library, such as Weibo_SDK
-
Component A depends on component B, while component B is independent When the following settings exist in the podspec file, component B will be judged as having static library dependencies:
-
- podspec sets s.static_framework = true
- podspec with s.dependency 'xxx_ The SDK relies on the static library xxx_SDK
- podspec as s.vendor_ libraries = 'libxxx. The static library libxxx is embedded in the a 'mode
-
At this point, if the project's Podfile is set to use_framework! This error is triggered when a is packaged as a dynamic link.
Cause of problem
Use is not used in Podfile_ frameworks! When, each pod will generate a corresponding a (static link library) file, and then manage pod code through static libraries. When Linked, it will include. A files of other pods referenced by the pod. When using use_frameworks! In Podfile, it will generate corresponding. Framework files, and then manage pod code through dynamic frameworks. When Linked, it will include other pods referenced by the pod D Framework file. In the above scenario, although the B component is referenced in the form of framework, the B component is actually a static library and needs to be copied and Linked to the pod. However, the dynamic framework does not do so, so an error is reported.
Solution
- Modify podspec in pod library and add pod_target_xcconfig, define FRAMEWORK_SEARCH_PATHS and OTHER_LDFLAGS two environment variables;
- hook verify_no_static_framework_transitive_dependencies method, kill it! Corresponding issue
- Modify the podspec in the pod library and turn on static_framework configuration s.static_framework = true
- verify_swift_pods_swift_version
Ensure that the Swift versions of the Swift Pod are correctly configured and compatible with each other.
- verify_swift_pods_have_module_dependencies
Check whether the dependent libraries of Swift library support module. The module here is mainly for Objective-C library. First, Swift naturally supports the module system to manage code. The Swift Module is built on LLVM Module Module system above. After parsing, Swift library will generate corresponding modulemap and umbrella H file, which is the standard configuration of LLVM Module. Similarly, Objective-C supports LLVM Module. When we introduce the Objective-C Library in the way of Dynamic Framework, Xcode supports configuring and generating header s, while static libraries a needs to write the corresponding umbrella H and modulemap. Secondly, if your Swift Pod relies on the Objective-C library and wants to package the Swift Pod in the form of static links, you need to ensure that the Objective-C library is enabled with modular_headers, so CocoaPods will generate corresponding modulemap and umbrella for us H to support LLVM Module. You can get it from this address- http://blog.cocoapods.org/CocoaPods-1.5.0/ See more details.
- verify_no_pods_used_with_multiple_swift_versions
Check whether there is a version consistency problem in all pod targets.
(5) Build project -- Integrate
This is the last step of pod install. It organizes all components after arbitration in the previous version in the form of Project files, and makes some user specified configurations in the Project.
def integrate #Execute pre in the installed specs and podfile_ Integrate hook run_podfile_pre_integrate_hooks # Generates the Xcode project(s) that go inside the `Pods/` directory. generate_pods_project if installation_options.integrate_targets? integrate_user_project else UI.section 'Skipping User Project Integration' end end
(6) Write dependencies – write_lockfiles
Write dependent updates to podfile Lock and manifest lock
def write_lockfiles @lockfile = generate_lockfile UI.message "- Writing Lockfile in #{UI.path config.lockfile_path}" do # No need to invoke Sandbox#update_changed_file here since this logic already handles checking if the # contents of the file are the same. @lockfile.write_to_disk(config.lockfile_path) end UI.message "- Writing Manifest in #{UI.path sandbox.manifest_path}" do # No need to invoke Sandbox#update_changed_file here since this logic already handles checking if the # contents of the file are the same. @lockfile.write_to_disk(sandbox.manifest_path) end end
(7) End callback – perform_post_install_action
The final work of install is to provide post installation operation and hook for all plug-ins.
def perform_post_install_actions #Execute the hook of post install in the installed specs and podfile run_plugins_post_install_hooks # Prints a warning for any pods that are deprecated warn_for_deprecations # Prints a warning for any pods that included script phases warn_for_installed_script_phases # Prints a warning if the project is not explicitly using the git based master specs repo. warn_for_removing_git_master_specs_repo print_post_install_message end
reference resources: https://www.zhihu.com/people/tu-tu-edmondmu/posts