blob: c6aa3d0dcfe9058c443d95dbcebb8e489a5fc851 [file] [log] [blame]
Kiyoung Kim62abd122020-10-06 17:16:44 +09001#!/usr/bin/env python
2#
3# Copyright (C) 2020 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16""" A tool to convert json file into pb with linker config format."""
17
18import argparse
19import collections
20import json
Kiyoung Kim24dfc1f2020-11-16 10:48:44 +090021import os
Jooyung Han3397b6a2023-03-08 05:44:17 +090022import sys
Kiyoung Kim62abd122020-10-06 17:16:44 +090023
Spandan Das1d4bfd82021-08-25 22:58:46 +000024import linker_config_pb2 #pylint: disable=import-error
Kiyoung Kim24dfc1f2020-11-16 10:48:44 +090025from google.protobuf.descriptor import FieldDescriptor
Kiyoung Kim62abd122020-10-06 17:16:44 +090026from google.protobuf.json_format import ParseDict
27from google.protobuf.text_format import MessageToString
28
29
Jooyung Hanf6fd4c22023-03-09 14:50:35 +090030def LoadJsonMessage(path):
31 """
32 Loads a message from a .json file with `//` comments strippedfor convenience.
33 """
34 json_content = ''
35 with open(path) as f:
36 for line in f:
37 if not line.lstrip().startswith('//'):
38 json_content += line
39 obj = json.loads(json_content, object_pairs_hook=collections.OrderedDict)
40 return ParseDict(obj, linker_config_pb2.LinkerConfig())
41
42
Kiyoung Kim62abd122020-10-06 17:16:44 +090043def Proto(args):
Jooyung Han3397b6a2023-03-08 05:44:17 +090044 """
45 Merges input json files (--source) into a protobuf message (--output).
46 Fails if the output file exists. Set --force or --append to deal with the existing
47 output file.
48 --force to overwrite the output file with the input (.json files).
49 --append to append the input to the output file.
50 """
Jooyung Han014ccd42023-01-09 16:23:14 +090051 pb = linker_config_pb2.LinkerConfig()
Jooyung Han3397b6a2023-03-08 05:44:17 +090052 if os.path.isfile(args.output):
53 if args.force:
54 pass
55 elif args.append:
56 with open(args.output, 'rb') as f:
57 pb.ParseFromString(f.read())
58 else:
59 sys.stderr.write(f'Error: {args.output} exists. Use --force or --append.\n')
60 sys.exit(1)
61
Jooyung Hanb531bee2023-03-04 08:28:40 +090062 if args.source:
63 for input in args.source.split(':'):
Jooyung Hanf6fd4c22023-03-09 14:50:35 +090064 pb.MergeFrom(LoadJsonMessage(input))
Spandan Das1d4bfd82021-08-25 22:58:46 +000065 with open(args.output, 'wb') as f:
66 f.write(pb.SerializeToString())
Kiyoung Kim62abd122020-10-06 17:16:44 +090067
68
69def Print(args):
Spandan Das1d4bfd82021-08-25 22:58:46 +000070 with open(args.source, 'rb') as f:
71 pb = linker_config_pb2.LinkerConfig()
72 pb.ParseFromString(f.read())
73 print(MessageToString(pb))
Kiyoung Kim62abd122020-10-06 17:16:44 +090074
75
Kiyoung Kim24dfc1f2020-11-16 10:48:44 +090076def SystemProvide(args):
Spandan Das1d4bfd82021-08-25 22:58:46 +000077 pb = linker_config_pb2.LinkerConfig()
78 with open(args.source, 'rb') as f:
79 pb.ParseFromString(f.read())
80 libraries = args.value.split()
Kiyoung Kim24dfc1f2020-11-16 10:48:44 +090081
Spandan Das1d4bfd82021-08-25 22:58:46 +000082 def IsInLibPath(lib_name):
83 lib_path = os.path.join(args.system, 'lib', lib_name)
84 lib64_path = os.path.join(args.system, 'lib64', lib_name)
85 return os.path.exists(lib_path) or os.path.islink(
86 lib_path) or os.path.exists(lib64_path) or os.path.islink(
87 lib64_path)
Kiyoung Kim24dfc1f2020-11-16 10:48:44 +090088
Spandan Das1d4bfd82021-08-25 22:58:46 +000089 installed_libraries = [lib for lib in libraries if IsInLibPath(lib)]
90 for item in installed_libraries:
91 if item not in getattr(pb, 'provideLibs'):
92 getattr(pb, 'provideLibs').append(item)
93 with open(args.output, 'wb') as f:
94 f.write(pb.SerializeToString())
Kiyoung Kim24dfc1f2020-11-16 10:48:44 +090095
96
Kiyoung Kim4ee686d2020-12-03 15:20:07 +090097def Append(args):
Spandan Das1d4bfd82021-08-25 22:58:46 +000098 pb = linker_config_pb2.LinkerConfig()
99 with open(args.source, 'rb') as f:
100 pb.ParseFromString(f.read())
Kiyoung Kim4ee686d2020-12-03 15:20:07 +0900101
Spandan Das1d4bfd82021-08-25 22:58:46 +0000102 if getattr(type(pb),
103 args.key).DESCRIPTOR.label == FieldDescriptor.LABEL_REPEATED:
104 for value in args.value.split():
105 getattr(pb, args.key).append(value)
106 else:
107 setattr(pb, args.key, args.value)
Kiyoung Kim4ee686d2020-12-03 15:20:07 +0900108
Spandan Das1d4bfd82021-08-25 22:58:46 +0000109 with open(args.output, 'wb') as f:
110 f.write(pb.SerializeToString())
111
Kiyoung Kim4ee686d2020-12-03 15:20:07 +0900112
Jooyung Hane134d092021-04-15 05:13:34 +0900113def Merge(args):
Spandan Das1d4bfd82021-08-25 22:58:46 +0000114 pb = linker_config_pb2.LinkerConfig()
115 for other in args.input:
116 with open(other, 'rb') as f:
117 pb.MergeFromString(f.read())
Jooyung Hane134d092021-04-15 05:13:34 +0900118
Spandan Das1d4bfd82021-08-25 22:58:46 +0000119 with open(args.out, 'wb') as f:
120 f.write(pb.SerializeToString())
121
Kiyoung Kim4ee686d2020-12-03 15:20:07 +0900122
Jooyung Han4bc10262023-09-08 11:51:45 +0900123def Validate(args):
124 if os.path.isdir(args.input):
125 config_file = os.path.join(args.input, 'etc/linker.config.pb')
126 if os.path.exists(config_file):
127 args.input = config_file
128 Validate(args)
129 # OK if there's no linker config file.
130 return
131
132 if not os.path.isfile(args.input):
133 sys.exit(f"{args.input} is not a file")
134
135 pb = linker_config_pb2.LinkerConfig()
136 with open(args.input, 'rb') as f:
137 pb.ParseFromString(f.read())
138
139 if args.type == 'apex':
140 # Shouldn't use provideLibs/requireLibs in APEX linker.config.pb
141 if getattr(pb, 'provideLibs'):
142 sys.exit(f'{args.input}: provideLibs is set. Use provideSharedLibs in apex_manifest')
143 if getattr(pb, 'requireLibs'):
144 sys.exit(f'{args.input}: requireLibs is set. Use requireSharedLibs in apex_manifest')
145 elif args.type == 'system':
146 if getattr(pb, 'visible'):
147 sys.exit(f'{args.input}: do not use visible, which is for APEX')
148 if getattr(pb, 'permittedPaths'):
149 sys.exit(f'{args.input}: do not use permittedPaths, which is for APEX')
150 else:
151 sys.exit(f'Unknown type: {args.type}')
152
153
Kiyoung Kim62abd122020-10-06 17:16:44 +0900154def GetArgParser():
Spandan Das1d4bfd82021-08-25 22:58:46 +0000155 parser = argparse.ArgumentParser()
156 subparsers = parser.add_subparsers()
Kiyoung Kim62abd122020-10-06 17:16:44 +0900157
Spandan Das1d4bfd82021-08-25 22:58:46 +0000158 parser_proto = subparsers.add_parser(
159 'proto',
160 help='Convert the input JSON configuration file into protobuf.')
161 parser_proto.add_argument(
162 '-s',
163 '--source',
Jooyung Hanb531bee2023-03-04 08:28:40 +0900164 nargs='?',
Spandan Das1d4bfd82021-08-25 22:58:46 +0000165 type=str,
Jooyung Han014ccd42023-01-09 16:23:14 +0900166 help='Colon-separated list of linker configuration files in JSON.')
Spandan Das1d4bfd82021-08-25 22:58:46 +0000167 parser_proto.add_argument(
168 '-o',
169 '--output',
170 required=True,
171 type=str,
172 help='Target path to create protobuf file.')
Jooyung Han3397b6a2023-03-08 05:44:17 +0900173 option_for_existing_output = parser_proto.add_mutually_exclusive_group()
174 option_for_existing_output.add_argument(
175 '-f',
176 '--force',
177 action='store_true',
178 help='Overwrite if the output file exists.')
179 option_for_existing_output.add_argument(
180 '-a',
181 '--append',
182 action='store_true',
183 help='Append the input to the output file if the output file exists.')
Spandan Das1d4bfd82021-08-25 22:58:46 +0000184 parser_proto.set_defaults(func=Proto)
Kiyoung Kim62abd122020-10-06 17:16:44 +0900185
Spandan Das1d4bfd82021-08-25 22:58:46 +0000186 print_proto = subparsers.add_parser(
187 'print', help='Print configuration in human-readable text format.')
188 print_proto.add_argument(
189 '-s',
190 '--source',
191 required=True,
192 type=str,
193 help='Source linker configuration file in protobuf.')
194 print_proto.set_defaults(func=Print)
Kiyoung Kim62abd122020-10-06 17:16:44 +0900195
Spandan Das1d4bfd82021-08-25 22:58:46 +0000196 system_provide_libs = subparsers.add_parser(
197 'systemprovide',
198 help='Append system provide libraries into the configuration.')
199 system_provide_libs.add_argument(
200 '-s',
201 '--source',
202 required=True,
203 type=str,
204 help='Source linker configuration file in protobuf.')
205 system_provide_libs.add_argument(
206 '-o',
207 '--output',
208 required=True,
209 type=str,
210 help='Target linker configuration file to write in protobuf.')
211 system_provide_libs.add_argument(
212 '--value',
213 required=True,
214 type=str,
215 help='Values of the libraries to append. If there are more than one '
216 'it should be separated by empty space'
217 )
218 system_provide_libs.add_argument(
219 '--system', required=True, type=str, help='Path of the system image.')
220 system_provide_libs.set_defaults(func=SystemProvide)
Kiyoung Kim24dfc1f2020-11-16 10:48:44 +0900221
Spandan Das1d4bfd82021-08-25 22:58:46 +0000222 append = subparsers.add_parser(
223 'append', help='Append value(s) to given key.')
224 append.add_argument(
225 '-s',
226 '--source',
227 required=True,
228 type=str,
229 help='Source linker configuration file in protobuf.')
230 append.add_argument(
231 '-o',
232 '--output',
233 required=True,
234 type=str,
235 help='Target linker configuration file to write in protobuf.')
236 append.add_argument('--key', required=True, type=str, help='.')
237 append.add_argument(
238 '--value',
239 required=True,
240 type=str,
241 help='Values of the libraries to append. If there are more than one'
242 'it should be separated by empty space'
243 )
244 append.set_defaults(func=Append)
Kiyoung Kim4ee686d2020-12-03 15:20:07 +0900245
Spandan Das1d4bfd82021-08-25 22:58:46 +0000246 append = subparsers.add_parser('merge', help='Merge configurations')
247 append.add_argument(
248 '-o',
249 '--out',
250 required=True,
251 type=str,
252 help='Output linker configuration file to write in protobuf.')
253 append.add_argument(
254 '-i',
255 '--input',
256 nargs='+',
257 type=str,
258 help='Linker configuration files to merge.')
259 append.set_defaults(func=Merge)
Jooyung Hane134d092021-04-15 05:13:34 +0900260
Jooyung Han4bc10262023-09-08 11:51:45 +0900261 validate = subparsers.add_parser('validate', help='Validate configuration')
262 validate.add_argument(
263 '--type',
264 required=True,
265 choices=['apex', 'system'],
266 help='Type of linker configuration')
267 validate.add_argument(
268 'input',
269 help='Input can be a directory which has etc/linker.config.pb or a path'
270 ' to the linker config file')
271 validate.set_defaults(func=Validate)
272
Spandan Das1d4bfd82021-08-25 22:58:46 +0000273 return parser
Kiyoung Kim62abd122020-10-06 17:16:44 +0900274
275
276def main():
Jooyung Han3397b6a2023-03-08 05:44:17 +0900277 parser = GetArgParser()
278 args = parser.parse_args()
279 if 'func' in args:
280 args.func(args)
281 else:
282 parser.print_help()
Kiyoung Kim62abd122020-10-06 17:16:44 +0900283
284
285if __name__ == '__main__':
Spandan Das1d4bfd82021-08-25 22:58:46 +0000286 main()