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#include <sstream> 6 7#include "testing/gtest/include/gtest/gtest.h" 8#include "tools/gn/ninja_binary_target_writer.h" 9#include "tools/gn/target.h" 10#include "tools/gn/test_with_scope.h" 11 12TEST(NinjaBinaryTargetWriter, SourceSet) { 13 TestWithScope setup; 14 Err err; 15 16 setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/")); 17 setup.settings()->set_target_os(Settings::WIN); 18 19 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar")); 20 target.set_output_type(Target::SOURCE_SET); 21 target.visibility().SetPublic(); 22 target.sources().push_back(SourceFile("//foo/input1.cc")); 23 target.sources().push_back(SourceFile("//foo/input2.cc")); 24 // Also test object files, which should be just passed through to the 25 // dependents to link. 26 target.sources().push_back(SourceFile("//foo/input3.o")); 27 target.sources().push_back(SourceFile("//foo/input4.obj")); 28 target.SetToolchain(setup.toolchain()); 29 ASSERT_TRUE(target.OnResolved(&err)); 30 31 // Source set itself. 32 { 33 std::ostringstream out; 34 NinjaBinaryTargetWriter writer(&target, out); 35 writer.Run(); 36 37 const char expected[] = 38 "defines =\n" 39 "include_dirs =\n" 40 "cflags =\n" 41 "cflags_c =\n" 42 "cflags_cc =\n" 43 "cflags_objc =\n" 44 "cflags_objcc =\n" 45 "root_out_dir = .\n" 46 "target_out_dir = obj/foo\n" 47 "target_output_name = bar\n" 48 "\n" 49 "build obj/foo/bar.input1.o: cxx ../../foo/input1.cc\n" 50 "build obj/foo/bar.input2.o: cxx ../../foo/input2.cc\n" 51 "\n" 52 "build obj/foo/bar.stamp: stamp obj/foo/bar.input1.o " 53 "obj/foo/bar.input2.o ../../foo/input3.o ../../foo/input4.obj\n"; 54 std::string out_str = out.str(); 55 EXPECT_EQ(expected, out_str); 56 } 57 58 // A shared library that depends on the source set. 59 Target shlib_target(setup.settings(), Label(SourceDir("//foo/"), "shlib")); 60 shlib_target.set_output_type(Target::SHARED_LIBRARY); 61 shlib_target.public_deps().push_back(LabelTargetPair(&target)); 62 shlib_target.SetToolchain(setup.toolchain()); 63 ASSERT_TRUE(shlib_target.OnResolved(&err)); 64 65 { 66 std::ostringstream out; 67 NinjaBinaryTargetWriter writer(&shlib_target, out); 68 writer.Run(); 69 70 const char expected[] = 71 "defines =\n" 72 "include_dirs =\n" 73 "cflags =\n" 74 "cflags_c =\n" 75 "cflags_cc =\n" 76 "cflags_objc =\n" 77 "cflags_objcc =\n" 78 "root_out_dir = .\n" 79 "target_out_dir = obj/foo\n" 80 "target_output_name = libshlib\n" 81 "\n" 82 "\n" 83 // Ordering of the obj files here should come out in the order 84 // specified, with the target's first, followed by the source set's, in 85 // order. 86 "build ./libshlib.so: solink obj/foo/bar.input1.o " 87 "obj/foo/bar.input2.o ../../foo/input3.o ../../foo/input4.obj\n" 88 " ldflags =\n" 89 " libs =\n" 90 " output_extension = .so\n"; 91 std::string out_str = out.str(); 92 EXPECT_EQ(expected, out_str); 93 } 94 95 // A static library that depends on the source set (should not link it). 96 Target stlib_target(setup.settings(), Label(SourceDir("//foo/"), "stlib")); 97 stlib_target.set_output_type(Target::STATIC_LIBRARY); 98 stlib_target.public_deps().push_back(LabelTargetPair(&target)); 99 stlib_target.SetToolchain(setup.toolchain()); 100 ASSERT_TRUE(stlib_target.OnResolved(&err)); 101 102 { 103 std::ostringstream out; 104 NinjaBinaryTargetWriter writer(&stlib_target, out); 105 writer.Run(); 106 107 const char expected[] = 108 "defines =\n" 109 "include_dirs =\n" 110 "cflags =\n" 111 "cflags_c =\n" 112 "cflags_cc =\n" 113 "cflags_objc =\n" 114 "cflags_objcc =\n" 115 "root_out_dir = .\n" 116 "target_out_dir = obj/foo\n" 117 "target_output_name = libstlib\n" 118 "\n" 119 "\n" 120 // There are no sources so there are no params to alink. (In practice 121 // this will probably fail in the archive tool.) 122 "build obj/foo/libstlib.a: alink\n" 123 " ldflags =\n" 124 " libs =\n" 125 " output_extension = \n"; 126 std::string out_str = out.str(); 127 EXPECT_EQ(expected, out_str); 128 } 129 130 // Make the static library 'complete', which means it should be linked. 131 stlib_target.set_complete_static_lib(true); 132 { 133 std::ostringstream out; 134 NinjaBinaryTargetWriter writer(&stlib_target, out); 135 writer.Run(); 136 137 const char expected[] = 138 "defines =\n" 139 "include_dirs =\n" 140 "cflags =\n" 141 "cflags_c =\n" 142 "cflags_cc =\n" 143 "cflags_objc =\n" 144 "cflags_objcc =\n" 145 "root_out_dir = .\n" 146 "target_out_dir = obj/foo\n" 147 "target_output_name = libstlib\n" 148 "\n" 149 "\n" 150 // Ordering of the obj files here should come out in the order 151 // specified, with the target's first, followed by the source set's, in 152 // order. 153 "build obj/foo/libstlib.a: alink obj/foo/bar.input1.o " 154 "obj/foo/bar.input2.o ../../foo/input3.o ../../foo/input4.obj\n" 155 " ldflags =\n" 156 " libs =\n" 157 " output_extension = \n"; 158 std::string out_str = out.str(); 159 EXPECT_EQ(expected, out_str); 160 } 161} 162 163// This tests that output extension overrides apply, and input dependencies 164// are applied. 165TEST(NinjaBinaryTargetWriter, ProductExtensionAndInputDeps) { 166 TestWithScope setup; 167 Err err; 168 169 setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/")); 170 setup.settings()->set_target_os(Settings::LINUX); 171 172 // An action for our library to depend on. 173 Target action(setup.settings(), Label(SourceDir("//foo/"), "action")); 174 action.set_output_type(Target::ACTION_FOREACH); 175 action.visibility().SetPublic(); 176 action.SetToolchain(setup.toolchain()); 177 ASSERT_TRUE(action.OnResolved(&err)); 178 179 // A shared library w/ the product_extension set to a custom value. 180 Target target(setup.settings(), Label(SourceDir("//foo/"), "shlib")); 181 target.set_output_type(Target::SHARED_LIBRARY); 182 target.set_output_extension(std::string("so.6")); 183 target.sources().push_back(SourceFile("//foo/input1.cc")); 184 target.sources().push_back(SourceFile("//foo/input2.cc")); 185 target.public_deps().push_back(LabelTargetPair(&action)); 186 target.SetToolchain(setup.toolchain()); 187 ASSERT_TRUE(target.OnResolved(&err)); 188 189 std::ostringstream out; 190 NinjaBinaryTargetWriter writer(&target, out); 191 writer.Run(); 192 193 const char expected[] = 194 "defines =\n" 195 "include_dirs =\n" 196 "cflags =\n" 197 "cflags_c =\n" 198 "cflags_cc =\n" 199 "cflags_objc =\n" 200 "cflags_objcc =\n" 201 "root_out_dir = .\n" 202 "target_out_dir = obj/foo\n" 203 "target_output_name = libshlib\n" 204 "\n" 205 "build obj/foo/shlib.inputdeps.stamp: stamp obj/foo/action.stamp\n" 206 "build obj/foo/libshlib.input1.o: cxx ../../foo/input1.cc" 207 " || obj/foo/shlib.inputdeps.stamp\n" 208 "build obj/foo/libshlib.input2.o: cxx ../../foo/input2.cc" 209 " || obj/foo/shlib.inputdeps.stamp\n" 210 "\n" 211 "build ./libshlib.so.6: solink obj/foo/libshlib.input1.o " 212 // The order-only dependency here is stricly unnecessary since the 213 // sources list this as an order-only dep. See discussion in the code 214 // that writes this. 215 "obj/foo/libshlib.input2.o || obj/foo/action.stamp\n" 216 " ldflags =\n" 217 " libs =\n" 218 " output_extension = .so.6\n"; 219 220 std::string out_str = out.str(); 221 EXPECT_EQ(expected, out_str); 222} 223 224TEST(NinjaBinaryTargetWriter, EmptyProductExtension) { 225 TestWithScope setup; 226 Err err; 227 228 setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/")); 229 setup.settings()->set_target_os(Settings::LINUX); 230 231 // This test is the same as ProductExtension, except that 232 // we call set_output_extension("") and ensure that we still get the default. 233 Target target(setup.settings(), Label(SourceDir("//foo/"), "shlib")); 234 target.set_output_type(Target::SHARED_LIBRARY); 235 target.set_output_extension(std::string()); 236 target.sources().push_back(SourceFile("//foo/input1.cc")); 237 target.sources().push_back(SourceFile("//foo/input2.cc")); 238 239 target.SetToolchain(setup.toolchain()); 240 ASSERT_TRUE(target.OnResolved(&err)); 241 242 std::ostringstream out; 243 NinjaBinaryTargetWriter writer(&target, out); 244 writer.Run(); 245 246 const char expected[] = 247 "defines =\n" 248 "include_dirs =\n" 249 "cflags =\n" 250 "cflags_c =\n" 251 "cflags_cc =\n" 252 "cflags_objc =\n" 253 "cflags_objcc =\n" 254 "root_out_dir = .\n" 255 "target_out_dir = obj/foo\n" 256 "target_output_name = libshlib\n" 257 "\n" 258 "build obj/foo/libshlib.input1.o: cxx ../../foo/input1.cc\n" 259 "build obj/foo/libshlib.input2.o: cxx ../../foo/input2.cc\n" 260 "\n" 261 "build ./libshlib.so: solink obj/foo/libshlib.input1.o " 262 "obj/foo/libshlib.input2.o\n" 263 " ldflags =\n" 264 " libs =\n" 265 " output_extension = .so\n"; 266 267 std::string out_str = out.str(); 268 EXPECT_EQ(expected, out_str); 269} 270