1 // Copyright (C) 2017 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "utils/header_abi_util.h" 16 17 #include <llvm/Support/FileSystem.h> 18 #include <llvm/Support/Path.h> 19 #include <llvm/Support/raw_ostream.h> 20 21 #include <set> 22 #include <string> 23 #include <vector> 24 25 26 namespace header_checker { 27 namespace utils { 28 29 30 static bool ShouldSkipFile(llvm::StringRef &file_name) { 31 // Ignore swap files, hidden files, and hidden directories. Do not recurse 32 // into hidden directories either. We should also not look at source files. 33 // Many projects include source files in their exports. 34 return (file_name.empty() || file_name.startswith(".") || 35 file_name.endswith(".swp") || file_name.endswith(".swo") || 36 file_name.endswith("#") || file_name.endswith(".cpp") || 37 file_name.endswith(".cc") || file_name.endswith(".c")); 38 } 39 40 std::string RealPath(const std::string &path) { 41 char file_abs_path[PATH_MAX]; 42 if (realpath(path.c_str(), file_abs_path) == nullptr) { 43 return ""; 44 } 45 return file_abs_path; 46 } 47 48 bool CollectExportedHeaderSet(const std::string &dir_name, 49 std::set<std::string> *exported_headers) { 50 std::error_code ec; 51 llvm::sys::fs::recursive_directory_iterator walker(dir_name, ec); 52 // Default construction - end of directory. 53 llvm::sys::fs::recursive_directory_iterator end; 54 for ( ; walker != end; walker.increment(ec)) { 55 if (ec) { 56 llvm::errs() << "Failed to walk directory: " << dir_name << ": " 57 << ec.message() << "\n"; 58 return false; 59 } 60 61 const std::string &file_path = walker->path(); 62 63 llvm::StringRef file_name(llvm::sys::path::filename(file_path)); 64 // Ignore swap files and hidden files / dirs. Do not recurse into them too. 65 // We should also not look at source files. Many projects include source 66 // files in their exports. 67 if (ShouldSkipFile(file_name)) { 68 walker.no_push(); 69 continue; 70 } 71 72 llvm::ErrorOr<llvm::sys::fs::basic_file_status> status = walker->status(); 73 if (!status) { 74 llvm::errs() << "Failed to stat file: " << file_path << "\n"; 75 return false; 76 } 77 78 if ((status->type() != llvm::sys::fs::file_type::symlink_file) && 79 (status->type() != llvm::sys::fs::file_type::regular_file)) { 80 // Ignore non regular files, except symlinks. 81 continue; 82 } 83 84 exported_headers->insert(RealPath(file_path)); 85 } 86 return true; 87 } 88 89 std::set<std::string> CollectAllExportedHeaders( 90 const std::vector<std::string> &exported_header_dirs) { 91 std::set<std::string> exported_headers; 92 for (auto &&dir : exported_header_dirs) { 93 if (!CollectExportedHeaderSet(dir, &exported_headers)) { 94 llvm::errs() << "Couldn't collect exported headers\n"; 95 ::exit(1); 96 } 97 } 98 return exported_headers; 99 } 100 101 } // namespace utils 102 } // namespace header_checker 103