Change next_proto member type.
[chromium-blink-merge.git] / tools / gn / filesystem_utils.cc
blob700b7b89f2e21ce96bb4b6b25d8cb9a5f7c66514
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.
5 #include "tools/gn/filesystem_utils.h"
7 #include <algorithm>
9 #include "base/files/file_util.h"
10 #include "base/logging.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "build/build_config.h"
14 #include "tools/gn/location.h"
15 #include "tools/gn/settings.h"
16 #include "tools/gn/source_dir.h"
18 namespace {
20 enum DotDisposition {
21 // The given dot is just part of a filename and is not special.
22 NOT_A_DIRECTORY,
24 // The given dot is the current directory.
25 DIRECTORY_CUR,
27 // The given dot is the first of a double dot that should take us up one.
28 DIRECTORY_UP
31 // When we find a dot, this function is called with the character following
32 // that dot to see what it is. The return value indicates what type this dot is
33 // (see above). This code handles the case where the dot is at the end of the
34 // input.
36 // |*consumed_len| will contain the number of characters in the input that
37 // express what we found.
38 DotDisposition ClassifyAfterDot(const std::string& path,
39 size_t after_dot,
40 size_t* consumed_len) {
41 if (after_dot == path.size()) {
42 // Single dot at the end.
43 *consumed_len = 1;
44 return DIRECTORY_CUR;
46 if (IsSlash(path[after_dot])) {
47 // Single dot followed by a slash.
48 *consumed_len = 2; // Consume the slash
49 return DIRECTORY_CUR;
52 if (path[after_dot] == '.') {
53 // Two dots.
54 if (after_dot + 1 == path.size()) {
55 // Double dot at the end.
56 *consumed_len = 2;
57 return DIRECTORY_UP;
59 if (IsSlash(path[after_dot + 1])) {
60 // Double dot folowed by a slash.
61 *consumed_len = 3;
62 return DIRECTORY_UP;
66 // The dots are followed by something else, not a directory.
67 *consumed_len = 1;
68 return NOT_A_DIRECTORY;
71 #if defined(OS_WIN)
72 inline char NormalizeWindowsPathChar(char c) {
73 if (c == '/')
74 return '\\';
75 return base::ToLowerASCII(c);
78 // Attempts to do a case and slash-insensitive comparison of two 8-bit Windows
79 // paths.
80 bool AreAbsoluteWindowsPathsEqual(const base::StringPiece& a,
81 const base::StringPiece& b) {
82 if (a.size() != b.size())
83 return false;
85 // For now, just do a case-insensitive ASCII comparison. We could convert to
86 // UTF-16 and use ICU if necessary. Or maybe base::strcasecmp is good enough?
87 for (size_t i = 0; i < a.size(); i++) {
88 if (NormalizeWindowsPathChar(a[i]) != NormalizeWindowsPathChar(b[i]))
89 return false;
91 return true;
94 bool DoesBeginWindowsDriveLetter(const base::StringPiece& path) {
95 if (path.size() < 3)
96 return false;
98 // Check colon first, this will generally fail fastest.
99 if (path[1] != ':')
100 return false;
102 // Check drive letter.
103 if (!IsAsciiAlpha(path[0]))
104 return false;
106 if (!IsSlash(path[2]))
107 return false;
108 return true;
110 #endif
112 // A wrapper around FilePath.GetComponents that works the way we need. This is
113 // not super efficient since it does some O(n) transformations on the path. If
114 // this is called a lot, we might want to optimize.
115 std::vector<base::FilePath::StringType> GetPathComponents(
116 const base::FilePath& path) {
117 std::vector<base::FilePath::StringType> result;
118 path.GetComponents(&result);
120 if (result.empty())
121 return result;
123 // GetComponents will preserve the "/" at the beginning, which confuses us.
124 // We don't expect to have relative paths in this function.
125 // Don't use IsSeparator since we always want to allow backslashes.
126 if (result[0] == FILE_PATH_LITERAL("/") ||
127 result[0] == FILE_PATH_LITERAL("\\"))
128 result.erase(result.begin());
130 #if defined(OS_WIN)
131 // On Windows, GetComponents will give us [ "C:", "/", "foo" ], and we
132 // don't want the slash in there. This doesn't support input like "C:foo"
133 // which means foo relative to the current directory of the C drive but
134 // that's basically legacy DOS behavior we don't need to support.
135 if (result.size() >= 2 && result[1].size() == 1 &&
136 IsSlash(static_cast<char>(result[1][0])))
137 result.erase(result.begin() + 1);
138 #endif
140 return result;
143 // Provides the equivalent of == for filesystem strings, trying to do
144 // approximately the right thing with case.
145 bool FilesystemStringsEqual(const base::FilePath::StringType& a,
146 const base::FilePath::StringType& b) {
147 #if defined(OS_WIN)
148 // Assume case-insensitive filesystems on Windows. We use the CompareString
149 // function to do a case-insensitive comparison based on the current locale
150 // (we don't want GN to depend on ICU which is large and requires data
151 // files). This isn't perfect, but getting this perfectly right is very
152 // difficult and requires I/O, and this comparison should cover 99.9999% of
153 // all cases.
155 // Note: The documentation for CompareString says it runs fastest on
156 // null-terminated strings with -1 passed for the length, so we do that here.
157 // There should not be embedded nulls in filesystem strings.
158 return ::CompareString(LOCALE_USER_DEFAULT, LINGUISTIC_IGNORECASE,
159 a.c_str(), -1, b.c_str(), -1) == CSTR_EQUAL;
160 #else
161 // Assume case-sensitive filesystems on non-Windows.
162 return a == b;
163 #endif
166 } // namespace
168 const char* GetExtensionForOutputType(Target::OutputType type,
169 Settings::TargetOS os) {
170 switch (os) {
171 case Settings::MAC:
172 switch (type) {
173 case Target::EXECUTABLE:
174 return "";
175 case Target::SHARED_LIBRARY:
176 return "dylib";
177 case Target::STATIC_LIBRARY:
178 return "a";
179 default:
180 NOTREACHED();
182 break;
184 case Settings::WIN:
185 switch (type) {
186 case Target::EXECUTABLE:
187 return "exe";
188 case Target::SHARED_LIBRARY:
189 return "dll.lib"; // Extension of import library.
190 case Target::STATIC_LIBRARY:
191 return "lib";
192 default:
193 NOTREACHED();
195 break;
197 case Settings::LINUX:
198 switch (type) {
199 case Target::EXECUTABLE:
200 return "";
201 case Target::SHARED_LIBRARY:
202 return "so";
203 case Target::STATIC_LIBRARY:
204 return "a";
205 default:
206 NOTREACHED();
208 break;
210 default:
211 NOTREACHED();
213 return "";
216 std::string FilePathToUTF8(const base::FilePath::StringType& str) {
217 #if defined(OS_WIN)
218 return base::WideToUTF8(str);
219 #else
220 return str;
221 #endif
224 base::FilePath UTF8ToFilePath(const base::StringPiece& sp) {
225 #if defined(OS_WIN)
226 return base::FilePath(base::UTF8ToWide(sp));
227 #else
228 return base::FilePath(sp.as_string());
229 #endif
232 size_t FindExtensionOffset(const std::string& path) {
233 for (int i = static_cast<int>(path.size()); i >= 0; i--) {
234 if (IsSlash(path[i]))
235 break;
236 if (path[i] == '.')
237 return i + 1;
239 return std::string::npos;
242 base::StringPiece FindExtension(const std::string* path) {
243 size_t extension_offset = FindExtensionOffset(*path);
244 if (extension_offset == std::string::npos)
245 return base::StringPiece();
246 return base::StringPiece(&path->data()[extension_offset],
247 path->size() - extension_offset);
250 size_t FindFilenameOffset(const std::string& path) {
251 for (int i = static_cast<int>(path.size()) - 1; i >= 0; i--) {
252 if (IsSlash(path[i]))
253 return i + 1;
255 return 0; // No filename found means everything was the filename.
258 base::StringPiece FindFilename(const std::string* path) {
259 size_t filename_offset = FindFilenameOffset(*path);
260 if (filename_offset == 0)
261 return base::StringPiece(*path); // Everything is the file name.
262 return base::StringPiece(&(*path).data()[filename_offset],
263 path->size() - filename_offset);
266 base::StringPiece FindFilenameNoExtension(const std::string* path) {
267 if (path->empty())
268 return base::StringPiece();
269 size_t filename_offset = FindFilenameOffset(*path);
270 size_t extension_offset = FindExtensionOffset(*path);
272 size_t name_len;
273 if (extension_offset == std::string::npos)
274 name_len = path->size() - filename_offset;
275 else
276 name_len = extension_offset - filename_offset - 1;
278 return base::StringPiece(&(*path).data()[filename_offset], name_len);
281 void RemoveFilename(std::string* path) {
282 path->resize(FindFilenameOffset(*path));
285 bool EndsWithSlash(const std::string& s) {
286 return !s.empty() && IsSlash(s[s.size() - 1]);
289 base::StringPiece FindDir(const std::string* path) {
290 size_t filename_offset = FindFilenameOffset(*path);
291 if (filename_offset == 0u)
292 return base::StringPiece();
293 return base::StringPiece(path->data(), filename_offset);
296 base::StringPiece FindLastDirComponent(const SourceDir& dir) {
297 const std::string& dir_string = dir.value();
299 if (dir_string.empty())
300 return base::StringPiece();
301 int cur = static_cast<int>(dir_string.size()) - 1;
302 DCHECK(dir_string[cur] == '/');
303 int end = cur;
304 cur--; // Skip before the last slash.
306 for (; cur >= 0; cur--) {
307 if (dir_string[cur] == '/')
308 return base::StringPiece(&dir_string[cur + 1], end - cur - 1);
310 return base::StringPiece(&dir_string[0], end);
313 bool EnsureStringIsInOutputDir(const SourceDir& dir,
314 const std::string& str,
315 const ParseNode* origin,
316 Err* err) {
317 // This check will be wrong for all proper prefixes "e.g. "/output" will
318 // match "/out" but we don't really care since this is just a sanity check.
319 const std::string& dir_str = dir.value();
320 if (str.compare(0, dir_str.length(), dir_str) == 0)
321 return true; // Output directory is hardcoded.
323 *err = Err(origin, "File is not inside output directory.",
324 "The given file should be in the output directory. Normally you would "
325 "specify\n\"$target_out_dir/foo\" or "
326 "\"$target_gen_dir/foo\". I interpreted this as\n\""
327 + str + "\".");
328 return false;
331 bool IsPathAbsolute(const base::StringPiece& path) {
332 if (path.empty())
333 return false;
335 if (!IsSlash(path[0])) {
336 #if defined(OS_WIN)
337 // Check for Windows system paths like "C:\foo".
338 if (path.size() > 2 && path[1] == ':' && IsSlash(path[2]))
339 return true;
340 #endif
341 return false; // Doesn't begin with a slash, is relative.
344 // Double forward slash at the beginning means source-relative (we don't
345 // allow backslashes for denoting this).
346 if (path.size() > 1 && path[1] == '/')
347 return false;
349 return true;
352 bool MakeAbsolutePathRelativeIfPossible(const base::StringPiece& source_root,
353 const base::StringPiece& path,
354 std::string* dest) {
355 DCHECK(IsPathAbsolute(source_root));
356 DCHECK(IsPathAbsolute(path));
358 dest->clear();
360 if (source_root.size() > path.size())
361 return false; // The source root is longer: the path can never be inside.
363 #if defined(OS_WIN)
364 // Source root should be canonical on Windows. Note that the initial slash
365 // must be forward slash, but that the other ones can be either forward or
366 // backward.
367 DCHECK(source_root.size() > 2 && source_root[0] != '/' &&
368 source_root[1] == ':' && IsSlash(source_root[2]));
370 size_t after_common_index = std::string::npos;
371 if (DoesBeginWindowsDriveLetter(path)) {
372 // Handle "C:\foo"
373 if (AreAbsoluteWindowsPathsEqual(source_root,
374 path.substr(0, source_root.size())))
375 after_common_index = source_root.size();
376 else
377 return false;
378 } else if (path[0] == '/' && source_root.size() <= path.size() - 1 &&
379 DoesBeginWindowsDriveLetter(path.substr(1))) {
380 // Handle "/C:/foo"
381 if (AreAbsoluteWindowsPathsEqual(source_root,
382 path.substr(1, source_root.size())))
383 after_common_index = source_root.size() + 1;
384 else
385 return false;
386 } else {
387 return false;
390 // If we get here, there's a match and after_common_index identifies the
391 // part after it.
393 // The base may or may not have a trailing slash, so skip all slashes from
394 // the path after our prefix match.
395 size_t first_after_slash = after_common_index;
396 while (first_after_slash < path.size() && IsSlash(path[first_after_slash]))
397 first_after_slash++;
399 dest->assign("//"); // Result is source root relative.
400 dest->append(&path.data()[first_after_slash],
401 path.size() - first_after_slash);
402 return true;
404 #else
406 // On non-Windows this is easy. Since we know both are absolute, just do a
407 // prefix check.
408 if (path.substr(0, source_root.size()) == source_root) {
409 // The base may or may not have a trailing slash, so skip all slashes from
410 // the path after our prefix match.
411 size_t first_after_slash = source_root.size();
412 while (first_after_slash < path.size() && IsSlash(path[first_after_slash]))
413 first_after_slash++;
415 dest->assign("//"); // Result is source root relative.
416 dest->append(&path.data()[first_after_slash],
417 path.size() - first_after_slash);
418 return true;
420 return false;
421 #endif
424 void NormalizePath(std::string* path) {
425 char* pathbuf = path->empty() ? NULL : &(*path)[0];
427 // top_index is the first character we can modify in the path. Anything
428 // before this indicates where the path is relative to.
429 size_t top_index = 0;
430 bool is_relative = true;
431 if (!path->empty() && pathbuf[0] == '/') {
432 is_relative = false;
434 if (path->size() > 1 && pathbuf[1] == '/') {
435 // Two leading slashes, this is a path into the source dir.
436 top_index = 2;
437 } else {
438 // One leading slash, this is a system-absolute path.
439 top_index = 1;
443 size_t dest_i = top_index;
444 for (size_t src_i = top_index; src_i < path->size(); /* nothing */) {
445 if (pathbuf[src_i] == '.') {
446 if (src_i == 0 || IsSlash(pathbuf[src_i - 1])) {
447 // Slash followed by a dot, see if it's something special.
448 size_t consumed_len;
449 switch (ClassifyAfterDot(*path, src_i + 1, &consumed_len)) {
450 case NOT_A_DIRECTORY:
451 // Copy the dot to the output, it means nothing special.
452 pathbuf[dest_i++] = pathbuf[src_i++];
453 break;
454 case DIRECTORY_CUR:
455 // Current directory, just skip the input.
456 src_i += consumed_len;
457 break;
458 case DIRECTORY_UP:
459 // Back up over previous directory component. If we're already
460 // at the top, preserve the "..".
461 if (dest_i > top_index) {
462 // The previous char was a slash, remove it.
463 dest_i--;
466 if (dest_i == top_index) {
467 if (is_relative) {
468 // We're already at the beginning of a relative input, copy the
469 // ".." and continue. We need the trailing slash if there was
470 // one before (otherwise we're at the end of the input).
471 pathbuf[dest_i++] = '.';
472 pathbuf[dest_i++] = '.';
473 if (consumed_len == 3)
474 pathbuf[dest_i++] = '/';
476 // This also makes a new "root" that we can't delete by going
477 // up more levels. Otherwise "../.." would collapse to
478 // nothing.
479 top_index = dest_i;
481 // Otherwise we're at the beginning of an absolute path. Don't
482 // allow ".." to go up another level and just eat it.
483 } else {
484 // Just find the previous slash or the beginning of input.
485 while (dest_i > 0 && !IsSlash(pathbuf[dest_i - 1]))
486 dest_i--;
488 src_i += consumed_len;
490 } else {
491 // Dot not preceeded by a slash, copy it literally.
492 pathbuf[dest_i++] = pathbuf[src_i++];
494 } else if (IsSlash(pathbuf[src_i])) {
495 if (src_i > 0 && IsSlash(pathbuf[src_i - 1])) {
496 // Two slashes in a row, skip over it.
497 src_i++;
498 } else {
499 // Just one slash, copy it, normalizing to foward slash.
500 pathbuf[dest_i] = '/';
501 dest_i++;
502 src_i++;
504 } else {
505 // Input nothing special, just copy it.
506 pathbuf[dest_i++] = pathbuf[src_i++];
509 path->resize(dest_i);
512 void ConvertPathToSystem(std::string* path) {
513 #if defined(OS_WIN)
514 for (size_t i = 0; i < path->size(); i++) {
515 if ((*path)[i] == '/')
516 (*path)[i] = '\\';
518 #endif
521 std::string MakeRelativePath(const std::string& input,
522 const std::string& dest) {
523 std::string ret;
525 // Skip the common prefixes of the source and dest as long as they end in
526 // a [back]slash.
527 size_t common_prefix_len = 0;
528 size_t max_common_length = std::min(input.size(), dest.size());
529 for (size_t i = common_prefix_len; i < max_common_length; i++) {
530 if (IsSlash(input[i]) && IsSlash(dest[i]))
531 common_prefix_len = i + 1;
532 else if (input[i] != dest[i])
533 break;
536 // Invert the dest dir starting from the end of the common prefix.
537 for (size_t i = common_prefix_len; i < dest.size(); i++) {
538 if (IsSlash(dest[i]))
539 ret.append("../");
542 // Append any remaining unique input.
543 ret.append(&input[common_prefix_len], input.size() - common_prefix_len);
545 // If the result is still empty, the paths are the same.
546 if (ret.empty())
547 ret.push_back('.');
549 return ret;
552 std::string RebasePath(const std::string& input,
553 const SourceDir& dest_dir,
554 const base::StringPiece& source_root) {
555 std::string ret;
556 DCHECK(source_root.empty() || !source_root.ends_with("/"));
558 bool input_is_source_path = (input.size() >= 2 &&
559 input[0] == '/' && input[1] == '/');
561 if (!source_root.empty() &&
562 (!input_is_source_path || !dest_dir.is_source_absolute())) {
563 std::string input_full;
564 std::string dest_full;
565 if (input_is_source_path) {
566 source_root.AppendToString(&input_full);
567 input_full.push_back('/');
568 input_full.append(input, 2, std::string::npos);
569 } else {
570 input_full.append(input);
572 if (dest_dir.is_source_absolute()) {
573 source_root.AppendToString(&dest_full);
574 dest_full.push_back('/');
575 dest_full.append(dest_dir.value(), 2, std::string::npos);
576 } else {
577 #if defined(OS_WIN)
578 // On Windows, SourceDir system-absolute paths start
579 // with /, e.g. "/C:/foo/bar".
580 const std::string& value = dest_dir.value();
581 if (value.size() > 2 && value[2] == ':')
582 dest_full.append(dest_dir.value().substr(1));
583 else
584 dest_full.append(dest_dir.value());
585 #else
586 dest_full.append(dest_dir.value());
587 #endif
589 bool remove_slash = false;
590 if (!EndsWithSlash(input_full)) {
591 input_full.push_back('/');
592 remove_slash = true;
594 ret = MakeRelativePath(input_full, dest_full);
595 if (remove_slash && ret.size() > 1)
596 ret.resize(ret.size() - 1);
597 return ret;
600 ret = MakeRelativePath(input, dest_dir.value());
601 return ret;
604 std::string DirectoryWithNoLastSlash(const SourceDir& dir) {
605 std::string ret;
607 if (dir.value().empty()) {
608 // Just keep input the same.
609 } else if (dir.value() == "/") {
610 ret.assign("/.");
611 } else if (dir.value() == "//") {
612 ret.assign("//.");
613 } else {
614 ret.assign(dir.value());
615 ret.resize(ret.size() - 1);
617 return ret;
620 SourceDir SourceDirForPath(const base::FilePath& source_root,
621 const base::FilePath& path) {
622 std::vector<base::FilePath::StringType> source_comp =
623 GetPathComponents(source_root);
624 std::vector<base::FilePath::StringType> path_comp =
625 GetPathComponents(path);
627 // See if path is inside the source root by looking for each of source root's
628 // components at the beginning of path.
629 bool is_inside_source;
630 if (path_comp.size() < source_comp.size() || source_root.empty()) {
631 // Too small to fit.
632 is_inside_source = false;
633 } else {
634 is_inside_source = true;
635 for (size_t i = 0; i < source_comp.size(); i++) {
636 if (!FilesystemStringsEqual(source_comp[i], path_comp[i])) {
637 is_inside_source = false;
638 break;
643 std::string result_str;
644 size_t initial_path_comp_to_use;
645 if (is_inside_source) {
646 // Construct a source-relative path beginning in // and skip all of the
647 // shared directories.
648 result_str = "//";
649 initial_path_comp_to_use = source_comp.size();
650 } else {
651 // Not inside source code, construct a system-absolute path.
652 result_str = "/";
653 initial_path_comp_to_use = 0;
656 for (size_t i = initial_path_comp_to_use; i < path_comp.size(); i++) {
657 result_str.append(FilePathToUTF8(path_comp[i]));
658 result_str.push_back('/');
660 return SourceDir(result_str);
663 SourceDir SourceDirForCurrentDirectory(const base::FilePath& source_root) {
664 base::FilePath cd;
665 base::GetCurrentDirectory(&cd);
666 return SourceDirForPath(source_root, cd);
669 std::string GetOutputSubdirName(const Label& toolchain_label, bool is_default) {
670 // The default toolchain has no subdir.
671 if (is_default)
672 return std::string();
674 // For now just assume the toolchain name is always a valid dir name. We may
675 // want to clean up the in the future.
676 return toolchain_label.name() + "/";
679 SourceDir GetToolchainOutputDir(const Settings* settings) {
680 return settings->toolchain_output_subdir().AsSourceDir(
681 settings->build_settings());
684 SourceDir GetToolchainOutputDir(const BuildSettings* build_settings,
685 const Label& toolchain_label, bool is_default) {
686 std::string result = build_settings->build_dir().value();
687 result.append(GetOutputSubdirName(toolchain_label, is_default));
688 return SourceDir(SourceDir::SWAP_IN, &result);
691 SourceDir GetToolchainGenDir(const Settings* settings) {
692 return GetToolchainGenDirAsOutputFile(settings).AsSourceDir(
693 settings->build_settings());
696 OutputFile GetToolchainGenDirAsOutputFile(const Settings* settings) {
697 OutputFile result(settings->toolchain_output_subdir());
698 result.value().append("gen/");
699 return result;
702 SourceDir GetToolchainGenDir(const BuildSettings* build_settings,
703 const Label& toolchain_label, bool is_default) {
704 std::string result = GetToolchainOutputDir(
705 build_settings, toolchain_label, is_default).value();
706 result.append("gen/");
707 return SourceDir(SourceDir::SWAP_IN, &result);
710 SourceDir GetOutputDirForSourceDir(const Settings* settings,
711 const SourceDir& source_dir) {
712 return GetOutputDirForSourceDirAsOutputFile(settings, source_dir).AsSourceDir(
713 settings->build_settings());
716 OutputFile GetOutputDirForSourceDirAsOutputFile(const Settings* settings,
717 const SourceDir& source_dir) {
718 OutputFile result = settings->toolchain_output_subdir();
719 result.value().append("obj/");
721 if (source_dir.is_source_absolute()) {
722 // The source dir is source-absolute, so we trim off the two leading
723 // slashes to append to the toolchain object directory.
724 result.value().append(&source_dir.value()[2],
725 source_dir.value().size() - 2);
726 } else {
727 // system-absolute
728 const std::string& build_dir =
729 settings->build_settings()->build_dir().value();
731 if (StartsWithASCII(source_dir.value(), build_dir, true)) {
732 size_t build_dir_size = build_dir.size();
733 result.value().append(&source_dir.value()[build_dir_size],
734 source_dir.value().size() - build_dir_size);
737 return result;
740 SourceDir GetGenDirForSourceDir(const Settings* settings,
741 const SourceDir& source_dir) {
742 return GetGenDirForSourceDirAsOutputFile(settings, source_dir).AsSourceDir(
743 settings->build_settings());
746 OutputFile GetGenDirForSourceDirAsOutputFile(const Settings* settings,
747 const SourceDir& source_dir) {
748 OutputFile result = GetToolchainGenDirAsOutputFile(settings);
750 if (source_dir.is_source_absolute()) {
751 // The source dir should be source-absolute, so we trim off the two leading
752 // slashes to append to the toolchain object directory.
753 DCHECK(source_dir.is_source_absolute());
754 result.value().append(&source_dir.value()[2],
755 source_dir.value().size() - 2);
757 return result;
760 SourceDir GetTargetOutputDir(const Target* target) {
761 return GetOutputDirForSourceDirAsOutputFile(
762 target->settings(), target->label().dir()).AsSourceDir(
763 target->settings()->build_settings());
766 OutputFile GetTargetOutputDirAsOutputFile(const Target* target) {
767 return GetOutputDirForSourceDirAsOutputFile(
768 target->settings(), target->label().dir());
771 SourceDir GetTargetGenDir(const Target* target) {
772 return GetTargetGenDirAsOutputFile(target).AsSourceDir(
773 target->settings()->build_settings());
776 OutputFile GetTargetGenDirAsOutputFile(const Target* target) {
777 return GetGenDirForSourceDirAsOutputFile(
778 target->settings(), target->label().dir());
781 SourceDir GetCurrentOutputDir(const Scope* scope) {
782 return GetOutputDirForSourceDirAsOutputFile(
783 scope->settings(), scope->GetSourceDir()).AsSourceDir(
784 scope->settings()->build_settings());
787 SourceDir GetCurrentGenDir(const Scope* scope) {
788 return GetGenDirForSourceDir(scope->settings(), scope->GetSourceDir());