blob: b7c23951e4be7b79dc31060ec77238685e7d6d0f [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()
Steven Morelandf9e62162017-11-02 17:00:50 -070046 ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(LibraryFactory))
Jiyong Park6a43f042017-10-12 23:05:00 +090047 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 Cross0af4b842015-04-30 16:36:18 -0700159var (
160 str11 = "01234567891"
161 str10 = str11[:10]
162 str9 = str11[:9]
163 str5 = str11[:5]
164 str4 = str11[:4]
165)
166
167var splitListForSizeTestCases = []struct {
168 in []string
169 out [][]string
170 size int
171}{
172 {
173 in: []string{str10},
174 out: [][]string{{str10}},
175 size: 10,
176 },
177 {
178 in: []string{str9},
179 out: [][]string{{str9}},
180 size: 10,
181 },
182 {
183 in: []string{str5},
184 out: [][]string{{str5}},
185 size: 10,
186 },
187 {
188 in: []string{str11},
189 out: nil,
190 size: 10,
191 },
192 {
193 in: []string{str10, str10},
194 out: [][]string{{str10}, {str10}},
195 size: 10,
196 },
197 {
198 in: []string{str9, str10},
199 out: [][]string{{str9}, {str10}},
200 size: 10,
201 },
202 {
203 in: []string{str10, str9},
204 out: [][]string{{str10}, {str9}},
205 size: 10,
206 },
207 {
208 in: []string{str5, str4},
209 out: [][]string{{str5, str4}},
210 size: 10,
211 },
212 {
213 in: []string{str5, str4, str5},
214 out: [][]string{{str5, str4}, {str5}},
215 size: 10,
216 },
217 {
218 in: []string{str5, str4, str5, str4},
219 out: [][]string{{str5, str4}, {str5, str4}},
220 size: 10,
221 },
222 {
223 in: []string{str5, str4, str5, str5},
224 out: [][]string{{str5, str4}, {str5}, {str5}},
225 size: 10,
226 },
227 {
228 in: []string{str5, str5, str5, str4},
229 out: [][]string{{str5}, {str5}, {str5, str4}},
230 size: 10,
231 },
232 {
233 in: []string{str9, str11},
234 out: nil,
235 size: 10,
236 },
237 {
238 in: []string{str11, str9},
239 out: nil,
240 size: 10,
241 },
242}
243
244func TestSplitListForSize(t *testing.T) {
245 for _, testCase := range splitListForSizeTestCases {
Colin Cross5b529592017-05-09 13:34:34 -0700246 out, _ := splitListForSize(android.PathsForTesting(testCase.in), testCase.size)
247
248 var outStrings [][]string
249
250 if len(out) > 0 {
251 outStrings = make([][]string, len(out))
252 for i, o := range out {
253 outStrings[i] = o.Strings()
254 }
255 }
256
257 if !reflect.DeepEqual(outStrings, testCase.out) {
Colin Cross0af4b842015-04-30 16:36:18 -0700258 t.Errorf("incorrect output:")
259 t.Errorf(" input: %#v", testCase.in)
260 t.Errorf(" size: %d", testCase.size)
261 t.Errorf(" expected: %#v", testCase.out)
Colin Cross5b529592017-05-09 13:34:34 -0700262 t.Errorf(" got: %#v", outStrings)
Colin Cross0af4b842015-04-30 16:36:18 -0700263 }
264 }
265}
Jeff Gaston294356f2017-09-27 17:05:30 -0700266
267var staticLinkDepOrderTestCases = []struct {
268 // This is a string representation of a map[moduleName][]moduleDependency .
269 // It models the dependencies declared in an Android.bp file.
270 in string
271
272 // allOrdered is a string representation of a map[moduleName][]moduleDependency .
273 // The keys of allOrdered specify which modules we would like to check.
274 // The values of allOrdered specify the expected result (of the transitive closure of all
275 // dependencies) for each module to test
276 allOrdered string
277
278 // outOrdered is a string representation of a map[moduleName][]moduleDependency .
279 // The keys of outOrdered specify which modules we would like to check.
280 // The values of outOrdered specify the expected result (of the ordered linker command line)
281 // for each module to test.
282 outOrdered string
283}{
284 // Simple tests
285 {
286 in: "",
287 outOrdered: "",
288 },
289 {
290 in: "a:",
291 outOrdered: "a:",
292 },
293 {
294 in: "a:b; b:",
295 outOrdered: "a:b; b:",
296 },
297 // Tests of reordering
298 {
299 // diamond example
300 in: "a:d,b,c; b:d; c:d; d:",
301 outOrdered: "a:b,c,d; b:d; c:d; d:",
302 },
303 {
304 // somewhat real example
305 in: "bsdiff_unittest:b,c,d,e,f,g,h,i; e:b",
306 outOrdered: "bsdiff_unittest:c,d,e,b,f,g,h,i; e:b",
307 },
308 {
309 // multiple reorderings
310 in: "a:b,c,d,e; d:b; e:c",
311 outOrdered: "a:d,b,e,c; d:b; e:c",
312 },
313 {
314 // should reorder without adding new transitive dependencies
315 in: "bin:lib2,lib1; lib1:lib2,liboptional",
316 allOrdered: "bin:lib1,lib2,liboptional; lib1:lib2,liboptional",
317 outOrdered: "bin:lib1,lib2; lib1:lib2,liboptional",
318 },
319 {
320 // multiple levels of dependencies
321 in: "a:b,c,d,e,f,g,h; f:b,c,d; b:c,d; c:d",
322 allOrdered: "a:e,f,b,c,d,g,h; f:b,c,d; b:c,d; c:d",
323 outOrdered: "a:e,f,b,c,d,g,h; f:b,c,d; b:c,d; c:d",
324 },
325 // tiebreakers for when two modules specifying different orderings and there is no dependency
326 // to dictate an order
327 {
328 // if the tie is between two modules at the end of a's deps, then a's order wins
329 in: "a1:b,c,d,e; a2:b,c,e,d; b:d,e; c:e,d",
330 outOrdered: "a1:b,c,d,e; a2:b,c,e,d; b:d,e; c:e,d",
331 },
332 {
333 // if the tie is between two modules at the start of a's deps, then c's order is used
334 in: "a1:d,e,b1,c1; b1:d,e; c1:e,d; a2:d,e,b2,c2; b2:d,e; c2:d,e",
335 outOrdered: "a1:b1,c1,e,d; b1:d,e; c1:e,d; a2:b2,c2,d,e; b2:d,e; c2:d,e",
336 },
337 // Tests involving duplicate dependencies
338 {
339 // simple duplicate
340 in: "a:b,c,c,b",
341 outOrdered: "a:c,b",
342 },
343 {
344 // duplicates with reordering
345 in: "a:b,c,d,c; c:b",
346 outOrdered: "a:d,c,b",
347 },
348 // Tests to confirm the nonexistence of infinite loops.
349 // These cases should never happen, so as long as the test terminates and the
350 // result is deterministic then that should be fine.
351 {
352 in: "a:a",
353 outOrdered: "a:a",
354 },
355 {
356 in: "a:b; b:c; c:a",
357 allOrdered: "a:b,c; b:c,a; c:a,b",
358 outOrdered: "a:b; b:c; c:a",
359 },
360 {
361 in: "a:b,c; b:c,a; c:a,b",
362 allOrdered: "a:c,a,b; b:a,b,c; c:b,c,a",
363 outOrdered: "a:c,b; b:a,c; c:b,a",
364 },
365}
366
367// converts from a string like "a:b,c; d:e" to (["a","b"], {"a":["b","c"], "d":["e"]}, [{"a", "a.o"}, {"b", "b.o"}])
368func parseModuleDeps(text string) (modulesInOrder []android.Path, allDeps map[android.Path][]android.Path) {
369 // convert from "a:b,c; d:e" to "a:b,c;d:e"
370 strippedText := strings.Replace(text, " ", "", -1)
371 if len(strippedText) < 1 {
372 return []android.Path{}, make(map[android.Path][]android.Path, 0)
373 }
374 allDeps = make(map[android.Path][]android.Path, 0)
375
376 // convert from "a:b,c;d:e" to ["a:b,c", "d:e"]
377 moduleTexts := strings.Split(strippedText, ";")
378
379 outputForModuleName := func(moduleName string) android.Path {
380 return android.PathForTesting(moduleName)
381 }
382
383 for _, moduleText := range moduleTexts {
384 // convert from "a:b,c" to ["a", "b,c"]
385 components := strings.Split(moduleText, ":")
386 if len(components) != 2 {
387 panic(fmt.Sprintf("illegal module dep string %q from larger string %q; must contain one ':', not %v", moduleText, text, len(components)-1))
388 }
389 moduleName := components[0]
390 moduleOutput := outputForModuleName(moduleName)
391 modulesInOrder = append(modulesInOrder, moduleOutput)
392
393 depString := components[1]
394 // convert from "b,c" to ["b", "c"]
395 depNames := strings.Split(depString, ",")
396 if len(depString) < 1 {
397 depNames = []string{}
398 }
399 var deps []android.Path
400 for _, depName := range depNames {
401 deps = append(deps, outputForModuleName(depName))
402 }
403 allDeps[moduleOutput] = deps
404 }
405 return modulesInOrder, allDeps
406}
407
408func TestStaticLinkDependencyOrdering(t *testing.T) {
409 for _, testCase := range staticLinkDepOrderTestCases {
410 errs := []string{}
411
412 // parse testcase
413 _, givenTransitiveDeps := parseModuleDeps(testCase.in)
414 expectedModuleNames, expectedTransitiveDeps := parseModuleDeps(testCase.outOrdered)
415 if testCase.allOrdered == "" {
416 // allow the test case to skip specifying allOrdered
417 testCase.allOrdered = testCase.outOrdered
418 }
419 _, expectedAllDeps := parseModuleDeps(testCase.allOrdered)
420
421 // For each module whose post-reordered dependencies were specified, validate that
422 // reordering the inputs produces the expected outputs.
423 for _, moduleName := range expectedModuleNames {
424 moduleDeps := givenTransitiveDeps[moduleName]
425 orderedAllDeps, orderedDeclaredDeps := orderDeps(moduleDeps, givenTransitiveDeps)
426
427 correctAllOrdered := expectedAllDeps[moduleName]
428 if !reflect.DeepEqual(orderedAllDeps, correctAllOrdered) {
429 errs = append(errs, fmt.Sprintf("orderDeps returned incorrect orderedAllDeps."+
430 "\nInput: %q"+
431 "\nmodule: %v"+
432 "\nexpected: %s"+
433 "\nactual: %s",
434 testCase.in, moduleName, correctAllOrdered, orderedAllDeps))
435 }
436
437 correctOutputDeps := expectedTransitiveDeps[moduleName]
438 if !reflect.DeepEqual(correctOutputDeps, orderedDeclaredDeps) {
439 errs = append(errs, fmt.Sprintf("orderDeps returned incorrect orderedDeclaredDeps."+
440 "\nInput: %q"+
441 "\nmodule: %v"+
442 "\nexpected: %s"+
443 "\nactual: %s",
444 testCase.in, moduleName, correctOutputDeps, orderedDeclaredDeps))
445 }
446 }
447
448 if len(errs) > 0 {
449 sort.Strings(errs)
450 for _, err := range errs {
451 t.Error(err)
452 }
453 }
454 }
455}
456func failIfErrored(t *testing.T, errs []error) {
457 if len(errs) > 0 {
458 for _, err := range errs {
459 t.Error(err)
460 }
461 t.FailNow()
462 }
463}
464
465func getOutputPaths(ctx *android.TestContext, variant string, moduleNames []string) (paths android.Paths) {
466 for _, moduleName := range moduleNames {
467 module := ctx.ModuleForTests(moduleName, variant).Module().(*Module)
468 output := module.outputFile.Path()
469 paths = append(paths, output)
470 }
471 return paths
472}
473
474func TestLibDeps(t *testing.T) {
475 ctx := testCc(t, `
476 cc_library {
477 name: "a",
478 static_libs: ["b", "c", "d"],
479 }
480 cc_library {
481 name: "b",
482 }
483 cc_library {
484 name: "c",
485 static_libs: ["b"],
486 }
487 cc_library {
488 name: "d",
489 }
490
491 `)
492
493 variant := "android_arm64_armv8-a_core_static"
494 moduleA := ctx.ModuleForTests("a", variant).Module().(*Module)
495 actual := moduleA.staticDepsInLinkOrder
496 expected := getOutputPaths(ctx, variant, []string{"c", "b", "d"})
497
498 if !reflect.DeepEqual(actual, expected) {
499 t.Errorf("staticDeps orderings were not propagated correctly"+
500 "\nactual: %v"+
501 "\nexpected: %v",
502 actual,
503 expected,
504 )
505 }
Jiyong Parkd08b6972017-09-26 10:50:54 +0900506}
Jeff Gaston294356f2017-09-27 17:05:30 -0700507
Jiyong Parkd08b6972017-09-26 10:50:54 +0900508var compilerFlagsTestCases = []struct {
509 in string
510 out bool
511}{
512 {
513 in: "a",
514 out: false,
515 },
516 {
517 in: "-a",
518 out: true,
519 },
520 {
521 in: "-Ipath/to/something",
522 out: false,
523 },
524 {
525 in: "-isystempath/to/something",
526 out: false,
527 },
528 {
529 in: "--coverage",
530 out: false,
531 },
532 {
533 in: "-include a/b",
534 out: true,
535 },
536 {
537 in: "-include a/b c/d",
538 out: false,
539 },
540 {
541 in: "-DMACRO",
542 out: true,
543 },
544 {
545 in: "-DMAC RO",
546 out: false,
547 },
548 {
549 in: "-a -b",
550 out: false,
551 },
552 {
553 in: "-DMACRO=definition",
554 out: true,
555 },
556 {
557 in: "-DMACRO=defi nition",
558 out: true, // TODO(jiyong): this should be false
559 },
560 {
561 in: "-DMACRO(x)=x + 1",
562 out: true,
563 },
564 {
565 in: "-DMACRO=\"defi nition\"",
566 out: true,
567 },
568}
569
570type mockContext struct {
571 BaseModuleContext
572 result bool
573}
574
575func (ctx *mockContext) PropertyErrorf(property, format string, args ...interface{}) {
576 // CheckBadCompilerFlags calls this function when the flag should be rejected
577 ctx.result = false
578}
579
580func TestCompilerFlags(t *testing.T) {
581 for _, testCase := range compilerFlagsTestCases {
582 ctx := &mockContext{result: true}
583 CheckBadCompilerFlags(ctx, "", []string{testCase.in})
584 if ctx.result != testCase.out {
585 t.Errorf("incorrect output:")
586 t.Errorf(" input: %#v", testCase.in)
587 t.Errorf(" expected: %#v", testCase.out)
588 t.Errorf(" got: %#v", ctx.result)
589 }
590 }
Jeff Gaston294356f2017-09-27 17:05:30 -0700591}