github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/soong/cc/ndk_library.go (about)

     1  // Copyright 2016 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  
    15  package cc
    16  
    17  import (
    18  	"fmt"
    19  	"strconv"
    20  	"strings"
    21  	"sync"
    22  
    23  	"github.com/google/blueprint"
    24  
    25  	"android/soong/android"
    26  )
    27  
    28  var (
    29  	toolPath = pctx.SourcePathVariable("toolPath", "build/soong/cc/gen_stub_libs.py")
    30  
    31  	genStubSrc = pctx.AndroidStaticRule("genStubSrc",
    32  		blueprint.RuleParams{
    33  			Command: "$toolPath --arch $arch --api $apiLevel --api-map " +
    34  				"$apiMap $vndk $in $out",
    35  			CommandDeps: []string{"$toolPath"},
    36  		}, "arch", "apiLevel", "apiMap", "vndk")
    37  
    38  	ndkLibrarySuffix = ".ndk"
    39  
    40  	ndkPrebuiltSharedLibs = []string{
    41  		"android",
    42  		"c",
    43  		"dl",
    44  		"EGL",
    45  		"GLESv1_CM",
    46  		"GLESv2",
    47  		"GLESv3",
    48  		"jnigraphics",
    49  		"log",
    50  		"mediandk",
    51  		"m",
    52  		"OpenMAXAL",
    53  		"OpenSLES",
    54  		"stdc++",
    55  		"vulkan",
    56  		"z",
    57  	}
    58  	ndkPrebuiltSharedLibraries = addPrefix(append([]string(nil), ndkPrebuiltSharedLibs...), "lib")
    59  
    60  	// These libraries have migrated over to the new ndk_library, which is added
    61  	// as a variation dependency via depsMutator.
    62  	ndkMigratedLibs     = []string{}
    63  	ndkMigratedLibsLock sync.Mutex // protects ndkMigratedLibs writes during parallel beginMutator
    64  )
    65  
    66  // Creates a stub shared library based on the provided version file.
    67  //
    68  // Example:
    69  //
    70  // ndk_library {
    71  //     name: "libfoo",
    72  //     symbol_file: "libfoo.map.txt",
    73  //     first_version: "9",
    74  // }
    75  //
    76  type libraryProperties struct {
    77  	// Relative path to the symbol map.
    78  	// An example file can be seen here: TODO(danalbert): Make an example.
    79  	Symbol_file *string
    80  
    81  	// The first API level a library was available. A library will be generated
    82  	// for every API level beginning with this one.
    83  	First_version *string
    84  
    85  	// The first API level that library should have the version script applied.
    86  	// This defaults to the value of first_version, and should almost never be
    87  	// used. This is only needed to work around platform bugs like
    88  	// https://github.com/android-ndk/ndk/issues/265.
    89  	Unversioned_until *string
    90  
    91  	// Private property for use by the mutator that splits per-API level.
    92  	ApiLevel string `blueprint:"mutated"`
    93  }
    94  
    95  type stubDecorator struct {
    96  	*libraryDecorator
    97  
    98  	properties libraryProperties
    99  
   100  	versionScriptPath android.ModuleGenPath
   101  	installPath       android.Path
   102  }
   103  
   104  // OMG GO
   105  func intMax(a int, b int) int {
   106  	if a > b {
   107  		return a
   108  	} else {
   109  		return b
   110  	}
   111  }
   112  
   113  func normalizeNdkApiLevel(ctx android.BaseContext, apiLevel string,
   114  	arch android.Arch) (string, error) {
   115  
   116  	if apiLevel == "current" {
   117  		return apiLevel, nil
   118  	}
   119  
   120  	minVersion := ctx.Config().MinSupportedSdkVersion()
   121  	firstArchVersions := map[android.ArchType]int{
   122  		android.Arm:    minVersion,
   123  		android.Arm64:  21,
   124  		android.Mips:   minVersion,
   125  		android.Mips64: 21,
   126  		android.X86:    minVersion,
   127  		android.X86_64: 21,
   128  	}
   129  
   130  	firstArchVersion, ok := firstArchVersions[arch.ArchType]
   131  	if !ok {
   132  		panic(fmt.Errorf("Arch %q not found in firstArchVersions", arch.ArchType))
   133  	}
   134  
   135  	if apiLevel == "minimum" {
   136  		return strconv.Itoa(firstArchVersion), nil
   137  	}
   138  
   139  	// If the NDK drops support for a platform version, we don't want to have to
   140  	// fix up every module that was using it as its SDK version. Clip to the
   141  	// supported version here instead.
   142  	version, err := strconv.Atoi(apiLevel)
   143  	if err != nil {
   144  		return "", fmt.Errorf("API level must be an integer (is %q)", apiLevel)
   145  	}
   146  	version = intMax(version, minVersion)
   147  
   148  	return strconv.Itoa(intMax(version, firstArchVersion)), nil
   149  }
   150  
   151  func getFirstGeneratedVersion(firstSupportedVersion string, platformVersion int) (int, error) {
   152  	if firstSupportedVersion == "current" {
   153  		return platformVersion + 1, nil
   154  	}
   155  
   156  	return strconv.Atoi(firstSupportedVersion)
   157  }
   158  
   159  func shouldUseVersionScript(stub *stubDecorator) (bool, error) {
   160  	// unversioned_until is normally empty, in which case we should use the version script.
   161  	if String(stub.properties.Unversioned_until) == "" {
   162  		return true, nil
   163  	}
   164  
   165  	if String(stub.properties.Unversioned_until) == "current" {
   166  		if stub.properties.ApiLevel == "current" {
   167  			return true, nil
   168  		} else {
   169  			return false, nil
   170  		}
   171  	}
   172  
   173  	if stub.properties.ApiLevel == "current" {
   174  		return true, nil
   175  	}
   176  
   177  	unversionedUntil, err := strconv.Atoi(String(stub.properties.Unversioned_until))
   178  	if err != nil {
   179  		return true, err
   180  	}
   181  
   182  	version, err := strconv.Atoi(stub.properties.ApiLevel)
   183  	if err != nil {
   184  		return true, err
   185  	}
   186  
   187  	return version >= unversionedUntil, nil
   188  }
   189  
   190  func generateStubApiVariants(mctx android.BottomUpMutatorContext, c *stubDecorator) {
   191  	platformVersion := mctx.Config().PlatformSdkVersionInt()
   192  
   193  	firstSupportedVersion, err := normalizeNdkApiLevel(mctx, String(c.properties.First_version),
   194  		mctx.Arch())
   195  	if err != nil {
   196  		mctx.PropertyErrorf("first_version", err.Error())
   197  	}
   198  
   199  	firstGenVersion, err := getFirstGeneratedVersion(firstSupportedVersion, platformVersion)
   200  	if err != nil {
   201  		// In theory this is impossible because we've already run this through
   202  		// normalizeNdkApiLevel above.
   203  		mctx.PropertyErrorf("first_version", err.Error())
   204  	}
   205  
   206  	var versionStrs []string
   207  	for version := firstGenVersion; version <= platformVersion; version++ {
   208  		versionStrs = append(versionStrs, strconv.Itoa(version))
   209  	}
   210  	versionStrs = append(versionStrs, mctx.Config().PlatformVersionActiveCodenames()...)
   211  	versionStrs = append(versionStrs, "current")
   212  
   213  	modules := mctx.CreateVariations(versionStrs...)
   214  	for i, module := range modules {
   215  		module.(*Module).compiler.(*stubDecorator).properties.ApiLevel = versionStrs[i]
   216  	}
   217  }
   218  
   219  func ndkApiMutator(mctx android.BottomUpMutatorContext) {
   220  	if m, ok := mctx.Module().(*Module); ok {
   221  		if m.Enabled() {
   222  			if compiler, ok := m.compiler.(*stubDecorator); ok {
   223  				generateStubApiVariants(mctx, compiler)
   224  			}
   225  		}
   226  	}
   227  }
   228  
   229  func (c *stubDecorator) compilerInit(ctx BaseModuleContext) {
   230  	c.baseCompiler.compilerInit(ctx)
   231  
   232  	name := ctx.baseModuleName()
   233  	if strings.HasSuffix(name, ndkLibrarySuffix) {
   234  		ctx.PropertyErrorf("name", "Do not append %q manually, just use the base name", ndkLibrarySuffix)
   235  	}
   236  
   237  	ndkMigratedLibsLock.Lock()
   238  	defer ndkMigratedLibsLock.Unlock()
   239  	for _, lib := range ndkMigratedLibs {
   240  		if lib == name {
   241  			return
   242  		}
   243  	}
   244  	ndkMigratedLibs = append(ndkMigratedLibs, name)
   245  }
   246  
   247  func addStubLibraryCompilerFlags(flags Flags) Flags {
   248  	flags.CFlags = append(flags.CFlags,
   249  		// We're knowingly doing some otherwise unsightly things with builtin
   250  		// functions here. We're just generating stub libraries, so ignore it.
   251  		"-Wno-incompatible-library-redeclaration",
   252  		"-Wno-builtin-requires-header",
   253  		"-Wno-invalid-noreturn",
   254  		"-Wall",
   255  		"-Werror",
   256  		// These libraries aren't actually used. Don't worry about unwinding
   257  		// (avoids the need to link an unwinder into a fake library).
   258  		"-fno-unwind-tables",
   259  	)
   260  	return flags
   261  }
   262  
   263  func (stub *stubDecorator) compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags {
   264  	flags = stub.baseCompiler.compilerFlags(ctx, flags, deps)
   265  	return addStubLibraryCompilerFlags(flags)
   266  }
   267  
   268  func compileStubLibrary(ctx ModuleContext, flags Flags, symbolFile, apiLevel, vndk string) (Objects, android.ModuleGenPath) {
   269  	arch := ctx.Arch().ArchType.String()
   270  
   271  	stubSrcPath := android.PathForModuleGen(ctx, "stub.c")
   272  	versionScriptPath := android.PathForModuleGen(ctx, "stub.map")
   273  	symbolFilePath := android.PathForModuleSrc(ctx, symbolFile)
   274  	apiLevelsJson := android.GetApiLevelsJson(ctx)
   275  	ctx.Build(pctx, android.BuildParams{
   276  		Rule:        genStubSrc,
   277  		Description: "generate stubs " + symbolFilePath.Rel(),
   278  		Outputs:     []android.WritablePath{stubSrcPath, versionScriptPath},
   279  		Input:       symbolFilePath,
   280  		Implicits:   []android.Path{apiLevelsJson},
   281  		Args: map[string]string{
   282  			"arch":     arch,
   283  			"apiLevel": apiLevel,
   284  			"apiMap":   apiLevelsJson.String(),
   285  			"vndk":     vndk,
   286  		},
   287  	})
   288  
   289  	subdir := ""
   290  	srcs := []android.Path{stubSrcPath}
   291  	return compileObjs(ctx, flagsToBuilderFlags(flags), subdir, srcs, nil, nil), versionScriptPath
   292  }
   293  
   294  func (c *stubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
   295  	if !strings.HasSuffix(String(c.properties.Symbol_file), ".map.txt") {
   296  		ctx.PropertyErrorf("symbol_file", "must end with .map.txt")
   297  	}
   298  
   299  	objs, versionScript := compileStubLibrary(ctx, flags, String(c.properties.Symbol_file),
   300  		c.properties.ApiLevel, "")
   301  	c.versionScriptPath = versionScript
   302  	return objs
   303  }
   304  
   305  func (linker *stubDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps {
   306  	return Deps{}
   307  }
   308  
   309  func (linker *stubDecorator) Name(name string) string {
   310  	return name + ndkLibrarySuffix
   311  }
   312  
   313  func (stub *stubDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
   314  	stub.libraryDecorator.libName = ctx.baseModuleName()
   315  	return stub.libraryDecorator.linkerFlags(ctx, flags)
   316  }
   317  
   318  func (stub *stubDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps,
   319  	objs Objects) android.Path {
   320  
   321  	useVersionScript, err := shouldUseVersionScript(stub)
   322  	if err != nil {
   323  		ctx.ModuleErrorf(err.Error())
   324  	}
   325  
   326  	if useVersionScript {
   327  		linkerScriptFlag := "-Wl,--version-script," + stub.versionScriptPath.String()
   328  		flags.LdFlags = append(flags.LdFlags, linkerScriptFlag)
   329  	}
   330  
   331  	return stub.libraryDecorator.link(ctx, flags, deps, objs)
   332  }
   333  
   334  func (stub *stubDecorator) install(ctx ModuleContext, path android.Path) {
   335  	arch := ctx.Target().Arch.ArchType.Name
   336  	apiLevel := stub.properties.ApiLevel
   337  
   338  	// arm64 isn't actually a multilib toolchain, so unlike the other LP64
   339  	// architectures it's just installed to lib.
   340  	libDir := "lib"
   341  	if ctx.toolchain().Is64Bit() && arch != "arm64" {
   342  		libDir = "lib64"
   343  	}
   344  
   345  	installDir := getNdkInstallBase(ctx).Join(ctx, fmt.Sprintf(
   346  		"platforms/android-%s/arch-%s/usr/%s", apiLevel, arch, libDir))
   347  	stub.installPath = ctx.InstallFile(installDir, path.Base(), path)
   348  }
   349  
   350  func newStubLibrary() *Module {
   351  	module, library := NewLibrary(android.DeviceSupported)
   352  	library.BuildOnlyShared()
   353  	module.stl = nil
   354  	module.sanitize = nil
   355  	library.StripProperties.Strip.None = BoolPtr(true)
   356  
   357  	stub := &stubDecorator{
   358  		libraryDecorator: library,
   359  	}
   360  	module.compiler = stub
   361  	module.linker = stub
   362  	module.installer = stub
   363  
   364  	module.AddProperties(&stub.properties, &library.MutatedProperties)
   365  
   366  	return module
   367  }
   368  
   369  func ndkLibraryFactory() android.Module {
   370  	module := newStubLibrary()
   371  	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
   372  	return module
   373  }