Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for the TASKING compiler family, and its MIL linking feature #12342

Merged
merged 3 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/markdown/Reference-tables.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ These are return values of the `get_id` (Compiler family) and
| armasm | Microsoft Macro Assembler for ARM and AARCH64 (Since 0.64.0) | |
| mwasmarm | Metrowerks Assembler for Embedded ARM | |
| mwasmeppc | Metrowerks Assembler for Embedded PowerPC | |
| tasking | TASKING VX-toolset | |

## Linker ids

Expand Down Expand Up @@ -80,6 +81,7 @@ These are return values of the `get_linker_id` method in a compiler object.
| 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 |
| tasking | TASKING VX-toolset |

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 Expand Up @@ -139,6 +141,7 @@ set in the cross file.
| wasm64 | 64 bit Webassembly |
| x86 | 32 bit x86 processor |
| x86_64 | 64 bit x86 processor |
| tricore | Tricore 32 bit processor |


Any cpu family not listed in the above list is not guaranteed to
Expand Down
21 changes: 16 additions & 5 deletions mesonbuild/backend/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@
from .. import programs
from .. import mesonlib
from .. import mlog
from ..compilers import LANGUAGES_USING_LDFLAGS, detect
from ..compilers import LANGUAGES_USING_LDFLAGS, detect, lang_suffixes
from ..mesonlib import (
File, MachineChoice, MesonException, OrderedSet,
ExecutableSerialisation, classify_unity_sources,
ExecutableSerialisation, EnvironmentException,
classify_unity_sources, get_compiler_for_source
)
from ..options import OptionKey

Expand Down Expand Up @@ -837,7 +838,7 @@ def canonicalize_filename(fname: str) -> str:
fname = fname.replace(ch, '_')
return hashed + fname

