Permalink
Cannot retrieve contributors at this time
Fetching contributors…
| # -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*- | |
| # | |
| # Copyright (C) 2016-2017 Canonical Ltd | |
| # | |
| # This program is free software: you can redistribute it and/or modify | |
| # it under the terms of the GNU General Public License version 3 as | |
| # published by the Free Software Foundation. | |
| # | |
| # This program is distributed in the hope that it will be useful, | |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| # GNU General Public License for more details. | |
| # | |
| # You should have received a copy of the GNU General Public License | |
| # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| import logging | |
| import multiprocessing | |
| import os | |
| import platform | |
| import sys | |
| from snapcraft.internal import common | |
| from snapcraft.internal.deprecations import handle_deprecation_notice | |
| from snapcraft.internal.errors import SnapcraftEnvironmentError | |
| logger = logging.getLogger(__name__) | |
| _ARCH_TRANSLATIONS = { | |
| 'armv7l': { | |
| 'kernel': 'arm', | |
| 'deb': 'armhf', | |
| 'uts_machine': 'arm', | |
| 'cross-compiler-prefix': 'arm-linux-gnueabihf-', | |
| 'cross-build-packages': ['gcc-arm-linux-gnueabihf', | |
| 'libc6-dev-armhf-cross'], | |
| 'triplet': 'arm-linux-gnueabihf', | |
| 'core-dynamic-linker': 'lib/ld-linux-armhf.so.3', | |
| }, | |
| 'aarch64': { | |
| 'kernel': 'arm64', | |
| 'deb': 'arm64', | |
| 'uts_machine': 'aarch64', | |
| 'cross-compiler-prefix': 'aarch64-linux-gnu-', | |
| 'cross-build-packages': ['gcc-aarch64-linux-gnu', | |
| 'libc6-dev-arm64-cross'], | |
| 'triplet': 'aarch64-linux-gnu', | |
| 'core-dynamic-linker': 'lib/ld-linux-aarch64.so.1', | |
| }, | |
| 'i686': { | |
| 'kernel': 'x86', | |
| 'deb': 'i386', | |
| 'uts_machine': 'i686', | |
| 'triplet': 'i386-linux-gnu', | |
| }, | |
| 'ppc64le': { | |
| 'kernel': 'powerpc', | |
| 'deb': 'ppc64el', | |
| 'uts_machine': 'ppc64el', | |
| 'cross-compiler-prefix': 'powerpc64le-linux-gnu-', | |
| 'cross-build-packages': ['gcc-powerpc64le-linux-gnu', | |
| 'libc6-dev-ppc64el-cross'], | |
| 'triplet': 'powerpc64le-linux-gnu', | |
| 'core-dynamic-linker': 'lib64/ld64.so.2', | |
| }, | |
| 'ppc': { | |
| 'kernel': 'powerpc', | |
| 'deb': 'powerpc', | |
| 'uts_machine': 'powerpc', | |
| 'cross-compiler-prefix': 'powerpc-linux-gnu-', | |
| 'cross-build-packages': ['gcc-powerpc-linux-gnu', | |
| 'libc6-dev-powerpc-cross'], | |
| 'triplet': 'powerpc-linux-gnu', | |
| }, | |
| 'x86_64': { | |
| 'kernel': 'x86', | |
| 'deb': 'amd64', | |
| 'uts_machine': 'x86_64', | |
| 'triplet': 'x86_64-linux-gnu', | |
| 'core-dynamic-linker': 'lib64/ld-linux-x86-64.so.2', | |
| }, | |
| 's390x': { | |
| 'kernel': 's390', | |
| 'deb': 's390x', | |
| 'uts_machine': 's390x', | |
| 'cross-compiler-prefix': 's390x-linux-gnu-', | |
| 'cross-build-packages': ['gcc-s390x-linux-gnu', | |
| 'libc6-dev-s390x-cross'], | |
| 'triplet': 's390x-linux-gnu', | |
| 'core-dynamic-linker': 'lib/ld64.so.1', | |
| } | |
| } | |
| _32BIT_USERSPACE_ARCHITECTURE = { | |
| 'aarch64': 'armv7l', | |
| 'armv8l': 'armv7l', | |
| 'ppc64le': 'ppc', | |
| 'x86_64': 'i686', | |
| } | |
| _WINDOWS_TRANSLATIONS = { | |
| 'AMD64': 'x86_64' | |
| } | |
| def _get_platform_architecture(): | |
| architecture = platform.machine() | |
| # Translate the windows architectures we know of to architectures | |
| # we can work with. | |
| if sys.platform == 'win32': | |
| architecture = _WINDOWS_TRANSLATIONS.get(architecture) | |
| if platform.architecture()[0] == '32bit': | |
| userspace = _32BIT_USERSPACE_ARCHITECTURE.get(architecture) | |
| if userspace: | |
| architecture = userspace | |
| return architecture | |
| class ProjectOptions: | |
| @property | |
| def use_geoip(self): | |
| return self.__use_geoip | |
| @property | |
| def parallel_builds(self): | |
| return self.__parallel_builds | |
| @property | |
| def parallel_build_count(self): | |
| build_count = 1 | |
| if self.__parallel_builds: | |
| try: | |
| build_count = multiprocessing.cpu_count() | |
| except NotImplementedError: | |
| logger.warning( | |
| 'Unable to determine CPU count; disabling parallel builds') | |
| return build_count | |
| @property | |
| def is_cross_compiling(self): | |
| return self.__target_machine != self.__platform_arch | |
| @property | |
| def target_arch(self): | |
| return self.__target_arch | |
| @property | |
| def cross_compiler_prefix(self): | |
| try: | |
| # cross-compilation of x86 32bit binaries on a x86_64 host is | |
| # possible by reusing the native toolchain - let Kbuild figure | |
| # it out by itself and pass down an empy cross-compiler-prefix | |
| # to start the build | |
| if (self.__platform_arch == 'x86_64' and | |
| self.__target_machine == 'i686'): | |
| return '' | |
| return self.__machine_info['cross-compiler-prefix'] | |
| except KeyError: | |
| raise SnapcraftEnvironmentError( | |
| 'Cross compilation not supported for target arch {!r}'.format( | |
| self.__target_machine)) | |
| @property | |
| def additional_build_packages(self): | |
| packages = [] | |
| if self.is_cross_compiling: | |
| packages.extend(self.__machine_info.get( | |
| 'cross-build-packages', [])) | |
| return packages | |
| @property | |
| def arch_triplet(self): | |
| return self.__machine_info['triplet'] | |
| @property | |
| def deb_arch(self): | |
| return self.__machine_info['deb'] | |
| @property | |
| def kernel_arch(self): | |
| return self.__machine_info['kernel'] | |
| @property | |
| def local_plugins_dir(self): | |
| deprecated_plugins_dir = os.path.join(self.parts_dir, 'plugins') | |
| if os.path.exists(deprecated_plugins_dir): | |
| handle_deprecation_notice('dn2') | |
| return deprecated_plugins_dir | |
| return os.path.join(self.__project_dir, 'snap', 'plugins') | |
| @property | |
| def parts_dir(self): | |
| return os.path.join(self.__project_dir, 'parts') | |
| @property | |
| def stage_dir(self): | |
| return os.path.join(self.__project_dir, 'stage') | |
| @property | |
| def prime_dir(self): | |
| return os.path.join(self.__project_dir, 'prime') | |
| @property | |
| def debug(self): | |
| return self.__debug | |
| def __init__(self, use_geoip=False, parallel_builds=True, | |
| target_deb_arch=None, debug=False): | |
| # TODO: allow setting a different project dir and check for | |
| # snapcraft.yaml | |
| self.__project_dir = os.getcwd() | |
| self.__use_geoip = use_geoip | |
| self.__parallel_builds = parallel_builds | |
| self._set_machine(target_deb_arch) | |
| self.__debug = debug | |
| def get_core_dynamic_linker(self): | |
| """Returns the dynamic linker used for the targeted core. | |
| If not found realpath for `/lib/ld-linux.so.2` is returned. | |
| However if core is not installed None will be returned. | |
| """ | |
| core_path = common.get_core_path() | |
| dynamic_linker_path = os.path.join( | |
| core_path, | |
| self.__machine_info.get('core-dynamic-linker', | |
| 'lib/ld-linux.so.2')) | |
| # We can't use os.path.realpath because any absolute symlinks | |
| # have to be interpreted relative to core_path, not the real | |
| # root. | |
| seen_paths = set() | |
| while True: | |
| if dynamic_linker_path in seen_paths: | |
| raise SnapcraftEnvironmentError( | |
| "found symlink loop resolving dynamic linker path") | |
| seen_paths.add(dynamic_linker_path) | |
| if not os.path.lexists(dynamic_linker_path): | |
| return None | |
| if not os.path.islink(dynamic_linker_path): | |
| return dynamic_linker_path | |
| link_contents = os.readlink(dynamic_linker_path) | |
| if os.path.isabs(link_contents): | |
| dynamic_linker_path = os.path.join( | |
| core_path, link_contents.lstrip('/')) | |
| else: | |
| dynamic_linker_path = os.path.join( | |
| os.path.dirname(dynamic_linker_path), link_contents) | |
| def _set_machine(self, target_deb_arch): | |
| self.__platform_arch = _get_platform_architecture() | |
| self.__target_arch = target_deb_arch | |
| if not target_deb_arch: | |
| self.__target_machine = self.__platform_arch | |
| else: | |
| self.__target_machine = _find_machine(target_deb_arch) | |
| logger.info('Setting target machine to {!r}'.format( | |
| target_deb_arch)) | |
| self.__machine_info = _ARCH_TRANSLATIONS[self.__target_machine] | |
| def _get_deb_arch(machine): | |
| return _ARCH_TRANSLATIONS[machine].get('deb', None) | |
| def _find_machine(deb_arch): | |
| for machine in _ARCH_TRANSLATIONS: | |
| if _ARCH_TRANSLATIONS[machine].get('deb', '') == deb_arch: | |
| return machine | |
| elif _ARCH_TRANSLATIONS[machine].get('uts_machine', '') == deb_arch: | |
| return machine | |
| raise SnapcraftEnvironmentError( | |
| 'Cannot set machine from deb_arch {!r}'.format(deb_arch)) |