xref: /aosp_15_r20/build/soong/cc/cc_preprocess_no_configuration.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1// Copyright 2024 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
17import (
18	"android/soong/android"
19	"slices"
20	"strings"
21)
22
23func init() {
24	RegisterCCPreprocessNoConfiguration(android.InitRegistrationContext)
25}
26
27func RegisterCCPreprocessNoConfiguration(ctx android.RegistrationContext) {
28	ctx.RegisterModuleType("cc_preprocess_no_configuration", ccPreprocessNoConfigurationFactory)
29}
30
31// cc_preprocess_no_configuration modules run the c preprocessor on a single input source file.
32// They also have "no configuration", meaning they don't have an arch or os associated with them,
33// they should be thought of as pure textual transformations of the input file. In some cases this
34// is good, in others you might want to do different transformations depending on what arch the
35// result will be compiled in, in which case you can use cc_object instead of this module.
36func ccPreprocessNoConfigurationFactory() android.Module {
37	m := &ccPreprocessNoConfiguration{}
38	m.AddProperties(&m.properties)
39	android.InitAndroidModule(m)
40	return m
41}
42
43type ccPreprocessNoConfigurationProps struct {
44	// Called Srcs for consistency with the other cc module types, but only accepts 1 input source
45	// file.
46	Srcs []string `android:"path"`
47	// The flags to pass to the c compiler. Must include -E in order to enable preprocessing-only
48	// mode.
49	Cflags []string `android:"path"`
50}
51
52type ccPreprocessNoConfiguration struct {
53	android.ModuleBase
54	properties ccPreprocessNoConfigurationProps
55}
56
57func (m *ccPreprocessNoConfiguration) GenerateAndroidBuildActions(ctx android.ModuleContext) {
58	srcs := android.PathsForModuleSrc(ctx, m.properties.Srcs)
59	if len(srcs) != 1 {
60		ctx.PropertyErrorf("Srcs", "cc_preprocess_no_configuration only accepts 1 source file, found: %v", srcs.Strings())
61		return
62	}
63	src := srcs[0]
64
65	hasE := false
66	for _, cflag := range m.properties.Cflags {
67		if cflag == "-E" {
68			hasE = true
69			break
70		} else if cflag == "-P" || strings.HasPrefix(cflag, "-D") {
71			// do nothing, allow it
72		} else {
73			ctx.PropertyErrorf("Cflags", "cc_preprocess_no_configuration only allows -D and -P flags, found: %q", cflag)
74			return
75		}
76	}
77	if !hasE {
78		ctx.PropertyErrorf("Cflags", "cc_preprocess_no_configuration must have a -E cflag")
79		return
80	}
81
82	cflags := slices.Clone(m.properties.Cflags)
83
84	// Match behavior of other cc modules:
85	// https://cs.android.com/android/platform/superproject/main/+/main:build/soong/cc/compiler.go;l=422;drc=7297f05ee8cda422ccb32c4af4d9d715d6bac10e
86	cflags = append(cflags, "-I"+ctx.ModuleDir())
87
88	var ccCmd string
89	switch src.Ext() {
90	case ".c":
91		ccCmd = "clang"
92	case ".cpp", ".cc", ".cxx", ".mm":
93		ccCmd = "clang++"
94	default:
95		ctx.PropertyErrorf("srcs", "File %s has unknown extension. Supported extensions: .c, .cpp, .cc, .cxx, .mm", src)
96		return
97	}
98
99	ccCmd = "${config.ClangBin}/" + ccCmd
100
101	outFile := android.PathForModuleOut(ctx, src.Base())
102
103	ctx.Build(pctx, android.BuildParams{
104		Rule:        cc,
105		Description: ccCmd + " " + src.Rel(),
106		Output:      outFile,
107		Input:       src,
108		Args: map[string]string{
109			"cFlags": strings.Join(cflags, " "),
110			"ccCmd":  ccCmd,
111		},
112	})
113
114	ctx.SetOutputFiles([]android.Path{outFile}, "")
115}
116