def object_filename_from_source(self, target: build.BuildTarget, source: 'FileOrString', targetdir: T.Optional[str] = None) -> str:
def object_filename_from_source(self, target: build.BuildTarget, compiler: Compiler, source: 'FileOrString', targetdir: T.Optional[str] = None) -> str:
assert isinstance(source, mesonlib.File)
if isinstance(target, build.CompileTarget):
return target.sources_map[source]
Expand Down Expand Up @@ -868,7 +869,16 @@ def object_filename_from_source(self, target: build.BuildTarget, source: 'FileOr
gen_source = os.path.relpath(os.path.join(build_dir, rel_src),
os.path.join(self.environment.get_source_dir(), target.get_subdir()))
machine = self.environment.machines[target.for_machine]
ret = self.canonicalize_filename(gen_source) + '.' + machine.get_object_suffix()
object_suffix = machine.get_object_suffix()
# For the TASKING compiler, in case of LTO or prelinking the object suffix has to be .mil
if compiler.get_id() == 'tasking':
if target.get_option(OptionKey('b_lto')) or (isinstance(target, build.StaticLibrary) and target.prelink):
if not source.rsplit('.', 1)[1] in lang_suffixes['c']:
if isinstance(target, build.StaticLibrary) and not target.prelink:
raise EnvironmentException('Tried using MIL linking for a static library with a assembly file. This can only be done if the static library is prelinked or disable \'b_lto\'.')
else:
object_suffix = 'mil'
ret = self.canonicalize_filename(gen_source) + '.' + object_suffix
if targetdir is not None:
return os.path.join(targetdir, ret)
return ret
Expand Down Expand Up @@ -924,7 +934,8 @@ def _determine_ext_objs(self, extobj: 'build.ExtractedObjects', proj_dir_to_buil
sources.append(_src)

for osrc in sources:
objname = self.object_filename_from_source(extobj.target, osrc, targetdir)
compiler = get_compiler_for_source(extobj.target.compilers.values(), osrc)
objname = self.object_filename_from_source(extobj.target, compiler, osrc, targetdir)
objpath = os.path.join(proj_dir_to_build_root, objname)
result.append(objpath)

Expand Down
76 changes: 67 additions & 9 deletions mesonbuild/backend/ninjabackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ def _quoter(x: NinjaCommandArg, qf: T.Callable[[str], str] = quote_func) -> str:
def write(self, outfile: T.TextIO) -> None:
rspfile_args = self.args
rspfile_quote_func: T.Callable[[str], str]
if self.rspfile_quote_style is RSPFileSyntax.MSVC:
if self.rspfile_quote_style in {RSPFileSyntax.MSVC, RSPFileSyntax.TASKING}:
rspfile_quote_func = cmd_quote
rspfile_args = [NinjaCommandArg('$in_newline', arg.quoting) if arg.s == '$in' else arg for arg in rspfile_args]
else:
Expand All @@ -258,7 +258,10 @@ def rule_iter() -> T.Iterable[str]:
for rsp in rule_iter():
outfile.write(f'rule {self.name}{rsp}\n')
if rsp == '_RSP':
outfile.write(' command = {} @$out.rsp\n'.format(' '.join([self._quoter(x) for x in self.command])))
if self.rspfile_quote_style is RSPFileSyntax.TASKING:
outfile.write(' command = {} --option-file=$out.rsp\n'.format(' '.join([self._quoter(x) for x in self.command])))
else:
outfile.write(' command = {} @$out.rsp\n'.format(' '.join([self._quoter(x) for x in self.command])))
outfile.write(' rspfile = $out.rsp\n')
outfile.write(' rspfile_content = {}\n'.format(' '.join([self._quoter(x, rspfile_quote_func) for x in rspfile_args])))
else:
Expand Down Expand Up @@ -410,7 +413,7 @@ def write(self, outfile: T.TextIO) -> None:
outfile.write(line)

if use_rspfile:
if self.rule.rspfile_quote_style is RSPFileSyntax.MSVC:
if self.rule.rspfile_quote_style in {RSPFileSyntax.MSVC, RSPFileSyntax.TASKING}:
qf = cmd_quote
else:
qf = gcc_rsp_quote
Expand Down Expand Up @@ -730,6 +733,11 @@ def generate_compdb(self) -> None:
for ext in ['', '_RSP']]
rules += [f"{rule}{ext}" for rule in [self.compiler_to_pch_rule_name(compiler)]
for ext in ['', '_RSP']]
# Add custom MIL link rules to get the files compiled by the TASKING compiler family to MIL files included in the database
if compiler.get_id() == 'tasking':
rule = self.get_compiler_rule_name('tasking_mil_compile', compiler.for_machine)
rules.append(rule)
rules.append(f'{rule}_RSP')
compdb_options = ['-x'] if mesonlib.version_compare(self.ninja_version, '>=1.9') else []
ninja_compdb = self.ninja_command + ['-t', 'compdb'] + compdb_options + rules
builddir = self.environment.get_build_dir()
Expand Down Expand Up @@ -1076,7 +1084,10 @@ def generate_target(self, target) -> None:
# Skip the link stage for this special type of target
return
linker, stdlib_args = self.determine_linker_and_stdlib_args(target)
if isinstance(target, build.StaticLibrary) and target.prelink:

if not isinstance(target, build.StaticLibrary):
final_obj_list = obj_list
elif target.prelink:
final_obj_list = self.generate_prelink(target, obj_list)
else:
final_obj_list = obj_list
Expand Down Expand Up @@ -2484,6 +2495,33 @@ def generate_llvm_ir_compile_rule(self, compiler) -> None:
self.add_rule(NinjaRule(rule, command, args, description, **options))
self.created_llvm_ir_rule[compiler.for_machine] = True

def generate_tasking_mil_compile_rules(self, compiler: Compiler) -> None:
rule = self.get_compiler_rule_name('tasking_mil_compile', compiler.for_machine)
depargs = NinjaCommandArg.list(compiler.get_dependency_gen_args('$out', '$DEPFILE'), Quoting.none)
command = compiler.get_exelist()
args = ['$ARGS'] + depargs + NinjaCommandArg.list(compiler.get_output_args('$out'), Quoting.none) + ['-cm', '$in']
description = 'Compiling to C object $in'
if compiler.get_argument_syntax() == 'msvc':
deps = 'msvc'
depfile = None
else:
deps = 'gcc'
depfile = '$DEPFILE'

options = self._rsp_options(compiler)

self.add_rule(NinjaRule(rule, command, args, description, **options, deps=deps, depfile=depfile))

def generate_tasking_mil_link_rules(self, compiler: Compiler) -> None:
rule = self.get_compiler_rule_name('tasking_mil_link', compiler.for_machine)
command = compiler.get_exelist()
args = ['$ARGS', '--mil-link'] + NinjaCommandArg.list(compiler.get_output_args('$out'), Quoting.none) + ['-c', '$in']
description = 'MIL linking object $out'

options = self._rsp_options(compiler)

self.add_rule(NinjaRule(rule, command, args, description, **options))

def generate_compile_rule_for(self, langname: str, compiler: Compiler) -> None:
if langname == 'java':
self.generate_java_compile_rule(compiler)
Expand Down Expand Up @@ -2574,6 +2612,8 @@ def generate_compile_rules(self) -> None:
for langname, compiler in clist.items():
if compiler.get_id() == 'clang':
self.generate_llvm_ir_compile_rule(compiler)
if compiler.get_id() == 'tasking':
self.generate_tasking_mil_compile_rules(compiler)
self.generate_compile_rule_for(langname, compiler)
self.generate_pch_rule_for(langname, compiler)
for mode in compiler.get_modes():
Expand Down Expand Up @@ -3013,7 +3053,7 @@ def generate_single_compile(self, target: build.BuildTarget, src,
raise AssertionError(f'BUG: broken generated source file handling for {src!r}')
else:
raise InvalidArguments(f'Invalid source type: {src!r}')
obj_basename = self.object_filename_from_source(target, src)
obj_basename = self.object_filename_from_source(target, compiler, src)
rel_obj = os.path.join(self.get_target_private_dir(target), obj_basename)
dep_file = compiler.depfile_for_object(rel_obj)

Expand All @@ -3034,8 +3074,17 @@ def generate_single_compile(self, target: build.BuildTarget, src,
i = os.path.join(self.get_target_private_dir(target), compiler.get_pch_name(pchlist[0]))
arr.append(i)
pch_dep = arr

compiler_name = self.compiler_to_rule_name(compiler)
# If TASKING compiler family is used and MIL linking is enabled for the target,
# then compilation rule name is a special one to output MIL files
# instead of object files for .c files
key = OptionKey('b_lto')
if compiler.get_id() == 'tasking':
if ((isinstance(target, build.StaticLibrary) and target.prelink) or target.get_option(key)) and src.rsplit('.', 1)[1] in compilers.lang_suffixes['c']:
compiler_name = self.get_compiler_rule_name('tasking_mil_compile', compiler.for_machine)
else:
compiler_name = self.compiler_to_rule_name(compiler)
else:
compiler_name = self.compiler_to_rule_name(compiler)
extra_deps = []
if compiler.get_language() == 'fortran':
# Can't read source file to scan for deps if it's generated later
Expand Down Expand Up @@ -3412,13 +3461,19 @@ def generate_prelink(self, target, obj_list):

prelinker = target.get_prelinker()
cmd = prelinker.exelist[:]
cmd += prelinker.get_prelink_args(prelink_name, obj_list)
obj_list, args = prelinker.get_prelink_args(prelink_name, obj_list)
cmd += args
if prelinker.get_prelink_append_compile_args():
compile_args = self._generate_single_compile_base_args(target, prelinker)
compile_args += self._generate_single_compile_target_args(target, prelinker)
compile_args = compile_args.compiler.compiler_args(compile_args)
cmd += compile_args.to_native()

cmd = self.replace_paths(target, cmd)
elem.add_item('COMMAND', cmd)
elem.add_item('description', f'Prelinking {prelink_name}')
self.add_build(elem)
return [prelink_name]
return obj_list

def generate_link(self, target: build.BuildTarget, outname, obj_list, linker: T.Union['Compiler', 'StaticLinker'], extra_args=None, stdlib_args=None):
extra_args = extra_args if extra_args is not None else []
Expand Down Expand Up @@ -3560,6 +3615,9 @@ def generate_link(self, target: build.BuildTarget, outname, obj_list, linker: T.
for t in target.link_depends])
elem = NinjaBuildElement(self.all_outputs, outname, linker_rule, obj_list, implicit_outs=implicit_outs)
elem.add_dep(dep_targets + custom_target_libraries)
if linker.get_id() == 'tasking':
if len([x for x in dep_targets + custom_target_libraries if x.endswith('.ma')]) > 0 and not target.get_option(OptionKey('b_lto')):
raise MesonException(f'Tried to link the target named \'{target.name}\' with a MIL archive without LTO enabled! This causes the compiler to ignore the archive.')

# Compiler args must be included in TI C28x linker commands.
if linker.get_id() in {'c2000', 'c6000', 'ti'}:
Expand Down
4 changes: 2 additions & 2 deletions mesonbuild/backend/vs2010backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -1725,7 +1725,7 @@ def path_normalize_add(path, lis):
self.add_preprocessor_defines(lang, inc_cl, file_defines)
self.add_include_dirs(lang, inc_cl, file_inc_dirs)
ET.SubElement(inc_cl, 'ObjectFileName').text = "$(IntDir)" + \
self.object_filename_from_source(target, s)
self.object_filename_from_source(target, compiler, s)
for s in gen_src:
if path_normalize_add(s, previous_sources):
inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=s)
Expand All @@ -1739,7 +1739,7 @@ def path_normalize_add(path, lis):
self.add_include_dirs(lang, inc_cl, file_inc_dirs)
s = File.from_built_file(target.get_subdir(), s)
ET.SubElement(inc_cl, 'ObjectFileName').text = "$(IntDir)" + \
self.object_filename_from_source(target, s)
self.object_filename_from_source(target, compiler, s)
for lang, headers in pch_sources.items():
impl = headers[1]
if impl and path_normalize_add(impl, previous_sources):
Expand Down
7 changes: 6 additions & 1 deletion mesonbuild/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -2019,6 +2019,8 @@ def post_init(self) -> None:
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'
elif ('c' in self.compilers and self.compilers['c'].get_id() == 'tasking'):
self.suffix = 'elf'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, you found this, good. :)

