• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2025 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <filesystem>
6 #include <fstream>
7 #include <iostream>
8 
9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h"
11 #include "base/json/json_reader.h"
12 #include "base/strings/string_util.h"
13 #include "base/values.h"
14 #include "gn/build_settings.h"
15 #include "gn/config.h"
16 #include "gn/filesystem_utils.h"
17 #include "gn/functions.h"
18 #include "gn/label_ptr.h"
19 #include "gn/parse_tree.h"
20 #include "gn/precise/precise.h"
21 #include "gn/settings.h"
22 #include "gn/substitution_writer.h"
23 #include "gn/target.h"
24 #include "gn/value.h"
25 
26 namespace fs = std::filesystem;
27 
28 PreciseManager* PreciseManager::instance_ = nullptr;
29 static int hFileDepth_ = INT_MAX;
30 static int cFileDepth_ = INT_MAX;
31 static int gnFileDepth_ = INT_MAX;
32 static int gnModuleDepth_ = INT_MAX;
33 static bool testOnly_ = false;
34 static std::string outDir_;
35 static std::string preciseConfig_;
36 static std::string modifyFilesPath_;
37 static std::string preciseResultPath_;
38 static std::string preciseLogPath_;
39 static std::vector<std::string> targetTypeList_;
40 static std::vector<std::string> modifyHFileList_;
41 static std::vector<std::string> modifyCFileList_;
42 static std::vector<std::string> modifyGnFileList_;
43 static std::vector<std::string> modifyGnModuleList_;
44 static std::vector<std::string> ignoreList_;
45 static std::vector<std::string> maxRangeList_;
46 
ReadFile(base::FilePath path,std::string & content)47 static bool ReadFile(base::FilePath path, std::string& content)
48 {
49     if (!base::ReadFileToString(path, &content)) {
50         return false;
51     }
52     return true;
53 }
54 
LoadHFileList(const base::Value & list)55 static void LoadHFileList(const base::Value& list)
56 {
57     for (const base::Value& value : list.GetList()) {
58         modifyHFileList_.push_back(value.GetString());
59     }
60 }
61 
LoadCFileList(const base::Value & list)62 static void LoadCFileList(const base::Value& list)
63 {
64     for (const base::Value& value : list.GetList()) {
65         modifyCFileList_.push_back(value.GetString());
66     }
67 }
68 
LoadGnFileList(const base::Value & list)69 static void LoadGnFileList(const base::Value& list)
70 {
71     for (const base::Value& value : list.GetList()) {
72         modifyGnFileList_.push_back(value.GetString());
73     }
74 }
75 
LoadGnModuleList(const base::Value & list)76 static void LoadGnModuleList(const base::Value& list)
77 {
78     for (const base::Value& value : list.GetList()) {
79         modifyGnModuleList_.push_back(value.GetString());
80     }
81 }
82 
LoadHFileDepth(const base::Value & depth)83 static void LoadHFileDepth(const base::Value& depth)
84 {
85     hFileDepth_ = depth.GetInt();
86 }
87 
LoadCFileDepth(const base::Value & depth)88 static void LoadCFileDepth(const base::Value& depth)
89 {
90     cFileDepth_ = depth.GetInt();
91 }
92 
LoadGnFileDepth(const base::Value & depth)93 static void LoadGnFileDepth(const base::Value& depth)
94 {
95     gnFileDepth_ = depth.GetInt();
96 }
97 
LoadGnModuleDepth(const base::Value & depth)98 static void LoadGnModuleDepth(const base::Value& depth)
99 {
100     gnModuleDepth_ = depth.GetInt();
101 }
102 
LoadIgnoreList(const base::Value & list)103 static void LoadIgnoreList(const base::Value& list)
104 {
105     for (const base::Value& value : list.GetList()) {
106         ignoreList_.push_back(value.GetString());
107     }
108 }
109 
LoadMaxRangeList(const base::Value & list)110 static void LoadMaxRangeList(const base::Value& list)
111 {
112     for (const base::Value& value : list.GetList()) {
113         maxRangeList_.push_back(value.GetString());
114     }
115 }
116 
LoadModifyFilesPath(const base::Value & value)117 static void LoadModifyFilesPath(const base::Value& value)
118 {
119     modifyFilesPath_ = value.GetString();
120     std::cout << "Precise config modify files path : " << modifyFilesPath_ << std::endl;
121 }
122 
LoadPreciseResultPath(const base::Value & value)123 static void LoadPreciseResultPath(const base::Value& value)
124 {
125     preciseResultPath_ = value.GetString();
126     std::cout << "Precise config result path : " << preciseResultPath_ << std::endl;
127 }
128 
LoadPreciseLogPath(const base::Value & value)129 static void LoadPreciseLogPath(const base::Value& value)
130 {
131     preciseLogPath_ = value.GetString();
132     std::cout << "Precise config log path : " << preciseLogPath_ << std::endl;
133 }
134 
LoadTestOnly(const base::Value & value)135 static void LoadTestOnly(const base::Value& value)
136 {
137     testOnly_ = value.GetBool();
138     std::cout << "Precise config testonly : " << testOnly_ << std::endl;
139 }
140 
LoadTargetTypeList(const base::Value & list)141 static void LoadTargetTypeList(const base::Value& list)
142 {
143     for (const base::Value& value : list.GetList()) {
144         targetTypeList_.push_back(value.GetString());
145     }
146 }
147 
148 static std::map<std::string, std::function<void(const base::Value& value)>> modifyMap_ = {
149     { "h_file", LoadHFileList },
150     { "c_file", LoadCFileList },
151     { "gn_file", LoadGnFileList },
152     { "gn_module", LoadGnModuleList },
153 };
154 
155 static std::map<std::string, std::function<void(const base::Value& value)>> configMap_ = {
156     { "h_file_depth", LoadHFileDepth },
157     { "c_file_depth", LoadCFileDepth },
158     { "gn_file_depth", LoadGnFileDepth },
159     { "gn_module_depth", LoadGnModuleDepth },
160     { "test_only", LoadTestOnly},
161     { "target_type_list", LoadTargetTypeList },
162     { "ignore_list", LoadIgnoreList },
163     { "max_range_list", LoadMaxRangeList },
164     { "modify_files_path", LoadModifyFilesPath },
165     { "precise_result_path", LoadPreciseResultPath },
166     { "precise_log_path", LoadPreciseLogPath },
167 };
168 
LoadModifyList()169 static void LoadModifyList()
170 {
171     std::string modifyListContent;
172     if (!ReadFile(base::FilePath(modifyFilesPath_), modifyListContent)) {
173         std::cout << "Load modify file list failed." << std::endl;
174         return;
175     }
176     const base::DictionaryValue* modifyListDict;
177     std::unique_ptr<base::Value> modifyList = base::JSONReader::ReadAndReturnError(modifyListContent,
178         base::JSONParserOptions::JSON_PARSE_RFC, nullptr, nullptr, nullptr, nullptr);
179     if (!modifyList) {
180         std::cout << "Read modify file json failed." << std::endl;
181         return;
182     }
183     if (!modifyList->GetAsDictionary(&modifyListDict)) {
184         std::cout << "Get modify file dictionary failed." << std::endl;
185         return;
186     }
187 
188     for (const auto kv : modifyListDict->DictItems()) {
189         auto iter = modifyMap_.find(kv.first);
190         if (iter != modifyMap_.end()) {
191             iter->second(kv.second);
192         }
193     }
194 }
195 
LoadPreciseConfig()196 static void LoadPreciseConfig()
197 {
198     std::string configContent;
199     if (!ReadFile(base::FilePath(preciseConfig_), configContent)) {
200         std::cout << "Load precise config failed." << std::endl;
201         return;
202     }
203     const base::DictionaryValue* configDict;
204     std::unique_ptr<base::Value> config = base::JSONReader::ReadAndReturnError(configContent,
205         base::JSONParserOptions::JSON_PARSE_RFC, nullptr, nullptr, nullptr, nullptr);
206     if (!config) {
207         std::cout << "Read precise config json failed." << std::endl;
208         return;
209     }
210     if (!config->GetAsDictionary(&configDict)) {
211         std::cout << "Get precise config dictionary failed." << std::endl;
212         return;
213     }
214 
215     for (const auto kv : configDict->DictItems()) {
216         auto iter = configMap_.find(kv.first);
217         if (iter != configMap_.end()) {
218             iter->second(kv.second);
219         }
220     }
221 }
222 
PreciseManager(const std::string & outDir,const std::string & preciseConfig)223 PreciseManager::PreciseManager(const std::string& outDir, const std::string& preciseConfig)
224 {
225     std::cout << "Read precise config from " << preciseConfig << std::endl;
226     outDir_ = outDir;
227     preciseConfig_ = preciseConfig;
228     LoadPreciseConfig();
229     LoadModifyList();
230 }
231 
AddModule(std::string name,Node * node)232 void PreciseManager::AddModule(std::string name, Node* node)
233 {
234     moduleList_[name] = node;
235 }
236 
IsIgnore(const std::string & name)237 bool PreciseManager::IsIgnore(const std::string& name)
238 {
239     auto result = std::find(ignoreList_.begin(), ignoreList_.end(), name);
240     if (result != ignoreList_.end()) {
241         return true;
242     }
243     return false;
244 }
245 
IsInMaxRange(const std::string & name)246 bool PreciseManager::IsInMaxRange(const std::string& name)
247 {
248     if (maxRangeList_.empty()) {
249         return true;
250     }
251     auto result = std::find(maxRangeList_.begin(), maxRangeList_.end(), name);
252     if (result != maxRangeList_.end()) {
253         return true;
254     }
255     return false;
256 }
257 
IsDependent(const Node * node)258 bool PreciseManager::IsDependent(const Node* node)
259 {
260     int size = node->GetFromList().size();
261     if (size == 0) {
262         return false;
263     }
264     if (size == 1) {
265         const Item* item = ((Module* )(node->GetFromList()[0]))->GetItem();
266         if(!FilterType(item)) {
267             return false;
268         }
269     }
270     return true;
271 }
272 
IsContainModifiedFiles(const std::string & file,bool isHFile)273 bool PreciseManager::IsContainModifiedFiles(const std::string& file, bool isHFile)
274 {
275     if (isHFile) {
276         for (const std::string& h : modifyHFileList_) {
277             if (base::starts_with(h, file)) {
278                 return true;
279             }
280         }
281         return false;
282     } else {
283         for (const std::string& c : modifyCFileList_) {
284             if (c == file) {
285                 return true;
286             }
287         }
288         return false;
289     }
290 }
291 
GetModule(const std::string & name)292 Node* PreciseManager::GetModule(const std::string& name)
293 {
294     return moduleList_[name];
295 }
296 
CheckIncludeInConfig(const Config * config)297 bool PreciseManager::CheckIncludeInConfig(const Config* config)
298 {
299     const std::vector<SourceDir> dirs = config->own_values().include_dirs();
300     for (const SourceDir& dir : dirs) {
301         if (IsContainModifiedFiles(dir.value(), true)) {
302             return true;
303         }
304     }
305     return false;
306 }
307 
CheckIncludeInTarget(const Item * item)308 bool PreciseManager::CheckIncludeInTarget(const Item* item)
309 {
310     if (item == nullptr) {
311         return false;
312     }
313 
314     std::vector<SourceDir> dirs;
315     if (item->GetItemTypeName() == "target") {
316         dirs = item->AsTarget()->include_dirs();
317     } else if (item->GetItemTypeName() == "config") {
318         dirs = item->AsConfig()->own_values().include_dirs();
319     } else {
320         return false;
321     }
322 
323     std::string name = item->label().GetUserVisibleName(false);
324     for (const SourceDir& dir : dirs) {
325         if (IsContainModifiedFiles(dir.value(), true)) {
326             return true;
327         }
328     }
329     return false;
330 }
331 
CheckSourceInTarget(const Item * item)332 bool PreciseManager::CheckSourceInTarget(const Item* item)
333 {
334     if (item == nullptr || item->GetItemTypeName() != "target") {
335         return false;
336     }
337 
338     const std::vector<SourceFile>& dirs = item->AsTarget()->sources();
339     for (const SourceFile& dir : dirs) {
340         if (IsContainModifiedFiles(dir.value(), false)) {
341             return true;
342         }
343     }
344     return false;
345 }
346 
CheckConfigInfo(const UniqueVector<LabelConfigPair> & configs)347 bool PreciseManager::CheckConfigInfo(const UniqueVector<LabelConfigPair>& configs)
348 {
349     for (const auto& config : configs) {
350         std::string label = config.label.GetUserVisibleName(false);
351         if (base::starts_with(label, "//build/config")) {
352             continue;
353         }
354         if (CheckIncludeInConfig(config.ptr)) {
355             return true;
356         }
357     }
358     return false;
359 }
360 
CheckPrivateConfigs(const Item * item)361 bool PreciseManager::CheckPrivateConfigs(const Item* item)
362 {
363     if (item == nullptr || item->GetItemTypeName() != "target") {
364         return false;
365     }
366 
367     const UniqueVector<LabelConfigPair> configs = item->AsTarget()->configs();
368     if (configs.size() > 0) {
369         if (CheckConfigInfo(configs)) {
370             return true;
371         }
372     }
373     return false;
374 }
375 
CheckPublicConfigs(const Item * item)376 bool PreciseManager::CheckPublicConfigs(const Item* item)
377 {
378     if (item == nullptr || item->GetItemTypeName() != "target") {
379         return false;
380     }
381 
382     const UniqueVector<LabelConfigPair> configs = item->AsTarget()->public_configs();
383     if (configs.size() > 0) {
384         if (CheckConfigInfo(configs)) {
385             return true;
386         }
387     }
388     return false;
389 }
390 
CheckAllDepConfigs(const Item * item)391 bool PreciseManager::CheckAllDepConfigs(const Item* item)
392 {
393     if (item == nullptr || item->GetItemTypeName() != "target") {
394         return false;
395     }
396 
397     const UniqueVector<LabelConfigPair> configs = item->AsTarget()->all_dependent_configs();
398     if (configs.size() > 0) {
399         if (CheckConfigInfo(configs)) {
400             return true;
401         }
402     }
403     return false;
404 }
405 
EnsurePathExists(const std::string & filePath)406 void PreciseManager::EnsurePathExists(const std::string& filePath)
407 {
408     fs::path path(filePath);
409     auto dirPath = path.parent_path();
410     if (!dirPath.empty() && !fs::exists(dirPath)) {
411         fs::create_directories(dirPath);
412     }
413 }
414 
WriteFile(const std::string & path,const std::string & info)415 void PreciseManager::WriteFile(const std::string& path, const std::string& info)
416 {
417     std::string outFile = outDir_ + "/" + path;
418     EnsurePathExists(outFile);
419     std::ofstream fileFd;
420     fileFd.open(outFile, std::ios::out);
421     fileFd << info;
422     fileFd.close();
423 }
424 
FilterType(const Item * item)425 bool PreciseManager::FilterType(const Item* item)
426 {
427     if (item == nullptr || item->GetItemTypeName() == "config") {
428         return false;
429     }
430 
431     std::string name = item->label().GetUserVisibleName(false);
432     if (base::ends_with(name, "__check")
433         || base::ends_with(name, "__collect")
434         || base::ends_with(name, "__notice")
435         || base::ends_with(name, "_info_install_info")
436         || base::ends_with(name, "_resource_copy")) {
437         return false;
438     }
439 
440     return true;
441 }
442 
IsTargetTypeMatch(const Item * item)443 bool PreciseManager::IsTargetTypeMatch(const Item* item)
444 {
445     if (item == nullptr || item->GetItemTypeName() == "config") {
446         return false;
447     }
448 
449     std::string type;
450     if (item->GetItemTypeName() == "target") {
451         std::string tmp(Target::GetStringForOutputType(item->AsTarget()->output_type()));
452         type += tmp;
453     } else {
454         type += item->GetItemTypeName();
455     }
456 
457     if (std::find(targetTypeList_.begin(), targetTypeList_.end(), type) != targetTypeList_.end()) {
458         return true;
459     }
460 
461     return false;
462 }
463 
IsTestOnlyMatch(const Item * item)464 bool PreciseManager::IsTestOnlyMatch(const Item* item)
465 {
466     if (item == nullptr || (testOnly_ && !item->testonly())) {
467         return false;
468     }
469 
470     return true;
471 }
472 
IsFirstRecord(const std::vector<std::string> & result,const std::string & name)473 bool PreciseManager::IsFirstRecord(const std::vector<std::string>& result, const std::string& name)
474 {
475     if (std::find(result.begin(), result.end(), name) == result.end()) {
476         return true;
477     }
478     return false;
479 }
480 
PreciseSearch(const Node * node,std::vector<std::string> & result,std::vector<std::string> & log,bool forGn,int depth,int maxDepth)481 void PreciseManager::PreciseSearch(const Node* node, std::vector<std::string>& result, std::vector<std::string>& log,
482     bool forGn, int depth, int maxDepth)
483 {
484     Module* module = (Module* )node;
485     const Item* item = module->GetItem();
486     std::string name = item->label().GetUserVisibleName(false);
487     log.push_back("Check:" + name);
488 
489     if (depth >= maxDepth) {
490         log.push_back("Over Depth:" + name);
491         return;
492     }
493 
494     if (!FilterType(item)) {
495         log.push_back("FilterType false:" + name);
496         return;
497     }
498 
499     if (IsTargetTypeMatch(item) && IsTestOnlyMatch(item) && IsFirstRecord(result, name)
500         && !IsIgnore(name) && IsInMaxRange(name)) {
501         log.push_back("OK:" + name);
502         result.push_back(name);
503         return;
504     }
505 
506     for (Node* parent : node->GetFromList()) {
507         Module* moduleParent = (Module* )parent;
508         const Item* itemParent = moduleParent->GetItem();
509         std::string nameParent = itemParent->label().GetUserVisibleName(false);
510         log.push_back("Check Parent:" + nameParent + "->" + name);
511         PreciseSearch(parent, result, log, forGn, depth + 1, maxDepth);
512     }
513 }
514 
CheckModuleInGn(const std::string & label)515 bool PreciseManager::CheckModuleInGn(const std::string& label)
516 {
517     for (const std::string& gn : modifyGnFileList_) {
518         size_t pos = label.find(":");
519         if (pos == std::string::npos) {
520             return false;
521         }
522         std::string labelPrefix = label.substr(0, pos);
523 
524         size_t posGn = gn.find("BUILD.gn");
525         if (posGn == std::string::npos) {
526             return false;
527         }
528         std::string filePrefix = gn.substr(0, posGn - 1);
529         if (labelPrefix == filePrefix) {
530             return true;
531         }
532     }
533     return false;
534 }
535 
CheckModuleMatch(const std::string & label)536 bool PreciseManager::CheckModuleMatch(const std::string& label)
537 {
538     for (const std::string& modify : modifyGnModuleList_) {
539         if (label == modify) {
540             return true;
541         }
542     }
543     return false;
544 }
545 
WritePreciseTargets(const std::vector<std::string> & result,const std::vector<std::string> & log)546 void PreciseManager::WritePreciseTargets(const std::vector<std::string>& result, const std::vector<std::string>& log)
547 {
548     std::string logInfo = "";
549     for(size_t i = 0; i < log.size(); ++i) {
550         logInfo += log[i];
551         logInfo += " ";
552         logInfo += "\n";
553     }
554     WriteFile(preciseLogPath_, logInfo);
555 
556     std::string resultInfo = "";
557     for(size_t i = 0; i < result.size(); ++i) {
558         resultInfo += result[i];
559         resultInfo += " ";
560         resultInfo += "\n";
561     }
562     WriteFile(preciseResultPath_, resultInfo);
563 }
564 
GeneratPreciseTargets()565 void PreciseManager::GeneratPreciseTargets()
566 {
567     std::cout << "GeneratPreciseTargets Begain." << std::endl;
568     std::vector<std::string> result;
569     std::vector<std::string> log;
570     log.push_back("Init Precise depth:" + std::to_string(hFileDepth_) + " " + std::to_string(cFileDepth_)
571         + " " + std::to_string(gnFileDepth_) + " " + std::to_string(gnModuleDepth_));
572 
573     for (const auto& pair : moduleList_) {
574         Module* module = (Module* )pair.second;
575         const Item* item = module->GetItem();
576         std::string label = item->label().GetUserVisibleName(false);
577         if (!FilterType(item)) {
578             continue;
579         }
580 
581         if (CheckSourceInTarget(item)) {
582             log.push_back("Hit C:");
583             PreciseSearch(pair.second, result, log, false, 0, cFileDepth_);
584         } else if (CheckIncludeInTarget(item) || CheckPrivateConfigs(item)
585             || CheckPublicConfigs(item) || CheckAllDepConfigs(item)) {
586             log.push_back("Hit H:");
587             PreciseSearch(pair.second, result, log, false, 0, hFileDepth_);
588         } else if (CheckModuleInGn(label)) {
589             log.push_back("Hit GN:");
590             PreciseSearch(pair.second, result, log, true, 0, gnFileDepth_);
591         } else if (CheckModuleMatch(label)) {
592             log.push_back("Hit Module:");
593             PreciseSearch(pair.second, result, log, true, 0, gnModuleDepth_);
594         }
595     }
596     WritePreciseTargets(result, log);
597 }