Home | History | Annotate | Download | only in build
      1 // Copyright 2017 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 build
     16 
     17 import (
     18 	"io/ioutil"
     19 	"os"
     20 	"path/filepath"
     21 	"text/template"
     22 )
     23 
     24 // Ensures the out directory exists, and has the proper files to prevent kati
     25 // from recursing into it.
     26 func SetupOutDir(ctx Context, config Config) {
     27 	ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "Android.mk"))
     28 	ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "CleanSpec.mk"))
     29 	ensureEmptyFileExists(ctx, filepath.Join(config.SoongOutDir(), ".soong.in_make"))
     30 	// The ninja_build file is used by our buildbots to understand that the output
     31 	// can be parsed as ninja output.
     32 	ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "ninja_build"))
     33 }
     34 
     35 var combinedBuildNinjaTemplate = template.Must(template.New("combined").Parse(`
     36 builddir = {{.OutDir}}
     37 include {{.KatiNinjaFile}}
     38 include {{.SoongNinjaFile}}
     39 build {{.CombinedNinjaFile}}: phony {{.SoongNinjaFile}}
     40 `))
     41 
     42 func createCombinedBuildNinjaFile(ctx Context, config Config) {
     43 	file, err := os.Create(config.CombinedNinjaFile())
     44 	if err != nil {
     45 		ctx.Fatalln("Failed to create combined ninja file:", err)
     46 	}
     47 	defer file.Close()
     48 
     49 	if err := combinedBuildNinjaTemplate.Execute(file, config); err != nil {
     50 		ctx.Fatalln("Failed to write combined ninja file:", err)
     51 	}
     52 }
     53 
     54 const (
     55 	BuildNone          = iota
     56 	BuildProductConfig = 1 << iota
     57 	BuildSoong         = 1 << iota
     58 	BuildKati          = 1 << iota
     59 	BuildNinja         = 1 << iota
     60 	BuildAll           = BuildProductConfig | BuildSoong | BuildKati | BuildNinja
     61 )
     62 
     63 func checkCaseSensitivity(ctx Context, config Config) {
     64 	outDir := config.OutDir()
     65 	lowerCase := filepath.Join(outDir, "casecheck.txt")
     66 	upperCase := filepath.Join(outDir, "CaseCheck.txt")
     67 	lowerData := "a"
     68 	upperData := "B"
     69 
     70 	err := ioutil.WriteFile(lowerCase, []byte(lowerData), 0777)
     71 	if err != nil {
     72 		ctx.Fatalln("Failed to check case sensitivity:", err)
     73 	}
     74 
     75 	err = ioutil.WriteFile(upperCase, []byte(upperData), 0777)
     76 	if err != nil {
     77 		ctx.Fatalln("Failed to check case sensitivity:", err)
     78 	}
     79 
     80 	res, err := ioutil.ReadFile(lowerCase)
     81 	if err != nil {
     82 		ctx.Fatalln("Failed to check case sensitivity:", err)
     83 	}
     84 
     85 	if string(res) != lowerData {
     86 		ctx.Println("************************************************************")
     87 		ctx.Println("You are building on a case-insensitive filesystem.")
     88 		ctx.Println("Please move your source tree to a case-sensitive filesystem.")
     89 		ctx.Println("************************************************************")
     90 		ctx.Fatalln("Case-insensitive filesystems not supported")
     91 	}
     92 }
     93 
     94 func help(ctx Context, config Config, what int) {
     95 	cmd := Command(ctx, config, "make",
     96 		"make", "-f", "build/core/help.mk")
     97 	cmd.Sandbox = makeSandbox
     98 	cmd.Stdout = ctx.Stdout()
     99 	cmd.Stderr = ctx.Stderr()
    100 	cmd.RunOrFatal()
    101 }
    102 
    103 // Build the tree. The 'what' argument can be used to chose which components of
    104 // the build to run.
    105 func Build(ctx Context, config Config, what int) {
    106 	ctx.Verboseln("Starting build with args:", config.Arguments())
    107 	ctx.Verboseln("Environment:", config.Environment().Environ())
    108 
    109 	if inList("help", config.Arguments()) {
    110 		help(ctx, config, what)
    111 		return
    112 	} else if inList("clean", config.Arguments()) || inList("clobber", config.Arguments()) {
    113 		clean(ctx, config, what)
    114 		return
    115 	}
    116 
    117 	// Start getting java version as early as possible
    118 	getJavaVersions(ctx, config)
    119 
    120 	// Make sure that no other Soong process is running with the same output directory
    121 	buildLock := BecomeSingletonOrFail(ctx, config)
    122 	defer buildLock.Unlock()
    123 
    124 	SetupOutDir(ctx, config)
    125 
    126 	checkCaseSensitivity(ctx, config)
    127 
    128 	ensureEmptyDirectoriesExist(ctx, config.TempDir())
    129 
    130 	if what&BuildProductConfig != 0 {
    131 		// Run make for product config
    132 		runMakeProductConfig(ctx, config)
    133 	}
    134 
    135 	if inList("installclean", config.Arguments()) {
    136 		installClean(ctx, config, what)
    137 		ctx.Println("Deleted images and staging directories.")
    138 		return
    139 	} else if inList("dataclean", config.Arguments()) {
    140 		dataClean(ctx, config, what)
    141 		ctx.Println("Deleted data files.")
    142 		return
    143 	}
    144 
    145 	if what&BuildSoong != 0 {
    146 		// Run Soong
    147 		runSoongBootstrap(ctx, config)
    148 		runSoong(ctx, config)
    149 	}
    150 
    151 	// Check the java versions we read earlier
    152 	checkJavaVersion(ctx, config)
    153 
    154 	if what&BuildKati != 0 {
    155 		// Run ckati
    156 		runKati(ctx, config)
    157 	}
    158 
    159 	if what&BuildNinja != 0 {
    160 		installCleanIfNecessary(ctx, config)
    161 
    162 		// Write combined ninja file
    163 		createCombinedBuildNinjaFile(ctx, config)
    164 
    165 		// Run ninja
    166 		runNinja(ctx, config)
    167 	}
    168 }
    169