Skip to content
This repository has been archived by the owner on Feb 15, 2025. It is now read-only.

Commit

Permalink
Initial support for Metrowerks C/C++ compiler
Browse files Browse the repository at this point in the history
  • Loading branch information
Nomura-RH authored and eli-schwartz committed Apr 24, 2023
1 parent bda799d commit 18cfa54
Show file tree
Hide file tree
Showing 14 changed files with 571 additions and 5 deletions.
28 changes: 28 additions & 0 deletions cross/metrowerks-arm.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# This file assumes that the path to your Metrowerks Embedded ARM
# toolchain is added to the environment(PATH) variable, so that
# Meson can find the binaries while building.

# You should also do one of the following to ensure Meson can
# locate the .lcf linker script:
# - Add the cross directory to PATH as well
# - Edit c_link_args and cpp_link_args with the full
# path to the .lcf file on your machine

[binaries]
c = 'mwccarm'
c_ld = 'mwldarm'
cpp = 'mwccarm'
cpp_ld = 'mwldarm'
ar = 'mwldarm'
as = 'mwasmarm'

[built-in options]
c_args = ['-lang', 'c99', '-D_NITRO', '-nosyspath']
c_link_args = 'metrowerks.lcf'
cpp_args = ['-lang', 'c++', '-D_NITRO', '-nosyspath']
cpp_link_args = 'metrowerks.lcf'

[host_machine]
system = 'bare metal'
cpu_family = 'arm'
endian = 'little'
28 changes: 28 additions & 0 deletions cross/metrowerks-eppc.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# This file assumes that the path to your Metrowerks toolchain
# of choice is added to the environment(PATH) variable, so that
# Meson can find the binaries while building.

# You should also do one of the following to ensure Meson can
# locate the .lcf linker script:
# - Add the cross directory to PATH as well
# - Edit c_link_args and cpp_link_args with the full
# path to the lcf file on your machine

[binaries]
c = 'mwcceppc'
c_ld = 'mwldeppc'
cpp = 'mwcceppc'
cpp_ld = 'mwldeppc'
ar = 'mwldeppc'
as = 'mwasmeppc'

[built-in options]
c_args = ['-lang', 'c99', '-nosyspath']
c_link_args = 'metrowerks.lcf'
cpp_args = ['-lang', 'c++', '-nosyspath']
cpp_link_args = 'metrowerks.lcf'

[host_machine]
system = 'bare metal'
cpu_family = 'ppc'
endian = 'little'
18 changes: 18 additions & 0 deletions cross/metrowerks.lcf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# General-purpose linker script for Metrowerks toolchains.
# This script will link a blank application. Its only purpose
# is to allow the toolchains to run Meson tests. To link an
# actual application, you need to write your own fine-tuned lcf.

MEMORY {
TEST (RWX) : ORIGIN=0, LENGTH=0
}

SECTIONS {
.TEST:{
* (.text)
* (.data)
* (.rodata)
* (.bss)
__startup=.;
} > TEST
}
4 changes: 4 additions & 0 deletions docs/markdown/Reference-tables.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ These are return values of the `get_id` (Compiler family) and
| lcc | Elbrus C/C++/Fortran Compiler | |
| llvm | LLVM-based compiler (Swift, D) | |
| mono | Xamarin C# compiler | |
| mwccarm | Metrowerks C/C++ compiler for Embedded ARM | |
| mwcceppc | Metrowerks C/C++ compiler for Embedded PowerPC | |
| msvc | Microsoft Visual Studio | msvc |
| nagfor | The NAG Fortran compiler | |
| nvidia_hpc| NVidia HPC SDK compilers | |
Expand Down Expand Up @@ -69,6 +71,8 @@ These are return values of the `get_linker_id` method in a compiler object.
| pgi | Portland/Nvidia PGI |
| nvlink | Nvidia Linker used with cuda |
| ccomp | CompCert used as the linker driver |
| mwldarm | The Metrowerks Linker with the ARM interface, used with mwccarm only |
| mwldeppc | The Metrowerks Linker with the PowerPC interface, used with mwcceppc only |

For languages that don't have separate dynamic linkers such as C# and Java, the
`get_linker_id` will return the compiler name.
Expand Down
5 changes: 5 additions & 0 deletions docs/markdown/snippets/add_metrowerks_compiler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## Added Metrowerks C/C++ toolchains

