123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- #!/usr/bin/env python3
- #
- # Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
- #
- # SPDX-License-Identifier: Apache-2.0 OR MIT
- #
- #
- """
- Package builder for vcpkg-based packages
- """
- from pathlib import Path
- import errno
- import json
- import os
- import pathlib
- import shutil
- import string
- import subprocess
- import platform
- class VcpkgBuilder(object):
- def __init__(self, packageName: str, portName: str, vcpkgDir: pathlib.Path, targetPlatform: str, static: bool):
- self._packageName = packageName
- self._portName = portName
- self._vcpkgDir = vcpkgDir
- self._triplet = VcpkgBuilder.tripletForPlatform(targetPlatform, static)
- self._customTripletsDir = Path(__file__).resolve().parents[1] / 'vcpkg/triplets'
- if targetPlatform == 'android' and 'ANDROID_NDK_HOME' not in os.environ:
- # Copy some of the logic from vcpkg's android ndk detection, and see if we can print a warning early
- if 'ProgramData' in os.environ:
- androidNdkFound = (pathlib.Path(os.environ['ProgramData']) / 'Microsoft/AndroidNDK64/android-ndk-r13b/').exists()
- else:
- androidNdkFound = False
- if not androidNdkFound and 'ProgramFiles(x86)' in os.environ:
- # Use Xamarin default installation folder
- androidNdkFound = (pathlib.Path(os.environ['ProgramFiles(x86)']) / 'Android/android-sdk/ndk-bundle').exists()
- if not androidNdkFound:
- raise RuntimeError('Unable to find the Android NDK. '
- 'Please set the ANDROID_NDK_HOME environment variable to the root of the Android NDK')
- @staticmethod
- def tripletForPlatform(platformName: str, static: bool):
- platformMap = {
- 'mac': {
- True: 'x64-osx',
- False: 'x64-osx-dynamic',
- },
- 'windows': {
- True: 'x64-windows-static',
- False: 'x64-windows',
- },
- 'linux': {
- True: 'x64-linux',
- False: 'x64-linux-shared',
- },
- 'android': {
- True: 'arm64-android-static', # arm64-v8a
- False: 'arm64-android', # arm64-v8a
- },
- 'ios': {
- True: 'arm64-ios',
- False: 'arm64-ios-dynamic',
- }
- }
- try:
- useStaticLibsMap = platformMap[platformName]
- except KeyError:
- raise RuntimeError(f'Platform {platformName} not supported')
- try:
- return useStaticLibsMap[static]
- except KeyError:
- raise RuntimeError('Platform {platformName} does not support building {linkageType} libraries'.format(
- platformName=platformName,
- linkageType='static' if static else 'dynamic',
- ))
- @staticmethod
- def defaultPackagePlatformName():
- platformMap = {
- 'Darwin': 'mac',
- 'Windows': 'windows',
- 'Linux': 'linux',
- }
- return platformMap[platform.system()]
- @property
- def customTripletsDir(self):
- return self._customTripletsDir
- @property
- def packageName(self):
- """The name of the package that this builder will build"""
- return self._packageName
- @property
- def portName(self):
- """The name of the vcpkg port that this builder will build"""
- return self._portName
- @property
- def vcpkgDir(self):
- """The directory where vcpkg will be cloned to"""
- return self._vcpkgDir
- @property
- def triplet(self):
- """The vcpkg triplet to build"""
- return self._triplet
- def cloneVcpkg(self, lockToCommit: str):
- if not (self.vcpkgDir / '.git').exists():
- subprocess.check_call(
- ['git', 'init',],
- cwd=self.vcpkgDir,
- )
- subprocess.check_call(
- ['git', 'remote', 'add', 'origin', 'https://github.com/microsoft/vcpkg.git',],
- cwd=self.vcpkgDir,
- )
- subprocess.check_call(
- ['git', 'fetch', 'origin', '--depth=1', lockToCommit,],
- cwd=self.vcpkgDir,
- )
- subprocess.check_call(
- ['git', 'checkout', lockToCommit,],
- cwd=self.vcpkgDir,
- )
- def bootstrap(self):
- if platform.system() == 'Windows':
- subprocess.check_call(
- ['powershell', '-NoProfile', '-ExecutionPolicy', 'Bypass', 'scripts/bootstrap.ps1',],
- cwd=self.vcpkgDir,
- )
- else:
- subprocess.check_call(
- [self.vcpkgDir / 'bootstrap-vcpkg.sh'],
- cwd=self.vcpkgDir,
- )
- def patch(self, patchFile: pathlib.Path):
- subprocess.check_output(
- ['git', 'apply', '--whitespace=fix', str(patchFile)],
- cwd=self.vcpkgDir,
- )
- def build(self):
- self.remove()
- subprocess.check_call(
- [str(self.vcpkgDir / 'vcpkg'), 'install', f'{self.portName}:{self.triplet}', '--no-binarycaching', f'--overlay-triplets={self.customTripletsDir}'],
- cwd=self.vcpkgDir,
- )
- def remove(self):
- subprocess.check_call(
- [str(self.vcpkgDir / 'vcpkg'), 'remove', f'{self.portName}:{self.triplet}', f'--overlay-triplets={self.customTripletsDir}'],
- cwd=self.vcpkgDir,
- )
- def copyBuildOutputTo(self, packageDir: pathlib.Path, extraFiles: dict, subdir:pathlib.Path=None):
- destdir = packageDir / self.packageName
- if subdir is not None:
- destdir /= subdir
- if destdir.exists():
- shutil.rmtree(destdir)
- shutil.copytree(
- src=self.vcpkgDir / 'packages' / f'{self.portName}_{self.triplet}',
- dst=destdir,
- symlinks=True,
- )
- for (src, dst) in extraFiles.items():
- try:
- shutil.copy2(src, dst)
- except IOError as e:
- # ENOENT(2): file does not exist, raised also on missing dest parent dir
- if e.errno != errno.ENOENT:
- raise
- # try creating parent directories
- Path(dst).parent.mkdir(parents=True, exist_ok=True)
- shutil.copy2(src, dst)
- def writePackageInfoFile(self, packageDir: pathlib.Path, settings: dict):
- with (packageDir / 'PackageInfo.json').open('w') as fh:
- json.dump(settings, fh, indent=4)
- def writeCMakeFindFile(self, packageDir: pathlib.Path, template, templateEnv:dict):
- cmakeFindFile = packageDir / f'Find{self.packageName}.cmake'
- cmakeFindFile.write_text(string.Template(template).substitute(templateEnv))
|