Merge "Restat clang linker outputs"
diff --git a/apex/apex.go b/apex/apex.go
index 685a774..e07fae0 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1300,7 +1300,23 @@
 
 type PrebuiltProperties struct {
 	// the path to the prebuilt .apex file to import.
-	Src string `android:"arch_variant"`
+	Source string `blueprint:"mutated"`
+
+	Src  *string
+	Arch struct {
+		Arm struct {
+			Src *string
+		}
+		Arm64 struct {
+			Src *string
+		}
+		X86 struct {
+			Src *string
+		}
+		X86_64 struct {
+			Src *string
+		}
+	}
 
 	// the name of the apex_key module that contains the matching public key to be installed.
 	Key *string
@@ -1312,11 +1328,37 @@
 		return
 	}
 	ctx.AddDependency(ctx.Module(), keyTag, *p.properties.Key)
+
+	// This is called before prebuilt_select and prebuilt_postdeps mutators
+	// The mutators requires that src to be set correctly for each arch so that
+	// arch variants are disabled when src is not provided for the arch.
+	if len(ctx.MultiTargets()) != 1 {
+		ctx.ModuleErrorf("compile_multilib shouldn't be \"both\" for prebuilt_apex")
+		return
+	}
+	var src string
+	switch ctx.MultiTargets()[0].Arch.ArchType {
+	case android.Arm:
+		src = String(p.properties.Arch.Arm.Src)
+	case android.Arm64:
+		src = String(p.properties.Arch.Arm64.Src)
+	case android.X86:
+		src = String(p.properties.Arch.X86.Src)
+	case android.X86_64:
+		src = String(p.properties.Arch.X86_64.Src)
+	default:
+		ctx.ModuleErrorf("prebuilt_apex does not support %q", ctx.MultiTargets()[0].Arch.String())
+		return
+	}
+	if src == "" {
+		src = String(p.properties.Src)
+	}
+	p.properties.Source = src
 }
 
 func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	// TODO(jungjw): Check the key validity.
-	p.inputApex = p.prebuilt.SingleSourcePath(ctx)
+	p.inputApex = p.Prebuilt().SingleSourcePath(ctx)
 	p.installDir = android.PathForModuleInstall(ctx, "apex")
 	ctx.InstallFile(p.installDir, ctx.ModuleName()+imageApexSuffix, p.inputApex)
 }
@@ -1348,7 +1390,7 @@
 func PrebuiltFactory() android.Module {
 	module := &Prebuilt{}
 	module.AddProperties(&module.properties)
-	android.InitSingleSourcePrebuiltModule(module, &module.properties.Src)
-	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	android.InitSingleSourcePrebuiltModule(module, &module.properties.Source)
+	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	return module
 }
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 2d9cca6..1e8d5b4 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -171,7 +171,8 @@
 		"custom_notice":                        nil,
 		"testkey2.avbpubkey":                   nil,
 		"testkey2.pem":                         nil,
-		"myapex.apex":                          nil,
+		"myapex-arm64.apex":                    nil,
+		"myapex-arm.apex":                      nil,
 	})
 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
 	android.FailIfErrored(t, errs)
