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