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/test_with_scope.h"
10
11TEST(NinjaBinaryTargetWriter, SourceSet) {
12  TestWithScope setup;
13  setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
14  setup.settings()->set_target_os(Settings::WIN);
15
16  Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
17  target.set_output_type(Target::SOURCE_SET);
18  target.sources().push_back(SourceFile("//foo/input1.cc"));
19  target.sources().push_back(SourceFile("//foo/input2.cc"));
20  // Also test object files, which should be just passed through to the
21  // dependents to link.
22  target.sources().push_back(SourceFile("//foo/input3.o"));
23  target.sources().push_back(SourceFile("//foo/input4.obj"));
24  target.OnResolved();
25
26  // Source set itself.
27  {
28    std::ostringstream out;
29    NinjaBinaryTargetWriter writer(&target, setup.toolchain(), out);
30    writer.Run();
31
32    // TODO(brettw) I think we'll need to worry about backslashes here
33    // depending if we're on actual Windows or Linux pretending to be Windows.
34    const char expected_win[] =
35        "defines =\n"
36        "includes =\n"
37        "cflags =\n"
38        "cflags_c =\n"
39        "cflags_cc =\n"
40        "cflags_objc =\n"
41        "cflags_objcc =\n"
42        "\n"
43        "build obj/foo/bar.input1.obj: cxx ../../foo/input1.cc\n"
44        "build obj/foo/bar.input2.obj: cxx ../../foo/input2.cc\n"
45        "\n"
46        "build obj/foo/bar.stamp: stamp obj/foo/bar.input1.obj "
47            "obj/foo/bar.input2.obj ../../foo/input3.o ../../foo/input4.obj\n";
48    std::string out_str = out.str();
49#if defined(OS_WIN)
50    std::replace(out_str.begin(), out_str.end(), '\\', '/');
51#endif
52    EXPECT_EQ(expected_win, out_str);
53  }
54
55  // A shared library that depends on the source set.
56  Target shlib_target(setup.settings(), Label(SourceDir("//foo/"), "shlib"));
57  shlib_target.set_output_type(Target::SHARED_LIBRARY);
58  shlib_target.deps().push_back(LabelTargetPair(&target));
59  shlib_target.OnResolved();
60
61  {
62    std::ostringstream out;
63    NinjaBinaryTargetWriter writer(&shlib_target, setup.toolchain(), out);
64    writer.Run();
65
66    // TODO(brettw) I think we'll need to worry about backslashes here
67    // depending if we're on actual Windows or Linux pretending to be Windows.
68    const char expected_win[] =
69        "defines =\n"
70        "includes =\n"
71        "cflags =\n"
72        "cflags_c =\n"
73        "cflags_cc =\n"
74        "cflags_objc =\n"
75        "cflags_objcc =\n"
76        "\n"
77        "\n"
78        "manifests = obj/foo/shlib.intermediate.manifest\n"
79        "ldflags = /MANIFEST /ManifestFile:obj/foo/shlib.intermediate."
80            "manifest\n"
81        "libs =\n"
82        // Ordering of the obj files here is arbitrary. Currently they're put
83        // in a set and come out sorted.
84        "build shlib.dll shlib.dll.lib: solink ../../foo/input3.o "
85            "../../foo/input4.obj obj/foo/bar.input1.obj "
86            "obj/foo/bar.input2.obj\n"
87        "  soname = shlib.dll\n"
88        "  lib = shlib.dll\n"
89        "  dll = shlib.dll\n"
90        "  implibflag = /IMPLIB:shlib.dll.lib\n\n";
91    std::string out_str = out.str();
92#if defined(OS_WIN)
93    std::replace(out_str.begin(), out_str.end(), '\\', '/');
94#endif
95    EXPECT_EQ(expected_win, out_str);
96  }
97
98  // A static library that depends on the source set (should not link it).
99  Target stlib_target(setup.settings(), Label(SourceDir("//foo/"), "stlib"));
100  stlib_target.set_output_type(Target::STATIC_LIBRARY);
101  stlib_target.deps().push_back(LabelTargetPair(&target));
102  stlib_target.OnResolved();
103
104  {
105    std::ostringstream out;
106    NinjaBinaryTargetWriter writer(&stlib_target, setup.toolchain(), out);
107    writer.Run();
108
109    // TODO(brettw) I think we'll need to worry about backslashes here
110    // depending if we're on actual Windows or Linux pretending to be Windows.
111    const char expected_win[] =
112        "defines =\n"
113        "includes =\n"
114        "cflags =\n"
115        "cflags_c =\n"
116        "cflags_cc =\n"
117        "cflags_objc =\n"
118        "cflags_objcc =\n"
119        "\n"
120        "\n"
121        "manifests = obj/foo/stlib.intermediate.manifest\n"
122        "ldflags = /MANIFEST /ManifestFile:obj/foo/stlib.intermediate.manifest\n"
123        "libs =\n"
124        // There are no sources so there are no params to alink.
125        "build obj/foo/stlib.lib: alink\n\n";
126    std::string out_str = out.str();
127#if defined(OS_WIN)
128    std::replace(out_str.begin(), out_str.end(), '\\', '/');
129#endif
130    EXPECT_EQ(expected_win, out_str);
131  }
132
133}
134
135TEST(NinjaBinaryTargetWriter, ProductExtension) {
136  TestWithScope setup;
137  setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
138  setup.settings()->set_target_os(Settings::LINUX);
139
140  // A shared library w/ the product_extension set to a custom value.
141  Target target(setup.settings(), Label(SourceDir("//foo/"), "shlib"));
142  target.set_output_type(Target::SHARED_LIBRARY);
143  target.set_output_extension(std::string("so.6"));
144  target.sources().push_back(SourceFile("//foo/input1.cc"));
145  target.sources().push_back(SourceFile("//foo/input2.cc"));
146  target.OnResolved();
147
148  std::ostringstream out;
149  NinjaBinaryTargetWriter writer(&target, setup.toolchain(), out);
150  writer.Run();
151
152  // TODO(brettw) I think we'll need to worry about backslashes here
153  // depending if we're on actual Windows or Linux pretending to be Windows.
154  const char expected[] =
155      "defines =\n"
156      "includes =\n"
157      "cflags =\n"
158      "cflags_c =\n"
159      "cflags_cc =\n"
160      "cflags_objc =\n"
161      "cflags_objcc =\n"
162      "\n"
163      "build obj/foo/shlib.input1.o: cxx ../../foo/input1.cc\n"
164      "build obj/foo/shlib.input2.o: cxx ../../foo/input2.cc\n"
165      "\n"
166      "ldflags =\n"
167      "libs =\n"
168      "build lib/libshlib.so.6: solink obj/foo/shlib.input1.o "
169          "obj/foo/shlib.input2.o\n"
170      "  soname = libshlib.so.6\n"
171      "  lib = lib/libshlib.so.6\n"
172      "\n";
173
174  std::string out_str = out.str();
175#if defined(OS_WIN)
176  std::replace(out_str.begin(), out_str.end(), '\\', '/');
177#endif
178  EXPECT_EQ(expected, out_str);
179}
180
181TEST(NinjaBinaryTargetWriter, EmptyProductExtension) {
182  TestWithScope setup;
183  setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
184  setup.settings()->set_target_os(Settings::LINUX);
185
186  // This test is the same as ProductExtension, except that
187  // we call set_output_extension("") and ensure that we still get the default.
188  Target target(setup.settings(), Label(SourceDir("//foo/"), "shlib"));
189  target.set_output_type(Target::SHARED_LIBRARY);
190  target.set_output_extension(std::string());
191  target.sources().push_back(SourceFile("//foo/input1.cc"));
192  target.sources().push_back(SourceFile("//foo/input2.cc"));
193
194  std::ostringstream out;
195  NinjaBinaryTargetWriter writer(&target, setup.toolchain(), out);
196  writer.Run();
197
198  // TODO(brettw) I think we'll need to worry about backslashes here
199  // depending if we're on actual Windows or Linux pretending to be Windows.
200  const char expected[] =
201      "defines =\n"
202      "includes =\n"
203      "cflags =\n"
204      "cflags_c =\n"
205      "cflags_cc =\n"
206      "cflags_objc =\n"
207      "cflags_objcc =\n"
208      "\n"
209      "build obj/foo/shlib.input1.o: cxx ../../foo/input1.cc\n"
210      "build obj/foo/shlib.input2.o: cxx ../../foo/input2.cc\n"
211      "\n"
212      "ldflags =\n"
213      "libs =\n"
214      "build lib/libshlib.so: solink obj/foo/shlib.input1.o "
215          "obj/foo/shlib.input2.o\n"
216      "  soname = libshlib.so\n"
217      "  lib = lib/libshlib.so\n"
218      "\n";
219
220  std::string out_str = out.str();
221#if defined(OS_WIN)
222  std::replace(out_str.begin(), out_str.end(), '\\', '/');
223#endif
224  EXPECT_EQ(expected, out_str);
225}
226