Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(134)

Side by Side Diff: tools/gn/substitution_writer.cc

Issue 497193002: Expand empty directories in GN to "." (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "tools/gn/substitution_writer.h" 5 #include "tools/gn/substitution_writer.h"
6 6
7 #include "tools/gn/build_settings.h" 7 #include "tools/gn/build_settings.h"
8 #include "tools/gn/escape.h" 8 #include "tools/gn/escape.h"
9 #include "tools/gn/filesystem_utils.h" 9 #include "tools/gn/filesystem_utils.h"
10 #include "tools/gn/output_file.h" 10 #include "tools/gn/output_file.h"
11 #include "tools/gn/settings.h" 11 #include "tools/gn/settings.h"
12 #include "tools/gn/source_file.h" 12 #include "tools/gn/source_file.h"
13 #include "tools/gn/string_utils.h" 13 #include "tools/gn/string_utils.h"
14 #include "tools/gn/substitution_list.h" 14 #include "tools/gn/substitution_list.h"
15 #include "tools/gn/substitution_pattern.h" 15 #include "tools/gn/substitution_pattern.h"
16 #include "tools/gn/target.h" 16 #include "tools/gn/target.h"
17 17
18 namespace { 18 namespace {
19 19
20 // This happens when the output of a substitution looks like 20 // Sets the given directory string to the destination, trimming any trailing
21 // <some_output_dir>/<other_stuff>. and we're computing a file in the output 21 // slash from the directory (SourceDirs and OutputFiles representing
22 // directory. If <some_output_dir> resolves to the empty string because it 22 // directories will end in a trailing slash). If the directory is empty
jamesr 2014/08/22 19:04:51 "If the directory is empty ...." what happens?
23 // refers to the root build directory, the result will start with a slash which 23 void SetDirOrDotWithNoSlash(const std::string& dir, std::string* dest) {
24 // is wrong. 24 if (!dir.empty() && dir[dir.size() - 1] == '/')
25 // 25 dest->assign(dir.data(), dir.size() - 1);
26 // There are several possible solutions: 26 else
27 // 27 dest->assign(dir);
28 // - Could convert empty directories to a ".". However, this looks weird in the
29 // Ninja file and Ninja doesn't canonicalize this away.
30 //
31 // - Make all substitutions compute SourceFiles and then convert to
32 // OutputFiles. The root_build_dir will never be empty in this case, and the
33 // Rebase function will properly strip the slash away when it is rebased to
34 // be relative to the output directory. However, we never need compiler and
35 // linker outputs as SourceFiles, and we do a lot of these conversions which
36 // requires a lot of unnecessary path rebasing.
37 //
38 // - Detect this as a special case and delete the slash.
39 //
40 // This function implements the special case solution. This problem only arises
41 // in the very specific case where we're appending a literal beginning in a
42 // slash, the result string is empty, and the preceeding pattern identifies
43 // an output directory.
44 //
45 // If we find too many problems with this implementation, it would probably be
46 // cleanest to implement the "round trip through SourceFile" solution for
47 // simplicity and guaranteed correctness, rather than adding even more special
48 // cases.
49 //
50 // This function only needs to be called when computing substitutions as
51 // OutputFiles (which are relative to the build dir) and not round-tripping
52 // through SourceFiles.
53 void AppendLiteralWithPossibleSlashEliding(
54 const std::vector<SubstitutionPattern::Subrange>& ranges,
55 size_t literal_index,
56 std::string* result) {
57 const std::string& literal = ranges[literal_index].literal;
58 28
59 if (// When the literal's index is 0 and it begins with a slash the user 29 if (dest->empty())
60 // must have wanted it to start with a slash. Likewise, if it's 2 or 30 dest->push_back('.');
61 // more, it's impossible to have a length > 1 sequence of substitutions
62 // that both make sense as a path and resolve to the build directory.
63 literal_index != 1 ||
64 // When the result is nonempty, appending the slash as a separator is
65 // always OK.
66 !result->empty() ||
67 // If the literal doesn't begin in a slash, appending directly is fine.
68 literal.empty() || literal[0] != '/') {
69 result->append(literal);
70 return;
71 }
72
73 // If we get here, we need to collapse the slash. Assert that the first
74 // substitution should have ended up in the output directory. This should
75 // have already been checked since linker and compiler outputs (which is
76 // what this is used for) should always bein the output directory.
77 DCHECK(SubstitutionIsInOutputDir(ranges[0].type));
78 result->append(&literal[1], literal.size() - 1);
79 } 31 }
80 32
81 } // namespace 33 } // namespace
82 34
83 const char kSourceExpansion_Help[] = 35 const char kSourceExpansion_Help[] =
84 "How Source Expansion Works\n" 36 "How Source Expansion Works\n"
85 "\n" 37 "\n"
86 " Source expansion is used for the action_foreach and copy target types\n" 38 " Source expansion is used for the action_foreach and copy target types\n"
87 " to map source file names to output file names or arguments.\n" 39 " to map source file names to output file names or arguments.\n"
88 "\n" 40 "\n"
(...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after
479 const Target* target, 431 const Target* target,
480 SubstitutionType type, 432 SubstitutionType type,
481 std::string* result) { 433 std::string* result) {
482 switch (type) { 434 switch (type) {
483 case SUBSTITUTION_LABEL: 435 case SUBSTITUTION_LABEL:
484 // Only include the toolchain for non-default toolchains. 436 // Only include the toolchain for non-default toolchains.
485 *result = target->label().GetUserVisibleName( 437 *result = target->label().GetUserVisibleName(
486 !target->settings()->is_default()); 438 !target->settings()->is_default());
487 break; 439 break;
488 case SUBSTITUTION_ROOT_GEN_DIR: 440 case SUBSTITUTION_ROOT_GEN_DIR:
489 *result = GetToolchainGenDirAsOutputFile(target->settings()).value(); 441 SetDirOrDotWithNoSlash(
490 TrimTrailingSlash(result); 442 GetToolchainGenDirAsOutputFile(target->settings()).value(),
443 result);
491 break; 444 break;
492 case SUBSTITUTION_ROOT_OUT_DIR: 445 case SUBSTITUTION_ROOT_OUT_DIR:
493 *result = target->settings()->toolchain_output_subdir().value(); 446 SetDirOrDotWithNoSlash(
494 TrimTrailingSlash(result); 447 target->settings()->toolchain_output_subdir().value(),
448 result);
495 break; 449 break;
496 case SUBSTITUTION_TARGET_GEN_DIR: 450 case SUBSTITUTION_TARGET_GEN_DIR:
497 *result = GetTargetGenDirAsOutputFile(target).value(); 451 SetDirOrDotWithNoSlash(
498 TrimTrailingSlash(result); 452 GetTargetGenDirAsOutputFile(target).value(),
453 result);
499 break; 454 break;
500 case SUBSTITUTION_TARGET_OUT_DIR: 455 case SUBSTITUTION_TARGET_OUT_DIR:
501 *result = GetTargetOutputDirAsOutputFile(target).value(); 456 SetDirOrDotWithNoSlash(
502 TrimTrailingSlash(result); 457 GetTargetOutputDirAsOutputFile(target).value(),
458 result);
503 break; 459 break;
504 case SUBSTITUTION_TARGET_OUTPUT_NAME: 460 case SUBSTITUTION_TARGET_OUTPUT_NAME:
505 *result = target->GetComputedOutputName(true); 461 *result = target->GetComputedOutputName(true);
506 break; 462 break;
507 default: 463 default:
508 return false; 464 return false;
509 } 465 }
510 return true; 466 return true;
511 } 467 }
512 468
513 // static 469 // static
514 std::string SubstitutionWriter::GetTargetSubstitution( 470 std::string SubstitutionWriter::GetTargetSubstitution(
515 const Target* target, 471 const Target* target,
516 SubstitutionType type) { 472 SubstitutionType type) {
517 std::string result; 473 std::string result;
518 GetTargetSubstitution(target, type, &result); 474 GetTargetSubstitution(target, type, &result);
519 return result; 475 return result;
520 } 476 }
521 477
522 // static 478 // static
523 OutputFile SubstitutionWriter::ApplyPatternToCompilerAsOutputFile( 479 OutputFile SubstitutionWriter::ApplyPatternToCompilerAsOutputFile(
524 const Target* target, 480 const Target* target,
525 const SourceFile& source, 481 const SourceFile& source,
526 const SubstitutionPattern& pattern) { 482 const SubstitutionPattern& pattern) {
527 OutputFile result; 483 OutputFile result;
528 for (size_t i = 0; i < pattern.ranges().size(); i++) { 484 for (size_t i = 0; i < pattern.ranges().size(); i++) {
529 const SubstitutionPattern::Subrange& subrange = pattern.ranges()[i]; 485 const SubstitutionPattern::Subrange& subrange = pattern.ranges()[i];
530 if (subrange.type == SUBSTITUTION_LITERAL) { 486 if (subrange.type == SUBSTITUTION_LITERAL) {
531 AppendLiteralWithPossibleSlashEliding( 487 result.value().append(subrange.literal);
532 pattern.ranges(), i, &result.value());
533 } else { 488 } else {
534 result.value().append( 489 result.value().append(
535 GetCompilerSubstitution(target, source, subrange.type)); 490 GetCompilerSubstitution(target, source, subrange.type));
536 } 491 }
537 } 492 }
538 return result; 493 return result;
539 } 494 }
540 495
541 // static 496 // static
542 void SubstitutionWriter::ApplyListToCompilerAsOutputFile( 497 void SubstitutionWriter::ApplyListToCompilerAsOutputFile(
(...skipping 25 matching lines...) Expand all
568 523
569 // static 524 // static
570 OutputFile SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( 525 OutputFile SubstitutionWriter::ApplyPatternToLinkerAsOutputFile(
571 const Target* target, 526 const Target* target,
572 const Tool* tool, 527 const Tool* tool,
573 const SubstitutionPattern& pattern) { 528 const SubstitutionPattern& pattern) {
574 OutputFile result; 529 OutputFile result;
575 for (size_t i = 0; i < pattern.ranges().size(); i++) { 530 for (size_t i = 0; i < pattern.ranges().size(); i++) {
576 const SubstitutionPattern::Subrange& subrange = pattern.ranges()[i]; 531 const SubstitutionPattern::Subrange& subrange = pattern.ranges()[i];
577 if (subrange.type == SUBSTITUTION_LITERAL) { 532 if (subrange.type == SUBSTITUTION_LITERAL) {
578 AppendLiteralWithPossibleSlashEliding( 533 result.value().append(subrange.literal);
579 pattern.ranges(), i, &result.value());
580 } else { 534 } else {
581 result.value().append(GetLinkerSubstitution(target, tool, subrange.type)); 535 result.value().append(GetLinkerSubstitution(target, tool, subrange.type));
582 } 536 }
583 } 537 }
584 return result; 538 return result;
585 } 539 }
586 540
587 // static 541 // static
588 void SubstitutionWriter::ApplyListToLinkerAsOutputFile( 542 void SubstitutionWriter::ApplyListToLinkerAsOutputFile(
589 const Target* target, 543 const Target* target,
(...skipping 24 matching lines...) Expand all
614 // does not include the dot but the tool's does. 568 // does not include the dot but the tool's does.
615 if (target->output_extension().empty()) 569 if (target->output_extension().empty())
616 return tool->default_output_extension(); 570 return tool->default_output_extension();
617 return std::string(".") + target->output_extension(); 571 return std::string(".") + target->output_extension();
618 572
619 default: 573 default:
620 NOTREACHED(); 574 NOTREACHED();
621 return std::string(); 575 return std::string();
622 } 576 }
623 } 577 }
OLDNEW
« no previous file with comments | « tools/gn/ninja_binary_target_writer_unittest.cc ('k') | tools/gn/substitution_writer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698