From ba860d72a96932608bb2b13a2f32ebda0087905a Mon Sep 17 00:00:00 2001 From: Liza Chevalier Date: Wed, 29 Oct 2025 11:17:00 -0500 Subject: compilers: add Microchip XC32 compiler The Microchip XC32 compiler is a GCC-based compiler implemented using existing GNU compiler classes. As the XC32 version and GCC version do not match mixins have been implemented to override versions used in versions checks where applicable. --- cross/xc32.txt | 17 ++ docs/markdown/Reference-tables.md | 3 + .../snippets/add_microchip_xc32_compiler.md | 3 + mesonbuild/compilers/c.py | 17 +- mesonbuild/compilers/cpp.py | 17 +- mesonbuild/compilers/detect.py | 44 +++-- mesonbuild/compilers/mixins/microchip.py | 195 +++++++++++++++++++++ mesonbuild/compilers/mixins/xc16.py | 111 ------------ mesonbuild/envconfig.py | 1 + mesonbuild/linkers/linkers.py | 28 +++ 10 files changed, 313 insertions(+), 123 deletions(-) create mode 100644 cross/xc32.txt create mode 100644 docs/markdown/snippets/add_microchip_xc32_compiler.md create mode 100644 mesonbuild/compilers/mixins/microchip.py delete mode 100644 mesonbuild/compilers/mixins/xc16.py diff --git a/cross/xc32.txt b/cross/xc32.txt new file mode 100644 index 000000000..dd3d026b8 --- /dev/null +++ b/cross/xc32.txt @@ -0,0 +1,17 @@ +# This file assumes that path to the Microchip XC32 toolchain is added +# to the environment(PATH) variable, so that Meson can find XC32 while building. + +[binaries] +c = 'xc32-gcc' +cpp = 'xc32-g++' +ar = 'xc32-ar' +bin2hex = 'xc32-bin2hex' + +[host_machine] +system = 'baremetal' +cpu_family = 'pic32' +cpu = 'pic32' +endian = 'little' + +[properties] +needs_exe_wrapper = true diff --git a/docs/markdown/Reference-tables.md b/docs/markdown/Reference-tables.md index 981bd18cf..0bb10e5e0 100644 --- a/docs/markdown/Reference-tables.md +++ b/docs/markdown/Reference-tables.md @@ -42,6 +42,7 @@ These are return values of the `get_id` (Compiler family) and | ti | Texas Instruments C/C++ Compiler | | | valac | Vala compiler | | | xc16 | Microchip XC16 C compiler | | +| xc32-gcc | Microchip XC32 C/C++ compiler | gcc | | cython | The Cython compiler | | | nasm | The NASM compiler (Since 0.64.0) | | | yasm | The YASM compiler (Since 0.64.0) | | @@ -73,6 +74,7 @@ These are return values of the `get_linker_id` method in a compiler object. | optlink | optlink (used with DMD) | | rlink | The Renesas linker, used with CCrx only | | xc16-ar | The Microchip linker, used with XC16 only | +| ld.xc32 | The Microchip linker, used with XC32 only | | ar2000 | The Texas Instruments linker, used with C2000 only | | ti-ar | The Texas Instruments linker | | ar6000 | The Texas Instruments linker, used with C6000 only | @@ -126,6 +128,7 @@ set in the cross file. | msp430 | 16 bit MSP430 processor | | parisc | HP PA-RISC processor | | pic24 | 16 bit Microchip PIC24 | +| pic32 | 32 bit Microchip PIC32 | | ppc | 32 bit PPC processors | | ppc64 | 64 bit PPC processors | | riscv32 | 32 bit RISC-V Open ISA | diff --git a/docs/markdown/snippets/add_microchip_xc32_compiler.md b/docs/markdown/snippets/add_microchip_xc32_compiler.md new file mode 100644 index 000000000..2b44f4681 --- /dev/null +++ b/docs/markdown/snippets/add_microchip_xc32_compiler.md @@ -0,0 +1,3 @@ +## Microchip XC32 compiler support + +The Microchip XC32 compiler is now supported. diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 424b61251..53ef28e13 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -15,7 +15,7 @@ from .c_function_attributes import C_FUNC_ATTRIBUTES from .mixins.apple import AppleCompilerMixin, AppleCStdsMixin from .mixins.clike import CLikeCompiler from .mixins.ccrx import CcrxCompiler -from .mixins.xc16 import Xc16Compiler +from .mixins.microchip import Xc16Compiler, Xc32Compiler, Xc32CStds from .mixins.compcert import CompCertCompiler from .mixins.ti import TICompiler from .mixins.arm import ArmCompiler, ArmclangCompiler @@ -643,6 +643,21 @@ class Xc16CCompiler(Xc16Compiler, CCompiler): path = '.' return ['-I' + path] + +class Xc32CCompiler(Xc32CStds, Xc32Compiler, GnuCCompiler): + + """Microchip XC32 C compiler.""" + + def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: MachineInfo, + linker: T.Optional[DynamicLinker] = None, + defines: T.Optional[T.Dict[str, str]] = None, + full_version: T.Optional[str] = None): + GnuCCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, + info, linker=linker, full_version=full_version, defines=defines) + Xc32Compiler.__init__(self) + + class CompCertCCompiler(CompCertCompiler, CCompiler): def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index 8533373a8..b57cbec62 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -32,6 +32,7 @@ from .mixins.pgi import PGICompiler from .mixins.emscripten import EmscriptenMixin from .mixins.metrowerks import MetrowerksCompiler from .mixins.metrowerks import mwccarm_instruction_set_args, mwcceppc_instruction_set_args +from .mixins.microchip import Xc32Compiler, Xc32CPPStds if T.TYPE_CHECKING: from ..options import MutableKeyedOptionDictType @@ -158,7 +159,7 @@ class CPPCompiler(CLikeCompiler, Compiler): } # Currently, remapping is only supported for Clang, Elbrus and GCC - assert self.id in frozenset(['clang', 'lcc', 'gcc', 'emscripten', 'armltdclang', 'intel-llvm', 'nvidia_hpc']) + assert self.id in frozenset(['clang', 'lcc', 'gcc', 'emscripten', 'armltdclang', 'intel-llvm', 'nvidia_hpc', 'xc32-gcc']) if cpp_std not in CPP_FALLBACKS: # 'c++03' and 'c++98' don't have fallback types @@ -1128,3 +1129,17 @@ class MetrowerksCPPCompilerEmbeddedPowerPC(MetrowerksCompiler, CPPCompiler): if std != 'none': args.append('-lang ' + std) return args + + +class Xc32CPPCompiler(Xc32CPPStds, Xc32Compiler, GnuCPPCompiler): + + """Microchip XC32 C++ compiler.""" + + def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: MachineInfo, + linker: T.Optional[DynamicLinker] = None, + defines: T.Optional[T.Dict[str, str]] = None, + full_version: T.Optional[str] = None): + GnuCPPCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross, + info, linker=linker, full_version=full_version, defines=defines) + Xc32Compiler.__init__(self) diff --git a/mesonbuild/compilers/detect.py b/mesonbuild/compilers/detect.py index 979b9ce60..0a5f55ddd 100644 --- a/mesonbuild/compilers/detect.py +++ b/mesonbuild/compilers/detect.py @@ -227,8 +227,11 @@ def detect_static_linker(env: 'Environment', compiler: Compiler) -> StaticLinker return linkers.DLinker(linker, compiler.arch) if err.startswith('Renesas') and 'rlink' in linker_name: return linkers.CcrxLinker(linker) - if out.startswith('GNU ar') and 'xc16-ar' in linker_name: - return linkers.Xc16Linker(linker) + if out.startswith('GNU ar'): + if 'xc16-ar' in linker_name: + return linkers.Xc16Linker(linker) + elif 'xc32-ar' in linker_name: + return linkers.Xc32ArLinker(compiler.for_machine, linker) if 'Texas Instruments Incorporated' in out: if 'ar2000' in linker_name: return linkers.C2000Linker(linker) @@ -343,7 +346,7 @@ def _detect_c_or_cpp_compiler(env: 'Environment', lang: str, for_machine: Machin guess_gcc_or_lcc = 'gcc' if 'e2k' in out and 'lcc' in out: guess_gcc_or_lcc = 'lcc' - if 'Microchip Technology' in out: + if 'Microchip' in out: # this output has "Free Software Foundation" in its version guess_gcc_or_lcc = None @@ -567,13 +570,34 @@ def _detect_c_or_cpp_compiler(env: 'Environment', lang: str, for_machine: Machin ccache, compiler, version, for_machine, is_cross, info, full_version=full_version, linker=linker) - if 'Microchip Technology' in out: - cls = c.Xc16CCompiler - env.add_lang_args(cls.language, cls, for_machine) - linker = linkers.Xc16DynamicLinker(for_machine, version=version) - return cls( - ccache, compiler, version, for_machine, is_cross, info, - full_version=full_version, linker=linker) + if 'Microchip' in out: + if 'XC32' in out: + # XC32 versions always have the form 'vMAJOR.MINOR' + match = re.search(r'XC32.*v(\d+\.\d+)', out) + if match: + version = match.group(1) + else: + raise EnvironmentException(f'Failed to detect XC32 compiler version: full version was\n{full_version}') + + cls = c.Xc32CCompiler if lang == 'c' else cpp.Xc32CPPCompiler + defines = _get_gnu_compiler_defines(compiler, lang) + cls.gcc_version = _get_gnu_version_from_defines(defines) + + env.add_lang_args(cls.language, cls, for_machine) + linker = linkers.Xc32DynamicLinker(compiler, for_machine, cls.LINKER_PREFIX, [], version=version) + + return cls( + ccache, compiler, version, for_machine, is_cross, + info, defines=defines, full_version=full_version, + linker=linker) + else: + cls = c.Xc16CCompiler + env.add_lang_args(cls.language, cls, for_machine) + linker = linkers.Xc16DynamicLinker(for_machine, version=version) + + return cls( + ccache, compiler, version, for_machine, is_cross, info, + full_version=full_version, linker=linker) if 'CompCert' in out: cls = c.CompCertCCompiler diff --git a/mesonbuild/compilers/mixins/microchip.py b/mesonbuild/compilers/mixins/microchip.py new file mode 100644 index 000000000..6b989cba8 --- /dev/null +++ b/mesonbuild/compilers/mixins/microchip.py @@ -0,0 +1,195 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2012-2019 The Meson development team + +from __future__ import annotations + +"""Representations specific to the Microchip XC C/C++ compiler family.""" + +import os +import typing as T + +from .gnu import GnuCStds, GnuCPPStds +from ..compilers import Compiler +from ...mesonlib import EnvironmentException, version_compare + +if T.TYPE_CHECKING: + from ...envconfig import MachineInfo + from ...environment import Environment + + CompilerBase = Compiler +else: + # This is a bit clever, for mypy we pretend that these mixins descend from + # Compiler, so we get all of the methods and attributes defined for us, but + # for runtime we make them descend from object (which all classes normally + # do). This gives up DRYer type checking, with no runtime impact + CompilerBase = object + +xc16_optimization_args: T.Dict[str, T.List[str]] = { + 'plain': [], + '0': ['-O0'], + 'g': ['-O0'], + '1': ['-O1'], + '2': ['-O2'], + '3': ['-O3'], + 's': ['-Os'] +} + +xc16_debug_args: T.Dict[bool, T.List[str]] = { + False: [], + True: [] +} + + +class Xc16Compiler(Compiler): + + id = 'xc16' + + def __init__(self) -> None: + if not self.is_cross: + raise EnvironmentException('xc16 supports only cross-compilation.') + # Assembly + self.can_compile_suffixes.add('s') + self.can_compile_suffixes.add('sx') + default_warn_args: T.List[str] = [] + self.warn_args = {'0': [], + '1': default_warn_args, + '2': default_warn_args + [], + '3': default_warn_args + [], + 'everything': default_warn_args + []} + + def get_always_args(self) -> T.List[str]: + return [] + + def get_pic_args(self) -> T.List[str]: + # PIC support is not enabled by default for xc16, + # if users want to use it, they need to add the required arguments explicitly + return [] + + def get_pch_suffix(self) -> str: + return 'pch' + + def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: + return [] + + def thread_flags(self, env: 'Environment') -> T.List[str]: + return [] + + def get_coverage_args(self) -> T.List[str]: + return [] + + def get_no_stdinc_args(self) -> T.List[str]: + return ['-nostdinc'] + + def get_no_stdlib_link_args(self) -> T.List[str]: + return ['--nostdlib'] + + def get_optimization_args(self, optimization_level: str) -> T.List[str]: + return xc16_optimization_args[optimization_level] + + def get_debug_args(self, is_debug: bool) -> T.List[str]: + return xc16_debug_args[is_debug] + + @classmethod + def _unix_args_to_native(cls, args: T.List[str], info: MachineInfo) -> T.List[str]: + result = [] + for i in args: + if i.startswith('-D'): + i = '-D' + i[2:] + if i.startswith('-I'): + i = '-I' + i[2:] + if i.startswith('-Wl,-rpath='): + continue + elif i == '--print-search-dirs': + continue + elif i.startswith('-L'): + continue + result.append(i) + return result + + 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[:9] == '-I': + parameter_list[idx] = i[:9] + os.path.normpath(os.path.join(build_dir, i[9:])) + + return parameter_list + + +class Xc32Compiler(CompilerBase): + + """Microchip XC32 compiler mixin. GCC based with some options disabled.""" + + id = 'xc32-gcc' + + gcc_version = '4.5.1' # Defaults to GCC version used by first XC32 release (v1.00). + + _COLOR_VERSION = ">=3.0" # XC32 version based on GCC 8.3.1+ + _WPEDANTIC_VERSION = ">=1.40" # XC32 version based on GCC 4.8.3+ + _LTO_AUTO_VERSION = "==-1" + _USE_MOLD_VERSION = "==-1" + + def __init__(self) -> None: + if not self.is_cross: + raise EnvironmentException("XC32 supports only cross-compilation.") + + def get_instruction_set_args(self, instruction_set: str) -> T.Optional[T.List[str]]: + return None + + def thread_flags(self, env: Environment) -> T.List[str]: + return [] + + def openmp_flags(self, env: Environment) -> T.List[str]: + return Compiler.openmp_flags(self, env) + + def get_pic_args(self) -> T.List[str]: + return Compiler.get_pic_args(self) + + def get_pie_args(self) -> T.List[str]: + return Compiler.get_pie_args(self) + + def get_profile_generate_args(self) -> T.List[str]: + return Compiler.get_profile_generate_args(self) + + def get_profile_use_args(self) -> T.List[str]: + return Compiler.get_profile_use_args(self) + + def sanitizer_compile_args(self, value: T.List[str]) -> T.List[str]: + return [] + + @classmethod + def use_linker_args(cls, linker: str, version: str) -> T.List[str]: + return [] + + def get_coverage_args(self) -> T.List[str]: + return [] + + def get_largefile_args(self) -> T.List[str]: + return [] + + def get_prelink_args(self, prelink_name: str, obj_list: T.List[str]) -> T.Tuple[T.List[str], T.List[str]]: + return Compiler.get_prelink_args(self, prelink_name, obj_list) + + def get_prelink_append_compile_args(self) -> bool: + return False + + def supported_warn_args(self, warn_args_by_version: T.Dict[str, T.List[str]]) -> T.List[str]: + result: T.List[str] = [] + for version, warn_args in warn_args_by_version.items(): + if version_compare(self.gcc_version, '>=' + version): + result += warn_args + return result + +class Xc32CStds(GnuCStds): + + """Mixin for setting C standards based on XC32 version.""" + + _C18_VERSION = ">=3.0" + _C2X_VERSION = "==-1" + _C23_VERSION = "==-1" + _C2Y_VERSION = "==-1" + +class Xc32CPPStds(GnuCPPStds): + + """Mixin for setting C++ standards based on XC32 version.""" + + _CPP23_VERSION = "==-1" + _CPP26_VERSION = "==-1" diff --git a/mesonbuild/compilers/mixins/xc16.py b/mesonbuild/compilers/mixins/xc16.py deleted file mode 100644 index d95674e3e..000000000 --- a/mesonbuild/compilers/mixins/xc16.py +++ /dev/null @@ -1,111 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -# Copyright 2012-2019 The Meson development team - -from __future__ import annotations - -"""Representations specific to the Microchip XC16 C compiler family.""" - -import os -import typing as T - -from ...mesonlib import EnvironmentException - -if T.TYPE_CHECKING: - from ...envconfig import MachineInfo - from ...environment import Environment - from ...compilers.compilers import Compiler -else: - # This is a bit clever, for mypy we pretend that these mixins descend from - # Compiler, so we get all of the methods and attributes defined for us, but - # for runtime we make them descend from object (which all classes normally - # do). This gives up DRYer type checking, with no runtime impact - Compiler = object - -xc16_optimization_args: T.Dict[str, T.List[str]] = { - 'plain': [], - '0': ['-O0'], - 'g': ['-O0'], - '1': ['-O1'], - '2': ['-O2'], - '3': ['-O3'], - 's': ['-Os'] -} - -xc16_debug_args: T.Dict[bool, T.List[str]] = { - False: [], - True: [] -} - - -class Xc16Compiler(Compiler): - - id = 'xc16' - - def __init__(self) -> None: - if not self.is_cross: - raise EnvironmentException('xc16 supports only cross-compilation.') - # Assembly - self.can_compile_suffixes.add('s') - self.can_compile_suffixes.add('sx') - default_warn_args: T.List[str] = [] - self.warn_args = {'0': [], - '1': default_warn_args, - '2': default_warn_args + [], - '3': default_warn_args + [], - 'everything': default_warn_args + []} - - def get_always_args(self) -> T.List[str]: - return [] - - def get_pic_args(self) -> T.List[str]: - # PIC support is not enabled by default for xc16, - # if users want to use it, they need to add the required arguments explicitly - return [] - - def get_pch_suffix(self) -> str: - return 'pch' - - def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: - return [] - - def thread_flags(self, env: 'Environment') -> T.List[str]: - return [] - - def get_coverage_args(self) -> T.List[str]: - return [] - - def get_no_stdinc_args(self) -> T.List[str]: - return ['-nostdinc'] - - def get_no_stdlib_link_args(self) -> T.List[str]: - return ['--nostdlib'] - - def get_optimization_args(self, optimization_level: str) -> T.List[str]: - return xc16_optimization_args[optimization_level] - - def get_debug_args(self, is_debug: bool) -> T.List[str]: - return xc16_debug_args[is_debug] - - @classmethod - def _unix_args_to_native(cls, args: T.List[str], info: MachineInfo) -> T.List[str]: - result = [] - for i in args: - if i.startswith('-D'): - i = '-D' + i[2:] - if i.startswith('-I'): - i = '-I' + i[2:] - if i.startswith('-Wl,-rpath='): - continue - elif i == '--print-search-dirs': - continue - elif i.startswith('-L'): - continue - result.append(i) - return result - - 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[:9] == '-I': - parameter_list[idx] = i[:9] + os.path.normpath(os.path.join(build_dir, i[9:])) - - return parameter_list diff --git a/mesonbuild/envconfig.py b/mesonbuild/envconfig.py index f4616ac14..048cc8a6d 100644 --- a/mesonbuild/envconfig.py +++ b/mesonbuild/envconfig.py @@ -56,6 +56,7 @@ known_cpu_families = ( 'msp430', 'parisc', 'pic24', + 'pic32', 'ppc', 'ppc64', 'riscv32', diff --git a/mesonbuild/linkers/linkers.py b/mesonbuild/linkers/linkers.py index a905f0667..461bcc279 100644 --- a/mesonbuild/linkers/linkers.py +++ b/mesonbuild/linkers/linkers.py @@ -479,6 +479,14 @@ class Xc16Linker(StaticLinker): def get_linker_always_args(self) -> T.List[str]: return ['rcs'] + +class Xc32ArLinker(ArLinker): + + """Static linker for Microchip XC32 compiler.""" + + id = 'xc32-ar' + + class CompCertLinker(StaticLinker): def __init__(self, exelist: T.List[str]): @@ -1112,6 +1120,26 @@ class Xc16DynamicLinker(DynamicLinker): target: BuildTarget, extra_paths: T.Optional[T.List[str]] = None) -> T.Tuple[T.List[str], T.Set[bytes]]: return ([], set()) + +class Xc32DynamicLinker(GnuDynamicLinker): + + """Linker for Microchip XC32 compiler.""" + + id = 'ld.xc32' + + def sanitizer_args(self, value: T.List[str]) -> T.List[str]: + return [] + + def get_coverage_args(self) -> T.List[str]: + return DynamicLinker.get_coverage_args(self) + + def get_pie_args(self) -> T.List[str]: + return DynamicLinker.get_pie_args(self) + + def thread_flags(self, env: Environment) -> T.List[str]: + return [] + + class CompCertDynamicLinker(DynamicLinker): """Linker for CompCert C compiler.""" -- cgit v1.2.3