blob: d031d83017bc8e3fd120dd8a6187ab6180416890 [file] [log] [blame]
Yifan Hong4d18bcc2017-04-07 21:47:16 +00001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Yifan Hong9aa63702017-05-16 16:37:50 -070017#include <getopt.h>
Yifan Hong4d18bcc2017-04-07 21:47:16 +000018#include <stdlib.h>
19#include <unistd.h>
20
21#include <fstream>
22#include <iostream>
23#include <unordered_map>
24#include <sstream>
25#include <string>
26
Yifan Hong9a8b1a72017-08-25 17:55:33 -070027#include <android-base/file.h>
28
Yifan Hong79efa8a2017-07-06 14:10:28 -070029#include <vintf/KernelConfigParser.h>
Yifan Hong4d18bcc2017-04-07 21:47:16 +000030#include <vintf/parse_string.h>
31#include <vintf/parse_xml.h>
32
Yifan Hong79efa8a2017-07-06 14:10:28 -070033#define BUFFER_SIZE sysconf(_SC_PAGESIZE)
34
Yifan Hong4d18bcc2017-04-07 21:47:16 +000035namespace android {
36namespace vintf {
37
Yifan Hong9a8b1a72017-08-25 17:55:33 -070038static const std::string gConfigPrefix = "android-base-";
39static const std::string gConfigSuffix = ".cfg";
40static const std::string gBaseConfig = "android-base.cfg";
41
Yifan Hong4d18bcc2017-04-07 21:47:16 +000042/**
43 * Slurps the device manifest file and add build time flag to it.
44 */
45class AssembleVintf {
Yifan Hong9a8b1a72017-08-25 17:55:33 -070046 using Condition = std::unique_ptr<KernelConfig>;
47 using ConditionedConfig = std::pair<Condition, std::vector<KernelConfig> /* configs */>;
48
49 public:
Yifan Hong4d18bcc2017-04-07 21:47:16 +000050 template<typename T>
51 static bool getFlag(const std::string& key, T* value) {
52 const char *envValue = getenv(key.c_str());
53 if (envValue == NULL) {
Yifan Hong488e16a2017-07-11 13:50:41 -070054 std::cerr << "Warning: " << key << " is missing, defaulted to " << (*value)
55 << std::endl;
56 return true;
Yifan Hong4d18bcc2017-04-07 21:47:16 +000057 }
58
59 if (!parse(envValue, value)) {
60 std::cerr << "Cannot parse " << envValue << "." << std::endl;
61 return false;
62 }
63 return true;
64 }
65
Yifan Hong4650ad82017-05-01 17:28:02 -070066 static std::string read(std::basic_istream<char>& is) {
67 std::stringstream ss;
68 ss << is.rdbuf();
69 return ss.str();
70 }
71
Yifan Hong9a8b1a72017-08-25 17:55:33 -070072 static bool isCommonConfig(const std::string& path) {
73 return ::android::base::Basename(path) == gBaseConfig;
74 }
75
Yifan Hong079ec242017-08-25 18:53:38 -070076 // nullptr on any error, otherwise the condition.
77 static Condition generateCondition(const std::string& path) {
78 std::string fname = ::android::base::Basename(path);
79 if (fname.size() <= gConfigPrefix.size() + gConfigSuffix.size() ||
80 !std::equal(gConfigPrefix.begin(), gConfigPrefix.end(), fname.begin()) ||
81 !std::equal(gConfigSuffix.rbegin(), gConfigSuffix.rend(), fname.rbegin())) {
82 return nullptr;
83 }
84
85 std::string sub = fname.substr(gConfigPrefix.size(),
86 fname.size() - gConfigPrefix.size() - gConfigSuffix.size());
87 if (sub.empty()) {
88 return nullptr; // should not happen
89 }
90 for (size_t i = 0; i < sub.size(); ++i) {
91 if (sub[i] == '-') {
92 sub[i] = '_';
93 continue;
94 }
95 if (isalnum(sub[i])) {
96 sub[i] = toupper(sub[i]);
97 continue;
98 }
99 std::cerr << "'" << fname << "' (in " << path
100 << ") is not a valid kernel config file name. Must match regex: "
101 << "android-base(-[0-9a-zA-Z-]+)?\\.cfg" << std::endl;
102 return nullptr;
103 }
104 sub.insert(0, "CONFIG_");
105 return std::make_unique<KernelConfig>(std::move(sub), Tristate::YES);
106 }
107
Yifan Hong79efa8a2017-07-06 14:10:28 -0700108 static bool parseFileForKernelConfigs(const std::string& path, std::vector<KernelConfig>* out) {
109 std::ifstream ifs{path};
110 if (!ifs.is_open()) {
111 std::cerr << "File '" << path << "' does not exist or cannot be read." << std::endl;
112 return false;
113 }
Yifan Hong02e94002017-07-10 15:41:56 -0700114 KernelConfigParser parser(true /* processComments */, true /* relaxedFormat */);
Yifan Hong79efa8a2017-07-06 14:10:28 -0700115 std::string content = read(ifs);
116 status_t err = parser.process(content.c_str(), content.size());
117 if (err != OK) {
Yifan Hongae53a0e2017-07-07 15:19:06 -0700118 std::cerr << parser.error();
Yifan Hong79efa8a2017-07-06 14:10:28 -0700119 return false;
120 }
121 err = parser.finish();
122 if (err != OK) {
Yifan Hongae53a0e2017-07-07 15:19:06 -0700123 std::cerr << parser.error();
Yifan Hong79efa8a2017-07-06 14:10:28 -0700124 return false;
125 }
126
127 for (auto& configPair : parser.configs()) {
128 out->push_back({});
129 KernelConfig& config = out->back();
130 config.first = std::move(configPair.first);
131 if (!parseKernelConfigTypedValue(configPair.second, &config.second)) {
132 std::cerr << "Unknown value type for key = '" << config.first << "', value = '"
133 << configPair.second << "'\n";
134 return false;
135 }
136 }
137 return true;
138 }
139
Yifan Hong9a8b1a72017-08-25 17:55:33 -0700140 static bool parseFilesForKernelConfigs(const std::string& path,
141 std::vector<ConditionedConfig>* out) {
142 out->clear();
143 ConditionedConfig commonConfig;
144 bool foundCommonConfig = false;
Steve Muckle0bef8682017-07-31 15:47:15 -0700145 bool ret = true;
146 char *pathIter;
147 char *modPath = new char[path.length() + 1];
148 strcpy(modPath, path.c_str());
149 pathIter = strtok(modPath, ":");
150 while (ret && pathIter != NULL) {
Yifan Hong9a8b1a72017-08-25 17:55:33 -0700151 if (isCommonConfig(pathIter)) {
152 ret &= parseFileForKernelConfigs(pathIter, &commonConfig.second);
153 foundCommonConfig = true;
154 } else {
Yifan Hong079ec242017-08-25 18:53:38 -0700155 Condition condition = generateCondition(pathIter);
156 ret &= (condition != nullptr);
157
Yifan Hong9a8b1a72017-08-25 17:55:33 -0700158 std::vector<KernelConfig> kernelConfigs;
159 if ((ret &= parseFileForKernelConfigs(pathIter, &kernelConfigs)))
Yifan Hong079ec242017-08-25 18:53:38 -0700160 out->emplace_back(std::move(condition), std::move(kernelConfigs));
Yifan Hong9a8b1a72017-08-25 17:55:33 -0700161 }
Steve Muckle0bef8682017-07-31 15:47:15 -0700162 pathIter = strtok(NULL, ":");
163 }
Luis A. Lozano82266ae2017-08-22 16:30:11 -0700164 delete[] modPath;
Yifan Hong9a8b1a72017-08-25 17:55:33 -0700165
166 if (!foundCommonConfig) {
167 std::cerr << "No android-base.cfg is found in these paths: '" << path << "'"
168 << std::endl;
169 }
170 ret &= foundCommonConfig;
171 // first element is always common configs (no conditions).
172 out->insert(out->begin(), std::move(commonConfig));
Steve Muckle0bef8682017-07-31 15:47:15 -0700173 return ret;
174 }
175
Yifan Hong9aa63702017-05-16 16:37:50 -0700176 std::basic_ostream<char>& out() const {
177 return mOutFileRef == nullptr ? std::cout : *mOutFileRef;
178 }
179
180 bool assembleHalManifest(HalManifest* halManifest) {
Yifan Hong4650ad82017-05-01 17:28:02 -0700181 std::string error;
Yifan Hong9aa63702017-05-16 16:37:50 -0700182
183 if (halManifest->mType == SchemaType::DEVICE) {
184 if (!getFlag("BOARD_SEPOLICY_VERS", &halManifest->device.mSepolicyVersion)) {
185 return false;
186 }
187 }
188
189 if (mOutputMatrix) {
190 CompatibilityMatrix generatedMatrix = halManifest->generateCompatibleMatrix();
191 if (!halManifest->checkCompatibility(generatedMatrix, &error)) {
192 std::cerr << "FATAL ERROR: cannot generate a compatible matrix: " << error
193 << std::endl;
194 }
195 out() << "<!-- \n"
196 " Autogenerated skeleton compatibility matrix. \n"
197 " Use with caution. Modify it to suit your needs.\n"
198 " All HALs are set to optional.\n"
199 " Many entries other than HALs are zero-filled and\n"
200 " require human attention. \n"
201 "-->\n"
Yifan Honga2635c42017-12-12 13:20:33 -0800202 << gCompatibilityMatrixConverter(generatedMatrix, mSerializeFlags);
Yifan Hong9aa63702017-05-16 16:37:50 -0700203 } else {
Yifan Honga2635c42017-12-12 13:20:33 -0800204 out() << gHalManifestConverter(*halManifest, mSerializeFlags);
Yifan Hong9aa63702017-05-16 16:37:50 -0700205 }
206 out().flush();
207
208 if (mCheckFile.is_open()) {
209 CompatibilityMatrix checkMatrix;
210 if (!gCompatibilityMatrixConverter(&checkMatrix, read(mCheckFile))) {
211 std::cerr << "Cannot parse check file as a compatibility matrix: "
212 << gCompatibilityMatrixConverter.lastError() << std::endl;
213 return false;
214 }
215 if (!halManifest->checkCompatibility(checkMatrix, &error)) {
216 std::cerr << "Not compatible: " << error << std::endl;
217 return false;
218 }
219 }
220
221 return true;
222 }
223
Yifan Honge88e1672017-08-24 14:42:54 -0700224 bool assembleFrameworkCompatibilityMatrixKernels(CompatibilityMatrix* matrix) {
Yifan Hong4c34fee2017-08-24 16:03:34 -0700225 if (!matrix->framework.mKernels.empty()) {
226 // Remove hard-coded <kernel version="x.y.z" /> in legacy files.
227 std::cerr << "WARNING: framework compatibility matrix has hard-coded kernel"
228 << " requirements for version";
229 for (const auto& kernel : matrix->framework.mKernels) {
230 std::cerr << " " << kernel.minLts();
231 }
232 std::cerr << ". Hard-coded requirements are removed." << std::endl;
233 matrix->framework.mKernels.clear();
234 }
Yifan Honge88e1672017-08-24 14:42:54 -0700235 for (const auto& pair : mKernels) {
Yifan Hong9a8b1a72017-08-25 17:55:33 -0700236 std::vector<ConditionedConfig> conditionedConfigs;
237 if (!parseFilesForKernelConfigs(pair.second, &conditionedConfigs)) {
Yifan Honge88e1672017-08-24 14:42:54 -0700238 return false;
239 }
Yifan Hong9a8b1a72017-08-25 17:55:33 -0700240 for (ConditionedConfig& conditionedConfig : conditionedConfigs) {
Yifan Hong48602df2017-08-28 13:04:12 -0700241 MatrixKernel kernel(KernelVersion{pair.first.majorVer, pair.first.minorVer, 0u},
242 std::move(conditionedConfig.second));
Yifan Hong079ec242017-08-25 18:53:38 -0700243 if (conditionedConfig.first != nullptr)
244 kernel.mConditions.push_back(std::move(*conditionedConfig.first));
245 matrix->framework.mKernels.push_back(std::move(kernel));
Yifan Hong9a8b1a72017-08-25 17:55:33 -0700246 }
Yifan Honge88e1672017-08-24 14:42:54 -0700247 }
248 return true;
249 }
250
Yifan Hong9aa63702017-05-16 16:37:50 -0700251 bool assembleCompatibilityMatrix(CompatibilityMatrix* matrix) {
252 std::string error;
253
254 KernelSepolicyVersion kernelSepolicyVers;
255 Version sepolicyVers;
256 if (matrix->mType == SchemaType::FRAMEWORK) {
257 if (!getFlag("BOARD_SEPOLICY_VERS", &sepolicyVers)) {
258 return false;
259 }
260 if (!getFlag("POLICYVERS", &kernelSepolicyVers)) {
261 return false;
262 }
Yifan Honge88e1672017-08-24 14:42:54 -0700263
264 if (!assembleFrameworkCompatibilityMatrixKernels(matrix)) {
265 return false;
Yifan Hong79efa8a2017-07-06 14:10:28 -0700266 }
Yifan Honge88e1672017-08-24 14:42:54 -0700267
Yifan Hong9aa63702017-05-16 16:37:50 -0700268 matrix->framework.mSepolicy =
269 Sepolicy(kernelSepolicyVers, {{sepolicyVers.majorVer, sepolicyVers.minorVer}});
Yifan Hong7f6c00c2017-07-06 19:50:29 +0000270
271 Version avbMetaVersion;
272 if (!getFlag("FRAMEWORK_VBMETA_VERSION", &avbMetaVersion)) {
273 return false;
274 }
275 matrix->framework.mAvbMetaVersion = avbMetaVersion;
Yifan Hong9aa63702017-05-16 16:37:50 -0700276 }
Yifan Honga2635c42017-12-12 13:20:33 -0800277 out() << gCompatibilityMatrixConverter(*matrix, mSerializeFlags);
Yifan Hong9aa63702017-05-16 16:37:50 -0700278 out().flush();
279
280 if (mCheckFile.is_open()) {
281 HalManifest checkManifest;
282 if (!gHalManifestConverter(&checkManifest, read(mCheckFile))) {
283 std::cerr << "Cannot parse check file as a HAL manifest: "
284 << gHalManifestConverter.lastError() << std::endl;
285 return false;
286 }
287 if (!checkManifest.checkCompatibility(*matrix, &error)) {
288 std::cerr << "Not compatible: " << error << std::endl;
289 return false;
290 }
291 }
292
293 return true;
294 }
295
Yifan Hongbfb3c1d2017-05-24 14:38:48 -0700296 enum AssembleStatus { SUCCESS, FAIL_AND_EXIT, TRY_NEXT };
297 template <typename Schema, typename AssembleFunc>
298 AssembleStatus tryAssemble(const XmlConverter<Schema>& converter, const std::string& schemaName,
299 AssembleFunc assemble) {
300 Schema schema;
301 if (!converter(&schema, read(mInFiles.front()))) {
302 return TRY_NEXT;
303 }
304 auto firstType = schema.type();
305 for (auto it = mInFiles.begin() + 1; it != mInFiles.end(); ++it) {
306 Schema additionalSchema;
307 if (!converter(&additionalSchema, read(*it))) {
308 std::cerr << "File \"" << mInFilePaths[std::distance(mInFiles.begin(), it)]
309 << "\" is not a valid " << firstType << " " << schemaName
310 << " (but the first file is a valid " << firstType << " " << schemaName
311 << "). Error: " << converter.lastError() << std::endl;
312 return FAIL_AND_EXIT;
313 }
314 if (additionalSchema.type() != firstType) {
315 std::cerr << "File \"" << mInFilePaths[std::distance(mInFiles.begin(), it)]
316 << "\" is a " << additionalSchema.type() << " " << schemaName
317 << " (but a " << firstType << " " << schemaName << " is expected)."
318 << std::endl;
319 return FAIL_AND_EXIT;
320 }
Yifan Hongeb14e302017-10-17 16:35:14 -0700321 std::string error;
322 if (!schema.addAll(std::move(additionalSchema), &error)) {
323 std::cerr << "File \"" << mInFilePaths[std::distance(mInFiles.begin(), it)]
324 << "\" cannot be added: conflict on HAL \"" << error
325 << "\" with an existing HAL. See <hal> with the same name "
326 << "in previously parsed files or previously declared in this file."
327 << std::endl;
328 return FAIL_AND_EXIT;
329 }
Yifan Hongbfb3c1d2017-05-24 14:38:48 -0700330 }
331 return assemble(&schema) ? SUCCESS : FAIL_AND_EXIT;
332 }
333
Yifan Hong9aa63702017-05-16 16:37:50 -0700334 bool assemble() {
Yifan Hongbfb3c1d2017-05-24 14:38:48 -0700335 using std::placeholders::_1;
336 if (mInFiles.empty()) {
Yifan Hong9aa63702017-05-16 16:37:50 -0700337 std::cerr << "Missing input file." << std::endl;
338 return false;
339 }
340
Yifan Hongbfb3c1d2017-05-24 14:38:48 -0700341 auto status = tryAssemble(gHalManifestConverter, "manifest",
342 std::bind(&AssembleVintf::assembleHalManifest, this, _1));
343 if (status == SUCCESS) return true;
344 if (status == FAIL_AND_EXIT) return false;
Yifan Hong4d18bcc2017-04-07 21:47:16 +0000345
Yifan Hongbfb3c1d2017-05-24 14:38:48 -0700346 resetInFiles();
Yifan Honga59d2562017-04-18 18:01:16 -0700347
Yifan Hongbfb3c1d2017-05-24 14:38:48 -0700348 status = tryAssemble(gCompatibilityMatrixConverter, "compatibility matrix",
349 std::bind(&AssembleVintf::assembleCompatibilityMatrix, this, _1));
350 if (status == SUCCESS) return true;
351 if (status == FAIL_AND_EXIT) return false;
Yifan Hong4d18bcc2017-04-07 21:47:16 +0000352
Yifan Hong959ee1b2017-04-28 14:37:56 -0700353 std::cerr << "Input file has unknown format." << std::endl
354 << "Error when attempting to convert to manifest: "
355 << gHalManifestConverter.lastError() << std::endl
356 << "Error when attempting to convert to compatibility matrix: "
357 << gCompatibilityMatrixConverter.lastError() << std::endl;
358 return false;
Yifan Hong4d18bcc2017-04-07 21:47:16 +0000359 }
Yifan Hong9aa63702017-05-16 16:37:50 -0700360
361 bool openOutFile(const char* path) {
362 mOutFileRef = std::make_unique<std::ofstream>();
363 mOutFileRef->open(path);
364 return mOutFileRef->is_open();
365 }
366
367 bool openInFile(const char* path) {
Yifan Hongbfb3c1d2017-05-24 14:38:48 -0700368 mInFilePaths.push_back(path);
369 mInFiles.push_back({});
370 mInFiles.back().open(path);
371 return mInFiles.back().is_open();
Yifan Hong9aa63702017-05-16 16:37:50 -0700372 }
373
374 bool openCheckFile(const char* path) {
375 mCheckFile.open(path);
376 return mCheckFile.is_open();
377 }
378
Yifan Hongbfb3c1d2017-05-24 14:38:48 -0700379 void resetInFiles() {
380 for (auto& inFile : mInFiles) {
381 inFile.clear();
382 inFile.seekg(0);
383 }
384 }
385
Yifan Hong9aa63702017-05-16 16:37:50 -0700386 void setOutputMatrix() { mOutputMatrix = true; }
387
Yifan Honga2635c42017-12-12 13:20:33 -0800388 bool setHalsOnly() {
389 if (mSerializeFlags) return false;
390 mSerializeFlags |= SerializeFlag::HALS_ONLY;
391 return true;
392 }
393
394 bool setNoHals() {
395 if (mSerializeFlags) return false;
396 mSerializeFlags |= SerializeFlag::NO_HALS;
397 return true;
398 }
399
Yifan Hong79efa8a2017-07-06 14:10:28 -0700400 bool addKernel(const std::string& kernelArg) {
401 auto ind = kernelArg.find(':');
402 if (ind == std::string::npos) {
403 std::cerr << "Unrecognized --kernel option '" << kernelArg << "'" << std::endl;
404 return false;
405 }
406 std::string kernelVerStr{kernelArg.begin(), kernelArg.begin() + ind};
407 std::string kernelConfigPath{kernelArg.begin() + ind + 1, kernelArg.end()};
408 Version kernelVer;
409 if (!parse(kernelVerStr, &kernelVer)) {
410 std::cerr << "Unrecognized kernel version '" << kernelVerStr << "'" << std::endl;
411 return false;
412 }
Yifan Hong48602df2017-08-28 13:04:12 -0700413 if (mKernels.find(kernelVer) != mKernels.end()) {
414 std::cerr << "Multiple --kernel for " << kernelVer << " is specified." << std::endl;
415 return false;
416 }
417 mKernels[kernelVer] = kernelConfigPath;
Yifan Hong79efa8a2017-07-06 14:10:28 -0700418 return true;
419 }
420
Yifan Hong9aa63702017-05-16 16:37:50 -0700421 private:
Yifan Hongbfb3c1d2017-05-24 14:38:48 -0700422 std::vector<std::string> mInFilePaths;
423 std::vector<std::ifstream> mInFiles;
Yifan Hong9aa63702017-05-16 16:37:50 -0700424 std::unique_ptr<std::ofstream> mOutFileRef;
425 std::ifstream mCheckFile;
426 bool mOutputMatrix = false;
Yifan Honga2635c42017-12-12 13:20:33 -0800427 SerializeFlags mSerializeFlags = SerializeFlag::EVERYTHING;
Yifan Hong48602df2017-08-28 13:04:12 -0700428 std::map<Version, std::string> mKernels;
Yifan Hong4d18bcc2017-04-07 21:47:16 +0000429};
430
431} // namespace vintf
432} // namespace android
433
434void help() {
Yifan Hong9aa63702017-05-16 16:37:50 -0700435 std::cerr << "assemble_vintf: Checks if a given manifest / matrix file is valid and \n"
436 " fill in build-time flags into the given file.\n"
437 "assemble_vintf -h\n"
438 " Display this help text.\n"
Yifan Hongbfb3c1d2017-05-24 14:38:48 -0700439 "assemble_vintf -i <input file>[:<input file>[...]] [-o <output file>] [-m]\n"
440 " [-c [<check file>]]\n"
Yifan Hong9aa63702017-05-16 16:37:50 -0700441 " Fill in build-time flags into the given file.\n"
Yifan Hongbfb3c1d2017-05-24 14:38:48 -0700442 " -i <input file>[:<input file>[...]]\n"
443 " A list of input files. Format is automatically detected for the\n"
444 " first file, and the remaining files must have the same format.\n"
445 " Files other than the first file should only have <hal> defined;\n"
446 " other entries are ignored.\n"
Yifan Hong9aa63702017-05-16 16:37:50 -0700447 " -o <output file>\n"
448 " Optional output file. If not specified, write to stdout.\n"
449 " -m\n"
450 " a compatible compatibility matrix is\n"
451 " generated instead; for example, given a device manifest,\n"
452 " a framework compatibility matrix is generated. This flag\n"
453 " is ignored when input is a compatibility matrix.\n"
454 " -c [<check file>]\n"
455 " After writing the output file, check compatibility between\n"
456 " output file and check file.\n"
457 " If -c is set but the check file is not specified, a warning\n"
458 " message is written to stderr. Return 0.\n"
459 " If the check file is specified but is not compatible, an error\n"
Yifan Hong79efa8a2017-07-06 14:10:28 -0700460 " message is written to stderr. Return 1.\n"
Steve Muckle0bef8682017-07-31 15:47:15 -0700461 " --kernel=<version>:<android-base.cfg>[:<android-base-arch.cfg>[...]]\n"
Yifan Hong79efa8a2017-07-06 14:10:28 -0700462 " Add a kernel entry to framework compatibility matrix.\n"
463 " Ignored for other input format.\n"
464 " <version> has format: 3.18\n"
Steve Muckle0bef8682017-07-31 15:47:15 -0700465 " <android-base.cfg> is the location of android-base.cfg\n"
466 " <android-base-arch.cfg> is the location of an optional\n"
Yifan Honga2635c42017-12-12 13:20:33 -0800467 " arch-specific config fragment, more than one may be specified\n"
468 " -l, --hals-only\n"
469 " Output has only <hal> entries. Cannot be used with -n.\n"
470 " -n, --no-hals\n"
471 " Output has no <hal> entries (but all other entries).\n"
472 " Cannot be used with -l.\n";
Yifan Hong4d18bcc2017-04-07 21:47:16 +0000473}
474
475int main(int argc, char **argv) {
Yifan Honga2635c42017-12-12 13:20:33 -0800476 const struct option longopts[] = {{"kernel", required_argument, NULL, 'k'},
477 {"hals-only", no_argument, NULL, 'l'},
478 {"no-hals", no_argument, NULL, 'n'},
479 {0, 0, 0, 0}};
Yifan Hong9aa63702017-05-16 16:37:50 -0700480
Yifan Hongbfb3c1d2017-05-24 14:38:48 -0700481 std::string outFilePath;
Yifan Hong9aa63702017-05-16 16:37:50 -0700482 ::android::vintf::AssembleVintf assembleVintf;
Yifan Hong4d18bcc2017-04-07 21:47:16 +0000483 int res;
Yifan Hong9aa63702017-05-16 16:37:50 -0700484 int optind;
Yifan Honga2635c42017-12-12 13:20:33 -0800485 while ((res = getopt_long(argc, argv, "hi:o:mc:nl", longopts, &optind)) >= 0) {
Yifan Hong4d18bcc2017-04-07 21:47:16 +0000486 switch (res) {
487 case 'i': {
Yifan Hongbfb3c1d2017-05-24 14:38:48 -0700488 char* inFilePath = strtok(optarg, ":");
489 while (inFilePath != NULL) {
490 if (!assembleVintf.openInFile(inFilePath)) {
491 std::cerr << "Failed to open " << optarg << std::endl;
492 return 1;
493 }
494 inFilePath = strtok(NULL, ":");
Yifan Hong4d18bcc2017-04-07 21:47:16 +0000495 }
496 } break;
497
498 case 'o': {
Yifan Hongbfb3c1d2017-05-24 14:38:48 -0700499 outFilePath = optarg;
Yifan Hong9aa63702017-05-16 16:37:50 -0700500 if (!assembleVintf.openOutFile(optarg)) {
Yifan Hong4d18bcc2017-04-07 21:47:16 +0000501 std::cerr << "Failed to open " << optarg << std::endl;
502 return 1;
503 }
Yifan Hong4d18bcc2017-04-07 21:47:16 +0000504 } break;
505
Yifan Honga59d2562017-04-18 18:01:16 -0700506 case 'm': {
Yifan Hong9aa63702017-05-16 16:37:50 -0700507 assembleVintf.setOutputMatrix();
Yifan Honga59d2562017-04-18 18:01:16 -0700508 } break;
509
Yifan Hong4650ad82017-05-01 17:28:02 -0700510 case 'c': {
511 if (strlen(optarg) != 0) {
Yifan Hong9aa63702017-05-16 16:37:50 -0700512 if (!assembleVintf.openCheckFile(optarg)) {
Yifan Hong4650ad82017-05-01 17:28:02 -0700513 std::cerr << "Failed to open " << optarg << std::endl;
514 return 1;
515 }
516 } else {
517 std::cerr << "WARNING: no compatibility check is done on "
Yifan Hongbfb3c1d2017-05-24 14:38:48 -0700518 << (outFilePath.empty() ? "output" : outFilePath) << std::endl;
Yifan Hong4650ad82017-05-01 17:28:02 -0700519 }
520 } break;
521
Yifan Hong79efa8a2017-07-06 14:10:28 -0700522 case 'k': {
523 if (!assembleVintf.addKernel(optarg)) {
524 std::cerr << "ERROR: Unrecognized --kernel argument." << std::endl;
525 return 1;
526 }
527 } break;
528
Yifan Honga2635c42017-12-12 13:20:33 -0800529 case 'l': {
530 if (!assembleVintf.setHalsOnly()) {
531 return 1;
532 }
533 } break;
534
535 case 'n': {
536 if (!assembleVintf.setNoHals()) {
537 return 1;
538 }
539 } break;
540
Yifan Hong4d18bcc2017-04-07 21:47:16 +0000541 case 'h':
542 default: {
543 help();
544 return 1;
545 } break;
546 }
547 }
548
Yifan Hong9aa63702017-05-16 16:37:50 -0700549 bool success = assembleVintf.assemble();
Yifan Hong4650ad82017-05-01 17:28:02 -0700550
551 return success ? 0 : 1;
Yifan Hong4d18bcc2017-04-07 21:47:16 +0000552}