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