Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f4465da1 authored by Colin Cross's avatar Colin Cross Committed by Gerrit Code Review
Browse files

Merge "genrule: add $(location) for inputs and outputs"

parents 08914b9c 08f15ab4
Loading
Loading
Loading
Loading
+70 −31
Original line number Diff line number Diff line
@@ -52,10 +52,9 @@ type HostToolProvider interface {

type hostToolDependencyTag struct {
	blueprint.BaseDependencyTag
	label string
}

var hostToolDepTag hostToolDependencyTag

type generatorProperties struct {
	// The command to run on one or more input files. Cmd supports substitution of a few variables
	// (the actual substitution is implemented in GenerateAndroidBuildActions below)
@@ -63,7 +62,7 @@ type generatorProperties struct {
	// Available variables for substitution:
	//
	//  $(location): the path to the first entry in tools or tool_files
	//  $(location <label>): the path to the tool or tool_file with name <label>
	//  $(location <label>): the path to the tool, tool_file, input or output with name <label>
	//  $(in): one or more input files
	//  $(out): a single output file
	//  $(depfile): a file to which dependencies will be written, if the depfile property is set to true
@@ -141,10 +140,14 @@ func (g *Module) DepsMutator(ctx android.BottomUpMutatorContext) {
	android.ExtractSourcesDeps(ctx, g.properties.Srcs)
	android.ExtractSourcesDeps(ctx, g.properties.Tool_files)
	if g, ok := ctx.Module().(*Module); ok {
		if len(g.properties.Tools) > 0 {
		for _, tool := range g.properties.Tools {
			tag := hostToolDependencyTag{label: tool}
			if m := android.SrcIsModule(tool); m != "" {
				tool = m
			}
			ctx.AddFarVariationDependencies([]blueprint.Variation{
				{Mutator: "arch", Variation: ctx.Config().BuildOsVariant},
			}, hostToolDepTag, g.properties.Tools...)
			}, tag, tool)
		}
	}
}
@@ -159,12 +162,25 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
		g.exportedIncludeDirs = append(g.exportedIncludeDirs, android.PathForModuleGen(ctx, ""))
	}

	tools := map[string]android.Path{}
	locationLabels := map[string][]string{}
	firstLabel := ""

	addLocationLabel := func(label string, paths []string) {
		if firstLabel == "" {
			firstLabel = label
		}
		if _, exists := locationLabels[label]; !exists {
			locationLabels[label] = paths
		} else {
			ctx.ModuleErrorf("multiple labels for %q, %q and %q",
				label, strings.Join(locationLabels[label], " "), strings.Join(paths, " "))
		}
	}

	if len(g.properties.Tools) > 0 {
		ctx.VisitDirectDepsBlueprint(func(module blueprint.Module) {
			switch ctx.OtherModuleDependencyTag(module) {
			case hostToolDepTag:
			switch tag := ctx.OtherModuleDependencyTag(module).(type) {
			case hostToolDependencyTag:
				tool := ctx.OtherModuleName(module)
				var path android.OptionalPath

@@ -192,11 +208,7 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {

				if path.Valid() {
					g.deps = append(g.deps, path.Path())
					if _, exists := tools[tool]; !exists {
						tools[tool] = path.Path()
					} else {
						ctx.ModuleErrorf("multiple tools for %q, %q and %q", tool, tools[tool], path.Path().String())
					}
					addLocationLabel(tag.label, []string{path.Path().String()})
				} else {
					ctx.ModuleErrorf("host tool %q missing output file", tool)
				}
@@ -208,21 +220,27 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
		return
	}

	toolFiles := ctx.ExpandSources(g.properties.Tool_files, nil)
	for _, tool := range toolFiles {
		g.deps = append(g.deps, tool)
		if _, exists := tools[tool.Rel()]; !exists {
			tools[tool.Rel()] = tool
		} else {
			ctx.ModuleErrorf("multiple tools for %q, %q and %q", tool, tools[tool.Rel()], tool.Rel())
		}
	for _, toolFile := range g.properties.Tool_files {
		paths := ctx.ExpandSources([]string{toolFile}, nil)
		g.deps = append(g.deps, paths...)
		addLocationLabel(toolFile, paths.Strings())
	}

	referencedDepfile := false
	var srcFiles android.Paths
	for _, in := range g.properties.Srcs {
		paths := ctx.ExpandSources([]string{in}, nil)
		srcFiles = append(srcFiles, paths...)
		addLocationLabel(in, paths.Strings())
	}

	srcFiles := ctx.ExpandSources(g.properties.Srcs, nil)
	task := g.taskGenerator(ctx, String(g.properties.Cmd), srcFiles)

	for _, out := range task.out {
		addLocationLabel(out.Rel(), []string{filepath.Join("__SBOX_OUT_DIR__", out.Rel())})
	}

	referencedDepfile := false

	rawCommand, err := android.Expand(task.cmd, func(name string) (string, error) {
		// report the error directly without returning an error to android.Expand to catch multiple errors in a
		// single run
@@ -233,13 +251,17 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {

		switch name {
		case "location":
			if len(g.properties.Tools) == 0 && len(toolFiles) == 0 {
			if len(g.properties.Tools) == 0 && len(g.properties.Tool_files) == 0 {
				return reportError("at least one `tools` or `tool_files` is required if $(location) is used")
			} else if len(g.properties.Tools) > 0 {
				return tools[g.properties.Tools[0]].String(), nil
			} else {
				return tools[toolFiles[0].Rel()].String(), nil
			}
			paths := locationLabels[firstLabel]
			if len(paths) == 0 {
				return reportError("default label %q has no files", firstLabel)
			} else if len(paths) > 1 {
				return reportError("default label %q has multiple files, use $(locations %s) to reference it",
					firstLabel, firstLabel)
			}
			return locationLabels[firstLabel][0], nil
		case "in":
			return "${in}", nil
		case "out":
@@ -255,14 +277,31 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
		default:
			if strings.HasPrefix(name, "location ") {
				label := strings.TrimSpace(strings.TrimPrefix(name, "location "))
				if tool, ok := tools[label]; ok {
					return tool.String(), nil
				if paths, ok := locationLabels[label]; ok {
					if len(paths) == 0 {
						return reportError("label %q has no files", label)
					} else if len(paths) > 1 {
						return reportError("label %q has multiple files, use $(locations %s) to reference it",
							label, label)
					}
					return paths[0], nil
				} else {
					return reportError("unknown location label %q", label)
				}
			} else if strings.HasPrefix(name, "locations ") {
				label := strings.TrimSpace(strings.TrimPrefix(name, "locations "))
				if paths, ok := locationLabels[label]; ok {
					if len(paths) == 0 {
						return reportError("label %q has no files", label)
					}
					return strings.Join(paths, " "), nil
				} else {
					return reportError("unknown locations label %q", label)
				}
			} else {
				return reportError("unknown variable '$(%s)'", name)
			}
		}
	})

	if err != nil {
+117 −2
Original line number Diff line number Diff line
@@ -132,6 +132,15 @@ func TestGenruleCmd(t *testing.T) {
			`,
			expect: "out/tool > __SBOX_OUT_FILES__",
		},
		{
			name: "empty location tool2",
			prop: `
				tools: [":tool"],
				out: ["out"],
				cmd: "$(location) > $(out)",
			`,
			expect: "out/tool > __SBOX_OUT_FILES__",
		},
		{
			name: "empty location tool file",
			prop: `
@@ -169,6 +178,15 @@ func TestGenruleCmd(t *testing.T) {
			`,
			expect: "out/tool > __SBOX_OUT_FILES__",
		},
		{
			name: "tool2",
			prop: `
				tools: [":tool"],
				out: ["out"],
				cmd: "$(location :tool) > $(out)",
			`,
			expect: "out/tool > __SBOX_OUT_FILES__",
		},
		{
			name: "tool file",
			prop: `
@@ -183,7 +201,7 @@ func TestGenruleCmd(t *testing.T) {
			prop: `
				tool_files: [":1tool_file"],
				out: ["out"],
				cmd: "$(location tool_file1) > $(out)",
				cmd: "$(location :1tool_file) > $(out)",
			`,
			expect: "tool_file1 > __SBOX_OUT_FILES__",
		},
@@ -192,7 +210,7 @@ func TestGenruleCmd(t *testing.T) {
			prop: `
				tool_files: [":tool_files"],
				out: ["out"],
				cmd: "$(location tool_file1) $(location tool_file2) > $(out)",
				cmd: "$(locations :tool_files) > $(out)",
			`,
			expect: "tool_file1 tool_file2 > __SBOX_OUT_FILES__",
		},
@@ -232,6 +250,42 @@ func TestGenruleCmd(t *testing.T) {
			`,
			expect: "cat ${in} > __SBOX_OUT_FILES__",
		},
		{
			name: "location in1",
			prop: `
				srcs: ["in1"],
				out: ["out"],
				cmd: "cat $(location in1) > $(out)",
			`,
			expect: "cat in1 > __SBOX_OUT_FILES__",
		},
		{
			name: "location in1 fg",
			prop: `
				srcs: [":1in"],
				out: ["out"],
				cmd: "cat $(location :1in) > $(out)",
			`,
			expect: "cat in1 > __SBOX_OUT_FILES__",
		},
		{
			name: "location ins",
			prop: `
				srcs: ["in1", "in2"],
				out: ["out"],
				cmd: "cat $(location in1) > $(out)",
			`,
			expect: "cat in1 > __SBOX_OUT_FILES__",
		},
		{
			name: "location ins fg",
			prop: `
				srcs: [":ins"],
				out: ["out"],
				cmd: "cat $(locations :ins) > $(out)",
			`,
			expect: "cat in1 in2 > __SBOX_OUT_FILES__",
		},
		{
			name: "outs",
			prop: `
@@ -240,6 +294,14 @@ func TestGenruleCmd(t *testing.T) {
			`,
			expect: "echo foo > __SBOX_OUT_FILES__",
		},
		{
			name: "location out",
			prop: `
				out: ["out", "out2"],
				cmd: "echo foo > $(location out2)",
			`,
			expect: "echo foo > __SBOX_OUT_DIR__/out2",
		},
		{
			name: "depfile",
			prop: `
@@ -266,6 +328,24 @@ func TestGenruleCmd(t *testing.T) {
			`,
			err: "at least one `tools` or `tool_files` is required if $(location) is used",
		},
		{
			name: "error empty location no files",
			prop: `
				tool_files: [":empty"],
				out: ["out"],
				cmd: "$(location) > $(out)",
			`,
			err: `default label ":empty" has no files`,
		},
		{
			name: "error empty location multiple files",
			prop: `
				tool_files: [":tool_files"],
				out: ["out"],
				cmd: "$(location) > $(out)",
			`,
			err: `default label ":tool_files" has multiple files`,
		},
		{
			name: "error location",
			prop: `
@@ -274,6 +354,41 @@ func TestGenruleCmd(t *testing.T) {
			`,
			err: `unknown location label "missing"`,
		},
		{
			name: "error locations",
			prop: `
					out: ["out"],
					cmd: "echo foo > $(locations missing)",
			`,
			err: `unknown locations label "missing"`,
		},
		{
			name: "error location no files",
			prop: `
					out: ["out"],
					srcs: [":empty"],
					cmd: "echo $(location :empty) > $(out)",
			`,
			err: `label ":empty" has no files`,
		},
		{
			name: "error locations no files",
			prop: `
					out: ["out"],
					srcs: [":empty"],
					cmd: "echo $(locations :empty) > $(out)",
			`,
			err: `label ":empty" has no files`,
		},
		{
			name: "error location multiple files",
			prop: `
					out: ["out"],
					srcs: [":ins"],
					cmd: "echo $(location :ins) > $(out)",
			`,
			err: `label ":ins" has multiple files`,
		},
		{
			name: "error variable",
			prop: `