blob: bd93d36a8e2e2a21319626b442f8e9c98c438336 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <sstream>
#include "tools/gn/ninja_build_writer.h"
#include "tools/gn/pool.h"
#include "tools/gn/scheduler.h"
#include "tools/gn/target.h"
#include "tools/gn/test_with_scheduler.h"
#include "tools/gn/test_with_scope.h"
#include "util/test/test.h"
using NinjaBuildWriterTest = TestWithScheduler;
TEST_F(NinjaBuildWriterTest, TwoTargets) {
TestWithScope setup;
Err err;
Target target_foo(setup.settings(), Label(SourceDir("//foo/"), "bar"));
target_foo.set_output_type(Target::ACTION);
target_foo.action_values().set_script(SourceFile("//foo/script.py"));
target_foo.action_values().outputs() = SubstitutionList::MakeForTest(
"//out/Debug/out1.out", "//out/Debug/out2.out");
target_foo.SetToolchain(setup.toolchain());
ASSERT_TRUE(target_foo.OnResolved(&err));
Target target_bar(setup.settings(), Label(SourceDir("//bar/"), "bar"));
target_bar.set_output_type(Target::ACTION);
target_bar.action_values().set_script(SourceFile("//bar/script.py"));
target_bar.action_values().outputs() = SubstitutionList::MakeForTest(
"//out/Debug/out3.out", "//out/Debug/out4.out");
target_bar.SetToolchain(setup.toolchain());
ASSERT_TRUE(target_bar.OnResolved(&err));
// Make a secondary toolchain that references two pools.
Label other_toolchain_label(SourceDir("//other/"), "toolchain");
Toolchain other_toolchain(setup.settings(), other_toolchain_label);
TestWithScope::SetupToolchain(&other_toolchain);
Pool other_regular_pool(
setup.settings(),
Label(SourceDir("//other/"), "depth_pool", other_toolchain_label.dir(),
other_toolchain_label.name()));
other_regular_pool.set_depth(42);
other_toolchain.GetTool(Toolchain::TYPE_LINK)
->set_pool(LabelPtrPair<Pool>(&other_regular_pool));
// The console pool must be in the default toolchain.
Pool console_pool(setup.settings(), Label(SourceDir("//"), "console",
setup.toolchain()->label().dir(),
setup.toolchain()->label().name()));
console_pool.set_depth(1);
other_toolchain.GetTool(Toolchain::TYPE_STAMP)
->set_pool(LabelPtrPair<Pool>(&console_pool));
// Settings to go with the other toolchain.
Settings other_settings(setup.build_settings(), "toolchain/");
other_settings.set_toolchain_label(other_toolchain_label);
std::unordered_map<const Settings*, const Toolchain*> used_toolchains;
used_toolchains[setup.settings()] = setup.toolchain();
used_toolchains[&other_settings] = &other_toolchain;
std::vector<const Target*> targets = {&target_foo, &target_bar};
std::ostringstream ninja_out;
std::ostringstream depfile_out;
NinjaBuildWriter writer(setup.build_settings(), used_toolchains,
setup.toolchain(), targets, ninja_out, depfile_out);
ASSERT_TRUE(writer.Run(&err));
const char expected_rule_gn[] = "rule gn\n";
const char expected_build_ninja[] =
"build build.ninja: gn\n"
" generator = 1\n"
" depfile = build.ninja.d\n";
const char expected_other_pool[] =
"pool other_toolchain_other_depth_pool\n"
" depth = 42\n";
const char expected_toolchain[] = "subninja toolchain.ninja\n";
const char expected_targets[] =
"build bar: phony obj/bar/bar.stamp\n"
"build foo$:bar: phony obj/foo/bar.stamp\n"
"build bar$:bar: phony obj/bar/bar.stamp\n";
const char expected_root_target[] =
"build all: phony $\n"
" obj/foo/bar.stamp $\n"
" obj/bar/bar.stamp\n";
const char expected_default[] = "default all\n";
std::string out_str = ninja_out.str();
#define EXPECT_SNIPPET(expected) \
EXPECT_NE(std::string::npos, out_str.find(expected)) \
<< "Expected to find: " << expected << "\n" \
<< "Within: " << out_str
EXPECT_SNIPPET(expected_rule_gn);
EXPECT_SNIPPET(expected_build_ninja);
EXPECT_SNIPPET(expected_other_pool);
EXPECT_SNIPPET(expected_toolchain);
EXPECT_SNIPPET(expected_targets);
EXPECT_SNIPPET(expected_root_target);
EXPECT_SNIPPET(expected_default);
#undef EXPECT_SNIPPET
// A pool definition for ninja's built-in console pool must not be written.
EXPECT_EQ(std::string::npos, out_str.find("pool console"));
}
TEST_F(NinjaBuildWriterTest, DuplicateOutputs) {
TestWithScope setup;
Err err;
Target target_foo(setup.settings(), Label(SourceDir("//foo/"), "bar"));
target_foo.set_output_type(Target::ACTION);
target_foo.action_values().set_script(SourceFile("//foo/script.py"));
target_foo.action_values().outputs() = SubstitutionList::MakeForTest(
"//out/Debug/out1.out", "//out/Debug/out2.out");
target_foo.SetToolchain(setup.toolchain());
ASSERT_TRUE(target_foo.OnResolved(&err));
Target target_bar(setup.settings(), Label(SourceDir("//bar/"), "bar"));
target_bar.set_output_type(Target::ACTION);
target_bar.action_values().set_script(SourceFile("//bar/script.py"));
target_bar.action_values().outputs() = SubstitutionList::MakeForTest(
"//out/Debug/out3.out", "//out/Debug/out2.out");
target_bar.SetToolchain(setup.toolchain());
ASSERT_TRUE(target_bar.OnResolved(&err));
std::unordered_map<const Settings*, const Toolchain*> used_toolchains;
used_toolchains[setup.settings()] = setup.toolchain();
std::vector<const Target*> targets = {&target_foo, &target_bar};
std::ostringstream ninja_out;
std::ostringstream depfile_out;
NinjaBuildWriter writer(setup.build_settings(), used_toolchains,
setup.toolchain(), targets, ninja_out, depfile_out);
ASSERT_FALSE(writer.Run(&err));
const char expected_help_test[] =
"Two or more targets generate the same output:\n"
" out2.out\n"
"\n"
"This is can often be fixed by changing one of the target names, or by \n"
"setting an output_name on one of them.\n"
"\n"
"Collisions:\n"
" //foo:bar\n"
" //bar:bar\n";
EXPECT_EQ(expected_help_test, err.help_text());
}