| // Copyright (c) 2013 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 "testing/gtest/include/gtest/gtest.h" |
| #include "tools/gn/build_settings.h" |
| #include "tools/gn/config.h" |
| #include "tools/gn/settings.h" |
| #include "tools/gn/target.h" |
| #include "tools/gn/test_with_scope.h" |
| #include "tools/gn/toolchain.h" |
| |
| // Tests that lib[_dir]s are inherited across deps boundaries for static |
| // libraries but not executables. |
| TEST(Target, LibInheritance) { |
| TestWithScope setup; |
| Err err; |
| |
| const std::string lib("foo"); |
| const SourceDir libdir("/foo_dir/"); |
| |
| // Leaf target with ldflags set. |
| Target z(setup.settings(), Label(SourceDir("//foo/"), "z")); |
| z.set_output_type(Target::STATIC_LIBRARY); |
| z.config_values().libs().push_back(lib); |
| z.config_values().lib_dirs().push_back(libdir); |
| z.visibility().SetPublic(); |
| z.SetToolchain(setup.toolchain()); |
| ASSERT_TRUE(z.OnResolved(&err)); |
| |
| // All lib[_dir]s should be set when target is resolved. |
| ASSERT_EQ(1u, z.all_libs().size()); |
| EXPECT_EQ(lib, z.all_libs()[0]); |
| ASSERT_EQ(1u, z.all_lib_dirs().size()); |
| EXPECT_EQ(libdir, z.all_lib_dirs()[0]); |
| |
| // Shared library target should inherit the libs from the static library |
| // and its own. Its own flag should be before the inherited one. |
| const std::string second_lib("bar"); |
| const SourceDir second_libdir("/bar_dir/"); |
| Target shared(setup.settings(), Label(SourceDir("//foo/"), "shared")); |
| shared.set_output_type(Target::SHARED_LIBRARY); |
| shared.config_values().libs().push_back(second_lib); |
| shared.config_values().lib_dirs().push_back(second_libdir); |
| shared.private_deps().push_back(LabelTargetPair(&z)); |
| shared.visibility().SetPublic(); |
| shared.SetToolchain(setup.toolchain()); |
| ASSERT_TRUE(shared.OnResolved(&err)); |
| |
| ASSERT_EQ(2u, shared.all_libs().size()); |
| EXPECT_EQ(second_lib, shared.all_libs()[0]); |
| EXPECT_EQ(lib, shared.all_libs()[1]); |
| ASSERT_EQ(2u, shared.all_lib_dirs().size()); |
| EXPECT_EQ(second_libdir, shared.all_lib_dirs()[0]); |
| EXPECT_EQ(libdir, shared.all_lib_dirs()[1]); |
| |
| // Executable target shouldn't get either by depending on shared. |
| Target exec(setup.settings(), Label(SourceDir("//foo/"), "exec")); |
| exec.set_output_type(Target::EXECUTABLE); |
| exec.private_deps().push_back(LabelTargetPair(&shared)); |
| exec.SetToolchain(setup.toolchain()); |
| ASSERT_TRUE(exec.OnResolved(&err)); |
| EXPECT_EQ(0u, exec.all_libs().size()); |
| EXPECT_EQ(0u, exec.all_lib_dirs().size()); |
| } |
| |
| // Test all_dependent_configs, public_config inheritance, and |
| // forward_dependent_configs_from |
| TEST(Target, DependentConfigs) { |
| TestWithScope setup; |
| Err err; |
| |
| // Set up a dependency chain of a -> b -> c |
| Target a(setup.settings(), Label(SourceDir("//foo/"), "a")); |
| a.set_output_type(Target::EXECUTABLE); |
| a.visibility().SetPublic(); |
| a.SetToolchain(setup.toolchain()); |
| Target b(setup.settings(), Label(SourceDir("//foo/"), "b")); |
| b.set_output_type(Target::STATIC_LIBRARY); |
| b.visibility().SetPublic(); |
| b.SetToolchain(setup.toolchain()); |
| Target c(setup.settings(), Label(SourceDir("//foo/"), "c")); |
| c.set_output_type(Target::STATIC_LIBRARY); |
| c.visibility().SetPublic(); |
| c.SetToolchain(setup.toolchain()); |
| a.private_deps().push_back(LabelTargetPair(&b)); |
| b.private_deps().push_back(LabelTargetPair(&c)); |
| |
| // Normal non-inherited config. |
| Config config(setup.settings(), Label(SourceDir("//foo/"), "config")); |
| c.configs().push_back(LabelConfigPair(&config)); |
| |
| // All dependent config. |
| Config all(setup.settings(), Label(SourceDir("//foo/"), "all")); |
| c.all_dependent_configs().push_back(LabelConfigPair(&all)); |
| |
| // Direct dependent config. |
| Config direct(setup.settings(), Label(SourceDir("//foo/"), "direct")); |
| c.public_configs().push_back(LabelConfigPair(&direct)); |
| |
| ASSERT_TRUE(c.OnResolved(&err)); |
| ASSERT_TRUE(b.OnResolved(&err)); |
| ASSERT_TRUE(a.OnResolved(&err)); |
| |
| // B should have gotten both dependent configs from C. |
| ASSERT_EQ(2u, b.configs().size()); |
| EXPECT_EQ(&all, b.configs()[0].ptr); |
| EXPECT_EQ(&direct, b.configs()[1].ptr); |
| ASSERT_EQ(1u, b.all_dependent_configs().size()); |
| EXPECT_EQ(&all, b.all_dependent_configs()[0].ptr); |
| |
| // A should have just gotten the "all" dependent config from C. |
| ASSERT_EQ(1u, a.configs().size()); |
| EXPECT_EQ(&all, a.configs()[0].ptr); |
| EXPECT_EQ(&all, a.all_dependent_configs()[0].ptr); |
| |
| // Making an an alternate A and B with B forwarding the direct dependents. |
| Target a_fwd(setup.settings(), Label(SourceDir("//foo/"), "a_fwd")); |
| a_fwd.set_output_type(Target::EXECUTABLE); |
| a_fwd.visibility().SetPublic(); |
| a_fwd.SetToolchain(setup.toolchain()); |
| Target b_fwd(setup.settings(), Label(SourceDir("//foo/"), "b_fwd")); |
| b_fwd.set_output_type(Target::STATIC_LIBRARY); |
| b_fwd.SetToolchain(setup.toolchain()); |
| b_fwd.visibility().SetPublic(); |
| a_fwd.private_deps().push_back(LabelTargetPair(&b_fwd)); |
| b_fwd.private_deps().push_back(LabelTargetPair(&c)); |
| b_fwd.forward_dependent_configs().push_back(LabelTargetPair(&c)); |
| |
| ASSERT_TRUE(b_fwd.OnResolved(&err)); |
| ASSERT_TRUE(a_fwd.OnResolved(&err)); |
| |
| // A_fwd should now have both configs. |
| ASSERT_EQ(2u, a_fwd.configs().size()); |
| EXPECT_EQ(&all, a_fwd.configs()[0].ptr); |
| EXPECT_EQ(&direct, a_fwd.configs()[1].ptr); |
| ASSERT_EQ(1u, a_fwd.all_dependent_configs().size()); |
| EXPECT_EQ(&all, a_fwd.all_dependent_configs()[0].ptr); |
| } |
| |
| TEST(Target, InheritLibs) { |
| TestWithScope setup; |
| Err err; |
| |
| // Create a dependency chain: |
| // A (executable) -> B (shared lib) -> C (static lib) -> D (source set) |
| Target a(setup.settings(), Label(SourceDir("//foo/"), "a")); |
| a.set_output_type(Target::EXECUTABLE); |
| a.visibility().SetPublic(); |
| a.SetToolchain(setup.toolchain()); |
| Target b(setup.settings(), Label(SourceDir("//foo/"), "b")); |
| b.set_output_type(Target::SHARED_LIBRARY); |
| b.visibility().SetPublic(); |
| b.SetToolchain(setup.toolchain()); |
| Target c(setup.settings(), Label(SourceDir("//foo/"), "c")); |
| c.set_output_type(Target::STATIC_LIBRARY); |
| c.visibility().SetPublic(); |
| c.SetToolchain(setup.toolchain()); |
| Target d(setup.settings(), Label(SourceDir("//foo/"), "d")); |
| d.set_output_type(Target::SOURCE_SET); |
| d.visibility().SetPublic(); |
| d.SetToolchain(setup.toolchain()); |
| a.private_deps().push_back(LabelTargetPair(&b)); |
| b.private_deps().push_back(LabelTargetPair(&c)); |
| c.private_deps().push_back(LabelTargetPair(&d)); |
| |
| ASSERT_TRUE(d.OnResolved(&err)); |
| ASSERT_TRUE(c.OnResolved(&err)); |
| ASSERT_TRUE(b.OnResolved(&err)); |
| ASSERT_TRUE(a.OnResolved(&err)); |
| |
| // C should have D in its inherited libs. |
| const UniqueVector<const Target*>& c_inherited = c.inherited_libraries(); |
| EXPECT_EQ(1u, c_inherited.size()); |
| EXPECT_TRUE(c_inherited.IndexOf(&d) != static_cast<size_t>(-1)); |
| |
| // B should have C and D in its inherited libs. |
| const UniqueVector<const Target*>& b_inherited = b.inherited_libraries(); |
| EXPECT_EQ(2u, b_inherited.size()); |
| EXPECT_TRUE(b_inherited.IndexOf(&c) != static_cast<size_t>(-1)); |
| EXPECT_TRUE(b_inherited.IndexOf(&d) != static_cast<size_t>(-1)); |
| |
| // A should have B in its inherited libs, but not any others (the shared |
| // library will include the static library and source set). |
| const UniqueVector<const Target*>& a_inherited = a.inherited_libraries(); |
| EXPECT_EQ(1u, a_inherited.size()); |
| EXPECT_TRUE(a_inherited.IndexOf(&b) != static_cast<size_t>(-1)); |
| } |
| |
| TEST(Target, InheritCompleteStaticLib) { |
| TestWithScope setup; |
| Err err; |
| |
| // Create a dependency chain: |
| // A (executable) -> B (complete static lib) -> C (source set) |
| Target a(setup.settings(), Label(SourceDir("//foo/"), "a")); |
| a.set_output_type(Target::EXECUTABLE); |
| a.visibility().SetPublic(); |
| a.SetToolchain(setup.toolchain()); |
| Target b(setup.settings(), Label(SourceDir("//foo/"), "b")); |
| b.set_output_type(Target::STATIC_LIBRARY); |
| b.visibility().SetPublic(); |
| b.set_complete_static_lib(true); |
| b.SetToolchain(setup.toolchain()); |
| Target c(setup.settings(), Label(SourceDir("//foo/"), "c")); |
| c.set_output_type(Target::SOURCE_SET); |
| c.visibility().SetPublic(); |
| c.SetToolchain(setup.toolchain()); |
| a.public_deps().push_back(LabelTargetPair(&b)); |
| b.public_deps().push_back(LabelTargetPair(&c)); |
| |
| ASSERT_TRUE(c.OnResolved(&err)); |
| ASSERT_TRUE(b.OnResolved(&err)); |
| ASSERT_TRUE(a.OnResolved(&err)); |
| |
| // B should have C in its inherited libs. |
| const UniqueVector<const Target*>& b_inherited = b.inherited_libraries(); |
| EXPECT_EQ(1u, b_inherited.size()); |
| EXPECT_TRUE(b_inherited.IndexOf(&c) != static_cast<size_t>(-1)); |
| |
| // A should have B in its inherited libs, but not any others (the complete |
| // static library will include the source set). |
| const UniqueVector<const Target*>& a_inherited = a.inherited_libraries(); |
| EXPECT_EQ(1u, a_inherited.size()); |
| EXPECT_TRUE(a_inherited.IndexOf(&b) != static_cast<size_t>(-1)); |
| } |
| |
| TEST(Target, InheritCompleteStaticLibNoDirectStaticLibDeps) { |
| TestWithScope setup; |
| Err err; |
| |
| // Create a dependency chain: |
| // A (complete static lib) -> B (static lib) |
| Target a(setup.settings(), Label(SourceDir("//foo/"), "a")); |
| a.set_output_type(Target::STATIC_LIBRARY); |
| a.visibility().SetPublic(); |
| a.set_complete_static_lib(true); |
| a.SetToolchain(setup.toolchain()); |
| Target b(setup.settings(), Label(SourceDir("//foo/"), "b")); |
| b.set_output_type(Target::STATIC_LIBRARY); |
| b.visibility().SetPublic(); |
| b.SetToolchain(setup.toolchain()); |
| |
| a.public_deps().push_back(LabelTargetPair(&b)); |
| ASSERT_TRUE(b.OnResolved(&err)); |
| ASSERT_FALSE(a.OnResolved(&err)); |
| } |
| |
| TEST(Target, InheritCompleteStaticLibNoIheritedStaticLibDeps) { |
| TestWithScope setup; |
| Err err; |
| |
| // Create a dependency chain: |
| // A (complete static lib) -> B (source set) -> C (static lib) |
| Target a(setup.settings(), Label(SourceDir("//foo/"), "a")); |
| a.set_output_type(Target::STATIC_LIBRARY); |
| a.visibility().SetPublic(); |
| a.set_complete_static_lib(true); |
| a.SetToolchain(setup.toolchain()); |
| Target b(setup.settings(), Label(SourceDir("//foo/"), "b")); |
| b.set_output_type(Target::SOURCE_SET); |
| b.visibility().SetPublic(); |
| b.SetToolchain(setup.toolchain()); |
| Target c(setup.settings(), Label(SourceDir("//foo/"), "c")); |
| c.set_output_type(Target::STATIC_LIBRARY); |
| c.visibility().SetPublic(); |
| c.SetToolchain(setup.toolchain()); |
| |
| a.public_deps().push_back(LabelTargetPair(&b)); |
| b.public_deps().push_back(LabelTargetPair(&c)); |
| |
| ASSERT_TRUE(c.OnResolved(&err)); |
| ASSERT_TRUE(b.OnResolved(&err)); |
| ASSERT_FALSE(a.OnResolved(&err)); |
| } |
| |
| TEST(Target, GetComputedOutputName) { |
| TestWithScope setup; |
| Err err; |
| |
| // Basic target with no prefix (executable type tool in the TestWithScope has |
| // no prefix) or output name. |
| Target basic(setup.settings(), Label(SourceDir("//foo/"), "bar")); |
| basic.set_output_type(Target::EXECUTABLE); |
| basic.SetToolchain(setup.toolchain()); |
| ASSERT_TRUE(basic.OnResolved(&err)); |
| EXPECT_EQ("bar", basic.GetComputedOutputName(false)); |
| EXPECT_EQ("bar", basic.GetComputedOutputName(true)); |
| |
| // Target with no prefix but an output name. |
| Target with_name(setup.settings(), Label(SourceDir("//foo/"), "bar")); |
| with_name.set_output_type(Target::EXECUTABLE); |
| with_name.set_output_name("myoutput"); |
| with_name.SetToolchain(setup.toolchain()); |
| ASSERT_TRUE(with_name.OnResolved(&err)); |
| EXPECT_EQ("myoutput", with_name.GetComputedOutputName(false)); |
| EXPECT_EQ("myoutput", with_name.GetComputedOutputName(true)); |
| |
| // Target with a "lib" prefix (the static library tool in the TestWithScope |
| // should specify a "lib" output prefix). |
| Target with_prefix(setup.settings(), Label(SourceDir("//foo/"), "bar")); |
| with_prefix.set_output_type(Target::STATIC_LIBRARY); |
| with_prefix.SetToolchain(setup.toolchain()); |
| ASSERT_TRUE(with_prefix.OnResolved(&err)); |
| EXPECT_EQ("bar", with_prefix.GetComputedOutputName(false)); |
| EXPECT_EQ("libbar", with_prefix.GetComputedOutputName(true)); |
| |
| // Target with a "lib" prefix that already has it applied. The prefix should |
| // not duplicate something already in the target name. |
| Target dup_prefix(setup.settings(), Label(SourceDir("//foo/"), "bar")); |
| dup_prefix.set_output_type(Target::STATIC_LIBRARY); |
| dup_prefix.set_output_name("libbar"); |
| dup_prefix.SetToolchain(setup.toolchain()); |
| ASSERT_TRUE(dup_prefix.OnResolved(&err)); |
| EXPECT_EQ("libbar", dup_prefix.GetComputedOutputName(false)); |
| EXPECT_EQ("libbar", dup_prefix.GetComputedOutputName(true)); |
| } |
| |
| // Test visibility failure case. |
| TEST(Target, VisibilityFails) { |
| TestWithScope setup; |
| Err err; |
| |
| Target b(setup.settings(), Label(SourceDir("//private/"), "b")); |
| b.set_output_type(Target::STATIC_LIBRARY); |
| b.SetToolchain(setup.toolchain()); |
| b.visibility().SetPrivate(b.label().dir()); |
| ASSERT_TRUE(b.OnResolved(&err)); |
| |
| // Make a target depending on "b". The dependency must have an origin to mark |
| // it as user-set so we check visibility. This check should fail. |
| Target a(setup.settings(), Label(SourceDir("//app/"), "a")); |
| a.set_output_type(Target::EXECUTABLE); |
| a.private_deps().push_back(LabelTargetPair(&b)); |
| IdentifierNode origin; // Dummy origin. |
| a.private_deps()[0].origin = &origin; |
| a.SetToolchain(setup.toolchain()); |
| ASSERT_FALSE(a.OnResolved(&err)); |
| } |
| |
| // Test visibility with a single data_dep. |
| TEST(Target, VisibilityDatadeps) { |
| TestWithScope setup; |
| Err err; |
| |
| Target b(setup.settings(), Label(SourceDir("//public/"), "b")); |
| b.set_output_type(Target::STATIC_LIBRARY); |
| b.SetToolchain(setup.toolchain()); |
| b.visibility().SetPublic(); |
| ASSERT_TRUE(b.OnResolved(&err)); |
| |
| // Make a target depending on "b". The dependency must have an origin to mark |
| // it as user-set so we check visibility. This check should fail. |
| Target a(setup.settings(), Label(SourceDir("//app/"), "a")); |
| a.set_output_type(Target::EXECUTABLE); |
| a.data_deps().push_back(LabelTargetPair(&b)); |
| IdentifierNode origin; // Dummy origin. |
| a.data_deps()[0].origin = &origin; |
| a.SetToolchain(setup.toolchain()); |
| ASSERT_TRUE(a.OnResolved(&err)) << err.help_text(); |
| } |
| |
| // Tests that A -> Group -> B where the group is visible from A but B isn't, |
| // passes visibility even though the group's deps get expanded into A. |
| TEST(Target, VisibilityGroup) { |
| TestWithScope setup; |
| Err err; |
| |
| IdentifierNode origin; // Dummy origin. |
| |
| // B has private visibility. This lets the group see it since the group is in |
| // the same directory. |
| Target b(setup.settings(), Label(SourceDir("//private/"), "b")); |
| b.set_output_type(Target::STATIC_LIBRARY); |
| b.SetToolchain(setup.toolchain()); |
| b.visibility().SetPrivate(b.label().dir()); |
| ASSERT_TRUE(b.OnResolved(&err)); |
| |
| // The group has public visibility and depends on b. |
| Target g(setup.settings(), Label(SourceDir("//private/"), "g")); |
| g.set_output_type(Target::GROUP); |
| g.SetToolchain(setup.toolchain()); |
| g.private_deps().push_back(LabelTargetPair(&b)); |
| g.private_deps()[0].origin = &origin; |
| g.visibility().SetPublic(); |
| ASSERT_TRUE(b.OnResolved(&err)); |
| |
| // Make a target depending on "g". This should succeed. |
| Target a(setup.settings(), Label(SourceDir("//app/"), "a")); |
| a.set_output_type(Target::EXECUTABLE); |
| a.private_deps().push_back(LabelTargetPair(&g)); |
| a.private_deps()[0].origin = &origin; |
| a.SetToolchain(setup.toolchain()); |
| ASSERT_TRUE(a.OnResolved(&err)); |
| } |
| |
| // Verifies that only testonly targets can depend on other testonly targets. |
| // Many of the above dependency checking cases covered the non-testonly |
| // case. |
| TEST(Target, Testonly) { |
| TestWithScope setup; |
| Err err; |
| |
| // "testlib" is a test-only library. |
| Target testlib(setup.settings(), Label(SourceDir("//test/"), "testlib")); |
| testlib.set_testonly(true); |
| testlib.set_output_type(Target::STATIC_LIBRARY); |
| testlib.visibility().SetPublic(); |
| testlib.SetToolchain(setup.toolchain()); |
| ASSERT_TRUE(testlib.OnResolved(&err)); |
| |
| // "test" is a test-only executable depending on testlib, this is OK. |
| Target test(setup.settings(), Label(SourceDir("//test/"), "test")); |
| test.set_testonly(true); |
| test.set_output_type(Target::EXECUTABLE); |
| test.private_deps().push_back(LabelTargetPair(&testlib)); |
| test.SetToolchain(setup.toolchain()); |
| ASSERT_TRUE(test.OnResolved(&err)); |
| |
| // "product" is a non-test depending on testlib. This should fail. |
| Target product(setup.settings(), Label(SourceDir("//app/"), "product")); |
| product.set_testonly(false); |
| product.set_output_type(Target::EXECUTABLE); |
| product.private_deps().push_back(LabelTargetPair(&testlib)); |
| product.SetToolchain(setup.toolchain()); |
| ASSERT_FALSE(product.OnResolved(&err)); |
| } |
| |
| TEST(Target, PublicConfigs) { |
| TestWithScope setup; |
| Err err; |
| |
| Label pub_config_label(SourceDir("//a/"), "pubconfig"); |
| Config pub_config(setup.settings(), pub_config_label); |
| |
| // This is the destination target that has a public config. |
| Target dest(setup.settings(), Label(SourceDir("//a/"), "a")); |
| dest.set_output_type(Target::SOURCE_SET); |
| dest.visibility().SetPublic(); |
| dest.SetToolchain(setup.toolchain()); |
| dest.public_configs().push_back(LabelConfigPair(&pub_config)); |
| ASSERT_TRUE(dest.OnResolved(&err)); |
| |
| // This target has a public dependency on dest. |
| Target pub(setup.settings(), Label(SourceDir("//a/"), "pub")); |
| pub.set_output_type(Target::SOURCE_SET); |
| pub.visibility().SetPublic(); |
| pub.SetToolchain(setup.toolchain()); |
| pub.public_deps().push_back(LabelTargetPair(&dest)); |
| ASSERT_TRUE(pub.OnResolved(&err)); |
| |
| // Depending on the target with the public dependency should forward dest's |
| // to the current target. |
| Target dep_on_pub(setup.settings(), Label(SourceDir("//a/"), "dop")); |
| dep_on_pub.set_output_type(Target::SOURCE_SET); |
| dep_on_pub.visibility().SetPublic(); |
| dep_on_pub.SetToolchain(setup.toolchain()); |
| dep_on_pub.private_deps().push_back(LabelTargetPair(&pub)); |
| ASSERT_TRUE(dep_on_pub.OnResolved(&err)); |
| ASSERT_EQ(1u, dep_on_pub.configs().size()); |
| EXPECT_EQ(&pub_config, dep_on_pub.configs()[0].ptr); |
| |
| // This target has a private dependency on dest for forwards configs. |
| Target forward(setup.settings(), Label(SourceDir("//a/"), "f")); |
| forward.set_output_type(Target::SOURCE_SET); |
| forward.visibility().SetPublic(); |
| forward.SetToolchain(setup.toolchain()); |
| forward.private_deps().push_back(LabelTargetPair(&dest)); |
| forward.forward_dependent_configs().push_back(LabelTargetPair(&dest)); |
| ASSERT_TRUE(forward.OnResolved(&err)); |
| |
| // Depending on the forward target should apply the config. |
| Target dep_on_forward(setup.settings(), Label(SourceDir("//a/"), "dof")); |
| dep_on_forward.set_output_type(Target::SOURCE_SET); |
| dep_on_forward.visibility().SetPublic(); |
| dep_on_forward.SetToolchain(setup.toolchain()); |
| dep_on_forward.private_deps().push_back(LabelTargetPair(&forward)); |
| ASSERT_TRUE(dep_on_forward.OnResolved(&err)); |
| ASSERT_EQ(1u, dep_on_forward.configs().size()); |
| EXPECT_EQ(&pub_config, dep_on_forward.configs()[0].ptr); |
| } |
| |
| // Tests that different link/depend outputs work for solink tools. |
| TEST(Target, LinkAndDepOutputs) { |
| TestWithScope setup; |
| Err err; |
| |
| Toolchain toolchain(setup.settings(), Label(SourceDir("//tc/"), "tc")); |
| |
| scoped_ptr<Tool> solink_tool(new Tool()); |
| solink_tool->set_output_prefix("lib"); |
| solink_tool->set_default_output_extension(".so"); |
| |
| const char kLinkPattern[] = |
| "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"; |
| SubstitutionPattern link_output = SubstitutionPattern::MakeForTest( |
| kLinkPattern); |
| solink_tool->set_link_output(link_output); |
| |
| const char kDependPattern[] = |
| "{{root_out_dir}}/{{target_output_name}}{{output_extension}}.TOC"; |
| SubstitutionPattern depend_output = SubstitutionPattern::MakeForTest( |
| kDependPattern); |
| solink_tool->set_depend_output(depend_output); |
| |
| solink_tool->set_outputs(SubstitutionList::MakeForTest( |
| kLinkPattern, kDependPattern)); |
| |
| toolchain.SetTool(Toolchain::TYPE_SOLINK, solink_tool.Pass()); |
| |
| Target target(setup.settings(), Label(SourceDir("//a/"), "a")); |
| target.set_output_type(Target::SHARED_LIBRARY); |
| target.SetToolchain(&toolchain); |
| ASSERT_TRUE(target.OnResolved(&err)); |
| |
| EXPECT_EQ("./liba.so", target.link_output_file().value()); |
| EXPECT_EQ("./liba.so.TOC", target.dependency_output_file().value()); |
| } |