Added support for the Metrowerks Embedded ARM and Metrowerks Embedded PowerPC toolchains (https://www.nxp.com/docs/en/reference-manual/CWMCUKINCMPREF.pdf).

The implementation is somewhat experimental. It has been tested on a few projects and works fairly well, but may have issues.
18 changes: 17 additions & 1 deletion mesonbuild/backend/ninjabackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -2446,7 +2446,12 @@ def generate_pch_rule_for(self, langname, compiler):
output = []
else:
output = NinjaCommandArg.list(compiler.get_output_args('$out'), Quoting.none)
command = compiler.get_exelist() + ['$ARGS'] + depargs + output + compiler.get_compile_only_args() + ['$in']

if 'mwcc' in compiler.id:
output[0].s = '-precompile'
command = compiler.get_exelist() + ['$ARGS'] + depargs + output + ['$in'] # '-c' must be removed
else:
command = compiler.get_exelist() + ['$ARGS'] + depargs + output + compiler.get_compile_only_args() + ['$in']
description = 'Precompiling header $in'
if compiler.get_argument_syntax() == 'msvc':
deps = 'msvc'
Expand Down Expand Up @@ -3024,6 +3029,13 @@ def generate_gcc_pch_command(self, target, compiler, pch):
dep = dst + '.' + compiler.get_depfile_suffix()
return commands, dep, dst, [] # Gcc does not create an object file during pch generation.

def generate_mwcc_pch_command(self, target, compiler, pch):
commands = self._generate_single_compile(target, compiler)
dst = os.path.join(self.get_target_private_dir(target),
os.path.basename(pch) + '.' + compiler.get_pch_suffix())
dep = os.path.splitext(dst)[0] + '.' + compiler.get_depfile_suffix()
return commands, dep, dst, [] # mwcc compilers do not create an object file during pch generation.

def generate_pch(self, target, header_deps=None):
header_deps = header_deps if header_deps is not None else []
pch_objects = []
Expand All @@ -3042,6 +3054,10 @@ def generate_pch(self, target, header_deps=None):
elif compiler.id == 'intel':
# Intel generates on target generation
continue
elif 'mwcc' in compiler.id:
src = os.path.join(self.build_to_src, target.get_source_subdir(), pch[0])
(commands, dep, dst, objs) = self.generate_mwcc_pch_command(target, compiler, pch[0])
extradep = None
else:
src = os.path.join(self.build_to_src, target.get_source_subdir(), pch[0])
(commands, dep, dst, objs) = self.generate_gcc_pch_command(target, compiler, pch[0])
Expand Down
3 changes: 3 additions & 0 deletions mesonbuild/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -1875,6 +1875,9 @@ def post_init(self) -> None:
elif ('c' in self.compilers and self.compilers['c'].get_id() in {'ti', 'c2000'} or
'cpp' in self.compilers and self.compilers['cpp'].get_id() in {'ti', 'c2000'}):
self.suffix = 'out'
elif ('c' in self.compilers and self.compilers['c'].get_id() in {'mwccarm', 'mwcceppc'} or
'cpp' in self.compilers and self.compilers['cpp'].get_id() in {'mwccarm', 'mwcceppc'}):
self.suffix = 'nef'
else:
self.suffix = machine.get_exe_suffix()
self.filename = self.name
Expand Down
59 changes: 59 additions & 0 deletions mesonbuild/compilers/c.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
from .mixins.elbrus import ElbrusCompiler
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 .compilers import (
gnu_winlibs,
msvc_winlibs,
Expand Down Expand Up @@ -738,3 +740,60 @@ def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]
class C2000CCompiler(TICCompiler):
# Required for backwards compat with projects created before ti-cgt support existed
id = 'c2000'

class MetrowerksCCompilerARM(MetrowerksCompiler, CCompiler):
id = 'mwccarm'

def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice,
is_cross: bool, info: 'MachineInfo',
exe_wrapper: T.Optional['ExternalProgram'] = None,
linker: T.Optional['DynamicLinker'] = None,
full_version: T.Optional[str] = None):
CCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross,
info, exe_wrapper, linker=linker, full_version=full_version)
MetrowerksCompiler.__init__(self)

def get_instruction_set_args(self, instruction_set: str) -> T.Optional[T.List[str]]:
return mwccarm_instruction_set_args.get(instruction_set, None)