@@ -1243,7 +1244,14 @@
 	ctx := testApex(t, `
 		prebuilt_apex {
 			name: "myapex",
-			src: "myapex.apex",
+			arch: {
+				arm64: {
+					src: "myapex-arm64.apex",
+				},
+				arm: {
+					src: "myapex-arm.apex",
+				},
+			},
 			key: "myapex.key"
 		}
 
@@ -1257,6 +1265,11 @@
 
 	prebuilt := ctx.ModuleForTests("myapex", "android_common").Module().(*Prebuilt)
 
+	expectedInput := "myapex-arm64.apex"
+	if prebuilt.inputApex.String() != expectedInput {
+		t.Errorf("inputApex invalid. expected: %q, actual: %q", expectedInput, prebuilt.inputApex.String())
+	}
+
 	// Check if the key module is added as a required module.
 	buf := &bytes.Buffer{}
 	prebuilt.AndroidMk().Extra[0](buf, nil)
diff --git a/scripts/setup_go_workspace_for_soong.sh b/scripts/setup_go_workspace_for_soong.sh
index e2fb9fa..6374aae 100755
--- a/scripts/setup_go_workspace_for_soong.sh
+++ b/scripts/setup_go_workspace_for_soong.sh
@@ -1,7 +1,7 @@
 #!/bin/bash
 set -e
 
-# Copyright 2017 Google Inc. All rights reserved.
+# Copyright 2019 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.
@@ -15,23 +15,174 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#mounts the components of soong into a directory structure that Go tools and editors expect
+# Mounts the components of soong into a directory structure that Go tools
+# and editors expect.
 
-#move to the script's directory
-cd "$(dirname $0)"
-SCRIPT_PATH="$PWD"
 
-#find the root of the Repo checkout
-cd "${SCRIPT_PATH}"/../../..
-ANDROID_PATH="${PWD}"
-OUTPUT_PATH="$(echo ${GOPATH} | sed 's/\:.*//')" #if GOPATH contains multiple paths, use the first one
-
-if [ -z "${OUTPUT_PATH}" ]; then
-  echo "Error; could not determine the desired location at which to create a Go-compatible workspace. Please update GOPATH to specify the desired destination directory"
+#####################################################################
+# Print the message to stderr with the prefix ERROR and abort this
+# script.
+#####################################################################
+function log_FATAL() {
+  echo "ERROR:" "$*" >&2
   exit 1
-fi
+}
 
-function confirm() {
+#####################################################################
+# Print the message to stderr with the prefix WARN
+#####################################################################
+function log_WARN() {
+  echo "WARN:" "$*" >&2
+}
+
+
+#####################################################################
+# Print the message with the prefix INFO.
+#####################################################################
+function log_INFO() {
+  echo "INFO:" "$*"
+}
+
+
+#####################################################################
+# Find the root project directory of this repo. This is done by
+# finding the directory of where this script lives and then go up one
+# directory to check the ".repo" directory exist. If not, keep going
+# up until we find the ".repo" file or we reached to the filesystem
+# root. Project root directory is printed to stdout.
+#####################################################################
+function root_dir() (
+  local dir
+  if ! dir="$("${readlink}" -e $(dirname "$0"))"; then
+    log_FATAL "failed to read the script's current directory."
+  fi
+
+  dir=${dir}/../../..
+  if ! dir="$("${readlink}" -e "${dir}")"; then
+    log_FATAL "Cannot find the root project directory"
+  fi
+
+  echo "${dir}"
+)
+
+
+#####################################################################
+# executes a shell command by printing out to the screen first and
+# then evaluating the command.
+#####################################################################
+function execute() {
+  echo "$@"
+  eval "$@"
+}
+
+
+#####################################################################
+# Returns the source directory of a passed in path from BIND_PATHS
+# array.
+#####################################################################
+function bind_path_src_dir() (
+  local -r bind_path="$1"
+  echo "${bind_path/%|*/}"
+)
+
+
+#####################################################################
+# Returns the destination directory of a passed in path from
+# BIND_PATHS array.
+#####################################################################
+function bind_path_dst_dir() (
+  local -r bind_path="$1"
+  echo  "${bind_path/#*|}"
+)
+
+
+#####################################################################
+# Executes the bindfs command in linux. Expects $1 to be src
+# directory and $2 to be destination directory.
+#####################################################################
+function linux_bind_dir() (
+  execute bindfs "$1" "$2"
+)
+
+#####################################################################
+# Executes the fusermount -u command in linux. Expects $1 to be the
+# destination directory.
+#####################################################################
+function linux_unbind_dir() (
+  execute fusermount -u "$1"
+)
+
+#####################################################################
+# Executes the bindfs command in darwin. Expects $1 to be src
+# directory and $2 to be destination directory.
+#####################################################################
+function darwin_bind_dir() (
+  execute bindfs -o allow_recursion -n "$1" "$2"
+)
+
+
+#####################################################################
+# Execute the umount command in darwin to unbind a directory. Expects
+# $1 to be the destination directory
+#####################################################################
+function darwin_unbind_dir() (
+  execute umount -f "$1"
+)
+
+
+#####################################################################
+# Bind all the paths that are specified in the BIND_PATHS array.
+#####################################################################
+function bind_all() (
+  local src_dir
+  local dst_dir
+
+  for path in ${BIND_PATHS[@]}; do
+    src_dir=$(bind_path_src_dir "${path}")
+
+    dst_dir=$(bind_path_dst_dir "${path}")
+    mkdir -p "${dst_dir}"
+
+    "${bind_dir}" ${src_dir} "${dst_dir}"
+  done
+
+  echo
+  log_INFO "Created GOPATH-compatible directory structure at ${OUTPUT_PATH}."
+)
+
+
+#####################################################################
+# Unbind all the paths that are specified in the BIND_PATHS array.
+#####################################################################
+function unbind_all() (
+  local dst_dir
+  local exit_code=0
+
+  # need to go into reverse since several parent directory may have been
+  # first before the child one.
+  for (( i=${#BIND_PATHS[@]}-1; i>=0; i-- )); do
+    dst_dir=$(bind_path_dst_dir "${BIND_PATHS[$i]}")
+
+    # continue to unmount even one of them fails
+    if ! "${unbind_dir}" "${dst_dir}"; then
+      log_WARN "Failed to umount ${dst_dir}."
+      exit_code=1
+    fi
+  done
+
+  if [[ ${exit_code} -ne 0 ]]; then
+    exit ${exit_code}
+  fi
+
+  echo
+  log_INFO "Unmounted the GOPATH-compatible directory structure at ${OUTPUT_PATH}."
+)
+
+
+#####################################################################
+# Asks the user to create the GOPATH-compatible directory structure.
+#####################################################################
+function confirm() (
   while true; do
     echo "Will create GOPATH-compatible directory structure at ${OUTPUT_PATH}"
     echo -n "Ok [Y/n]?"
@@ -42,48 +193,162 @@
       if [ "${decision}" == "n" ]; then
         return 1
       else
-        echo "Invalid choice ${decision}; choose either 'y' or 'n'"
+        log_WARN "Invalid choice ${decision}; choose either 'y' or 'n'"
       fi
     fi
   done
+)
+
+
+#####################################################################
+# Help function.
+#####################################################################
+function help() (
+  cat <<EOF
+Mounts the components of soong into a directory structure that Go tools
+and editors expect.
+
+  --help
+    This help
+
+  --bind
+    Create the directory structure that Go tools and editors expect by
+    binding the one to aosp build directory.
+
+  --unbind
+    Reverse operation of bind.
+
+If no flags were specified, the --bind one is selected by default.
+EOF
+)
+
+
+#####################################################################
+# Parse the arguments passed in to this script.
+#####################################################################
+function parse_arguments() {
+  while [[ -n "$1" ]]; do
+    case "$1" in
+          --bind)
+            ACTION="bind"
+            shift
+            ;;
+          --unbind)
+            ACTION="unbind"
+            shift
+            ;;
+          --help )
+            help
+            shift
+            exit 0
+            ;;
+          *)
+            log_WARN "Unknown option: $1"
+            help
+            exit 1
+            ;;
+    esac
+  done
+
+  if [[ -z "${ACTION}" ]]; then
+    ACTION=bind
+  fi
 }
 
-function bindAll() {
-  bindOne "${ANDROID_PATH}/build/blueprint" "${OUTPUT_PATH}/src/github.com/google/blueprint"
-  bindOne "${ANDROID_PATH}/build/soong" "${OUTPUT_PATH}/src/android/soong"
 
-  bindOne "${ANDROID_PATH}/art/build" "${OUTPUT_PATH}/src/android/soong/art"
-  bindOne "${ANDROID_PATH}/external/golang-protobuf" "${OUTPUT_PATH}/src/github.com/golang/protobuf"
-  bindOne "${ANDROID_PATH}/external/llvm/soong" "${OUTPUT_PATH}/src/android/soong/llvm"
-  bindOne "${ANDROID_PATH}/external/clang/soong" "${OUTPUT_PATH}/src/android/soong/clang"
-  echo
-  echo "Created GOPATH-compatible directory structure at ${OUTPUT_PATH}"
-}
+#####################################################################
+# Verifies that a list of required binaries are installed in the
+# host in order to run this script.
+#####################################################################
+function check_exec_existence() (
+  function check() {
+    if ! hash "$1" &>/dev/null; then
+      log_FATAL "missing $1"
+    fi
+  }
 
-function bindOne() {
-  #causes $newPath to mirror $existingPath
-  existingPath="$1"
-  newPath="$2"
-  mkdir -p "$newPath"
-  case $(uname -s) in
+  local bins
+  case "${os_type}" in
     Darwin)
-      echoAndDo bindfs -o allow_recursion -n "${existingPath}" "${newPath}"
+      bins=("bindfs" "greadlink")
       ;;
     Linux)
-      echoAndDo bindfs "${existingPath}" "${newPath}"
+      bins=("bindfs" "fusermount")
       ;;
+    *)
+      log_FATAL "${os_type} is not a recognized system."
   esac
+
+  for bin in "${bins[@]}"; do
+    check "${bin}"
+  done
+)
+
+
+function main() {
+  parse_arguments "$@"
+
+  check_exec_existence
+
+  if [[ "${ACTION}" == "bind" ]]; then
+    if confirm; then
+      echo
+      bind_all
+    else
+      echo "skipping due to user request"
+      exit 1
+    fi
+  else
+    echo
+    unbind_all
+  fi
 }
 
-function echoAndDo() {
-  echo "$@"
-  eval "$@"
-}
+readonly os_type="$(uname -s)"
+case "${os_type}" in
+  Darwin)
+    bind_dir=darwin_bind_dir
+    unbind_dir=darwin_unbind_dir
+    readlink=greadlink
+    ;;
+  Linux)
+    bind_dir=linux_bind_dir
+    unbind_dir=linux_unbind_dir
+    readlink=readlink
+    ;;
+    *)
+    log_FATAL "${os_type} is not a recognized system."
+esac
+readonly bind_dir
+readonly unbind_dir
+readonly readlink
 
-if confirm; then
-  echo
-  bindAll
-else
-  echo "skipping due to user request"
-  exit 1
+
+if ! ANDROID_PATH="$(root_dir)"; then
+  log_FATAL "failed to find the root of the repo checkout"
 fi
+readonly ANDROID_PATH
+
+#if GOPATH contains multiple paths, use the first one
+if ! OUTPUT_PATH="$(echo ${GOPATH} | sed 's/\:.*//')"; then
+  log_FATAL "failed to extract the first GOPATH environment variable"
+fi
+readonly OUTPUT_PATH
+if [ -z "${OUTPUT_PATH}" ]; then
+  log_FATAL "Could not determine the desired location at which to create a" \
+            "Go-compatible workspace. Please update GOPATH to specify the" \
+            "desired destination directory."
+fi
+
+# Below are the paths to bind from src to dst. The paths are separated by |
+# where the left side is the source and the right side is destination.
+readonly BIND_PATHS=(
+  "${ANDROID_PATH}/build/blueprint|${OUTPUT_PATH}/src/github.com/google/blueprint"
+  "${ANDROID_PATH}/build/soong|${OUTPUT_PATH}/src/android/soong"
+  "${ANDROID_PATH}/art/build|${OUTPUT_PATH}/src/android/soong/art"
+  "${ANDROID_PATH}/external/golang-protobuf|${OUTPUT_PATH}/src/github.com/golang/protobuf"
+  "${ANDROID_PATH}/external/llvm/soong|${OUTPUT_PATH}/src/android/soong/llvm"
+  "${ANDROID_PATH}/external/clang/soong|${OUTPUT_PATH}/src/android/soong/clang"
+)
+
+main "$@"