blob: 38bb141ca7e01b72806e0f77bc2673f9c3382d5d [file] [log] [blame]
Colin Cross3f40fa42015-01-30 17:27:36 -08001// Copyright 2015 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
15package cc
16
17// This file generates the final rules for compiling all C/C++. All properties related to
18// compiling should have been translated into builderFlags or another argument to the Transform*
19// functions.
20
21import (
22 "android/soong/common"
Colin Cross0af4b842015-04-30 16:36:18 -070023 "fmt"
24 "runtime"
25 "strconv"
Colin Cross3f40fa42015-01-30 17:27:36 -080026
Colin Cross3f40fa42015-01-30 17:27:36 -080027 "path/filepath"
28 "strings"
Colin Crossed4cf0b2015-03-26 14:43:45 -070029
30 "github.com/google/blueprint"
Colin Cross3f40fa42015-01-30 17:27:36 -080031)
32
33const (
Dan Albertc3144b12015-04-28 18:17:56 -070034 objectExtension = ".o"
Colin Cross3f40fa42015-01-30 17:27:36 -080035 staticLibraryExtension = ".a"
36)
37
38var (
Dan Willemsen34cc69e2015-09-23 15:26:20 -070039 pctx = common.NewPackageContext("android/soong/cc")
Colin Cross3f40fa42015-01-30 17:27:36 -080040
41 cc = pctx.StaticRule("cc",
42 blueprint.RuleParams{
43 Depfile: "${out}.d",
44 Deps: blueprint.DepsGCC,
Dan Willemsene6540452015-10-20 15:21:33 -070045 Command: "$relPwd $ccCmd -c $cFlags -MD -MF ${out}.d -o $out $in",
Dan Willemsenc94a7682015-11-17 15:27:28 -080046 CommandDeps: []string{"$ccCmd"},
Colin Cross3f40fa42015-01-30 17:27:36 -080047 Description: "cc $out",
48 },
Dan Willemsen322a0a62015-11-17 15:19:46 -080049 "ccCmd", "cFlags")
Colin Cross3f40fa42015-01-30 17:27:36 -080050
51 ld = pctx.StaticRule("ld",
52 blueprint.RuleParams{
Colin Cross7d21c442015-03-30 17:47:53 -070053 Command: "$ldCmd ${ldDirFlags} ${crtBegin} @${out}.rsp " +
Colin Cross28344522015-04-22 13:07:53 -070054 "${libFlags} ${crtEnd} -o ${out} ${ldFlags}",
Dan Willemsenc94a7682015-11-17 15:27:28 -080055 CommandDeps: []string{"$ldCmd"},
Colin Cross7d21c442015-03-30 17:47:53 -070056 Description: "ld $out",
57 Rspfile: "${out}.rsp",
58 RspfileContent: "${in}",
Colin Cross3f40fa42015-01-30 17:27:36 -080059 },
Colin Cross28344522015-04-22 13:07:53 -070060 "ldCmd", "ldDirFlags", "crtBegin", "libFlags", "crtEnd", "ldFlags")
Colin Cross3f40fa42015-01-30 17:27:36 -080061
62 partialLd = pctx.StaticRule("partialLd",
63 blueprint.RuleParams{
Colin Cross41280a42015-11-23 14:01:42 -080064 Command: "$ldCmd -nostdlib -Wl,-r ${in} -o ${out} ${ldFlags}",
Dan Willemsenc94a7682015-11-17 15:27:28 -080065 CommandDeps: []string{"$ldCmd"},
Colin Cross3f40fa42015-01-30 17:27:36 -080066 Description: "partialLd $out",
67 },
Colin Cross41280a42015-11-23 14:01:42 -080068 "ldCmd", "ldFlags")
Colin Cross3f40fa42015-01-30 17:27:36 -080069
70 ar = pctx.StaticRule("ar",
71 blueprint.RuleParams{
Colin Cross7d21c442015-03-30 17:47:53 -070072 Command: "rm -f ${out} && $arCmd $arFlags $out @${out}.rsp",
Dan Willemsenc94a7682015-11-17 15:27:28 -080073 CommandDeps: []string{"$arCmd"},
Colin Cross7d21c442015-03-30 17:47:53 -070074 Description: "ar $out",
75 Rspfile: "${out}.rsp",
76 RspfileContent: "${in}",
Colin Cross3f40fa42015-01-30 17:27:36 -080077 },
78 "arCmd", "arFlags")
79
Colin Cross0af4b842015-04-30 16:36:18 -070080 darwinAr = pctx.StaticRule("darwinAr",
81 blueprint.RuleParams{
82 Command: "rm -f ${out} && $arCmd $arFlags $out $in",
Dan Willemsenc94a7682015-11-17 15:27:28 -080083 CommandDeps: []string{"$arCmd"},
Colin Cross0af4b842015-04-30 16:36:18 -070084 Description: "ar $out",
85 },
86 "arCmd", "arFlags")
87
88 darwinAppendAr = pctx.StaticRule("darwinAppendAr",
89 blueprint.RuleParams{
90 Command: "cp -f ${inAr} ${out}.tmp && $arCmd $arFlags ${out}.tmp $in && mv ${out}.tmp ${out}",
Dan Willemsenc94a7682015-11-17 15:27:28 -080091 CommandDeps: []string{"$arCmd"},
Colin Cross0af4b842015-04-30 16:36:18 -070092 Description: "ar $out",
93 },
94 "arCmd", "arFlags", "inAr")
95
Colin Crossbfae8852015-03-26 14:44:11 -070096 prefixSymbols = pctx.StaticRule("prefixSymbols",
97 blueprint.RuleParams{
98 Command: "$objcopyCmd --prefix-symbols=${prefix} ${in} ${out}",
Dan Willemsenc94a7682015-11-17 15:27:28 -080099 CommandDeps: []string{"$objcopyCmd"},
Colin Crossbfae8852015-03-26 14:44:11 -0700100 Description: "prefixSymbols $out",
101 },
102 "objcopyCmd", "prefix")
103
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700104 copyGccLibPath = pctx.SourcePathVariable("copyGccLibPath", "build/soong/copygcclib.sh")
Colin Cross3f40fa42015-01-30 17:27:36 -0800105
106 copyGccLib = pctx.StaticRule("copyGccLib",
107 blueprint.RuleParams{
108 Depfile: "${out}.d",
109 Deps: blueprint.DepsGCC,
110 Command: "$copyGccLibPath $out $ccCmd $cFlags -print-file-name=${libName}",
Dan Willemsenc94a7682015-11-17 15:27:28 -0800111 CommandDeps: []string{"$copyGccLibPath", "$ccCmd"},
Colin Cross3f40fa42015-01-30 17:27:36 -0800112 Description: "copy gcc $out",
113 },
114 "ccCmd", "cFlags", "libName")
115)
116
Dan Willemsen322a0a62015-11-17 15:19:46 -0800117func init() {
118 // We run gcc/clang with PWD=/proc/self/cwd to remove $TOP from the
119 // debug output. That way two builds in two different directories will
120 // create the same output.
121 if runtime.GOOS != "darwin" {
122 pctx.StaticVariable("relPwd", "PWD=/proc/self/cwd")
123 } else {
124 // Darwin doesn't have /proc
125 pctx.StaticVariable("relPwd", "")
126 }
127}
128
Colin Cross3f40fa42015-01-30 17:27:36 -0800129type builderFlags struct {
130 globalFlags string
131 asFlags string
132 cFlags string
133 conlyFlags string
134 cppFlags string
135 ldFlags string
Colin Cross581c1892015-04-07 16:50:10 -0700136 yaccFlags string
Colin Cross3f40fa42015-01-30 17:27:36 -0800137 nocrt bool
Colin Cross97ba0732015-03-23 17:50:24 -0700138 toolchain Toolchain
Colin Cross3f40fa42015-01-30 17:27:36 -0800139 clang bool
140}
141
142// Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700143func TransformSourceToObj(ctx common.AndroidModuleContext, subdir string, srcFiles common.Paths,
144 flags builderFlags, deps common.Paths) (objFiles common.Paths) {
Colin Cross581c1892015-04-07 16:50:10 -0700145
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700146 objFiles = make(common.Paths, len(srcFiles))
Colin Cross3f40fa42015-01-30 17:27:36 -0800147
148 cflags := flags.globalFlags + " " + flags.cFlags + " " + flags.conlyFlags
149 cppflags := flags.globalFlags + " " + flags.cFlags + " " + flags.cppFlags
150 asflags := flags.globalFlags + " " + flags.asFlags
151
Dan Willemsenbe03f342016-03-03 17:21:04 -0800152 if flags.clang {
153 cflags += " ${noOverrideClangGlobalCflags}"
154 cppflags += " ${noOverrideClangGlobalCflags}"
155 } else {
156 cflags += " ${noOverrideGlobalCflags}"
157 cppflags += " ${noOverrideGlobalCflags}"
158 }
159
Colin Cross3f40fa42015-01-30 17:27:36 -0800160 for i, srcFile := range srcFiles {
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700161 objFile := common.ObjPathWithExt(ctx, srcFile, subdir, "o")
Colin Cross3f40fa42015-01-30 17:27:36 -0800162
163 objFiles[i] = objFile
164
165 var moduleCflags string
166 var ccCmd string
167
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700168 switch srcFile.Ext() {
Colin Cross3f40fa42015-01-30 17:27:36 -0800169 case ".S", ".s":
170 ccCmd = "gcc"
171 moduleCflags = asflags
172 case ".c":
173 ccCmd = "gcc"
174 moduleCflags = cflags
175 case ".cpp", ".cc":
176 ccCmd = "g++"
177 moduleCflags = cppflags
178 default:
179 ctx.ModuleErrorf("File %s has unknown extension", srcFile)
180 continue
181 }
182
183 if flags.clang {
184 switch ccCmd {
185 case "gcc":
186 ccCmd = "clang"
187 case "g++":
188 ccCmd = "clang++"
189 default:
190 panic("unrecoginzied ccCmd")
191 }
192
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700193 ccCmd = "${clangPath}/" + ccCmd
Colin Cross3f40fa42015-01-30 17:27:36 -0800194 } else {
195 ccCmd = gccCmd(flags.toolchain, ccCmd)
196 }
197
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700198 ctx.ModuleBuild(pctx, common.ModuleBuildParams{
Colin Cross3f40fa42015-01-30 17:27:36 -0800199 Rule: cc,
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700200 Output: objFile,
201 Input: srcFile,
Dan Willemsenb40aab62016-04-20 14:21:14 -0700202 OrderOnly: deps,
Colin Cross3f40fa42015-01-30 17:27:36 -0800203 Args: map[string]string{
Colin Cross28344522015-04-22 13:07:53 -0700204 "cFlags": moduleCflags,
205 "ccCmd": ccCmd,
Colin Cross3f40fa42015-01-30 17:27:36 -0800206 },
207 })
208 }
209
210 return objFiles
211}
212
213// Generate a rule for compiling multiple .o files to a static library (.a)
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700214func TransformObjToStaticLib(ctx common.AndroidModuleContext, objFiles common.Paths,
215 flags builderFlags, outputFile common.ModuleOutPath) {
Colin Cross3f40fa42015-01-30 17:27:36 -0800216
217 arCmd := gccCmd(flags.toolchain, "ar")
218 arFlags := "crsPD"
219
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700220 ctx.ModuleBuild(pctx, common.ModuleBuildParams{
221 Rule: ar,
222 Output: outputFile,
223 Inputs: objFiles,
Colin Cross3f40fa42015-01-30 17:27:36 -0800224 Args: map[string]string{
225 "arFlags": arFlags,
226 "arCmd": arCmd,
227 },
228 })
229}
230
Colin Cross0af4b842015-04-30 16:36:18 -0700231// Generate a rule for compiling multiple .o files to a static library (.a) on
232// darwin. The darwin ar tool doesn't support @file for list files, and has a
233// very small command line length limit, so we have to split the ar into multiple
234// steps, each appending to the previous one.
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700235func TransformDarwinObjToStaticLib(ctx common.AndroidModuleContext, objFiles common.Paths,
236 flags builderFlags, outputPath common.ModuleOutPath) {
Colin Cross0af4b842015-04-30 16:36:18 -0700237
Dan Willemsencf7c71b2015-12-14 20:02:44 -0800238 arCmd := "${macArPath}"
Colin Cross0af4b842015-04-30 16:36:18 -0700239 arFlags := "cqs"
240
241 // ARG_MAX on darwin is 262144, use half that to be safe
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700242 objFilesLists, err := splitListForSize(objFiles.Strings(), 131072)
Colin Cross0af4b842015-04-30 16:36:18 -0700243 if err != nil {
244 ctx.ModuleErrorf("%s", err.Error())
245 }
246
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700247 outputFile := outputPath.String()
248
Colin Cross0af4b842015-04-30 16:36:18 -0700249 var in, out string
250 for i, l := range objFilesLists {
251 in = out
252 out = outputFile
253 if i != len(objFilesLists)-1 {
254 out += "." + strconv.Itoa(i)
255 }
256
257 if in == "" {
258 ctx.Build(pctx, blueprint.BuildParams{
259 Rule: darwinAr,
260 Outputs: []string{out},
261 Inputs: l,
262 Args: map[string]string{
263 "arFlags": arFlags,
264 "arCmd": arCmd,
265 },
266 })
267 } else {
268 ctx.Build(pctx, blueprint.BuildParams{
269 Rule: darwinAppendAr,
270 Outputs: []string{out},
271 Inputs: l,
272 Implicits: []string{in},
273 Args: map[string]string{
274 "arFlags": arFlags,
275 "arCmd": arCmd,
276 "inAr": in,
277 },
278 })
279 }
280 }
281}
282
Colin Cross3f40fa42015-01-30 17:27:36 -0800283// Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries,
284// and shared libraires, to a shared library (.so) or dynamic executable
285func TransformObjToDynamicBinary(ctx common.AndroidModuleContext,
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700286 objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps common.Paths,
287 crtBegin, crtEnd common.OptionalPath, groupLate bool, flags builderFlags, outputFile common.WritablePath) {
Colin Cross3f40fa42015-01-30 17:27:36 -0800288
289 var ldCmd string
290 if flags.clang {
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700291 ldCmd = "${clangPath}/clang++"
Colin Cross3f40fa42015-01-30 17:27:36 -0800292 } else {
293 ldCmd = gccCmd(flags.toolchain, "g++")
294 }
295
296 var ldDirs []string
297 var libFlagsList []string
298
299 if len(wholeStaticLibs) > 0 {
Dan Willemsen490fd492015-11-24 17:53:15 -0800300 if ctx.Host() && ctx.Darwin() {
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700301 libFlagsList = append(libFlagsList, common.JoinWithPrefix(wholeStaticLibs.Strings(), "-force_load "))
Colin Cross0af4b842015-04-30 16:36:18 -0700302 } else {
303 libFlagsList = append(libFlagsList, "-Wl,--whole-archive ")
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700304 libFlagsList = append(libFlagsList, wholeStaticLibs.Strings()...)
Colin Cross0af4b842015-04-30 16:36:18 -0700305 libFlagsList = append(libFlagsList, "-Wl,--no-whole-archive ")
306 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800307 }
308
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700309 libFlagsList = append(libFlagsList, staticLibs.Strings()...)
Colin Cross3f40fa42015-01-30 17:27:36 -0800310
Dan Willemsenedc385f2015-07-08 13:02:23 -0700311 if groupLate && len(lateStaticLibs) > 0 {
312 libFlagsList = append(libFlagsList, "-Wl,--start-group")
313 }
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700314 libFlagsList = append(libFlagsList, lateStaticLibs.Strings()...)
Dan Willemsenedc385f2015-07-08 13:02:23 -0700315 if groupLate && len(lateStaticLibs) > 0 {
316 libFlagsList = append(libFlagsList, "-Wl,--end-group")
317 }
318
Colin Cross3f40fa42015-01-30 17:27:36 -0800319 for _, lib := range sharedLibs {
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700320 dir, file := filepath.Split(lib.String())
Colin Cross3f40fa42015-01-30 17:27:36 -0800321 if !strings.HasPrefix(file, "lib") {
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700322 panic("shared library " + lib.String() + " does not start with lib")
Colin Cross3f40fa42015-01-30 17:27:36 -0800323 }
Dan Willemsen490fd492015-11-24 17:53:15 -0800324 if !strings.HasSuffix(file, flags.toolchain.ShlibSuffix()) {
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700325 panic("shared library " + lib.String() + " does not end with " + flags.toolchain.ShlibSuffix())
Colin Cross3f40fa42015-01-30 17:27:36 -0800326 }
327 libFlagsList = append(libFlagsList,
Dan Willemsen490fd492015-11-24 17:53:15 -0800328 "-l"+strings.TrimSuffix(strings.TrimPrefix(file, "lib"), flags.toolchain.ShlibSuffix()))
Colin Cross3f40fa42015-01-30 17:27:36 -0800329 ldDirs = append(ldDirs, dir)
330 }
331
Colin Cross3f40fa42015-01-30 17:27:36 -0800332 deps = append(deps, sharedLibs...)
333 deps = append(deps, staticLibs...)
Colin Cross3075ad02015-03-17 10:47:08 -0700334 deps = append(deps, lateStaticLibs...)
Colin Cross3f40fa42015-01-30 17:27:36 -0800335 deps = append(deps, wholeStaticLibs...)
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700336 if crtBegin.Valid() {
337 deps = append(deps, crtBegin.Path(), crtEnd.Path())
Colin Cross3f40fa42015-01-30 17:27:36 -0800338 }
339
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700340 ctx.ModuleBuild(pctx, common.ModuleBuildParams{
Colin Cross3f40fa42015-01-30 17:27:36 -0800341 Rule: ld,
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700342 Output: outputFile,
Colin Cross3f40fa42015-01-30 17:27:36 -0800343 Inputs: objFiles,
344 Implicits: deps,
345 Args: map[string]string{
346 "ldCmd": ldCmd,
347 "ldDirFlags": ldDirsToFlags(ldDirs),
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700348 "crtBegin": crtBegin.String(),
Colin Cross3f40fa42015-01-30 17:27:36 -0800349 "libFlags": strings.Join(libFlagsList, " "),
350 "ldFlags": flags.ldFlags,
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700351 "crtEnd": crtEnd.String(),
Colin Cross3f40fa42015-01-30 17:27:36 -0800352 },
353 })
354}
355
356// Generate a rule for compiling multiple .o files to a .o using ld partial linking
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700357func TransformObjsToObj(ctx common.AndroidModuleContext, objFiles common.Paths,
358 flags builderFlags, outputFile common.WritablePath) {
Colin Cross3f40fa42015-01-30 17:27:36 -0800359
Colin Cross41280a42015-11-23 14:01:42 -0800360 var ldCmd string
361 if flags.clang {
362 ldCmd = "${clangPath}clang++"
363 } else {
364 ldCmd = gccCmd(flags.toolchain, "g++")
365 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800366
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700367 ctx.ModuleBuild(pctx, common.ModuleBuildParams{
368 Rule: partialLd,
369 Output: outputFile,
370 Inputs: objFiles,
Colin Cross3f40fa42015-01-30 17:27:36 -0800371 Args: map[string]string{
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700372 "ldCmd": ldCmd,
Colin Cross41280a42015-11-23 14:01:42 -0800373 "ldFlags": flags.ldFlags,
Colin Cross3f40fa42015-01-30 17:27:36 -0800374 },
375 })
376}
377
Colin Crossbfae8852015-03-26 14:44:11 -0700378// Generate a rule for runing objcopy --prefix-symbols on a binary
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700379func TransformBinaryPrefixSymbols(ctx common.AndroidModuleContext, prefix string, inputFile common.Path,
380 flags builderFlags, outputFile common.WritablePath) {
Colin Crossbfae8852015-03-26 14:44:11 -0700381
382 objcopyCmd := gccCmd(flags.toolchain, "objcopy")
383
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700384 ctx.ModuleBuild(pctx, common.ModuleBuildParams{
385 Rule: prefixSymbols,
386 Output: outputFile,
387 Input: inputFile,
Colin Crossbfae8852015-03-26 14:44:11 -0700388 Args: map[string]string{
389 "objcopyCmd": objcopyCmd,
390 "prefix": prefix,
391 },
392 })
393}
394
Colin Cross3f40fa42015-01-30 17:27:36 -0800395func CopyGccLib(ctx common.AndroidModuleContext, libName string,
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700396 flags builderFlags, outputFile common.WritablePath) {
Colin Cross3f40fa42015-01-30 17:27:36 -0800397
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700398 ctx.ModuleBuild(pctx, common.ModuleBuildParams{
399 Rule: copyGccLib,
400 Output: outputFile,
Colin Cross3f40fa42015-01-30 17:27:36 -0800401 Args: map[string]string{
402 "ccCmd": gccCmd(flags.toolchain, "gcc"),
403 "cFlags": flags.globalFlags,
404 "libName": libName,
405 },
406 })
407}
408
Colin Cross97ba0732015-03-23 17:50:24 -0700409func gccCmd(toolchain Toolchain, cmd string) string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800410 return filepath.Join(toolchain.GccRoot(), "bin", toolchain.GccTriple()+"-"+cmd)
411}
Colin Cross0af4b842015-04-30 16:36:18 -0700412
413func splitListForSize(list []string, limit int) (lists [][]string, err error) {
414 var i int
415
416 start := 0
417 bytes := 0
418 for i = range list {
419 l := len(list[i])
420 if l > limit {
421 return nil, fmt.Errorf("list element greater than size limit (%d)", limit)
422 }
423 if bytes+l > limit {
424 lists = append(lists, list[start:i])
425 start = i
426 bytes = 0
427 }
428 bytes += l + 1 // count a space between each list element
429 }
430
431 lists = append(lists, list[start:])
432
433 totalLen := 0
434 for _, l := range lists {
435 totalLen += len(l)
436 }
437 if totalLen != len(list) {
438 panic(fmt.Errorf("Failed breaking up list, %d != %d", len(list), totalLen))
439 }
440 return lists, nil
441}