fastlane-plugin-analyze_ios_linkmap 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,38 @@
1
+ module Fastlane
2
+ UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
3
+ module Helper
4
+ module LinkMap
5
+ require_relative 'analyze_ios_file_helper'
6
+
7
+ # Dead Stripped Symbols:
8
+ # Size File Name
9
+ # <<dead>> 0x00000030 [ 26] ___destroy_helper_block_e8_32s40s48s
10
+ # <<dead>> 0x00000008 [ 26] ___copy_helper_block_e8_32s
11
+ # <<dead>> 0x00000008 [ 26] ___destroy_helper_block_e8_32s
12
+
13
+ class DeadStrippedSymbol
14
+ attr_accessor(:size, :file, :name, :invalid) #=> file 并不是【文件名】, 而是【文件 id】
15
+
16
+ def initialize(line)
17
+ if line =~ %r(^<<dead>>\s+0x(.+?)\s+\[(.+?)\]\w*)
18
+ @size = $1.to_i(16)
19
+ @file = $2.to_i
20
+ @invalid = false
21
+ else
22
+ @invalid = true
23
+ # UI.error "#{line.inspect} can not match symbol regular"
24
+ end
25
+ end
26
+
27
+ def to_hash
28
+ {
29
+ size: @size,
30
+ format_size: FileHelper.format_size(@size),
31
+ file: @file,
32
+ name: @name
33
+ }
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,7 @@
1
+ require_relative 'analyze_ios_file_helper'
2
+ require_relative 'linkmap_library'
3
+ require_relative 'linkmap_segment'
4
+ require_relative 'linkmap_section'
5
+ require_relative 'linkmap_object_file'
6
+ require_relative 'linkmap_dead_stripped_symbol'
7
+ require_relative 'linkmap_symbol'
@@ -0,0 +1,55 @@
1
+ module Fastlane
2
+ UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
3
+ module Helper
4
+ module LinkMap
5
+ require_relative 'analyze_ios_file_helper'
6
+
7
+ #
8
+ # Linkmap.txt 结构中, 并没有这种结构, 自己抽象出的
9
+ #
10
+
11
+ class Library
12
+ attr_accessor(:name, :size, :object_files, :dead_symbol_size, :podspec_name)
13
+
14
+ def initialize(options = {})
15
+ @name = options[:name]
16
+ @size = options[:size]
17
+ @object_files = options[:object_files]
18
+ @dead_symbol_size = options[:dead_symbol_size]
19
+ @podspec_name = options[:podspec_name]
20
+ end
21
+
22
+ def to_hash(all_objects)
23
+ #
24
+ # ─── FIX pod spec name ───────────────────────────────────────────────────────────
25
+ #
26
+ # <podspec name> ==> <library name>
27
+ #
28
+ # "AsyncSwift": "Async",
29
+ # "Light-Untar": "Light_Untar",
30
+ # "UIAlertView-Blocks": "UIAlertView_Blocks",
31
+ # "UIDevice-Hardware": "UIDevice_Hardware",
32
+ # "Yoga": "yoga",
33
+ # "lottie-ios": "Lottie"
34
+ #
35
+ podspec_name = if @podspec_name
36
+ @podspec_name # => 优先使用 podspec_name
37
+ else
38
+ @name # => 如果【没有】podspec_name, 就使用 library_name 作为 podspec_name
39
+ end
40
+
41
+ h = {
42
+ name: @name,
43
+ size: @size,
44
+ format_size: FileHelper.format_size(@size),
45
+ dead_symbol_size: @dead_symbol_size,
46
+ format_dead_symbol_size: FileHelper.format_size(@dead_symbol_size),
47
+ podspec_name: podspec_name
48
+ }
49
+ h[:object_files] = @object_files if all_objects
50
+ h
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,143 @@
1
+ module Fastlane
2
+ UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
3
+ module Helper
4
+ module LinkMap
5
+ require_relative 'analyze_ios_file_helper'
6
+
7
+ # Object files:
8
+ # ..........
9
+ # [ 12] /Users/xiongzenghui/App/Pods/BangcleCryptoTool/BangcleCryptoTool/libs/libbangcle_crypto_tool.a(lsm4.o)
10
+ # ..........
11
+ # [ 25] /Users/xiongzenghui/App/Pods/AFNetworking/AFNetworking.framework/AFNetworking(AFHTTPSessionManager.o)
12
+ # ------------------------------------------------------------------------------
13
+ # @param index : 25、26、...、31
14
+ # @param filename : AFHTTPSessionManager.o
15
+ # @param library : 所属 静态库 文件名
16
+ # @param framework : 如果 静态库 是 xx.framework 形态的, 则获取其 framework 名字
17
+ # @param symbols : 这个 AFHTTPSessionManager.o 包含的所有的 symbol 对象
18
+ # @param size : 所有符号的总大小
19
+ # @param dead_symbol_size: strip 掉的符号总大小
20
+ #
21
+
22
+ OBJECT_FILE_TYPE_USER_LIBRARY = 0
23
+ OBJECT_FILE_TYPE_OTHERS = 1
24
+ OBJECT_FILE_TYPE_SYSTEM = 2
25
+
26
+ class ObjectFile
27
+ attr_accessor(:index, :file_name, :library, :framework, :symbols, :size, :dead_symbol_size)
28
+ alias framework? framework
29
+
30
+ def initialize(line, &blk)
31
+ if line =~ /\[(.*)\].*\/(.*)\((.*)\)/
32
+ # [ 5] /Users/xiongzenghui/App/Pods/BangcleCryptoTool/BangcleCryptoTool/libs/libbangcle_crypto_tool.a(aes.o)
33
+ # [ 6] /Users/xiongzenghui/App/Pods/BangcleCryptoTool/BangcleCryptoTool/libs/libbangcle_crypto_tool.a(crypto.o)
34
+ # [ 7] /Users/xiongzenghui/App/Pods/BangcleCryptoTool/BangcleCryptoTool/libs/libbangcle_crypto_tool.a(des.o)
35
+ # ...............
36
+ # [ 23] /Users/xiongzenghui/App/Pods/AFNetworking/AFNetworking.framework/AFNetworking(AFAutoPurgingImageCache.o)
37
+ # [ 24] /Users/xiongzenghui/App/Pods/AFNetworking/AFNetworking.framework/AFNetworking(AFHTTPSessionManager.o)
38
+ # [ 25] /Users/xiongzenghui/App/Pods/AFNetworking/AFNetworking.framework/AFNetworking(AFImageDownloader.o)
39
+
40
+ index = $1.to_i #=> 6 , 23
41
+ library = $2 #=> libbangcle_crypto_tool.a , AFNetworking
42
+ file_name = $3 #=> crypto.o , AFAutoPurgingImageCache.o
43
+ # puts "index: #{index}"
44
+ # puts "library: #{library}"
45
+ # puts "file_name: #{file_name}"
46
+
47
+ @index = index
48
+ @file_name = file_name
49
+ @library = library
50
+ @framework = if line.include?('.framework')
51
+ true
52
+ else
53
+ false
54
+ end
55
+ @symbols = Array.new
56
+ @size = 0
57
+ @dead_symbol_size = 0
58
+
59
+ blk.call(self, OBJECT_FILE_TYPE_USER_LIBRARY)
60
+ elsif line =~ /\[(.*)\].*\/(.*)/
61
+ # [ 3] /path/to/Release-iphoneos/App.build/Objects-normal/arm64/main.o
62
+ # [100] /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/System/Library/Frameworks/UIKit.framework/UIKit.tbd
63
+ # [9742] /path/to/Pods/du.framework/du
64
+ # [8659] /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphoneos/libswiftDispatch.dylib
65
+
66
+ index = $1.to_i
67
+ file_name = $2
68
+ # puts "index: #{index}"
69
+ # puts "file_name: #{file_name}"
70
+
71
+ @index = index
72
+ @file_name = file_name
73
+ @library = if line.include?('.framework') && !file_name.include?('.') #=> /path/to/du.framework/du 【用户】动态库
74
+ file_name
75
+ else
76
+ if line.end_with?('.a') #=> \.a$ xcode 内置的 静态库
77
+ file_name
78
+ else
79
+ if file_name.end_with?('.tbd') #=> \.tbd$ iOS 系统 动态库 软链接
80
+ 'tdb'
81
+ elsif file_name.end_with?('.dylib') #=> \.dylib$ iOS 系统 动态库
82
+ 'dylib'
83
+ elsif file_name.end_with?('.o') #=> \.o$ 用户 目标文件
84
+ 'main' #=> main.o、ZHUIAutoTest.o、swift.o ... 散落在 App 工程中的 xxx.o
85
+ else
86
+ 'system'
87
+ end
88
+ end
89
+ end
90
+ @framework = if line.include?('.framework') && !file_name.include?('.')
91
+ true
92
+ else
93
+ false
94
+ end
95
+ @symbols = Array.new
96
+ @size = 0
97
+ @dead_symbol_size = 0
98
+
99
+ blk.call(self, OBJECT_FILE_TYPE_OTHERS)
100
+ elsif line =~ /\[(.*)\]\s*([\w\s]+)/
101
+ # [ 0] linker synthesized
102
+ # [ 1] dtrace
103
+
104
+ index = $1.to_i
105
+ file_name = $2
106
+ # puts "index: #{index}"
107
+ # puts "file_name: #{file_name}"
108
+
109
+ @index = index
110
+ @file_name = file_name
111
+ @library = nil
112
+ @framework = false
113
+ @symbols = Array.new
114
+ @size = 0
115
+ @dead_symbol_size = 0
116
+
117
+ blk.call(self, OBJECT_FILE_TYPE_SYSTEM)
118
+ end
119
+ end
120
+
121
+ def to_hash(all_symbols)
122
+ h = {
123
+ index: @index,
124
+ file_name: @file_name,
125
+ library: @library,
126
+ size: @size,
127
+ format_size: FileHelper.format_size(@size),
128
+ dead_symbol_size: @dead_symbol_size,
129
+ format_dead_symbol_size: FileHelper.format_size(@dead_symbol_size),
130
+ }
131
+ h[:symbols] = @symbols.map { |e| e.to_hash } if all_symbols
132
+ h
133
+ end
134
+
135
+ # ObjectFile 追加 Symbol
136
+ def add_symbol(symbol)
137
+ @symbols.push(symbol)
138
+ @size += symbol.size #=> 累加 ObjectFile 所有 Symbol 大小
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,71 @@
1
+ module Fastlane
2
+ UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
3
+ module Helper
4
+ module LinkMap
5
+ require_relative 'analyze_ios_file_helper'
6
+
7
+ # Sections:
8
+ # Address Size Segment Section
9
+ # 0x1000048A0 0x055656A8 __TEXT __text
10
+ # 0x105569F48 0x000090E4 __TEXT __stubs
11
+ # 0x10557302C 0x000079D4 __TEXT __stub_helper
12
+ # 0x10557AA00 0x002D4E1A __TEXT __cstring
13
+
14
+ class Section
15
+ attr_accessor(:name, :symbol_size, :residual_size, :start_addr, :end_addr, :segment)
16
+
17
+ def to_hash
18
+ {
19
+ name: @name,
20
+ symbol_size: @symbol_size,
21
+ format_symbol_size: FileHelper.format_size(@symbol_size),
22
+ residual_size: @residual_size,
23
+ format_residual_size: FileHelper.format_size(@residual_size),
24
+ start_addr: @start_addr,
25
+ end_addr: @end_addr,
26
+ segment: @segment
27
+ }
28
+ end
29
+
30
+ def initialize(line)
31
+ lines = line.split(' ').map(&:strip)
32
+
33
+ address = lines[0]
34
+ size = lines[1]
35
+ segment = lines[2]
36
+ section = lines[3]
37
+ # puts "address: #{address}"
38
+ # puts "size: #{size}"
39
+ # puts "segment: #{segment}"
40
+ # puts "section: #{section}"
41
+
42
+ start_addr = address.to_i(16)
43
+ residual_size = size.to_i(16)
44
+ end_addr = start_addr + residual_size
45
+ # puts "start_addr: #{start_addr}"
46
+ # puts "residual_size: #{residual_size}"
47
+ # puts "end_addr: #{end_addr}"
48
+
49
+ @name = section
50
+ @symbol_size = 0
51
+ @residual_size = residual_size
52
+ @start_addr = start_addr
53
+ @end_addr = end_addr
54
+ @segment = segment
55
+ end
56
+
57
+ # 【注意】
58
+ # `section name` may be dulicate in different segment
59
+ # 所以使用 <segment_name + section_name> 作为 map 的 key 存储
60
+ # @section_map[section.key] = section
61
+ def key
62
+ "#{segment}:#{name}".to_sym
63
+ end
64
+
65
+ def to_segment
66
+ key.to_s.split(':')[0].to_sym
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,31 @@
1
+ module Fastlane
2
+ UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
3
+ module Helper
4
+ module LinkMap
5
+ require_relative 'analyze_ios_file_helper'
6
+
7
+ #
8
+ # Linkmap.txt 结构中, 没有直接给出, 只能由【所有的 Section】累加计算得到
9
+ #
10
+ class Segment
11
+ attr_accessor(:name, :size, :residual_size)
12
+
13
+ def initialize(options = {})
14
+ @name = options[:name]
15
+ @size = options[:size]
16
+ @residual_size = options[:residual_size]
17
+ end
18
+
19
+ def to_hash
20
+ {
21
+ name: @name,
22
+ size: @size,
23
+ format_size: FileHelper.format_size(@size),
24
+ residual_size: @residual_size,
25
+ format_residual_size: FileHelper.format_size(@residual_size)
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,41 @@
1
+ module Fastlane
2
+ UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
3
+ module Helper
4
+ module LinkMap
5
+ require_relative 'analyze_ios_file_helper'
6
+
7
+ # Symbols:
8
+ # Address Size File Name
9
+ # 0x1000048A0 0x000000A4 [ 2] _main
10
+ # 0x100004944 0x00000028 [ 5] _Bangcle_WB_AES_encrypt
11
+ #
12
+
13
+ class Symbol
14
+ attr_accessor(:address, :size, :file, :name, :invalid) #=> file 并不是【文件名】, 而是【文件 id】
15
+
16
+ def initialize(line, &blk)
17
+ if line =~ %r(^0x(.+?)\s+0x(.+?)\s+\[(.+?)\]\s(.*))
18
+ @address = $1.to_i(16) #=> Address
19
+ @size = $2.to_i(16) #=> Size
20
+ @file = $3.to_i #=> File
21
+ @name = $4 #=> Name
22
+ @invalid = false
23
+ else
24
+ @invalid = true
25
+ # UI.error "#{line.inspect} can not match symbol regular"
26
+ end
27
+ end
28
+
29
+ def to_hash
30
+ {
31
+ address: @address,
32
+ size: @size,
33
+ format_size: FileHelper.format_size(@size),
34
+ file: @file,
35
+ name: @name
36
+ }
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module AnalyzeIosLinkmap
3
- VERSION = "0.1.1"
3
+ VERSION = "0.1.2"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane-plugin-analyze_ios_linkmap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - xiongzenghui
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-14 00:00:00.000000000 Z
11
+ date: 2019-12-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -147,7 +147,14 @@ files:
147
147
  - lib/fastlane/plugin/analyze_ios_linkmap.rb
148
148
  - lib/fastlane/plugin/analyze_ios_linkmap/actions/analyze_ios_linkmap_action.rb
149
149
  - lib/fastlane/plugin/analyze_ios_linkmap/helper/analyze_ios_file_helper.rb
150
- - lib/fastlane/plugin/analyze_ios_linkmap/helper/analyze_ios_linkmap_helper.rb
150
+ - lib/fastlane/plugin/analyze_ios_linkmap/helper/analyze_ios_linkmap_parser.rb
151
+ - lib/fastlane/plugin/analyze_ios_linkmap/helper/linkmap_dead_stripped_symbol.rb
152
+ - lib/fastlane/plugin/analyze_ios_linkmap/helper/linkmap_helper.rb
153
+ - lib/fastlane/plugin/analyze_ios_linkmap/helper/linkmap_library.rb
154
+ - lib/fastlane/plugin/analyze_ios_linkmap/helper/linkmap_object_file.rb
155
+ - lib/fastlane/plugin/analyze_ios_linkmap/helper/linkmap_section.rb
156
+ - lib/fastlane/plugin/analyze_ios_linkmap/helper/linkmap_segment.rb
157
+ - lib/fastlane/plugin/analyze_ios_linkmap/helper/linkmap_symbol.rb
151
158
  - lib/fastlane/plugin/analyze_ios_linkmap/version.rb
152
159
  homepage: https://github.com/xzhhe/fastlane-plugin-analyze_ios_linkmap
153
160
  licenses:
@@ -168,7 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
168
175
  - !ruby/object:Gem::Version
169
176
  version: '0'
170
177
  requirements: []
171
- rubygems_version: 3.0.4
178
+ rubygems_version: 3.0.6
172
179
  signing_key:
173
180
  specification_version: 4
174
181
  summary: iOS parse linkmap.txt to ruby Hash
@@ -1,493 +0,0 @@
1
- require 'fastlane_core/ui/ui'
2
-
3
- module Fastlane
4
- UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
5
- module Helper
6
- module LinkMap
7
- require 'pp'
8
-
9
- # Symbols:
10
- # Address Size File Name
11
- # 0x100001710 0x00000039 [ 2] -[ViewController viewDidLoad]
12
- Symbol = Struct.new(:address, :size, :object_file_id, :name)
13
-
14
- # Dead Stripped Symbols:
15
- # Size File Name
16
- # <<dead>> 0x00000018 [ 2] CIE
17
- DeadStrippedSymbol = Struct.new(:size, :object_file_id, :name)
18
-
19
- # Sections:
20
- # Address Size Segment Section
21
- # 0x100001710 0x00000333 __TEXT __text
22
- Section = Struct.new(:section, :segment, :start_addr, :end_addr, :symbol_size, :residual_size) do
23
- def key
24
- "#{segment}:#{section}".to_sym
25
- end
26
-
27
- def parse_segment
28
- key.to_s.split(':')[0].to_sym
29
- end
30
- end
31
-
32
- # Linkmap.txt 中, 没有直接给出, 只能由【所有的 Section】统计得出
33
- Segment = Struct.new(:name, :symbol_size, :residual_size)
34
-
35
- #
36
- #<FastlaneCore::Helper::LinkMap::ObjectFile:0x007ff93ec4fc90
37
- # @file_id=39,
38
- # object="ViewController.o",
39
- # @framework=false,
40
- # @library="libbangcle_crypto_tool.a",
41
- # @symbols=[
42
- # <struct FastlaneCore::Helper::LinkMap::Symbol
43
- # address=4294976749,
44
- # size=15,
45
- # object_file_id=2,
46
- # name="literal string: ViewController"
47
- # >,
48
- # <struct FastlaneCore::Helper::LinkMap::Symbol
49
- # address=4294974150,
50
- # size=12,
51
- # object_file_id=2,
52
- # name="literal string: viewDidLoad"
53
- # >
54
- # ]
55
- # >
56
- ObjectFile = Struct.new(:file_id, :object, :library, :framework, :symbols, :size, :dead_symbol_size)
57
-
58
- #
59
- # "AFNetworking"=>
60
- # <struct FastlaneCore::Helper::LinkMap::Library
61
- # name="AFNetworking",
62
- # size=0,
63
- # object_file_ids=[23,24,25,26,27,28,29,30],
64
- # dead_symbol_size=0,
65
- # pod_name="AFNetworking"
66
- # >
67
- #
68
- Library = Struct.new(:name, :size, :object_file_ids, :dead_symbol_size, :pod_name)
69
-
70
- class Parser
71
- attr_accessor(:object_map, :library_map, :section_map, :segment_map)
72
-
73
- def initialize(options)
74
- @filepath = options[:filepath]
75
- @all_symbols = options[:all_symbols]
76
-
77
- UI.user_error!("❌ #{@filepath} not pass") unless @filepath
78
- UI.user_error!("❌ #{@filepath} not exist") unless File.exist?(@filepath)
79
-
80
- @object_map = {}
81
- @library_map = {}
82
- @section_map = {}
83
- @segment_map = {} # 根据 @section_map 统计【所有的 section】得出
84
-
85
- parse
86
- end
87
-
88
- def pretty_json
89
- JSON.pretty_generate(pretty_hash)
90
- end
91
-
92
- def pretty_hash
93
- return @result if @result
94
-
95
- # sort object_map[i].ObjectFile.symbols
96
- @object_map.each do |ofid, object|
97
- next unless object.symbols
98
-
99
- object.symbols.sort! do |sym1, sym2|
100
- sym2[:size] <=> sym1[:size]
101
- end
102
- end
103
-
104
- # 计算 linkmap.txt 所有的 symbol 总大小
105
- total_size = @library_map.values.map(&:size).inject(:+)
106
- total_dead_size = @library_map.values.map(&:dead_symbol_size).inject(:+)
107
-
108
- # sort object_map[i]
109
- library_map_values = @library_map.values.sort do |a, b|
110
- b.size <=> a.size
111
- end
112
- library_map_values.compact!
113
-
114
- library_maps = library_map_values.map do |lib|
115
- pod_name = lib.name
116
- unless lib.pod_name.empty?
117
- pod_name = lib.pod_name
118
- end
119
-
120
- if @all_symbols
121
- {
122
- library: lib.name,
123
- pod: pod_name,
124
- total: lib.size,
125
- format_total: Fastlane::Helper::LinkMap::FileHelper.format_size(lib.size),
126
- total_dead: lib.dead_symbol_size,
127
- format_total_dead: Fastlane::Helper::LinkMap::FileHelper.format_size(lib.dead_symbol_size),
128
- objects: lib.object_file_ids.map do |object_file_id|
129
- # Struct.new(:file_id, :object, :library, :framework, :symbols, :size, :dead_symbol_size)
130
- object_file = @object_map[object_file_id]
131
- if object_file
132
- {
133
- object: object_file.object,
134
- symbols: object_file.symbols.map do |symb|
135
- {
136
- name: symb.name,
137
- total: symb.size,
138
- format_total: Fastlane::Helper::LinkMap::FileHelper.format_size(symb.size),
139
- }
140
- end
141
- }
142
- else
143
- nil
144
- end
145
- end
146
- }
147
- else
148
- {
149
- library: lib.name,
150
- pod: pod_name,
151
- total: lib.size,
152
- format_total: Fastlane::Helper::LinkMap::FileHelper.format_size(lib.size),
153
- total_dead: lib.dead_symbol_size,
154
- format_total_dead: Fastlane::Helper::LinkMap::FileHelper.format_size(lib.dead_symbol_size)
155
- }
156
- end
157
- end
158
-
159
- @result = {
160
- total_count: library_maps.count,
161
- total_size: total_size,
162
- format_total_size: Fastlane::Helper::LinkMap::FileHelper.format_size(total_size),
163
- total_dead_size: total_dead_size,
164
- format_total_dead_size: Fastlane::Helper::LinkMap::FileHelper.format_size(total_dead_size),
165
- librarys: library_maps
166
- }
167
-
168
- @result
169
- end
170
-
171
- def pretty_merge_by_pod_hash
172
- return @merge_by_pod_result if @merge_by_pod_result
173
-
174
- @merge_by_pod_result = {
175
- total_count: pretty_hash[:total_count],
176
- total_size: pretty_hash[:total_size],
177
- format_total_size: pretty_hash[:format_total_size],
178
- total_dead_size: pretty_hash[:total_dead_size],
179
- format_total_dead_size: pretty_hash[:format_total_dead_size]
180
- }
181
-
182
- pods = Hash.new
183
- pretty_hash[:librarys].each do |lib|
184
- apod_librarys = pods[lib[:pod]]
185
- apod_librarys ||= Array.new
186
- apod_librarys << lib
187
- pods[lib[:pod]] = apod_librarys
188
- end
189
- @merge_by_pod_result[:pods] = pods
190
-
191
- @merge_by_pod_result
192
- end
193
-
194
- def pretty_merge_by_pod_json
195
- JSON.pretty_generate(pretty_merge_by_pod_hash)
196
- end
197
-
198
- def parse
199
- # 读取 Linkmap.txt 【每一行】进行解析
200
- File.foreach(@filepath).with_index do |line, line_num|
201
- begin
202
- unless line.valid_encoding?
203
- line = line.encode("UTF-16", :invalid => :replace, :replace => "?").encode('UTF-8')
204
- end
205
-
206
- if line.start_with? "#"
207
- if line.start_with? "# Object files:" #=> 初始化 @object_map
208
- @subparser = :parse_object_files
209
- elsif line.start_with? "# Sections:" #=> 初始化 @section_map
210
- @subparser = :parse_sections
211
- elsif line.start_with? "# Symbols:" #=> 解析得到每一个 symbol 【占用】大小
212
- @subparser = :parse_symbols
213
- elsif line.start_with? '# Dead Stripped Symbols:' #=> 解析得到 dead strpped 【废弃】大小
214
- @subparser = :parse_dead
215
- end
216
- else
217
- send(@subparser, line) #=> self.func(line)
218
- end
219
- rescue => e
220
- UI.error "Exception on Link map file line #{line_num}"
221
- UI.message "Content is: "
222
- UI.message line
223
- end
224
- end
225
- # puts "There are #{@section_map.values.map{|value| value[:residual_size]}.inject(:+)} Byte in some section can not be analyze"
226
- end
227
-
228
- def parse_object_files(line)
229
- if line =~ %r(\[(.*)\].*\/(.*)\((.*)\))
230
- # Object files:
231
- # [ 5] /Users/xiongzenghui/Desktop/launching_time/osee2unified/osee2unified/Pods/BangcleCryptoTool/BangcleCryptoTool/libs/libbangcle_crypto_tool.a(aes.o)
232
- # [ 6] /Users/xiongzenghui/Desktop/launching_time/osee2unified/osee2unified/Pods/BangcleCryptoTool/BangcleCryptoTool/libs/libbangcle_crypto_tool.a(crypto.o)
233
- # [ 7] /Users/xiongzenghui/Desktop/launching_time/osee2unified/osee2unified/Pods/BangcleCryptoTool/BangcleCryptoTool/libs/libbangcle_crypto_tool.a(des.o)
234
- # ...............
235
- # [ 23] /Users/xxx/ci-jenkins/workspace/xxx-iOS-module/VenomShellProject/osee2unified/Pods/AFNetworking/AFNetworking.framework/AFNetworking(AFAutoPurgingImageCache.o)
236
- # [ 24] /Users/xxx/ci-jenkins/workspace/xxx-iOS-module/VenomShellProject/osee2unified/Pods/AFNetworking/AFNetworking.framework/AFNetworking(AFHTTPSessionManager.o)
237
- # [ 25] /Users/xxx/ci-jenkins/workspace/xxx-iOS-module/VenomShellProject/osee2unified/Pods/AFNetworking/AFNetworking.framework/AFNetworking(AFImageDownloader.o)
238
- # ...........
239
-
240
- # 1.
241
- objc_file_id = $1.to_i #=> 6 , 23
242
- library_name = $2 #=> libbangcle_crypto_tool.a , AFNetworking
243
- object_file = $3 #=> crypto.o , AFAutoPurgingImageCache.o
244
-
245
- # 2.
246
- of = ObjectFile.new(
247
- objc_file_id,
248
- object_file,
249
- library_name,
250
- if line.include?('.framework')
251
- true
252
- else
253
- false
254
- end,
255
- Array.new,
256
- 0,
257
- 0
258
- )
259
-
260
- # 3. 保存解析 xx.o (object file) 的数据
261
- @object_map[objc_file_id] = of
262
-
263
- # 4. 创建【静态库 library】对应的实体对象
264
- library = @library_map[library_name]
265
- library ||= Library.new(library_name, 0, [], 0, '')
266
-
267
- # 5. 【追加】 xx.o 文件位于 ``# Object Files`` 后面的 [ n] 标号
268
- library.object_file_ids << objc_file_id
269
-
270
- # 6. 确认 library 的 pod_name 名字
271
- if line.include?('/Pods/')
272
- # [ 23] /Users/xxx/ci-jenkins/workspace/xxx-iOS-module/VenomShellProject/osee2unified/Pods/AFNetworking/AFNetworking.framework/AFNetworking(AFAutoPurgingImageCache.o)
273
- divstr = line.split('/Pods/').last #=> AFNetworking/AFNetworking.framework/AFNetworking(AFAutoPurgingImageCache.o
274
- pod_name = divstr.split('/').first #=> AFNetworking
275
- library.pod_name = pod_name
276
- else
277
- library.pod_name = ''
278
- end
279
-
280
- # 7.
281
- @library_map[library_name] = library
282
- elsif line =~ %r(\[(.*)\].*\/(.*))
283
- # [ 3] /SomePath/Release-iphoneos/CrashDemo.build/Objects-normal/arm64/main.o
284
- # [100] /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/System/Library/Frameworks/UIKit.framework/UIKit.tbd
285
- # [9742] /SomePath/Pods/du.framework/du
286
- # [8659] /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphoneos/libswiftDispatch.dylib
287
-
288
- # 1.
289
- objc_file_id = $1.to_i #=> 3
290
- object_file = $2 #=> main.o
291
-
292
- # 2.
293
- library_name = ''
294
- if line.include?('.framework') && !object_file.include?('.') #=> /path/to/du.framework/du 【用户】动态库
295
- library_name = object_file
296
- else
297
- if line.end_with?('.a')
298
- library_name = object_file
299
- else
300
- library_name = if object_file.end_with?('.tbd')
301
- 'tdb'
302
- elsif object_file.end_with?('.dylib')
303
- 'dylib'
304
- elsif object_file.end_with?('.o')
305
- 'main'
306
- else
307
- 'system'
308
- end
309
- end
310
- end
311
-
312
- # 3.
313
- of = ObjectFile.new(
314
- objc_file_id,
315
- object_file,
316
- library_name,
317
- if line.include?('.framework') && !object_file.include?('.')
318
- true
319
- else
320
- false
321
- end,
322
- Array.new,
323
- 0,
324
- 0
325
- )
326
-
327
- # 4.
328
- @object_map[objc_file_id] = of
329
- # puts "#{objc_file_id} -- #{library_name}"
330
-
331
- # 5.
332
- library = @library_map[library_name]
333
- library ||= Library.new(library_name, 0, [], 0, '')
334
-
335
- # 6.
336
- library.object_file_ids << objc_file_id
337
-
338
- # 7.
339
- @library_map[library_name] = library
340
- elsif line =~ /\[(.*)\]\s*([\w\s]+)/
341
- # Sample:
342
- # [ 0] linker synthesized
343
- # [ 1] dtrace
344
-
345
- # 1.
346
- objc_file_id = $1.to_i
347
-
348
- # 2.
349
- of = ObjectFile.new(
350
- objc_file_id,
351
- $2,
352
- '',
353
- false,
354
- Array.new,
355
- 0,
356
- 0
357
- )
358
-
359
- # 3.
360
- @object_map[objc_file_id] = of
361
- end
362
- end
363
-
364
- def parse_sections(line)
365
- # Sections:
366
- # Address Size Segment Section
367
- # 0x1000048A0 0x055656A8 __TEXT __text
368
- # 0x105569F48 0x000090E4 __TEXT __stubs
369
- # 0x10557302C 0x000079D4 __TEXT __stub_helper
370
- # 0x10557AA00 0x002D4E1A __TEXT __cstring
371
- #
372
-
373
- lines = line.split(' ').each(&:strip)
374
- section_name = lines[3]
375
- segment_name = lines[2]
376
- start_addr = lines.first.to_i(16)
377
- end_addr = start_addr + lines[1].to_i(16)
378
- residual_size = lines[1].to_i(16)
379
-
380
- section = Section.new(
381
- section_name,
382
- segment_name,
383
- start_addr,
384
- end_addr,
385
- 0,
386
- residual_size
387
- )
388
-
389
- # 【section name】may be dulicate in different segment
390
- # 所以使用 segment_name + section_name 作为 map 的 key 存储
391
- @section_map[section.key] = section
392
- end
393
-
394
- def parse_symbols(line)
395
- # Symbols:
396
- # Address Size File Name
397
- # 0x1000048A0 0x000000A4 [ 2] _main
398
- # 0x100004944 0x00000028 [ 5] _Bangcle_WB_AES_encrypt
399
-
400
- if line =~ %r(^0x(.+?)\s+0x(.+?)\s+\[(.+?)\]\s(.*))
401
- # 1.
402
- symbol_address = $1.to_i(16) #=> Address
403
- symbol_size = $2.to_i(16) #=> Size
404
- object_file_id = $3.to_i #=> File
405
- symbol_name = $4 #=> Name
406
-
407
- # 2.
408
- object_file = @object_map[object_file_id]
409
-
410
- # 3.
411
- unless object_file
412
- UI.error "#{line.inspect} can not found object file"
413
- return
414
- end
415
-
416
- # 4.
417
- symbol = Symbol.new(
418
- symbol_address,
419
- symbol_size,
420
- object_file_id,
421
- symbol_name
422
- )
423
-
424
- # 5. 追加【symbol】符号
425
- object_file.symbols.push(symbol)
426
-
427
- # 6. 统计【Object File】总大小
428
- object_file.size += symbol_size
429
-
430
- # 7. 统计【library/framework】总大小
431
- library = @library_map[object_file.library]
432
- library.size += symbol_size if library
433
-
434
- # 8. 统计【segment】总大小
435
- sections = @section_map.detect do |seg_sec_name, sec|
436
- if sec
437
- (sec.start_addr...sec.end_addr).include?(symbol_address)
438
- else
439
- false
440
- end
441
- end
442
- # pp "⚠️ seg_sec_names=#{seg_sec_names}"
443
-
444
- if sections
445
- section = sections[1]
446
- segment_name = section.parse_segment
447
- segment = @segment_map[segment_name]
448
- # pp "⚠️ segment_name=#{segment_name}"
449
-
450
- unless segment
451
- segment = Segment.new(segment_name, symbol_size, symbol_size)
452
- else
453
- segment.symbol_size += symbol_size
454
- segment.residual_size += symbol_size
455
- end
456
- # pp "⚠️ #{segment.name} #{segment.symbol_size} - #{segment.residual_size}"
457
- @segment_map[segment_name] = segment
458
- end
459
- else
460
- UI.error "#{line.inspect} can not match symbol regular"
461
- end
462
- end
463
-
464
- def parse_dead(line)
465
- # Dead Stripped Symbols:
466
- # Size File Name
467
- # <<dead>> 0x00000028 [ 2] literal string: com.xxx.audioBook.notifications.start
468
- # <<dead>> 0x00000029 [ 2] literal string: com.xxx.audioBook.notifications.stoped
469
- # <<dead>> 0x0000002A [ 2] literal string: com.xxx.audioBook.notificaitons.loading
470
- # <<dead>> 0x0000002A [ 2] literal string: com.xxx.audioBook.notificaitons.palying
471
- # <<dead>> 0x0000002D [ 2] literal string: com.xxx.audioBook.notificaitons.paySuccess
472
- # <<dead>> 0x00000006 [ 2] literal string: appId
473
- # <<dead>> 0x00000008 [ 2] literal string: fakeURL
474
- # <<dead>> 0x00000007 [ 2] literal string: 300300
475
-
476
- if line =~ %r(^<<dead>>\s+0x(.+?)\s+\[(.+?)\]\w*)
477
- size = $1.to_i(16)
478
- file = $2.to_i
479
-
480
- object_file = @object_map[file]
481
- return unless object_file
482
-
483
- # 累加 xx.o 的 dead symbol size
484
- object_file.dead_symbol_size += size
485
-
486
- # 累加 library(xx.o) 的 dead symbol size
487
- @library_map[object_file.library].dead_symbol_size += size
488
- end
489
- end
490
- end
491
- end
492
- end
493
- end