docs: def prepare_build_environment(self,
                                    user_sdk_dir,
                                    user_ndk_dir,
                                    user_android_api,
                                    user_ndk_api):
          '''Checks that build dependencies exist and sets internal variables
          for the Android SDK etc.
  
          ..warning:: This *must* be called before trying any build stuff
  
          '''
  
          self.ensure_dirs()
  
          if self._build_env_prepared:
              return
  
          ok = True
  
          # Work out where the Android SDK is
          sdk_dir = None
          if user_sdk_dir:
              sdk_dir = user_sdk_dir
          # This is the old P4A-specific var
          if sdk_dir is None:
              sdk_dir = environ.get('ANDROIDSDK', None)
          # This seems used more conventionally
          if sdk_dir is None:
              sdk_dir = environ.get('ANDROID_HOME', None)
          # Checks in the buildozer SDK dir, useful for debug tests of p4a
          if sdk_dir is None:
              possible_dirs = glob.glob(expanduser(join(
                  '~', '.buildozer', 'android', 'platform', 'android-sdk-*')))
              possible_dirs = [d for d in possible_dirs if not
                               (d.endswith('.bz2') or d.endswith('.gz'))]
              if possible_dirs:
                  info('Found possible SDK dirs in buildozer dir: {}'.format(
                      ', '.join([d.split(os.sep)[-1] for d in possible_dirs])))
                  info('Will attempt to use SDK at {}'.format(possible_dirs[0]))
                  warning('This SDK lookup is intended for debug only, if you '
                          'use python-for-android much you should probably '
                          'maintain your own SDK download.')
                  sdk_dir = possible_dirs[0]
          if sdk_dir is None:
              raise BuildInterruptingException('Android SDK dir was not specified, exiting.')
          self.sdk_dir = realpath(sdk_dir)
  
          # Check what Android API we're using
          android_api = None
          if user_android_api:
              android_api = user_android_api
              info('Getting Android API version from user argument: {}'.format(android_api))
          elif 'ANDROIDAPI' in environ:
              android_api = environ['ANDROIDAPI']
              info('Found Android API target in $ANDROIDAPI: {}'.format(android_api))
          else:
              info('Android API target was not set manually, using '
                   'the default of {}'.format(RECOMMENDED_TARGET_API))
              android_api = RECOMMENDED_TARGET_API
          android_api = int(android_api)
          self.android_api = android_api
  
          check_target_api(android_api, self.archs[0].arch)
  
          if exists(join(sdk_dir, 'tools', 'bin', 'avdmanager')):
              avdmanager = sh.Command(join(sdk_dir, 'tools', 'bin', 'avdmanager'))
              targets = avdmanager('list', 'target').stdout.decode('utf-8').split('\n')
          elif exists(join(sdk_dir, 'tools', 'android')):
              android = sh.Command(join(sdk_dir, 'tools', 'android'))
              targets = android('list').stdout.decode('utf-8').split('\n')
          else:
              raise BuildInterruptingException(
                  'Could not find `android` or `sdkmanager` binaries in Android SDK',
                  instructions='Make sure the path to the Android SDK is correct')
          apis = [s for s in targets if re.match(r'^ *API level: ', s)]
          apis = [re.findall(r'[0-9]+', s) for s in apis]
          apis = [int(s[0]) for s in apis if s]
          info('Available Android APIs are ({})'.format(
              ', '.join(map(str, apis))))
          if android_api in apis:
              info(('Requested API target {} is available, '
                    'continuing.').format(android_api))
          else:
              raise BuildInterruptingException(
                  ('Requested API target {} is not available, install '
                   'it with the SDK android tool.').format(android_api))
  
          # Find the Android NDK
          # Could also use ANDROID_NDK, but doesn't look like many tools use this
          ndk_dir = None
          if user_ndk_dir:
              ndk_dir = user_ndk_dir
              info('Getting NDK dir from from user argument')
          if ndk_dir is None:  # The old P4A-specific dir
              ndk_dir = environ.get('ANDROIDNDK', None)
              if ndk_dir is not None:
                  info('Found NDK dir in $ANDROIDNDK: {}'.format(ndk_dir))
          if ndk_dir is None:  # Apparently the most common convention
              ndk_dir = environ.get('NDK_HOME', None)
              if ndk_dir is not None:
                  info('Found NDK dir in $NDK_HOME: {}'.format(ndk_dir))
          if ndk_dir is None:  # Another convention (with maven?)
              ndk_dir = environ.get('ANDROID_NDK_HOME', None)
              if ndk_dir is not None:
                  info('Found NDK dir in $ANDROID_NDK_HOME: {}'.format(ndk_dir))
          if ndk_dir is None:  # Checks in the buildozer NDK dir, useful
              #                # for debug tests of p4a
              possible_dirs = glob.glob(expanduser(join(
                  '~', '.buildozer', 'android', 'platform', 'android-ndk-r*')))
              if possible_dirs:
                  info('Found possible NDK dirs in buildozer dir: {}'.format(
                      ', '.join([d.split(os.sep)[-1] for d in possible_dirs])))
                  info('Will attempt to use NDK at {}'.format(possible_dirs[0]))
                  warning('This NDK lookup is intended for debug only, if you '
                          'use python-for-android much you should probably '
                          'maintain your own NDK download.')
                  ndk_dir = possible_dirs[0]
          if ndk_dir is None:
              raise BuildInterruptingException('Android NDK dir was not specified')
          self.ndk_dir = realpath(ndk_dir)
  
          check_ndk_version(ndk_dir)
  
          ndk_api = None
          if user_ndk_api:
              ndk_api = user_ndk_api
              info('Getting NDK API version (i.e. minimum supported API) from user argument')
          elif 'NDKAPI' in environ:
              ndk_api = environ.get('NDKAPI', None)
              info('Found Android API target in $NDKAPI')
          else:
              ndk_api = min(self.android_api, RECOMMENDED_NDK_API)
              warning('NDK API target was not set manually, using '
                      'the default of {} = min(android-api={}, default ndk-api={})'.format(
                          ndk_api, self.android_api, RECOMMENDED_NDK_API))
          ndk_api = int(ndk_api)
          self.ndk_api = ndk_api
  
          check_ndk_api(ndk_api, self.android_api)
  
          virtualenv = get_virtualenv_executable()
          if virtualenv is None:
              raise IOError('Couldn\'t find a virtualenv executable, '
                            'you must install this to use p4a.')
          self.virtualenv = virtualenv
          info('Found virtualenv at {}'.format(virtualenv))
  
          # path to some tools
          self.ccache = sh.which("ccache")
          if not self.ccache:
              info('ccache is missing, the build will not be optimized in the '
                   'future.')
          for cython_fn in ("cython", "cython3", "cython2", "cython-2.7"):
              cython = sh.which(cython_fn)
              if cython:
                  self.cython = cython
                  break
          else:
              raise BuildInterruptingException('No cython binary found.')
          if not self.cython:
              ok = False
              warning("Missing requirement: cython is not installed")
  
          # This would need to be changed if supporting multiarch APKs
          arch = self.archs[0]
          platform_dir = arch.platform_dir
          toolchain_prefix = arch.toolchain_prefix
          toolchain_version = None
          self.ndk_platform = join(
              self.ndk_dir,
              'platforms',
              'android-{}'.format(self.ndk_api),
              platform_dir)
          if not exists(self.ndk_platform):
              warning('ndk_platform doesn\'t exist: {}'.format(
                  self.ndk_platform))
              ok = False
  
          py_platform = sys.platform
          if py_platform in ['linux2', 'linux3']:
              py_platform = 'linux'
  
          toolchain_versions = []
          toolchain_path = join(self.ndk_dir, 'toolchains')
          if isdir(toolchain_path):
              toolchain_contents = glob.glob('{}/{}-*'.format(toolchain_path,
                                                              toolchain_prefix))
              toolchain_versions = [split(path)[-1][len(toolchain_prefix) + 1:]
                                    for path in toolchain_contents]
          else:
              warning('Could not find toolchain subdirectory!')
              ok = False
          toolchain_versions.sort()
  
          toolchain_versions_gcc = []
          for toolchain_version in toolchain_versions:
              if toolchain_version[0].isdigit():
                  # GCC toolchains begin with a number
                  toolchain_versions_gcc.append(toolchain_version)
  
          if toolchain_versions:
              info('Found the following toolchain versions: {}'.format(
                  toolchain_versions))
              info('Picking the latest gcc toolchain, here {}'.format(
                  toolchain_versions_gcc[-1]))
              toolchain_version = toolchain_versions_gcc[-1]
          else:
              warning('Could not find any toolchain for {}!'.format(
                  toolchain_prefix))
              ok = False
  
          self.toolchain_prefix = toolchain_prefix
          self.toolchain_version = toolchain_version
          # Modify the path so that sh finds modules appropriately
          environ['PATH'] = (
              '{ndk_dir}/toolchains/{toolchain_prefix}-{toolchain_version}/'
              'prebuilt/{py_platform}-x86/bin/:{ndk_dir}/toolchains/'
              '{toolchain_prefix}-{toolchain_version}/prebuilt/'
              '{py_platform}-x86_64/bin/:{ndk_dir}:{sdk_dir}/'
              'tools:{path}').format(
                  sdk_dir=self.sdk_dir, ndk_dir=self.ndk_dir,
                  toolchain_prefix=toolchain_prefix,
                  toolchain_version=toolchain_version,
                  py_platform=py_platform, path=environ.get('PATH'))
  
          for executable in ("pkg-config", "autoconf", "automake", "libtoolize",
                             "tar", "bzip2", "unzip", "make", "gcc", "g++"):
              if not sh.which(executable):
                  warning("Missing executable: {} is not installed".format(
                      executable))
  
          if not ok:
              raise BuildInterruptingException(
                  'python-for-android cannot continue due to the missing executables above')