else:
self.suffix = machine.get_exe_suffix()
self.filename = self.name
Expand Down Expand Up @@ -2174,7 +2176,10 @@ def post_init(self) -> None:
elif self.rust_crate_type == 'staticlib':
self.suffix = 'a'
else:
self.suffix = 'a'
if 'c' in self.compilers and self.compilers['c'].get_id() == 'tasking':
self.suffix = 'ma' if self.options.get_value('b_lto') and not self.prelink else 'a'
else:
self.suffix = 'a'
self.filename = self.prefix + self.name + '.' + self.suffix
self.outputs[0] = self.filename

Expand Down
12 changes: 12 additions & 0 deletions mesonbuild/compilers/c.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from .mixins.emscripten import EmscriptenMixin
from .mixins.metrowerks import MetrowerksCompiler
from .mixins.metrowerks import mwccarm_instruction_set_args, mwcceppc_instruction_set_args
from .mixins.tasking import TaskingCompiler

Check failure

Code scanning / CodeQL

Module-level cyclic import

'TaskingCompiler' may not be defined if module [mesonbuild.compilers.mixins.tasking](1) is imported before module [mesonbuild.compilers.c](2), as the [definition](3) of TaskingCompiler occurs after the cyclic [import](4) of mesonbuild.compilers.c. 'TaskingCompiler' may not be defined if module [mesonbuild.compilers.mixins.tasking](1) is imported before module [mesonbuild.compilers.c](2), as the [definition](3) of TaskingCompiler occurs after the cyclic [import](5) of mesonbuild.compilers.c. 'TaskingCompiler' may not be defined if module [mesonbuild.compilers.mixins.tasking](1) is imported before module [mesonbuild.compilers.c](2), as the [definition](3) of TaskingCompiler occurs after the cyclic [import](6) of mesonbuild.compilers.c. 'TaskingCompiler' may not be defined if module [mesonbuild.compilers.mixins.tasking](1) is imported before module [mesonbuild.compilers.c](2), as the [definition](3) of TaskingCompiler occurs after the cyclic [import](7) of mesonbuild.compilers.c.
from .compilers import (
gnu_winlibs,
msvc_winlibs,
Expand Down Expand Up @@ -830,3 +831,14 @@ def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]
if std != 'none':
args.append('-lang ' + std)
return args

