Add cc_preprocess_no_configuration modules

This is intended to replace the cc_object modules in external/cronet,
which are only used for the c preprocessor. However, they have java
modules that consume their result, so they have a dependency from the
common arch to the first arch. This only worked because of the 1-variant
fallback, which we're trying to remove, so add an archless module that
runs clang that they can use.

Bug: 372091092
Test: go test
Change-Id: I4fff3eabb7e31d2888b6e70c39310113acf5590e
diff --git a/cc/cc_preprocess_no_configuration.go b/cc/cc_preprocess_no_configuration.go
new file mode 100644
index 0000000..3d1d0a5
--- /dev/null
+++ b/cc/cc_preprocess_no_configuration.go
@@ -0,0 +1,108 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+	"android/soong/android"
+	"strings"
+)
+
+func init() {
+	RegisterCCPreprocessNoConfiguration(android.InitRegistrationContext)
+}
+
+func RegisterCCPreprocessNoConfiguration(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("cc_preprocess_no_configuration", ccPreprocessNoConfigurationFactory)
+}
+
+// cc_preprocess_no_configuration modules run the c preprocessor on a single input source file.
+// They also have "no configuration", meaning they don't have an arch or os associated with them,
+// they should be thought of as pure textual transformations of the input file. In some cases this
+// is good, in others you might want to do different transformations depending on what arch the
+// result will be compiled in, in which case you can use cc_object instead of this module.
+func ccPreprocessNoConfigurationFactory() android.Module {
+	m := &ccPreprocessNoConfiguration{}
+	m.AddProperties(&m.properties)
+	android.InitAndroidModule(m)
+	return m
+}
+
+type ccPreprocessNoConfigurationProps struct {
+	// Called Srcs for consistency with the other cc module types, but only accepts 1 input source
+	// file.
+	Srcs []string `android:"path"`
+	// The flags to pass to the c compiler. Must include -E in order to enable preprocessing-only
+	// mode.
+	Cflags []string `android:"path"`
+}
+
+type ccPreprocessNoConfiguration struct {
+	android.ModuleBase
+	properties ccPreprocessNoConfigurationProps
+}
+
+func (m *ccPreprocessNoConfiguration) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	srcs := android.PathsForModuleSrc(ctx, m.properties.Srcs)
+	if len(srcs) != 1 {
+		ctx.PropertyErrorf("Srcs", "cc_preprocess_no_configuration only accepts 1 source file, found: %v", srcs.Strings())
+		return
+	}
+	src := srcs[0]
+
+	hasE := false
+	for _, cflag := range m.properties.Cflags {
+		if cflag == "-E" {
+			hasE = true
+			break
+		} else if cflag == "-P" || strings.HasPrefix(cflag, "-D") {
+			// do nothing, allow it
+		} else {
+			ctx.PropertyErrorf("Cflags", "cc_preprocess_no_configuration only allows -D and -P flags, found: %q", cflag)
+			return
+		}
+	}
+	if !hasE {
+		ctx.PropertyErrorf("Cflags", "cc_preprocess_no_configuration must have a -E cflag")
+		return
+	}
+
+	var ccCmd string
+	switch src.Ext() {
+	case ".c":
+		ccCmd = "clang"
+	case ".cpp", ".cc", ".cxx", ".mm":
+		ccCmd = "clang++"
+	default:
+		ctx.PropertyErrorf("srcs", "File %s has unknown extension. Supported extensions: .c, .cpp, .cc, .cxx, .mm", src)
+		return
+	}
+
+	ccCmd = "${config.ClangBin}/" + ccCmd
+
+	outFile := android.PathForModuleOut(ctx, src.Base())
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        cc,
+		Description: ccCmd + " " + src.Rel(),
+		Output:      outFile,
+		Input:       src,
+		Args: map[string]string{
+			"cFlags": strings.Join(m.properties.Cflags, " "),
+			"ccCmd":  ccCmd,
+		},
+	})
+
+	ctx.SetOutputFiles([]android.Path{outFile}, "")
+}