blob: dc04a4e14c8d13685d4ea9bee791d3bf137f03e2 [file] [log] [blame]
Colin Cross74d1ec02015-04-28 13:30:13 -07001package cc
2
3import (
Colin Cross5b529592017-05-09 13:34:34 -07004 "android/soong/android"
Jeff Gaston294356f2017-09-27 17:05:30 -07005 "fmt"
Jiyong Park6a43f042017-10-12 23:05:00 +09006 "io/ioutil"
7 "os"
Colin Cross74d1ec02015-04-28 13:30:13 -07008 "reflect"
Jeff Gaston294356f2017-09-27 17:05:30 -07009 "sort"
10 "strings"
Colin Cross74d1ec02015-04-28 13:30:13 -070011 "testing"
Jiyong Park6a43f042017-10-12 23:05:00 +090012
13 "github.com/google/blueprint/proptools"
Colin Cross74d1ec02015-04-28 13:30:13 -070014)
15
Jiyong Park6a43f042017-10-12 23:05:00 +090016var buildDir string
17
18func setUp() {
19 var err error
20 buildDir, err = ioutil.TempDir("", "soong_cc_test")
21 if err != nil {
22 panic(err)
23 }
24}
25
26func tearDown() {
27 os.RemoveAll(buildDir)
28}
29
30func TestMain(m *testing.M) {
31 run := func() int {
32 setUp()
33 defer tearDown()
34
35 return m.Run()
36 }
37
38 os.Exit(run())
39}
40
41func testCc(t *testing.T, bp string) *android.TestContext {
42 config := android.TestArchConfig(buildDir, nil)
43 config.ProductVariables.DeviceVndkVersion = proptools.StringPtr("current")
44
45 ctx := android.NewTestArchContext()
46 ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(libraryFactory))
47 ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(toolchainLibraryFactory))
48 ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(llndkLibraryFactory))
Jeff Gaston294356f2017-09-27 17:05:30 -070049 ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(objectFactory))
Jiyong Park6a43f042017-10-12 23:05:00 +090050 ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
51 ctx.BottomUp("image", vendorMutator).Parallel()
52 ctx.BottomUp("link", linkageMutator).Parallel()
53 ctx.BottomUp("vndk", vndkMutator).Parallel()
54 })
55 ctx.Register()
56
Jeff Gaston294356f2017-09-27 17:05:30 -070057 // add some modules that are required by the compiler and/or linker
58 bp = bp + `
59 toolchain_library {
60 name: "libatomic",
61 vendor_available: true,
62 }
63
64 toolchain_library {
65 name: "libcompiler_rt-extras",
66 vendor_available: true,
67 }
68
69 toolchain_library {
70 name: "libgcc",
71 vendor_available: true,
72 }
73
74 cc_library {
75 name: "libc",
76 no_libgcc : true,
77 nocrt : true,
78 system_shared_libs: [],
79 }
80 llndk_library {
81 name: "libc",
82 symbol_file: "",
83 }
84 cc_library {
85 name: "libm",
86 no_libgcc : true,
87 nocrt : true,
88 system_shared_libs: [],
89 }
90 llndk_library {
91 name: "libm",
92 symbol_file: "",
93 }
94 cc_library {
95 name: "libdl",
96 no_libgcc : true,
97 nocrt : true,
98 system_shared_libs: [],
99 }
100 llndk_library {
101 name: "libdl",
102 symbol_file: "",
103 }
104
105 cc_object {
106 name: "crtbegin_so",
107 }
108
109 cc_object {
110 name: "crtend_so",
111 }
112
113`
114
Jiyong Park6a43f042017-10-12 23:05:00 +0900115 ctx.MockFileSystem(map[string][]byte{
116 "Android.bp": []byte(bp),
117 "foo.c": nil,
118 "bar.c": nil,
119 })
120
121 _, errs := ctx.ParseBlueprintsFiles("Android.bp")
Jeff Gaston294356f2017-09-27 17:05:30 -0700122 failIfErrored(t, errs)
Jiyong Park6a43f042017-10-12 23:05:00 +0900123 _, errs = ctx.PrepareBuildActions(config)
Jeff Gaston294356f2017-09-27 17:05:30 -0700124 failIfErrored(t, errs)
Jiyong Park6a43f042017-10-12 23:05:00 +0900125
126 return ctx
127}
128
129func TestVendorSrc(t *testing.T) {
130 ctx := testCc(t, `
131 cc_library {
132 name: "libTest",
133 srcs: ["foo.c"],
134 no_libgcc : true,
135 nocrt : true,
136 system_shared_libs : [],
137 vendor_available: true,
138 target: {
139 vendor: {
140 srcs: ["bar.c"],
141 },
142 },
143 }
Jiyong Park6a43f042017-10-12 23:05:00 +0900144 `)
145
146 ld := ctx.ModuleForTests("libTest", "android_arm_armv7-a-neon_vendor_shared").Rule("ld")
147 var objs []string
148 for _, o := range ld.Inputs {
149 objs = append(objs, o.Base())
150 }
151 if len(objs) != 2 {
152 t.Errorf("inputs of libTest is expected to 2, but was %d.", len(objs))
153 }
154 if objs[0] != "foo.o" || objs[1] != "bar.o" {
155 t.Errorf("inputs of libTest must be []string{\"foo.o\", \"bar.o\"}, but was %#v.", objs)
156 }
157}
158
Colin Crossdd84e052017-05-17 13:44:16 -0700159var firstUniqueElementsTestCases = []struct {
160 in []string
161 out []string
162}{
163 {
164 in: []string{"a"},
165 out: []string{"a"},
166 },
167 {
168 in: []string{"a", "b"},
169 out: []string{"a", "b"},
170 },
171 {
172 in: []string{"a", "a"},
173 out: []string{"a"},
174 },
175 {
176 in: []string{"a", "b", "a"},
177 out: []string{"a", "b"},
178 },
179 {
180 in: []string{"b", "a", "a"},
181 out: []string{"b", "a"},
182 },
183 {
184 in: []string{"a", "a", "b"},
185 out: []string{"a", "b"},
186 },
187 {
188 in: []string{"a", "b", "a", "b"},
189 out: []string{"a", "b"},
190 },
191 {
192 in: []string{"liblog", "libdl", "libc++", "libdl", "libc", "libm"},
193 out: []string{"liblog", "libdl", "libc++", "libc", "libm"},
194 },
195}
196
197func TestFirstUniqueElements(t *testing.T) {
198 for _, testCase := range firstUniqueElementsTestCases {
199 out := firstUniqueElements(testCase.in)
200 if !reflect.DeepEqual(out, testCase.out) {
201 t.Errorf("incorrect output:")
202 t.Errorf(" input: %#v", testCase.in)
203 t.Errorf(" expected: %#v", testCase.out)
204 t.Errorf(" got: %#v", out)
205 }
206 }
207}
208
Colin Cross74d1ec02015-04-28 13:30:13 -0700209var lastUniqueElementsTestCases = []struct {
210 in []string
211 out []string
212}{
213 {
214 in: []string{"a"},
215 out: []string{"a"},
216 },
217 {
218 in: []string{"a", "b"},
219 out: []string{"a", "b"},
220 },
221 {
222 in: []string{"a", "a"},
223 out: []string{"a"},
224 },
225 {
226 in: []string{"a", "b", "a"},
227 out: []string{"b", "a"},
228 },
229 {
230 in: []string{"b", "a", "a"},
231 out: []string{"b", "a"},
232 },
233 {
234 in: []string{"a", "a", "b"},
235 out: []string{"a", "b"},
236 },
237 {
238 in: []string{"a", "b", "a", "b"},
239 out: []string{"a", "b"},
240 },
241 {
242 in: []string{"liblog", "libdl", "libc++", "libdl", "libc", "libm"},
243 out: []string{"liblog", "libc++", "libdl", "libc", "libm"},
244 },
245}
246
247func TestLastUniqueElements(t *testing.T) {
248 for _, testCase := range lastUniqueElementsTestCases {
249 out := lastUniqueElements(testCase.in)
250 if !reflect.DeepEqual(out, testCase.out) {
251 t.Errorf("incorrect output:")
252 t.Errorf(" input: %#v", testCase.in)
253 t.Errorf(" expected: %#v", testCase.out)
254 t.Errorf(" got: %#v", out)
255 }
256 }
257}
Colin Cross0af4b842015-04-30 16:36:18 -0700258
259var (
260 str11 = "01234567891"
261 str10 = str11[:10]
262 str9 = str11[:9]
263 str5 = str11[:5]
264 str4 = str11[:4]
265)
266
267var splitListForSizeTestCases = []struct {
268 in []string
269 out [][]string
270 size int
271}{
272 {
273 in: []string{str10},
274 out: [][]string{{str10}},
275 size: 10,
276 },
277 {
278 in: []string{str9},
279 out: [][]string{{str9}},
280 size: 10,
281 },
282 {
283 in: []string{str5},
284 out: [][]string{{str5}},
285 size: 10,
286 },
287 {
288 in: []string{str11},
289 out: nil,
290 size: 10,
291 },
292 {
293 in: []string{str10, str10},
294 out: [][]string{{str10}, {str10}},
295 size: 10,
296 },
297 {
298 in: []string{str9, str10},
299 out: [][]string{{str9}, {str10}},
300 size: 10,
301 },
302 {
303 in: []string{str10, str9},
304 out: [][]string{{str10}, {str9}},
305 size: 10,
306 },
307 {
308 in: []string{str5, str4},
309 out: [][]string{{str5, str4}},
310 size: 10,
311 },
312 {
313 in: []string{str5, str4, str5},
314 out: [][]string{{str5, str4}, {str5}},
315 size: 10,
316 },
317 {
318 in: []string{str5, str4, str5, str4},
319 out: [][]string{{str5, str4}, {str5, str4}},
320 size: 10,
321 },
322 {
323 in: []string{str5, str4, str5, str5},
324 out: [][]string{{str5, str4}, {str5}, {str5}},
325 size: 10,
326 },
327 {
328 in: []string{str5, str5, str5, str4},
329 out: [][]string{{str5}, {str5}, {str5, str4}},
330 size: 10,
331 },
332 {
333 in: []string{str9, str11},
334 out: nil,
335 size: 10,
336 },
337 {
338 in: []string{str11, str9},
339 out: nil,
340 size: 10,
341 },
342}
343
344func TestSplitListForSize(t *testing.T) {
345 for _, testCase := range splitListForSizeTestCases {
Colin Cross5b529592017-05-09 13:34:34 -0700346 out, _ := splitListForSize(android.PathsForTesting(testCase.in), testCase.size)
347
348 var outStrings [][]string
349
350 if len(out) > 0 {
351 outStrings = make([][]string, len(out))
352 for i, o := range out {
353 outStrings[i] = o.Strings()
354 }
355 }
356
357 if !reflect.DeepEqual(outStrings, testCase.out) {
Colin Cross0af4b842015-04-30 16:36:18 -0700358 t.Errorf("incorrect output:")
359 t.Errorf(" input: %#v", testCase.in)
360 t.Errorf(" size: %d", testCase.size)
361 t.Errorf(" expected: %#v", testCase.out)
Colin Cross5b529592017-05-09 13:34:34 -0700362 t.Errorf(" got: %#v", outStrings)
Colin Cross0af4b842015-04-30 16:36:18 -0700363 }
364 }
365}
Jeff Gaston294356f2017-09-27 17:05:30 -0700366
367var staticLinkDepOrderTestCases = []struct {
368 // This is a string representation of a map[moduleName][]moduleDependency .
369 // It models the dependencies declared in an Android.bp file.
370 in string
371
372 // allOrdered is a string representation of a map[moduleName][]moduleDependency .
373 // The keys of allOrdered specify which modules we would like to check.
374 // The values of allOrdered specify the expected result (of the transitive closure of all
375 // dependencies) for each module to test
376 allOrdered string
377
378 // outOrdered is a string representation of a map[moduleName][]moduleDependency .
379 // The keys of outOrdered specify which modules we would like to check.
380 // The values of outOrdered specify the expected result (of the ordered linker command line)
381 // for each module to test.
382 outOrdered string
383}{
384 // Simple tests
385 {
386 in: "",
387 outOrdered: "",
388 },
389 {
390 in: "a:",
391 outOrdered: "a:",
392 },
393 {
394 in: "a:b; b:",
395 outOrdered: "a:b; b:",
396 },
397 // Tests of reordering
398 {
399 // diamond example
400 in: "a:d,b,c; b:d; c:d; d:",
401 outOrdered: "a:b,c,d; b:d; c:d; d:",
402 },
403 {
404 // somewhat real example
405 in: "bsdiff_unittest:b,c,d,e,f,g,h,i; e:b",
406 outOrdered: "bsdiff_unittest:c,d,e,b,f,g,h,i; e:b",
407 },
408 {
409 // multiple reorderings
410 in: "a:b,c,d,e; d:b; e:c",
411 outOrdered: "a:d,b,e,c; d:b; e:c",
412 },
413 {
414 // should reorder without adding new transitive dependencies
415 in: "bin:lib2,lib1; lib1:lib2,liboptional",
416 allOrdered: "bin:lib1,lib2,liboptional; lib1:lib2,liboptional",
417 outOrdered: "bin:lib1,lib2; lib1:lib2,liboptional",
418 },
419 {
420 // multiple levels of dependencies
421 in: "a:b,c,d,e,f,g,h; f:b,c,d; b:c,d; c:d",
422 allOrdered: "a:e,f,b,c,d,g,h; f:b,c,d; b:c,d; c:d",
423 outOrdered: "a:e,f,b,c,d,g,h; f:b,c,d; b:c,d; c:d",
424 },
425 // tiebreakers for when two modules specifying different orderings and there is no dependency
426 // to dictate an order
427 {
428 // if the tie is between two modules at the end of a's deps, then a's order wins
429 in: "a1:b,c,d,e; a2:b,c,e,d; b:d,e; c:e,d",
430 outOrdered: "a1:b,c,d,e; a2:b,c,e,d; b:d,e; c:e,d",
431 },
432 {
433 // if the tie is between two modules at the start of a's deps, then c's order is used
434 in: "a1:d,e,b1,c1; b1:d,e; c1:e,d; a2:d,e,b2,c2; b2:d,e; c2:d,e",
435 outOrdered: "a1:b1,c1,e,d; b1:d,e; c1:e,d; a2:b2,c2,d,e; b2:d,e; c2:d,e",
436 },
437 // Tests involving duplicate dependencies
438 {
439 // simple duplicate
440 in: "a:b,c,c,b",
441 outOrdered: "a:c,b",
442 },
443 {
444 // duplicates with reordering
445 in: "a:b,c,d,c; c:b",
446 outOrdered: "a:d,c,b",
447 },
448 // Tests to confirm the nonexistence of infinite loops.
449 // These cases should never happen, so as long as the test terminates and the
450 // result is deterministic then that should be fine.
451 {
452 in: "a:a",
453 outOrdered: "a:a",
454 },
455 {
456 in: "a:b; b:c; c:a",
457 allOrdered: "a:b,c; b:c,a; c:a,b",
458 outOrdered: "a:b; b:c; c:a",
459 },
460 {
461 in: "a:b,c; b:c,a; c:a,b",
462 allOrdered: "a:c,a,b; b:a,b,c; c:b,c,a",
463 outOrdered: "a:c,b; b:a,c; c:b,a",
464 },
465}
466
467// converts from a string like "a:b,c; d:e" to (["a","b"], {"a":["b","c"], "d":["e"]}, [{"a", "a.o"}, {"b", "b.o"}])
468func parseModuleDeps(text string) (modulesInOrder []android.Path, allDeps map[android.Path][]android.Path) {
469 // convert from "a:b,c; d:e" to "a:b,c;d:e"
470 strippedText := strings.Replace(text, " ", "", -1)
471 if len(strippedText) < 1 {
472 return []android.Path{}, make(map[android.Path][]android.Path, 0)
473 }
474 allDeps = make(map[android.Path][]android.Path, 0)
475
476 // convert from "a:b,c;d:e" to ["a:b,c", "d:e"]
477 moduleTexts := strings.Split(strippedText, ";")
478
479 outputForModuleName := func(moduleName string) android.Path {
480 return android.PathForTesting(moduleName)
481 }
482
483 for _, moduleText := range moduleTexts {
484 // convert from "a:b,c" to ["a", "b,c"]
485 components := strings.Split(moduleText, ":")
486 if len(components) != 2 {
487 panic(fmt.Sprintf("illegal module dep string %q from larger string %q; must contain one ':', not %v", moduleText, text, len(components)-1))
488 }
489 moduleName := components[0]
490 moduleOutput := outputForModuleName(moduleName)
491 modulesInOrder = append(modulesInOrder, moduleOutput)
492
493 depString := components[1]
494 // convert from "b,c" to ["b", "c"]
495 depNames := strings.Split(depString, ",")
496 if len(depString) < 1 {
497 depNames = []string{}
498 }
499 var deps []android.Path
500 for _, depName := range depNames {
501 deps = append(deps, outputForModuleName(depName))
502 }
503 allDeps[moduleOutput] = deps
504 }
505 return modulesInOrder, allDeps
506}
507
508func TestStaticLinkDependencyOrdering(t *testing.T) {
509 for _, testCase := range staticLinkDepOrderTestCases {
510 errs := []string{}
511
512 // parse testcase
513 _, givenTransitiveDeps := parseModuleDeps(testCase.in)
514 expectedModuleNames, expectedTransitiveDeps := parseModuleDeps(testCase.outOrdered)
515 if testCase.allOrdered == "" {
516 // allow the test case to skip specifying allOrdered
517 testCase.allOrdered = testCase.outOrdered
518 }
519 _, expectedAllDeps := parseModuleDeps(testCase.allOrdered)
520
521 // For each module whose post-reordered dependencies were specified, validate that
522 // reordering the inputs produces the expected outputs.
523 for _, moduleName := range expectedModuleNames {
524 moduleDeps := givenTransitiveDeps[moduleName]
525 orderedAllDeps, orderedDeclaredDeps := orderDeps(moduleDeps, givenTransitiveDeps)
526
527 correctAllOrdered := expectedAllDeps[moduleName]
528 if !reflect.DeepEqual(orderedAllDeps, correctAllOrdered) {
529 errs = append(errs, fmt.Sprintf("orderDeps returned incorrect orderedAllDeps."+
530 "\nInput: %q"+
531 "\nmodule: %v"+
532 "\nexpected: %s"+
533 "\nactual: %s",
534 testCase.in, moduleName, correctAllOrdered, orderedAllDeps))
535 }
536
537 correctOutputDeps := expectedTransitiveDeps[moduleName]
538 if !reflect.DeepEqual(correctOutputDeps, orderedDeclaredDeps) {
539 errs = append(errs, fmt.Sprintf("orderDeps returned incorrect orderedDeclaredDeps."+
540 "\nInput: %q"+
541 "\nmodule: %v"+
542 "\nexpected: %s"+
543 "\nactual: %s",
544 testCase.in, moduleName, correctOutputDeps, orderedDeclaredDeps))
545 }
546 }
547
548 if len(errs) > 0 {
549 sort.Strings(errs)
550 for _, err := range errs {
551 t.Error(err)
552 }
553 }
554 }
555}
556func failIfErrored(t *testing.T, errs []error) {
557 if len(errs) > 0 {
558 for _, err := range errs {
559 t.Error(err)
560 }
561 t.FailNow()
562 }
563}
564
565func getOutputPaths(ctx *android.TestContext, variant string, moduleNames []string) (paths android.Paths) {
566 for _, moduleName := range moduleNames {
567 module := ctx.ModuleForTests(moduleName, variant).Module().(*Module)
568 output := module.outputFile.Path()
569 paths = append(paths, output)
570 }
571 return paths
572}
573
574func TestLibDeps(t *testing.T) {
575 ctx := testCc(t, `
576 cc_library {
577 name: "a",
578 static_libs: ["b", "c", "d"],
579 }
580 cc_library {
581 name: "b",
582 }
583 cc_library {
584 name: "c",
585 static_libs: ["b"],
586 }
587 cc_library {
588 name: "d",
589 }
590
591 `)
592
593 variant := "android_arm64_armv8-a_core_static"
594 moduleA := ctx.ModuleForTests("a", variant).Module().(*Module)
595 actual := moduleA.staticDepsInLinkOrder
596 expected := getOutputPaths(ctx, variant, []string{"c", "b", "d"})
597
598 if !reflect.DeepEqual(actual, expected) {
599 t.Errorf("staticDeps orderings were not propagated correctly"+
600 "\nactual: %v"+
601 "\nexpected: %v",
602 actual,
603 expected,
604 )
605 }
Jiyong Parkd08b6972017-09-26 10:50:54 +0900606}
Jeff Gaston294356f2017-09-27 17:05:30 -0700607
Jiyong Parkd08b6972017-09-26 10:50:54 +0900608var compilerFlagsTestCases = []struct {
609 in string
610 out bool
611}{
612 {
613 in: "a",
614 out: false,
615 },
616 {
617 in: "-a",
618 out: true,
619 },
620 {
621 in: "-Ipath/to/something",
622 out: false,
623 },
624 {
625 in: "-isystempath/to/something",
626 out: false,
627 },
628 {
629 in: "--coverage",
630 out: false,
631 },
632 {
633 in: "-include a/b",
634 out: true,
635 },
636 {
637 in: "-include a/b c/d",
638 out: false,
639 },
640 {
641 in: "-DMACRO",
642 out: true,
643 },
644 {
645 in: "-DMAC RO",
646 out: false,
647 },
648 {
649 in: "-a -b",
650 out: false,
651 },
652 {
653 in: "-DMACRO=definition",
654 out: true,
655 },
656 {
657 in: "-DMACRO=defi nition",
658 out: true, // TODO(jiyong): this should be false
659 },
660 {
661 in: "-DMACRO(x)=x + 1",
662 out: true,
663 },
664 {
665 in: "-DMACRO=\"defi nition\"",
666 out: true,
667 },
668}
669
670type mockContext struct {
671 BaseModuleContext
672 result bool
673}
674
675func (ctx *mockContext) PropertyErrorf(property, format string, args ...interface{}) {
676 // CheckBadCompilerFlags calls this function when the flag should be rejected
677 ctx.result = false
678}
679
680func TestCompilerFlags(t *testing.T) {
681 for _, testCase := range compilerFlagsTestCases {
682 ctx := &mockContext{result: true}
683 CheckBadCompilerFlags(ctx, "", []string{testCase.in})
684 if ctx.result != testCase.out {
685 t.Errorf("incorrect output:")
686 t.Errorf(" input: %#v", testCase.in)
687 t.Errorf(" expected: %#v", testCase.out)
688 t.Errorf(" got: %#v", ctx.result)
689 }
690 }
Jeff Gaston294356f2017-09-27 17:05:30 -0700691}