class TaskingCCompiler(TaskingCompiler, CCompiler):
id = 'tasking'

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,
full_version: T.Optional[str] = None):
CCompiler.__init__(self, ccache, exelist, version, for_machine, is_cross,
info, linker=linker, full_version=full_version)
TaskingCompiler.__init__(self)
dcbaker marked this conversation as resolved.
Show resolved Hide resolved
8 changes: 6 additions & 2 deletions mesonbuild/compilers/compilers.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,8 +432,8 @@ class CompileResult(HoldableObject):
output_name: T.Optional[str] = field(default=None, init=False)
cached: bool = field(default=False, init=False)


class Compiler(HoldableObject, metaclass=abc.ABCMeta):

# Libraries to ignore in find_library() since they are provided by the
# compiler or the C library. Currently only used for MSVC.
ignore_libs: T.List[str] = []
Expand Down Expand Up @@ -1327,9 +1327,13 @@ def get_feature_args(self, kwargs: DFeatures, build_to_src: str) -> T.List[str]:
# TODO: using a TypeDict here would improve this
raise EnvironmentException(f'{self.id} does not implement get_feature_args')

def get_prelink_args(self, prelink_name: str, obj_list: T.List[str]) -> T.List[str]:
def get_prelink_args(self, prelink_name: str, obj_list: T.List[str]) -> T.Tuple[T.List[str], T.List[str]]:
raise EnvironmentException(f'{self.id} does not know how to do prelinking.')

