blob: bdc8c178a83cdf572890f2be7e7d8a36af7f1a78 [file] [log] [blame]
Colin Crossd00350c2017-11-17 10:55:38 -08001// Copyright 2017 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Colin Cross74d1ec02015-04-28 13:30:13 -070015package cc
16
17import (
Colin Cross5b529592017-05-09 13:34:34 -070018 "android/soong/android"
Colin Crossf18e1102017-11-16 14:33:08 -080019 "android/soong/genrule"
20
Jeff Gaston294356f2017-09-27 17:05:30 -070021 "fmt"
Jiyong Park6a43f042017-10-12 23:05:00 +090022 "io/ioutil"
23 "os"
Colin Cross74d1ec02015-04-28 13:30:13 -070024 "reflect"
Jeff Gaston294356f2017-09-27 17:05:30 -070025 "sort"
26 "strings"
Colin Cross74d1ec02015-04-28 13:30:13 -070027 "testing"
28)
29
Jiyong Park6a43f042017-10-12 23:05:00 +090030var buildDir string
31
32func setUp() {
33 var err error
34 buildDir, err = ioutil.TempDir("", "soong_cc_test")
35 if err != nil {
36 panic(err)
37 }
38}
39
40func tearDown() {
41 os.RemoveAll(buildDir)
42}
43
44func TestMain(m *testing.M) {
45 run := func() int {
46 setUp()
47 defer tearDown()
48
49 return m.Run()
50 }
51
52 os.Exit(run())
53}
54
55func testCc(t *testing.T, bp string) *android.TestContext {
56 config := android.TestArchConfig(buildDir, nil)
Nan Zhang0007d812017-11-07 10:57:05 -080057 config.ProductVariables.DeviceVndkVersion = StringPtr("current")
Jiyong Park6a43f042017-10-12 23:05:00 +090058
59 ctx := android.NewTestArchContext()
Steven Morelandf9e62162017-11-02 17:00:50 -070060 ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(LibraryFactory))
Colin Crossf18e1102017-11-16 14:33:08 -080061 ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(LibrarySharedFactory))
Jiyong Park6a43f042017-10-12 23:05:00 +090062 ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(toolchainLibraryFactory))
63 ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(llndkLibraryFactory))
Jeff Gaston294356f2017-09-27 17:05:30 -070064 ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(objectFactory))
Colin Crossf18e1102017-11-16 14:33:08 -080065 ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(genrule.FileGroupFactory))
Jiyong Park6a43f042017-10-12 23:05:00 +090066 ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
67 ctx.BottomUp("image", vendorMutator).Parallel()
68 ctx.BottomUp("link", linkageMutator).Parallel()
69 ctx.BottomUp("vndk", vndkMutator).Parallel()
70 })
71 ctx.Register()
72
Jeff Gaston294356f2017-09-27 17:05:30 -070073 // add some modules that are required by the compiler and/or linker
74 bp = bp + `
75 toolchain_library {
76 name: "libatomic",
77 vendor_available: true,
78 }
79
80 toolchain_library {
81 name: "libcompiler_rt-extras",
82 vendor_available: true,
83 }
84
85 toolchain_library {
86 name: "libgcc",
87 vendor_available: true,
88 }
89
90 cc_library {
91 name: "libc",
92 no_libgcc : true,
93 nocrt : true,
94 system_shared_libs: [],
95 }
96 llndk_library {
97 name: "libc",
98 symbol_file: "",
99 }
100 cc_library {
101 name: "libm",
102 no_libgcc : true,
103 nocrt : true,
104 system_shared_libs: [],
105 }
106 llndk_library {
107 name: "libm",
108 symbol_file: "",
109 }
110 cc_library {
111 name: "libdl",
112 no_libgcc : true,
113 nocrt : true,
114 system_shared_libs: [],
115 }
116 llndk_library {
117 name: "libdl",
118 symbol_file: "",
119 }
120
121 cc_object {
122 name: "crtbegin_so",
123 }
124
125 cc_object {
126 name: "crtend_so",
127 }
128
Colin Crossad59e752017-11-16 14:29:11 -0800129 cc_library {
130 name: "libprotobuf-cpp-lite",
131 }
132
Jeff Gaston294356f2017-09-27 17:05:30 -0700133`
134
Jiyong Park6a43f042017-10-12 23:05:00 +0900135 ctx.MockFileSystem(map[string][]byte{
136 "Android.bp": []byte(bp),
137 "foo.c": nil,
138 "bar.c": nil,
Colin Crossad59e752017-11-16 14:29:11 -0800139 "a.proto": nil,
Colin Crossf18e1102017-11-16 14:33:08 -0800140 "b.aidl": nil,
Jiyong Park6a43f042017-10-12 23:05:00 +0900141 })
142
Jeff Gastond3e141d2017-08-08 17:46:01 -0700143 _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
Jeff Gaston294356f2017-09-27 17:05:30 -0700144 failIfErrored(t, errs)
Jiyong Park6a43f042017-10-12 23:05:00 +0900145 _, errs = ctx.PrepareBuildActions(config)
Jeff Gaston294356f2017-09-27 17:05:30 -0700146 failIfErrored(t, errs)
Jiyong Park6a43f042017-10-12 23:05:00 +0900147
148 return ctx
149}
150
151func TestVendorSrc(t *testing.T) {
152 ctx := testCc(t, `
153 cc_library {
154 name: "libTest",
155 srcs: ["foo.c"],
156 no_libgcc : true,
157 nocrt : true,
158 system_shared_libs : [],
159 vendor_available: true,
160 target: {
161 vendor: {
162 srcs: ["bar.c"],
163 },
164 },
165 }
Jiyong Park6a43f042017-10-12 23:05:00 +0900166 `)
167
168 ld := ctx.ModuleForTests("libTest", "android_arm_armv7-a-neon_vendor_shared").Rule("ld")
169 var objs []string
170 for _, o := range ld.Inputs {
171 objs = append(objs, o.Base())
172 }
173 if len(objs) != 2 {
174 t.Errorf("inputs of libTest is expected to 2, but was %d.", len(objs))
175 }
176 if objs[0] != "foo.o" || objs[1] != "bar.o" {
177 t.Errorf("inputs of libTest must be []string{\"foo.o\", \"bar.o\"}, but was %#v.", objs)
178 }
179}
180
Colin Cross0af4b842015-04-30 16:36:18 -0700181var (
182 str11 = "01234567891"
183 str10 = str11[:10]
184 str9 = str11[:9]
185 str5 = str11[:5]
186 str4 = str11[:4]
187)
188
189var splitListForSizeTestCases = []struct {
190 in []string
191 out [][]string
192 size int
193}{
194 {
195 in: []string{str10},
196 out: [][]string{{str10}},
197 size: 10,
198 },
199 {
200 in: []string{str9},
201 out: [][]string{{str9}},
202 size: 10,
203 },
204 {
205 in: []string{str5},
206 out: [][]string{{str5}},
207 size: 10,
208 },
209 {
210 in: []string{str11},
211 out: nil,
212 size: 10,
213 },
214 {
215 in: []string{str10, str10},
216 out: [][]string{{str10}, {str10}},
217 size: 10,
218 },
219 {
220 in: []string{str9, str10},
221 out: [][]string{{str9}, {str10}},
222 size: 10,
223 },
224 {
225 in: []string{str10, str9},
226 out: [][]string{{str10}, {str9}},
227 size: 10,
228 },
229 {
230 in: []string{str5, str4},
231 out: [][]string{{str5, str4}},
232 size: 10,
233 },
234 {
235 in: []string{str5, str4, str5},
236 out: [][]string{{str5, str4}, {str5}},
237 size: 10,
238 },
239 {
240 in: []string{str5, str4, str5, str4},
241 out: [][]string{{str5, str4}, {str5, str4}},
242 size: 10,
243 },
244 {
245 in: []string{str5, str4, str5, str5},
246 out: [][]string{{str5, str4}, {str5}, {str5}},
247 size: 10,
248 },
249 {
250 in: []string{str5, str5, str5, str4},
251 out: [][]string{{str5}, {str5}, {str5, str4}},
252 size: 10,
253 },
254 {
255 in: []string{str9, str11},
256 out: nil,
257 size: 10,
258 },
259 {
260 in: []string{str11, str9},
261 out: nil,
262 size: 10,
263 },
264}
265
266func TestSplitListForSize(t *testing.T) {
267 for _, testCase := range splitListForSizeTestCases {
Colin Cross5b529592017-05-09 13:34:34 -0700268 out, _ := splitListForSize(android.PathsForTesting(testCase.in), testCase.size)
269
270 var outStrings [][]string
271
272 if len(out) > 0 {
273 outStrings = make([][]string, len(out))
274 for i, o := range out {
275 outStrings[i] = o.Strings()
276 }
277 }
278
279 if !reflect.DeepEqual(outStrings, testCase.out) {
Colin Cross0af4b842015-04-30 16:36:18 -0700280 t.Errorf("incorrect output:")
281 t.Errorf(" input: %#v", testCase.in)
282 t.Errorf(" size: %d", testCase.size)
283 t.Errorf(" expected: %#v", testCase.out)
Colin Cross5b529592017-05-09 13:34:34 -0700284 t.Errorf(" got: %#v", outStrings)
Colin Cross0af4b842015-04-30 16:36:18 -0700285 }
286 }
287}
Jeff Gaston294356f2017-09-27 17:05:30 -0700288
289var staticLinkDepOrderTestCases = []struct {
290 // This is a string representation of a map[moduleName][]moduleDependency .
291 // It models the dependencies declared in an Android.bp file.
292 in string
293
294 // allOrdered is a string representation of a map[moduleName][]moduleDependency .
295 // The keys of allOrdered specify which modules we would like to check.
296 // The values of allOrdered specify the expected result (of the transitive closure of all
297 // dependencies) for each module to test
298 allOrdered string
299
300 // outOrdered is a string representation of a map[moduleName][]moduleDependency .
301 // The keys of outOrdered specify which modules we would like to check.
302 // The values of outOrdered specify the expected result (of the ordered linker command line)
303 // for each module to test.
304 outOrdered string
305}{
306 // Simple tests
307 {
308 in: "",
309 outOrdered: "",
310 },
311 {
312 in: "a:",
313 outOrdered: "a:",
314 },
315 {
316 in: "a:b; b:",
317 outOrdered: "a:b; b:",
318 },
319 // Tests of reordering
320 {
321 // diamond example
322 in: "a:d,b,c; b:d; c:d; d:",
323 outOrdered: "a:b,c,d; b:d; c:d; d:",
324 },
325 {
326 // somewhat real example
327 in: "bsdiff_unittest:b,c,d,e,f,g,h,i; e:b",
328 outOrdered: "bsdiff_unittest:c,d,e,b,f,g,h,i; e:b",
329 },
330 {
331 // multiple reorderings
332 in: "a:b,c,d,e; d:b; e:c",
333 outOrdered: "a:d,b,e,c; d:b; e:c",
334 },
335 {
336 // should reorder without adding new transitive dependencies
337 in: "bin:lib2,lib1; lib1:lib2,liboptional",
338 allOrdered: "bin:lib1,lib2,liboptional; lib1:lib2,liboptional",
339 outOrdered: "bin:lib1,lib2; lib1:lib2,liboptional",
340 },
341 {
342 // multiple levels of dependencies
343 in: "a:b,c,d,e,f,g,h; f:b,c,d; b:c,d; c:d",
344 allOrdered: "a:e,f,b,c,d,g,h; f:b,c,d; b:c,d; c:d",
345 outOrdered: "a:e,f,b,c,d,g,h; f:b,c,d; b:c,d; c:d",
346 },
347 // tiebreakers for when two modules specifying different orderings and there is no dependency
348 // to dictate an order
349 {
350 // if the tie is between two modules at the end of a's deps, then a's order wins
351 in: "a1:b,c,d,e; a2:b,c,e,d; b:d,e; c:e,d",
352 outOrdered: "a1:b,c,d,e; a2:b,c,e,d; b:d,e; c:e,d",
353 },
354 {
355 // if the tie is between two modules at the start of a's deps, then c's order is used
356 in: "a1:d,e,b1,c1; b1:d,e; c1:e,d; a2:d,e,b2,c2; b2:d,e; c2:d,e",
357 outOrdered: "a1:b1,c1,e,d; b1:d,e; c1:e,d; a2:b2,c2,d,e; b2:d,e; c2:d,e",
358 },
359 // Tests involving duplicate dependencies
360 {
361 // simple duplicate
362 in: "a:b,c,c,b",
363 outOrdered: "a:c,b",
364 },
365 {
366 // duplicates with reordering
367 in: "a:b,c,d,c; c:b",
368 outOrdered: "a:d,c,b",
369 },
370 // Tests to confirm the nonexistence of infinite loops.
371 // These cases should never happen, so as long as the test terminates and the
372 // result is deterministic then that should be fine.
373 {
374 in: "a:a",
375 outOrdered: "a:a",
376 },
377 {
378 in: "a:b; b:c; c:a",
379 allOrdered: "a:b,c; b:c,a; c:a,b",
380 outOrdered: "a:b; b:c; c:a",
381 },
382 {
383 in: "a:b,c; b:c,a; c:a,b",
384 allOrdered: "a:c,a,b; b:a,b,c; c:b,c,a",
385 outOrdered: "a:c,b; b:a,c; c:b,a",
386 },
387}
388
389// converts from a string like "a:b,c; d:e" to (["a","b"], {"a":["b","c"], "d":["e"]}, [{"a", "a.o"}, {"b", "b.o"}])
390func parseModuleDeps(text string) (modulesInOrder []android.Path, allDeps map[android.Path][]android.Path) {
391 // convert from "a:b,c; d:e" to "a:b,c;d:e"
392 strippedText := strings.Replace(text, " ", "", -1)
393 if len(strippedText) < 1 {
394 return []android.Path{}, make(map[android.Path][]android.Path, 0)
395 }
396 allDeps = make(map[android.Path][]android.Path, 0)
397
398 // convert from "a:b,c;d:e" to ["a:b,c", "d:e"]
399 moduleTexts := strings.Split(strippedText, ";")
400
401 outputForModuleName := func(moduleName string) android.Path {
402 return android.PathForTesting(moduleName)
403 }
404
405 for _, moduleText := range moduleTexts {
406 // convert from "a:b,c" to ["a", "b,c"]
407 components := strings.Split(moduleText, ":")
408 if len(components) != 2 {
409 panic(fmt.Sprintf("illegal module dep string %q from larger string %q; must contain one ':', not %v", moduleText, text, len(components)-1))
410 }
411 moduleName := components[0]
412 moduleOutput := outputForModuleName(moduleName)
413 modulesInOrder = append(modulesInOrder, moduleOutput)
414
415 depString := components[1]
416 // convert from "b,c" to ["b", "c"]
417 depNames := strings.Split(depString, ",")
418 if len(depString) < 1 {
419 depNames = []string{}
420 }
421 var deps []android.Path
422 for _, depName := range depNames {
423 deps = append(deps, outputForModuleName(depName))
424 }
425 allDeps[moduleOutput] = deps
426 }
427 return modulesInOrder, allDeps
428}
429
430func TestStaticLinkDependencyOrdering(t *testing.T) {
431 for _, testCase := range staticLinkDepOrderTestCases {
432 errs := []string{}
433
434 // parse testcase
435 _, givenTransitiveDeps := parseModuleDeps(testCase.in)
436 expectedModuleNames, expectedTransitiveDeps := parseModuleDeps(testCase.outOrdered)
437 if testCase.allOrdered == "" {
438 // allow the test case to skip specifying allOrdered
439 testCase.allOrdered = testCase.outOrdered
440 }
441 _, expectedAllDeps := parseModuleDeps(testCase.allOrdered)
442
443 // For each module whose post-reordered dependencies were specified, validate that
444 // reordering the inputs produces the expected outputs.
445 for _, moduleName := range expectedModuleNames {
446 moduleDeps := givenTransitiveDeps[moduleName]
447 orderedAllDeps, orderedDeclaredDeps := orderDeps(moduleDeps, givenTransitiveDeps)
448
449 correctAllOrdered := expectedAllDeps[moduleName]
450 if !reflect.DeepEqual(orderedAllDeps, correctAllOrdered) {
451 errs = append(errs, fmt.Sprintf("orderDeps returned incorrect orderedAllDeps."+
452 "\nInput: %q"+
453 "\nmodule: %v"+
454 "\nexpected: %s"+
455 "\nactual: %s",
456 testCase.in, moduleName, correctAllOrdered, orderedAllDeps))
457 }
458
459 correctOutputDeps := expectedTransitiveDeps[moduleName]
460 if !reflect.DeepEqual(correctOutputDeps, orderedDeclaredDeps) {
461 errs = append(errs, fmt.Sprintf("orderDeps returned incorrect orderedDeclaredDeps."+
462 "\nInput: %q"+
463 "\nmodule: %v"+
464 "\nexpected: %s"+
465 "\nactual: %s",
466 testCase.in, moduleName, correctOutputDeps, orderedDeclaredDeps))
467 }
468 }
469
470 if len(errs) > 0 {
471 sort.Strings(errs)
472 for _, err := range errs {
473 t.Error(err)
474 }
475 }
476 }
477}
478func failIfErrored(t *testing.T, errs []error) {
479 if len(errs) > 0 {
480 for _, err := range errs {
481 t.Error(err)
482 }
483 t.FailNow()
484 }
485}
486
487func getOutputPaths(ctx *android.TestContext, variant string, moduleNames []string) (paths android.Paths) {
488 for _, moduleName := range moduleNames {
489 module := ctx.ModuleForTests(moduleName, variant).Module().(*Module)
490 output := module.outputFile.Path()
491 paths = append(paths, output)
492 }
493 return paths
494}
495
496func TestLibDeps(t *testing.T) {
497 ctx := testCc(t, `
498 cc_library {
499 name: "a",
500 static_libs: ["b", "c", "d"],
501 }
502 cc_library {
503 name: "b",
504 }
505 cc_library {
506 name: "c",
507 static_libs: ["b"],
508 }
509 cc_library {
510 name: "d",
511 }
512
513 `)
514
515 variant := "android_arm64_armv8-a_core_static"
516 moduleA := ctx.ModuleForTests("a", variant).Module().(*Module)
517 actual := moduleA.staticDepsInLinkOrder
518 expected := getOutputPaths(ctx, variant, []string{"c", "b", "d"})
519
520 if !reflect.DeepEqual(actual, expected) {
521 t.Errorf("staticDeps orderings were not propagated correctly"+
522 "\nactual: %v"+
523 "\nexpected: %v",
524 actual,
525 expected,
526 )
527 }
Jiyong Parkd08b6972017-09-26 10:50:54 +0900528}
Jeff Gaston294356f2017-09-27 17:05:30 -0700529
Jiyong Parkd08b6972017-09-26 10:50:54 +0900530var compilerFlagsTestCases = []struct {
531 in string
532 out bool
533}{
534 {
535 in: "a",
536 out: false,
537 },
538 {
539 in: "-a",
540 out: true,
541 },
542 {
543 in: "-Ipath/to/something",
544 out: false,
545 },
546 {
547 in: "-isystempath/to/something",
548 out: false,
549 },
550 {
551 in: "--coverage",
552 out: false,
553 },
554 {
555 in: "-include a/b",
556 out: true,
557 },
558 {
559 in: "-include a/b c/d",
560 out: false,
561 },
562 {
563 in: "-DMACRO",
564 out: true,
565 },
566 {
567 in: "-DMAC RO",
568 out: false,
569 },
570 {
571 in: "-a -b",
572 out: false,
573 },
574 {
575 in: "-DMACRO=definition",
576 out: true,
577 },
578 {
579 in: "-DMACRO=defi nition",
580 out: true, // TODO(jiyong): this should be false
581 },
582 {
583 in: "-DMACRO(x)=x + 1",
584 out: true,
585 },
586 {
587 in: "-DMACRO=\"defi nition\"",
588 out: true,
589 },
590}
591
592type mockContext struct {
593 BaseModuleContext
594 result bool
595}
596
597func (ctx *mockContext) PropertyErrorf(property, format string, args ...interface{}) {
598 // CheckBadCompilerFlags calls this function when the flag should be rejected
599 ctx.result = false
600}
601
602func TestCompilerFlags(t *testing.T) {
603 for _, testCase := range compilerFlagsTestCases {
604 ctx := &mockContext{result: true}
605 CheckBadCompilerFlags(ctx, "", []string{testCase.in})
606 if ctx.result != testCase.out {
607 t.Errorf("incorrect output:")
608 t.Errorf(" input: %#v", testCase.in)
609 t.Errorf(" expected: %#v", testCase.out)
610 t.Errorf(" got: %#v", ctx.result)
611 }
612 }
Jeff Gaston294356f2017-09-27 17:05:30 -0700613}