|
| 1 | +from dan.core.requirements import RequiredPackage |
| 2 | +from dan.core.target import Target, FileDependency, Installer |
| 3 | +from dan.core.runners import async_run |
| 4 | +from dan.core.pm import re_match |
| 5 | +from dan.core import aiofiles |
| 6 | +from dan.core.find import find_executable, find_file |
| 7 | +from dan.cxx import Toolchain |
| 8 | + |
| 9 | +import typing as t |
| 10 | + |
| 11 | + |
| 12 | +class Project(Target, internal=True): |
| 13 | + |
| 14 | + cmake_targets: list[str] = None |
| 15 | + cmake_config_definitions: dict[str, str] = dict() |
| 16 | + cmake_patch_debug_postfix: list = None |
| 17 | + cmake_options: dict[str, tuple[str, t.Any, str]] = None |
| 18 | + |
| 19 | + def __init__(self, *args, **kwargs): |
| 20 | + super().__init__(*args, **kwargs) |
| 21 | + self.cmake_cache_dep = FileDependency(self.build_path / 'CMakeCache.txt') |
| 22 | + self.dependencies.add(self.cmake_cache_dep) |
| 23 | + self.toolchain : Toolchain = self.context.get('cxx_target_toolchain') |
| 24 | + |
| 25 | + async def _cmake(self, *cmake_args, **kwargs): |
| 26 | + return await async_run(['cmake', *cmake_args], logger=self, cwd=self.build_path, **kwargs, env=self.toolchain.env) |
| 27 | + |
| 28 | + @property |
| 29 | + def _target_args(self): |
| 30 | + targets_args = [] |
| 31 | + if self.cmake_targets is not None: |
| 32 | + for target in self.cmake_targets: |
| 33 | + targets_args.extend(('-t', target)) |
| 34 | + return targets_args |
| 35 | + |
| 36 | + async def __initialize__(self): |
| 37 | + if self.cmake_options is not None: |
| 38 | + for name, (cmake_name, default, help) in self.cmake_options.items(): |
| 39 | + opt = self.options.add(name, default, help) |
| 40 | + setattr(opt, 'cmake_name', cmake_name) |
| 41 | + return await super().__initialize__() |
| 42 | + |
| 43 | + async def __build__(self): |
| 44 | + cmake_options = dict() |
| 45 | + for opt in self.options: |
| 46 | + if hasattr(opt, 'cmake_name'): |
| 47 | + value = opt.value |
| 48 | + if isinstance(value, bool): |
| 49 | + value = 'ON' if value else 'OFF' |
| 50 | + cmake_options[opt.cmake_name] = value |
| 51 | + |
| 52 | + cmake_options['CMAKE_PREFIX_PATH'] = self.makefile.root.pkgs_path.as_posix() |
| 53 | + |
| 54 | + base_opts = [] |
| 55 | + if self.toolchain.system.startswith('msys'): |
| 56 | + make = find_executable(r'.+make', self.toolchain.env['PATH'].split(';'), default_paths=False) |
| 57 | + base_opts.extend((f'-GMinGW Makefiles', f'-DCMAKE_MAKE_PROGRAM={make.as_posix()}')) |
| 58 | + |
| 59 | + await self._cmake( |
| 60 | + self.source_path, |
| 61 | + *base_opts, |
| 62 | + f'-DCMAKE_BUILD_TYPE={self.toolchain.build_type.name.upper()}', |
| 63 | + f'-DCMAKE_CONFIGURATION_TYPES={self.toolchain.build_type.name.upper()}', |
| 64 | + f'-DCMAKE_C_COMPILER={self.toolchain.cc.as_posix()}', |
| 65 | + f'-DCMAKE_CXX_COMPILER={self.toolchain.cxx.as_posix()}', |
| 66 | + *[f'-D{k}={v}' for k, v in self.cmake_config_definitions.items()], |
| 67 | + *[f'-D{k}={v}' for k, v in cmake_options.items()] |
| 68 | + ) |
| 69 | + await self._cmake('--build', '.', '--parallel', *self._target_args) |
| 70 | + |
| 71 | + async def __install__(self, installer: Installer): |
| 72 | + await self.build() |
| 73 | + await self._cmake('.', f'-DCMAKE_INSTALL_PREFIX={installer.settings.destination}') |
| 74 | + await self._cmake('--install', '.', *self._target_args) |
| 75 | + await super().__install__(installer) |
| 76 | + async with aiofiles.open(self.build_path / 'install_manifest.txt') as manifest_file: |
| 77 | + manifest = await manifest_file.readlines() |
| 78 | + |
| 79 | + if self.cmake_patch_debug_postfix is not None and self.toolchain.build_type.is_debug_mode: |
| 80 | + # fix: no 'd' postfix in MSVC pkgconfig |
| 81 | + seach_paths = [ |
| 82 | + installer.settings.data_destination / 'pkgconfig', |
| 83 | + installer.settings.libraries_destination / 'pkgconfig', |
| 84 | + ] |
| 85 | + for provided in self.provides: |
| 86 | + pc_file = find_file(rf'{provided}\.pc', paths=seach_paths) |
| 87 | + self.debug('patching %s', pc_file) |
| 88 | + for name in self.cmake_patch_debug_postfix: |
| 89 | + await aiofiles.sub(pc_file, rf'-l{name}(\s)', rf'-l{name}d\g<1>') |
| 90 | + |
| 91 | + installer.installed_files.extend(manifest) |
0 commit comments