pod install installation process

Posted by rashpal on Mon, 20 Dec 2021 10:29:13 +0100

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:

    1. Both component A and component B depend on component C, which is a static library, such as Weibo_SDK

    2. 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:

      1. podspec sets s.static_framework = true
      2. podspec with s.dependency 'xxx_ The SDK relies on the static library xxx_SDK
      3. 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

  1. Modify podspec in pod library and add pod_target_xcconfig, define FRAMEWORK_SEARCH_PATHS and OTHER_LDFLAGS two environment variables;
  2. hook verify_no_static_framework_transitive_dependencies method, kill it! Corresponding issue
  3. 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

Topics: Ruby Back-end