def get_prelink_append_compile_args(self) -> bool:
"""Controls whether compile args have to be used for prelinking or not"""
return False

def rsp_file_syntax(self) -> 'RSPFileSyntax':
"""The format of the RSP file that this compiler supports.
Expand Down
19 changes: 19 additions & 0 deletions mesonbuild/compilers/detect.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ def detect_static_linker(env: 'Environment', compiler: Compiler) -> StaticLinker
return linkers.MetrowerksStaticLinkerARM(linker)
else:
return linkers.MetrowerksStaticLinkerEmbeddedPowerPC(linker)
if 'TASKING VX-toolset' in err:
return linkers.TaskingStaticLinker(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 @@ -605,6 +607,23 @@ def sanitize(p: T.Optional[str]) -> T.Optional[str]:
return cls(
ccache, compiler, compiler_version, for_machine, is_cross, info,
full_version=full_version, linker=linker)
if 'TASKING VX-toolset' in err:
cls = c.TaskingCCompiler
lnk = linkers.TaskingLinker

tasking_ver_match = re.search(r'v([0-9]+)\.([0-9]+)r([0-9]+) Build ([0-9]+)', err)
assert tasking_ver_match is not None, 'for mypy'
tasking_version = '.'.join(x for x in tasking_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')
dcbaker marked this conversation as resolved.
Show resolved Hide resolved
if ld is None:
raise MesonException(f'{cls.language}_ld was not properly defined in your cross file')

linker = lnk(ld, for_machine, version=tasking_version)
return cls(
ccache, compiler, tasking_version, for_machine, is_cross, info,
full_version=full_version, linker=linker)

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