diff --git a/docs/markdown/Reference-tables.md b/docs/markdown/Reference-tables.md index 981bd18cf256..74e032209fff 100644 --- a/docs/markdown/Reference-tables.md +++ b/docs/markdown/Reference-tables.md @@ -50,6 +50,7 @@ These are return values of the `get_id` (Compiler family) and | mwasmarm | Metrowerks Assembler for Embedded ARM | | | mwasmeppc | Metrowerks Assembler for Embedded PowerPC | | | tasking | TASKING VX-toolset | | +| diab | Wind River Diab | | ## Linker ids @@ -83,6 +84,7 @@ These are return values of the `get_linker_id` method in a compiler object. | mwldarm | The Metrowerks Linker with the ARM interface, used with mwccarm only | | mwldeppc | The Metrowerks Linker with the PowerPC interface, used with mwcceppc only | | tasking | TASKING VX-toolset | +| diab | Wind River Diab | For languages that don't have separate dynamic linkers such as C# and Java, the `get_linker_id` will return the compiler name. diff --git a/docs/markdown/Release-notes.md b/docs/markdown/Release-notes.md index d7de275fc3f8..55780e6e6f0c 100644 --- a/docs/markdown/Release-notes.md +++ b/docs/markdown/Release-notes.md @@ -1 +1,6 @@ # Release notes + +## Added Wind River Diab compiler suite for bare-metal PowerPC + +Tested with C++, C and assembler using [Diab](https://www.windriver.com/products/diab-compiler) 5.2.1.0 from 2004. + diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index fa032ec7968f..edbc716f031b 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -6,6 +6,7 @@ import functools import os.path import typing as T +import enum from .. import options from .. import mlog @@ -39,7 +40,7 @@ from ..envconfig import MachineInfo from ..environment import Environment from ..linkers.linkers import DynamicLinker - from ..mesonlib import MachineChoice + from ..mesonlib import MachineChoice, File, FileOrString from ..build import BuildTarget CompilerMixinBase = CLikeCompiler else: @@ -1128,3 +1129,255 @@ def get_option_std_args(self, target: BuildTarget, env: Environment, subproject: if std != 'none': args.append('-lang ' + std) return args + +class DiabCppCompiler(CPPCompiler): + """The Wind River Diab compiler suite for bare-metal PowerPC + + The suite entry program _dplus_ handles c++, c and assembler sources, and linking. + + This object should have a DiabLinker instance in its `linker` member. + + Archiving can be done with DiabArchiver. + """ + id = "diab" + + # Target processor + processor = [ + "PPC", # Generic PowerPC + "MGT5200", + "PPC401", + "PPC403", + "PPC405", + "PPC440", + "PPC440GX", + "PPC505", + "PPC509", + "PPC553", + "PPC555", + "PPC561", + "PPC565", + "PPC601", + "PPC602", + "PPC603", + "PPC603e", + "PPC604", + "PPC740", + "PPC745", + "PPC750", + "PPC755", + "PPC801", + "PPC821", + "PPC823", + "PPC850", + "PPC852", + "PPC855", + "PPC857", + "PPC859", + "PPC860", + "PPC862", + "PPC866", + "PPC970", + "PPCE500", + "PPC5500", + "PPC5534", + "PPC5534V", + "PPC5534N", + "PPC5553", + "PPC5554", + "PPC7400", + "PPC7410", + "PPC7440", + "PPC7441", + "PPC7445", + "PPC7447", + "PPC7450", + "PPC7451", + "PPC7455", + "PPC7457", + "PPC8240", + "PPC8241", + "PPC8245", + "PPC8250", + "PPC8255", + "PPC8260", + "PPC8264", + "PPC8265", + "PPC8266", + "PPC8270", + "PPC8275", + "PPC8280", + "PPC8540", + "PPC8541", + "PPC8543", + "PPC8545", + "PPC8547", + "PPC8548", + "PPC8560", + "POWER", + ] + + # Object format + object_format = { + 'EABI': 'E', # ELF using EABI conventions + 'Motorola': 'C', # Motorola compressible ELF + 'no-small-section': 'F', # global and static scalar variables may be placed in a local data area + 'little-endian': 'L', # little-endian + 'COFF': 'D' # COFF using AIX conventions + } + + # Floating point support + floating_point = { + 'Hard': 'H', # Hardware floating point + 'HardSingle': 'F', # Single precision uses hardware, double precision uses software emulation + 'HardSingleOnly': 'G', # Single precision uses hardware, double precision is mapped to single precision + 'Vector': 'V', # Vector floating point for AltiVec with the PPC7400 or PPC970 processor only + 'Soft': 'S', # Software floating point emulation provided with the compiler + 'None': 'N' # No floating point support + } + + # Basic operating system functions + os_impl = { + 'stdinout': 'simple', # Simple character input/output for stdin and stdout only + 'ramdisk': 'cross' # Ram-disk file input/output + } + + optimization_args: T.Dict[str, T.List[str]] = { + "plain": [], + "0": [], + "g": ["-O", "-Xno-optimized-debug"], + "1": ["-O"], + "2": ["-O", "-Xinline=40"], + "3": ["XO"], + "s": ["-Xsize-opt"], + } + + class Prefix(enum.Enum): + CPP = "cpp" + CXX = "c++" + C = "c" + AS = "as" + LD = "ld" + + def _apply_prefix(self, prefix: Prefix, arg: T.Union[str, T.List[str]]) -> T.List[str]: + """Prefix commands to redirect to compiler suite sub programs""" + args = [arg] if isinstance(arg, str) else arg + return [f"-W:{prefix.value}:,{arg}" for arg in args] + + @functools.lru_cache(maxsize=None) + def can_compile(self, src: FileOrString) -> bool: + if super().can_compile(src): + return True + if isinstance(src, File): + src = src.fname + suffix = os.path.splitext(src)[1] + return suffix in {".s", ".c"} + + def get_include_args(self, path: str, is_system: bool) -> T.List[str]: + return super().get_include_args(path, is_system) + self._apply_prefix(self.Prefix.AS, f"-I{path}") + + def get_warn_args(self, level: str) -> T.List[str]: + """No such levels""" + return [] + + def get_werror_args(self) -> T.List[str]: + return ["-Xstop-on-warning"] + + def get_optimization_args(self, optimization_level: str) -> T.List[str]: + return self.optimization_args[optimization_level] + + def get_debug_args(self, is_debug: bool) -> T.List[str]: + return ['-g'] if is_debug else [] + + def _create_string_option(self, key: str, description: str) -> T.Tuple[options.OptionKey, options.UserStringArrayOption]: + return self.form_compileropt_key(key), options.UserStringArrayOption(key, description, []) + + def _create_boolean_option(self, key: str, description: str, default: bool) -> T.Tuple[options.OptionKey, options.UserBooleanOption]: + return self.form_compileropt_key(key), options.UserBooleanOption(key, description, default) + + def _create_combo_option(self, key: str, description: str, choices: T.Iterable[str]) -> T.Tuple[options.OptionKey, options.UserComboOption]: + choices = list(choices) + return self.form_compileropt_key(key), options.UserComboOption(key, description, choices[0], choices=choices) + + def get_options(self) -> 'MutableKeyedOptionDictType': + opts = super().get_options() + key = self.form_compileropt_key("std") + std_opt = opts[key] + assert isinstance(std_opt, options.UserStdOption), "for mypy" + std_opt.set_versions(["c++98"]) + opts.update([ + self._create_string_option('args', "compile args"), + self._create_string_option('link_args', "link args"), + self._create_boolean_option('eh', 'C++ exception handling', True), + self._create_boolean_option('rtti', 'RTTI enabled', True), + self._create_boolean_option('lic_wait', 'Enable waiting for available license', False), + self._create_boolean_option('subprog_cmd', 'Print subprogram cmd lines with args as they are executed', False), + self._create_boolean_option('map', 'Save linker memory map', False), + self._create_combo_option('tgt_proc', "Target processor", self.processor), + self._create_combo_option('tgt_fmt', "Target object format", self.object_format), + self._create_combo_option('tgt_fp', "Target floating point processing", self.floating_point), + self._create_combo_option('os_impl', "Basic operating system functions", self.os_impl), + ]) + return opts + + def _get_option_common_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: + args: T.List[str] = [] + + if self.get_compileropt_value('lic_wait', env, target, subproject): + args.append('-Xlicense-wait') + if self.get_compileropt_value('subprog_cmd', env, target, subproject): + args.append('-#') + + tgt_fmt = self.get_compileropt_value("tgt_fmt", env, target, subproject) + assert isinstance(tgt_fmt, str) + tgt_fp = self.get_compileropt_value("tgt_fp", env, target, subproject) + assert isinstance(tgt_fp, str) + + args.append( + "-t{0}{1}{2}:simple".format( + self.get_compileropt_value("tgt_proc", env, target, subproject), + self.object_format[tgt_fmt], + self.floating_point[tgt_fp], + ) + ) + + return args + + def get_option_compile_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: + args = self._get_option_common_args(target, env, subproject) + + if not self.get_compileropt_value('eh', env, target, subproject): + args += self._apply_prefix(self.Prefix.CXX, '-Xexceptions-off') + if not self.get_compileropt_value('rtti', env, target, subproject): + args += self._apply_prefix(self.Prefix.CXX, '-Xrtti-off') + + return args + + def get_option_std_args(self, target: BuildTarget, env: Environment, subproject: T.Optional[str] = None) -> T.List[str]: + std = self.get_compileropt_value('std', env, target, subproject) + assert isinstance(std, str) + if std == 'c++98': + return self._apply_prefix(self.Prefix.CXX, '-Xstrict-ansi') + else: + return [] + + def get_option_link_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: + args = self._get_option_common_args(target, env, subproject) + + if self.get_compileropt_value('map', env, target, subproject): + args += self.linker._apply_prefix(['-m2', '-Xunused-sections-list', '-Xcheck-overlapping', f'-@O={target.filename}.map']) + + return args + + def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], build_dir: str) -> T.List[str]: + for idx, i in enumerate(parameter_list): + if i[:2] == '-I' or i[:2] == '-L': + parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:])) + + return parameter_list + + def get_always_args(self) -> T.List[str]: + """Disable super's large-file-support""" + return [] + + def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: + return super(CPPCompiler, self).get_compiler_check_args(mode) diff --git a/mesonbuild/compilers/detect.py b/mesonbuild/compilers/detect.py index a0ae8108d7dd..6a2f75018283 100644 --- a/mesonbuild/compilers/detect.py +++ b/mesonbuild/compilers/detect.py @@ -20,6 +20,7 @@ import tempfile import os import typing as T +import itertools if T.TYPE_CHECKING: from .compilers import Compiler @@ -200,6 +201,8 @@ def detect_static_linker(env: 'Environment', compiler: Compiler) -> StaticLinker arg = '/?' elif linker_name in {'ar2000', 'ar2000.exe', 'ar430', 'ar430.exe', 'armar', 'armar.exe', 'ar6x', 'ar6x.exe'}: arg = '?' + elif linker_name in {'dar'}: + arg = '-V' else: arg = '--version' try: @@ -244,6 +247,8 @@ def detect_static_linker(env: 'Environment', compiler: Compiler) -> StaticLinker return linkers.MetrowerksStaticLinkerEmbeddedPowerPC(linker) if 'TASKING VX-toolset' in err: return linkers.TaskingStaticLinker(linker) + if 'Wind River Systems, Inc.' in out: + return linkers.DiabArchiver(linker) if p.returncode == 0: return linkers.ArLinker(compiler.for_machine, linker) if p.returncode == 1 and err.startswith('usage'): # OSX @@ -252,6 +257,7 @@ def detect_static_linker(env: 'Environment', compiler: Compiler) -> StaticLinker return linkers.AIXArLinker(linker) if p.returncode == 1 and err.startswith('ar: bad option: --'): # Solaris return linkers.ArLinker(compiler.for_machine, linker) + _handle_exceptions(popen_exceptions, trials, 'linker') raise EnvironmentException('Unreachable code (exception to make mypy happy)') @@ -321,6 +327,9 @@ def sanitize(p: T.Optional[str]) -> T.Optional[str]: elif compiler_name in {'icl', 'icl.exe'}: # if you pass anything to icl you get stuck in a pager arg = '' + elif compiler_name in {f'd{name}{suffix}' for name, suffix in itertools.product(['cc', 'plus'], ['', '.exe'])}: + # Wind River Diab + arg = '-V' else: arg = '--version' @@ -629,6 +638,11 @@ def sanitize(p: T.Optional[str]) -> T.Optional[str]: ccache, compiler, tasking_version, for_machine, is_cross, info, full_version=full_version, linker=linker) + if 'Wind River Systems, Inc.' in out: + if lang == "cpp": + linker = linkers.DiabLinker(compiler, for_machine, '-W:ld:,', [], system='none', version=version) + return cpp.DiabCppCompiler(ccache, compiler, version, for_machine, is_cross, info, linker) + _handle_exceptions(popen_exceptions, compilers) raise EnvironmentException(f'Unknown compiler {compilers}') diff --git a/mesonbuild/linkers/linkers.py b/mesonbuild/linkers/linkers.py index a905f0667bff..a3434072e3c5 100644 --- a/mesonbuild/linkers/linkers.py +++ b/mesonbuild/linkers/linkers.py @@ -8,6 +8,7 @@ import os import typing as T import re +import itertools from .base import ArLikeLinker, RSPFileSyntax from .. import mesonlib @@ -1788,3 +1789,36 @@ def get_link_whole_for(self, args: T.List[str]) -> T.List[str]: for a in args: l.extend(self._apply_prefix('-Wl--whole-archive=' + a)) return l + +class DiabLinker(DynamicLinker): + """Linker for DiabCppCompiler + + When used by DiabCppCompiler, prefix should be `-W:ld:,`, and empty if instantiated + independently controlling the Diab ld program _dld_ directly. + """ + id = 'diab' + + def get_output_args(self, outputname: str) -> T.List[str]: + return ["-o", outputname] + + def get_search_args(self, dirname: str) -> T.List[str]: + return ["-L", dirname] + + def get_allow_undefined_args(self) -> T.List[str]: + return [] + + def get_link_whole_for(self, args: T.List[str]) -> T.List[str]: + return list(itertools.chain(*([self._apply_prefix("-A")[0], arg] for arg in args))) + +class DiabArchiver(StaticLinker): + """Archiver for DiabCppCompiler""" + id = 'diab' + + def can_linker_accept_rsp(self) -> bool: + return False + + def get_output_args(self, target: str) -> T.List[str]: + return [target] + + def get_std_link_args(self, env: 'Environment', is_thin: bool) -> T.List[str]: + return ["-rc"]