xref: /aosp_15_r20/build/soong/etc/install_symlink.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2023 Google Inc. All rights reserved.
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Workerpackage etc
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Workerimport (
18*333d2b36SAndroid Build Coastguard Worker	"android/soong/android"
19*333d2b36SAndroid Build Coastguard Worker	"path/filepath"
20*333d2b36SAndroid Build Coastguard Worker	"strings"
21*333d2b36SAndroid Build Coastguard Worker)
22*333d2b36SAndroid Build Coastguard Worker
23*333d2b36SAndroid Build Coastguard Workerfunc init() {
24*333d2b36SAndroid Build Coastguard Worker	RegisterInstallSymlinkBuildComponents(android.InitRegistrationContext)
25*333d2b36SAndroid Build Coastguard Worker}
26*333d2b36SAndroid Build Coastguard Worker
27*333d2b36SAndroid Build Coastguard Workerfunc RegisterInstallSymlinkBuildComponents(ctx android.RegistrationContext) {
28*333d2b36SAndroid Build Coastguard Worker	ctx.RegisterModuleType("install_symlink", InstallSymlinkFactory)
29*333d2b36SAndroid Build Coastguard Worker	ctx.RegisterModuleType("install_symlink_host", InstallSymlinkHostFactory)
30*333d2b36SAndroid Build Coastguard Worker}
31*333d2b36SAndroid Build Coastguard Worker
32*333d2b36SAndroid Build Coastguard Worker// install_symlink can be used to install an symlink with an arbitrary target to an arbitrary path
33*333d2b36SAndroid Build Coastguard Worker// on the device.
34*333d2b36SAndroid Build Coastguard Workerfunc InstallSymlinkFactory() android.Module {
35*333d2b36SAndroid Build Coastguard Worker	module := &InstallSymlink{}
36*333d2b36SAndroid Build Coastguard Worker	module.AddProperties(&module.properties)
37*333d2b36SAndroid Build Coastguard Worker	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
38*333d2b36SAndroid Build Coastguard Worker	return module
39*333d2b36SAndroid Build Coastguard Worker}
40*333d2b36SAndroid Build Coastguard Worker
41*333d2b36SAndroid Build Coastguard Worker// install_symlink can be used to install an symlink to an arbitrary path on the host.
42*333d2b36SAndroid Build Coastguard Workerfunc InstallSymlinkHostFactory() android.Module {
43*333d2b36SAndroid Build Coastguard Worker	module := &InstallSymlink{}
44*333d2b36SAndroid Build Coastguard Worker	module.AddProperties(&module.properties)
45*333d2b36SAndroid Build Coastguard Worker	android.InitAndroidMultiTargetsArchModule(module, android.HostSupported, android.MultilibCommon)
46*333d2b36SAndroid Build Coastguard Worker	return module
47*333d2b36SAndroid Build Coastguard Worker}
48*333d2b36SAndroid Build Coastguard Worker
49*333d2b36SAndroid Build Coastguard Workertype InstallSymlinkProperties struct {
50*333d2b36SAndroid Build Coastguard Worker	// Where to install this symlink, relative to the partition it's installed on.
51*333d2b36SAndroid Build Coastguard Worker	// Which partition it's installed on can be controlled by the vendor, system_ext, ramdisk, etc.
52*333d2b36SAndroid Build Coastguard Worker	// properties.
53*333d2b36SAndroid Build Coastguard Worker	Installed_location string
54*333d2b36SAndroid Build Coastguard Worker	// The target of the symlink, aka where the symlink points.
55*333d2b36SAndroid Build Coastguard Worker	Symlink_target string
56*333d2b36SAndroid Build Coastguard Worker}
57*333d2b36SAndroid Build Coastguard Worker
58*333d2b36SAndroid Build Coastguard Workertype InstallSymlink struct {
59*333d2b36SAndroid Build Coastguard Worker	android.ModuleBase
60*333d2b36SAndroid Build Coastguard Worker	properties InstallSymlinkProperties
61*333d2b36SAndroid Build Coastguard Worker
62*333d2b36SAndroid Build Coastguard Worker	output        android.Path
63*333d2b36SAndroid Build Coastguard Worker	installedPath android.InstallPath
64*333d2b36SAndroid Build Coastguard Worker}
65*333d2b36SAndroid Build Coastguard Worker
66*333d2b36SAndroid Build Coastguard Workerfunc (m *InstallSymlink) GenerateAndroidBuildActions(ctx android.ModuleContext) {
67*333d2b36SAndroid Build Coastguard Worker	if filepath.Clean(m.properties.Symlink_target) != m.properties.Symlink_target {
68*333d2b36SAndroid Build Coastguard Worker		ctx.PropertyErrorf("symlink_target", "Should be a clean filepath")
69*333d2b36SAndroid Build Coastguard Worker		return
70*333d2b36SAndroid Build Coastguard Worker	}
71*333d2b36SAndroid Build Coastguard Worker	if filepath.Clean(m.properties.Installed_location) != m.properties.Installed_location {
72*333d2b36SAndroid Build Coastguard Worker		ctx.PropertyErrorf("installed_location", "Should be a clean filepath")
73*333d2b36SAndroid Build Coastguard Worker		return
74*333d2b36SAndroid Build Coastguard Worker	}
75*333d2b36SAndroid Build Coastguard Worker	if strings.HasPrefix(m.properties.Installed_location, "../") || strings.HasPrefix(m.properties.Installed_location, "/") {
76*333d2b36SAndroid Build Coastguard Worker		ctx.PropertyErrorf("installed_location", "Should not start with / or ../")
77*333d2b36SAndroid Build Coastguard Worker		return
78*333d2b36SAndroid Build Coastguard Worker	}
79*333d2b36SAndroid Build Coastguard Worker
80*333d2b36SAndroid Build Coastguard Worker	out := android.PathForModuleOut(ctx, "out.txt")
81*333d2b36SAndroid Build Coastguard Worker	android.WriteFileRuleVerbatim(ctx, out, "")
82*333d2b36SAndroid Build Coastguard Worker	m.output = out
83*333d2b36SAndroid Build Coastguard Worker
84*333d2b36SAndroid Build Coastguard Worker	name := filepath.Base(m.properties.Installed_location)
85*333d2b36SAndroid Build Coastguard Worker	installDir := android.PathForModuleInstall(ctx, filepath.Dir(m.properties.Installed_location))
86*333d2b36SAndroid Build Coastguard Worker	m.installedPath = ctx.InstallAbsoluteSymlink(installDir, name, m.properties.Symlink_target)
87*333d2b36SAndroid Build Coastguard Worker}
88*333d2b36SAndroid Build Coastguard Worker
89*333d2b36SAndroid Build Coastguard Workerfunc (m *InstallSymlink) AndroidMkEntries() []android.AndroidMkEntries {
90*333d2b36SAndroid Build Coastguard Worker	return []android.AndroidMkEntries{{
91*333d2b36SAndroid Build Coastguard Worker		Class: "FAKE",
92*333d2b36SAndroid Build Coastguard Worker		// Need at least one output file in order for this to take effect.
93*333d2b36SAndroid Build Coastguard Worker		OutputFile: android.OptionalPathForPath(m.output),
94*333d2b36SAndroid Build Coastguard Worker		Include:    "$(BUILD_PHONY_PACKAGE)",
95*333d2b36SAndroid Build Coastguard Worker		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
96*333d2b36SAndroid Build Coastguard Worker			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
97*333d2b36SAndroid Build Coastguard Worker				entries.AddStrings("LOCAL_SOONG_INSTALL_SYMLINKS", m.installedPath.String())
98*333d2b36SAndroid Build Coastguard Worker			},
99*333d2b36SAndroid Build Coastguard Worker		},
100*333d2b36SAndroid Build Coastguard Worker	}}
101*333d2b36SAndroid Build Coastguard Worker}
102