def get_options(self) -> 'MutableKeyedOptionDictType':
opts = CCompiler.get_options(self)
c_stds = ['c99']
opts[OptionKey('std', machine=self.for_machine, lang=self.language)].choices = ['none'] + c_stds
return opts

def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
args = []
std = options[OptionKey('std', machine=self.for_machine, lang=self.language)]
if std.value != 'none':
args.append('-lang')
args.append(std.value)
return args

class MetrowerksCCompilerEmbeddedPowerPC(MetrowerksCompiler, CCompiler):
id = 'mwcceppc'

def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice,
is_cross: bool, info: 'MachineInfo',
exe_wrapper: T.Optional['ExternalProgram'] = None,
linker: T.Optional['DynamicLinker'] = None,
full_version: T.Optional[str] = None):
CCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross,
info, exe_wrapper, linker=linker, full_version=full_version)
MetrowerksCompiler.__init__(self)

def get_instruction_set_args(self, instruction_set: str) -> T.Optional[T.List[str]]:
return mwcceppc_instruction_set_args.get(instruction_set, None)

def get_options(self) -> 'MutableKeyedOptionDictType':
opts = CCompiler.get_options(self)
c_stds = ['c99']
opts[OptionKey('std', machine=self.for_machine, lang=self.language)].choices = ['none'] + c_stds
return opts

def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
args = []
std = options[OptionKey('std', machine=self.for_machine, lang=self.language)]
if std.value != 'none':
args.append('-lang ' + std.value)
return args
59 changes: 59 additions & 0 deletions mesonbuild/compilers/cpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
from .mixins.elbrus import ElbrusCompiler
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

if T.TYPE_CHECKING:
from .compilers import CompileCheckMode
Expand Down Expand Up @@ -893,3 +895,60 @@ def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
class C2000CPPCompiler(TICPPCompiler):
# Required for backwards compat with projects created before ti-cgt support existed
id = 'c2000'

class MetrowerksCPPCompilerARM(MetrowerksCompiler, CPPCompiler):
id = 'mwccarm'

def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice,
is_cross: bool, info: 'MachineInfo',
exe_wrapper: T.Optional['ExternalProgram'] = None,
linker: T.Optional['DynamicLinker'] = None,
full_version: T.Optional[str] = None):
CPPCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross,
info, exe_wrapper, linker=linker, full_version=full_version)
MetrowerksCompiler.__init__(self)

def get_instruction_set_args(self, instruction_set: str) -> T.Optional[T.List[str]]:
return mwccarm_instruction_set_args.get(instruction_set, None)

def get_options(self) -> 'MutableKeyedOptionDictType':
opts = CPPCompiler.get_options(self)
key = OptionKey('std', machine=self.for_machine, lang=self.language)
opts[key].choices = ['none']
return opts

def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
args = []
std = options[OptionKey('std', machine=self.for_machine, lang=self.language)]
if std.value != 'none':
args.append('-lang')
args.append(std.value)
return args

class MetrowerksCPPCompilerEmbeddedPowerPC(MetrowerksCompiler, CPPCompiler):
id = 'mwcceppc'

def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice,
is_cross: bool, info: 'MachineInfo',
exe_wrapper: T.Optional['ExternalProgram'] = None,
linker: T.Optional['DynamicLinker'] = None,
full_version: T.Optional[str] = None):
CPPCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross,
info, exe_wrapper, linker=linker, full_version=full_version)
MetrowerksCompiler.__init__(self)

def get_instruction_set_args(self, instruction_set: str) -> T.Optional[T.List[str]]:
return mwcceppc_instruction_set_args.get(instruction_set, None)

def get_options(self) -> 'MutableKeyedOptionDictType':
opts = CPPCompiler.get_options(self)
key = OptionKey('std', machine=self.for_machine, lang=self.language)
opts[key].choices = ['none']
return opts

def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
args = []
std = options[OptionKey('std', machine=self.for_machine, lang=self.language)]
if std.value != 'none':
args.append('-lang ' + std.value)
return args
41 changes: 38 additions & 3 deletions mesonbuild/compilers/detect.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from .cpp import CPPCompiler
from .fortran import FortranCompiler
from .rust import RustCompiler
from ..linkers import StaticLinker
from ..linkers import StaticLinker, DynamicLinker
from ..environment import Environment
from ..programs import ExternalProgram

