1// Copyright (c) 2013 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#ifndef TOOLS_GN_FILESYSTEM_UTILS_H_ 6#define TOOLS_GN_FILESYSTEM_UTILS_H_ 7 8#include <stddef.h> 9 10#include <string> 11#include <string_view> 12 13#include "base/files/file_path.h" 14#include "gn/settings.h" 15#include "gn/target.h" 16 17class Err; 18 19std::string FilePathToUTF8(const base::FilePath::StringType& str); 20inline std::string FilePathToUTF8(const base::FilePath& path) { 21 return FilePathToUTF8(path.value()); 22} 23base::FilePath UTF8ToFilePath(std::string_view sp); 24 25// Extensions ----------------------------------------------------------------- 26 27// Returns the index of the extension (character after the last dot not after a 28// slash). Returns std::string::npos if not found. Returns path.size() if the 29// file ends with a dot. 30size_t FindExtensionOffset(const std::string& path); 31 32// Returns a string piece pointing into the input string identifying the 33// extension. Note that the input pointer must outlive the output. 34std::string_view FindExtension(const std::string* path); 35 36// Filename parts ------------------------------------------------------------- 37 38// Returns the offset of the character following the last slash, or 39// 0 if no slash was found. Returns path.size() if the path ends with a slash. 40// Note that the input pointer must outlive the output. 41size_t FindFilenameOffset(const std::string& path); 42 43// Returns a string piece pointing into the input string identifying the 44// file name (following the last slash, including the extension). Note that the 45// input pointer must outlive the output. 46std::string_view FindFilename(const std::string* path); 47 48// Like FindFilename but does not include the extension. 49std::string_view FindFilenameNoExtension(const std::string* path); 50 51// Removes everything after the last slash. The last slash, if any, will be 52// preserved. 53void RemoveFilename(std::string* path); 54 55// Returns if the given character is a slash. This allows both slashes and 56// backslashes for consistency between Posix and Windows (as opposed to 57// FilePath::IsSeparator which is based on the current platform). 58inline bool IsSlash(const char ch) { 59 return ch == '/' || ch == '\\'; 60} 61 62// Returns true if the given path ends with a slash. 63bool EndsWithSlash(std::string_view s); 64 65// Path parts ----------------------------------------------------------------- 66 67// Returns a string piece pointing into the input string identifying the 68// directory name of the given path, including the last slash. Note that the 69// input pointer must outlive the output. 70std::string_view FindDir(const std::string* path); 71 72// Returns the substring identifying the last component of the dir, or the 73// empty substring if none. For example "//foo/bar/" -> "bar". 74std::string_view FindLastDirComponent(const SourceDir& dir); 75 76// Returns true if the given string is in the given output dir. This is pretty 77// stupid and doesn't handle "." and "..", etc., it is designed for a sanity 78// check to keep people from writing output files to the source directory 79// accidentally. 80bool IsStringInOutputDir(const SourceDir& output_dir, const std::string& str); 81 82// Verifies that the given string references a file inside of the given 83// directory. This just uses IsStringInOutputDir above. 84// 85// The origin will be blamed in the error. 86// 87// If the file isn't in the dir, returns false and sets the error. Otherwise 88// returns true and leaves the error untouched. 89bool EnsureStringIsInOutputDir(const SourceDir& output_dir, 90 const std::string& str, 91 const ParseNode* origin, 92 Err* err); 93 94// ---------------------------------------------------------------------------- 95 96// Returns true if the input string is absolute. Double-slashes at the 97// beginning are treated as source-relative paths. On Windows, this handles 98// paths of both the native format: "C:/foo" and ours "/C:/foo" 99bool IsPathAbsolute(std::string_view path); 100 101// Returns true if the input string is source-absolute. Source-absolute 102// paths begin with two forward slashes and resolve as if they are 103// relative to the source root. 104bool IsPathSourceAbsolute(std::string_view path); 105 106// Given an absolute path, checks to see if is it is inside the source root. 107// If it is, fills a source-absolute path into the given output and returns 108// true. If it isn't, clears the dest and returns false. 109// 110// The source_root should be a base::FilePath converted to UTF-8. On Windows, 111// it should begin with a "C:/" rather than being our SourceFile's style 112// ("/C:/"). The source root can end with a slash or not. 113// 114// Note that this does not attempt to normalize slashes in the output. 115bool MakeAbsolutePathRelativeIfPossible(std::string_view source_root, 116 std::string_view path, 117 std::string* dest); 118 119// Given two absolute paths |base| and |target|, returns a relative path to 120// |target| as if the current directory was |base|. The relative path returned 121// is minimal. For example, if "../../a/b/" and "../b" are both valid, then the 122// latter will be returned. On Windows, it's impossible to have a relative path 123// from C:\foo to D:\bar, so the absolute path |target| is returned instead for 124// this case. 125base::FilePath MakeAbsoluteFilePathRelativeIfPossible( 126 const base::FilePath& base, 127 const base::FilePath& target); 128 129// Collapses "." and sequential "/"s and evaluates "..". |path| may be 130// system-absolute, source-absolute, or relative. If |path| is source-absolute 131// and |source_root| is non-empty, |path| may be system absolute after this 132// function returns, if |path| references the filesystem outside of 133// |source_root| (ex. path = "//.."). In this case on Windows, |path| will have 134// a leading slash. Otherwise, |path| will retain its relativity. |source_root| 135// must not end with a slash. 136void NormalizePath(std::string* path, 137 std::string_view source_root = std::string_view()); 138 139// Converts slashes to backslashes for Windows. Keeps the string unchanged 140// for other systems. 141void ConvertPathToSystem(std::string* path); 142 143// Takes a path, |input|, and makes it relative to the given directory 144// |dest_dir|. Both inputs may be source-relative (e.g. begins with 145// with "//") or may be absolute. 146// 147// If supplied, the |source_root| parameter is the absolute path to 148// the source root and not end in a slash. Unless you know that the 149// inputs are always source relative, this should be supplied. 150std::string RebasePath(const std::string& input, 151 const SourceDir& dest_dir, 152 std::string_view source_root = std::string_view()); 153 154// Resolves a file or dir name (parameter input) relative to 155// value directory. Will return an empty SourceDir/File on error 156// and set the give *err pointer (required). Empty input is always an error. 157// Returned value can be used to set value in either SourceFile or SourceDir 158// (based on as_file parameter). 159// 160// Parameter as_file defines whether result path will look like a file path 161// or it should be treated as a directory (contains "/" and the end 162// of the string). 163// 164// If source_root is supplied, these functions will additionally handle the 165// case where the input is a system-absolute but still inside the source 166// tree. This is the case for some external tools. 167std::string ResolveRelative(std::string_view input, 168 const std::string& value, 169 bool as_file, 170 std::string_view source_root); 171 172// Resolves source file or directory relative to some given source root. Returns 173// an empty file path on error. 174base::FilePath ResolvePath(const std::string& value, 175 bool as_file, 176 const base::FilePath& source_root); 177 178// Returns the given directory with no terminating slash at the end, such that 179// appending a slash and more stuff will produce a valid path. 180// 181// If the directory refers to either the source or system root, we'll append 182// a "." so this remains valid. 183std::string DirectoryWithNoLastSlash(const SourceDir& dir); 184 185// Returns the "best" SourceDir representing the given path. If it's inside the 186// given source_root, a source-relative directory will be returned (e.g. 187// "//foo/bar.cc". If it's outside of the source root or the source root is 188// empty, a system-absolute directory will be returned. 189SourceDir SourceDirForPath(const base::FilePath& source_root, 190 const base::FilePath& path); 191 192// Like SourceDirForPath but returns the SourceDir representing the current 193// directory. 194SourceDir SourceDirForCurrentDirectory(const base::FilePath& source_root); 195 196// Given the label of a toolchain and whether that toolchain is the default 197// toolchain, returns the name of the subdirectory for that toolchain's 198// output. This will be the empty string to indicate that the toolchain outputs 199// go in the root build directory. Otherwise, the result will end in a slash. 200std::string GetOutputSubdirName(const Label& toolchain_label, bool is_default); 201 202// Returns true if the contents of the file and stream given are equal, false 203// otherwise. 204bool ContentsEqual(const base::FilePath& file_path, const std::string& data); 205 206// Writes given stream contents to the given file. Returns true if data was 207// successfully written, false otherwise. |err| is set on error if not nullptr. 208bool WriteFile(const base::FilePath& file_path, 209 const std::string& data, 210 Err* err); 211 212// ----------------------------------------------------------------------------- 213 214enum class BuildDirType { 215 // Returns the root toolchain dir rather than the generated or output 216 // subdirectories. This is valid only for the toolchain directory getters. 217 // Asking for this for a target or source dir makes no sense. 218 TOOLCHAIN_ROOT, 219 220 // Generated file directory. 221 GEN, 222 223 // Output file directory. 224 OBJ, 225 226 // Phony file directory. As the name implies, this is not a real file 227 // directory, but a path that is used for the declaration of phony targets. 228 // This is done to avoid duplicate target names between real files and phony 229 // aliases that point to them. 230 PHONY, 231}; 232 233// In different contexts, different information is known about the toolchain in 234// question. If you have a Target or settings object, everything can be 235// extracted from there. But when querying label information on something in 236// another toolchain, for example, the only thing known (it may not even exist) 237// is the toolchain label string and whether it matches the default toolchain. 238// 239// This object extracts the relevant information from a variety of input 240// types for the convenience of the caller. 241class BuildDirContext { 242 public: 243 // Extracts toolchain information associated with the given target. 244 explicit BuildDirContext(const Target* target); 245 246 // Extracts toolchain information associated with the given settings object. 247 explicit BuildDirContext(const Settings* settings); 248 249 // Extrats toolchain information from the current toolchain of the scope. 250 explicit BuildDirContext(const Scope* execution_scope); 251 252 // Extracts the default toolchain information from the given execution 253 // scope. The toolchain you want to query must be passed in. This doesn't 254 // use the settings object from the Scope so one can query other toolchains. 255 // If you want to use the scope's current toolchain, use the version above. 256 BuildDirContext(const Scope* execution_scope, const Label& toolchain_label); 257 258 // Specify all information manually. 259 BuildDirContext(const BuildSettings* build_settings, 260 const Label& toolchain_label, 261 bool is_default_toolchain); 262 263 const BuildSettings* build_settings; 264 const Label& toolchain_label; 265 bool is_default_toolchain; 266}; 267 268// Returns the root, object, or generated file directory for the toolchain. 269// 270// The toolchain object file root is never exposed in GN (there is no 271// root_obj_dir variable) so BuildDirType::OBJ would normally never be passed 272// to this function except when it's called by one of the variants below that 273// append paths to it. 274SourceDir GetBuildDirAsSourceDir(const BuildDirContext& context, 275 BuildDirType type); 276OutputFile GetBuildDirAsOutputFile(const BuildDirContext& context, 277 BuildDirType type); 278 279// Returns the output or generated file directory corresponding to the given 280// source directory. 281SourceDir GetSubBuildDirAsSourceDir(const BuildDirContext& context, 282 const SourceDir& source_dir, 283 BuildDirType type); 284OutputFile GetSubBuildDirAsOutputFile(const BuildDirContext& context, 285 const SourceDir& source_dir, 286 BuildDirType type); 287 288// Returns the output or generated file directory corresponding to the given 289// target. 290SourceDir GetBuildDirForTargetAsSourceDir(const Target* target, 291 BuildDirType type); 292OutputFile GetBuildDirForTargetAsOutputFile(const Target* target, 293 BuildDirType type); 294 295// Returns the scope's current directory. 296SourceDir GetScopeCurrentBuildDirAsSourceDir(const Scope* scope, 297 BuildDirType type); 298// Lack of OutputDir version is due only to it not currently being needed, 299// please add one if you need it. 300 301#endif // TOOLS_GN_FILESYSTEM_UTILS_H_ 302