blob: 31da3f653b8fbfb53414d4f6351b142564c30748 [file] [log] [blame]
Cole Faustdff9c142023-09-01 16:11:47 -07001// Copyright 2023 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 etc
16
17import (
18 "android/soong/android"
19 "path/filepath"
20 "strings"
Luca Stefani0e8b5e22025-04-11 13:57:17 +020021
22 "github.com/google/blueprint/proptools"
Cole Faustdff9c142023-09-01 16:11:47 -070023)
24
25func init() {
26 RegisterInstallSymlinkBuildComponents(android.InitRegistrationContext)
27}
28
29func RegisterInstallSymlinkBuildComponents(ctx android.RegistrationContext) {
30 ctx.RegisterModuleType("install_symlink", InstallSymlinkFactory)
Nelson Li90584fb2024-09-30 07:46:02 +000031 ctx.RegisterModuleType("install_symlink_host", InstallSymlinkHostFactory)
Cole Faustdff9c142023-09-01 16:11:47 -070032}
33
34// install_symlink can be used to install an symlink with an arbitrary target to an arbitrary path
35// on the device.
36func InstallSymlinkFactory() android.Module {
37 module := &InstallSymlink{}
38 module.AddProperties(&module.properties)
39 android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
40 return module
41}
42
Nelson Li90584fb2024-09-30 07:46:02 +000043// install_symlink can be used to install an symlink to an arbitrary path on the host.
44func InstallSymlinkHostFactory() android.Module {
45 module := &InstallSymlink{}
46 module.AddProperties(&module.properties)
47 android.InitAndroidMultiTargetsArchModule(module, android.HostSupported, android.MultilibCommon)
48 return module
49}
50
Cole Faustdff9c142023-09-01 16:11:47 -070051type InstallSymlinkProperties struct {
52 // Where to install this symlink, relative to the partition it's installed on.
53 // Which partition it's installed on can be controlled by the vendor, system_ext, ramdisk, etc.
54 // properties.
55 Installed_location string
56 // The target of the symlink, aka where the symlink points.
Luca Stefani0e8b5e22025-04-11 13:57:17 +020057 Symlink_target proptools.Configurable[string]
Cole Faustdff9c142023-09-01 16:11:47 -070058}
59
60type InstallSymlink struct {
61 android.ModuleBase
62 properties InstallSymlinkProperties
63
64 output android.Path
65 installedPath android.InstallPath
66}
67
68func (m *InstallSymlink) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Luca Stefani0e8b5e22025-04-11 13:57:17 +020069 symlink_target := m.properties.Symlink_target.GetOrDefault(ctx, "")
70 if filepath.Clean(symlink_target) != symlink_target {
Cole Faustdff9c142023-09-01 16:11:47 -070071 ctx.PropertyErrorf("symlink_target", "Should be a clean filepath")
72 return
73 }
74 if filepath.Clean(m.properties.Installed_location) != m.properties.Installed_location {
75 ctx.PropertyErrorf("installed_location", "Should be a clean filepath")
76 return
77 }
78 if strings.HasPrefix(m.properties.Installed_location, "../") || strings.HasPrefix(m.properties.Installed_location, "/") {
79 ctx.PropertyErrorf("installed_location", "Should not start with / or ../")
80 return
81 }
82
83 out := android.PathForModuleOut(ctx, "out.txt")
84 android.WriteFileRuleVerbatim(ctx, out, "")
85 m.output = out
86
87 name := filepath.Base(m.properties.Installed_location)
88 installDir := android.PathForModuleInstall(ctx, filepath.Dir(m.properties.Installed_location))
Luca Stefani0e8b5e22025-04-11 13:57:17 +020089 m.installedPath = ctx.InstallAbsoluteSymlink(installDir, name, symlink_target)
Cole Faustdff9c142023-09-01 16:11:47 -070090}
91
92func (m *InstallSymlink) AndroidMkEntries() []android.AndroidMkEntries {
93 return []android.AndroidMkEntries{{
94 Class: "FAKE",
95 // Need at least one output file in order for this to take effect.
96 OutputFile: android.OptionalPathForPath(m.output),
97 Include: "$(BUILD_PHONY_PACKAGE)",
98 ExtraEntries: []android.AndroidMkExtraEntriesFunc{
99 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
100 entries.AddStrings("LOCAL_SOONG_INSTALL_SYMLINKS", m.installedPath.String())
101 },
102 },
103 }}
104}