Expand Down Expand Up @@ -237,6 +237,11 @@ def detect_static_linker(env: 'Environment', compiler: Compiler) -> StaticLinker
return linkers.TILinker(linker)
if out.startswith('The CompCert'):
return linkers.CompCertLinker(linker)
if out.strip().startswith('Metrowerks') or out.strip().startswith('Freescale'):
if 'ARM' in out:
return linkers.MetrowerksStaticLinkerARM(linker)
else:
return linkers.MetrowerksStaticLinkerEmbeddedPowerPC(linker)
if p.returncode == 0:
return linkers.ArLinker(compiler.for_machine, linker)
if p.returncode == 1 and err.startswith('usage'): # OSX
Expand Down Expand Up @@ -269,6 +274,7 @@ def _detect_c_or_cpp_compiler(env: 'Environment', lang: str, for_machine: Machin
is_cross = env.is_cross_build(for_machine)
info = env.machines[for_machine]
cls: T.Union[T.Type[CCompiler], T.Type[CPPCompiler]]
lnk: T.Union[T.Type[StaticLinker], T.Type[DynamicLinker]]

for compiler in compilers:
if isinstance(compiler, str):
Expand Down Expand Up @@ -529,7 +535,6 @@ def sanitize(p: str) -> str:
ccache, compiler, version, for_machine, is_cross, info,
exe_wrap, full_version=full_version, linker=l)
if 'TMS320C2000 C/C++' in out or 'MSP430 C/C++' in out or 'TI ARM C/C++ Compiler' in out:
lnk: T.Union[T.Type[linkers.C2000DynamicLinker], T.Type[linkers.TIDynamicLinker]]
if 'TMS320C2000 C/C++' in out:
cls = c.C2000CCompiler if lang == 'c' else cpp.C2000CPPCompiler
lnk = linkers.C2000DynamicLinker
Expand All @@ -542,7 +547,7 @@ def sanitize(p: str) -> str:
return cls(
ccache, compiler, version, for_machine, is_cross, info,
exe_wrap, full_version=full_version, linker=linker)
if 'ARM' in out:
if 'ARM' in out and not ('Metrowerks' in out or 'Freescale' in out):
cls = c.ArmCCompiler if lang == 'c' else cpp.ArmCPPCompiler
env.coredata.add_lang_args(cls.language, cls, for_machine, env)
linker = linkers.ArmDynamicLinker(for_machine, version=version)
Expand Down Expand Up @@ -573,6 +578,36 @@ def sanitize(p: str) -> str:
ccache, compiler, version, for_machine, is_cross, info,
exe_wrap, full_version=full_version, linker=linker)

if 'Metrowerks C/C++' in out or 'Freescale C/C++' in out:
if 'ARM' in out:
cls = c.MetrowerksCCompilerARM if lang == 'c' else cpp.MetrowerksCPPCompilerARM
lnk = linkers.MetrowerksLinkerARM
else:
cls = c.MetrowerksCCompilerEmbeddedPowerPC if lang == 'c' else cpp.MetrowerksCPPCompilerEmbeddedPowerPC
lnk = linkers.MetrowerksLinkerEmbeddedPowerPC

mwcc_ver_match = re.search(r'Version (\d+)\.(\d+)\.?(\d+)? build (\d+)', out)
assert mwcc_ver_match is not None, 'for mypy' # because mypy *should* be complaning that this could be None
compiler_version = '.'.join(x for x in mwcc_ver_match.groups() if x is not None)

env.coredata.add_lang_args(cls.language, cls, for_machine, env)
ld = env.lookup_binary_entry(for_machine, cls.language + '_ld')

if ld is not None:
_, o_ld, _ = Popen_safe(ld + ['--version'])

mwld_ver_match = re.search(r'Version (\d+)\.(\d+)\.?(\d+)? build (\d+)', o_ld)
assert mwld_ver_match is not None, 'for mypy' # because mypy *should* be complaning that this could be None
linker_version = '.'.join(x for x in mwld_ver_match.groups() if x is not None)

linker = lnk(ld, for_machine, version=linker_version)
else:
raise EnvironmentException(f'Failed to detect linker for {cls.id!r} compiler. Please update your cross file(s).')

return cls(
ccache, compiler, compiler_version, for_machine, is_cross, info,
exe_wrap, full_version=full_version, linker=linker)

_handle_exceptions(popen_exceptions, compilers)
raise EnvironmentException(f'Unknown compiler {compilers}')

Expand Down
Loading

0 comments on commit 18cfa54

Please sign in to comment.