backends: Add Nasm support to Xcode through a custom build rule

pull/11737/head
L. E. Segovia 2 years ago
parent 7b77fa0174
commit c0696889ff
  1. 39
      mesonbuild/backend/backends.py
  2. 68
      mesonbuild/backend/xcodebackend.py

@ -2013,6 +2013,34 @@ class Backend:
env.prepend('PATH', list(extra_paths)) env.prepend('PATH', list(extra_paths))
return env return env
def compiler_to_generator_args(self, target: build.BuildTarget,
compiler: 'Compiler', output: str = '@OUTPUT@',
depfile: T.Union[str, None] = '@DEPFILE@',
extras: T.Union[T.List[str], None] = None,
input: str = '@INPUT@') -> CompilerArgs:
'''
The VS and Xcode backends need the full set of arguments for making a
custom build rule. This is a convenience method to convert a Compiler
to its arguments, for later concatenation.
'''
# FIXME: There are many other args missing
commands = self.generate_basic_compiler_args(target, compiler)
if depfile:
commands += compiler.get_dependency_gen_args(output, depfile)
commands += compiler.get_output_args(output)
commands += self.get_source_dir_include_args(target, compiler)
commands += self.get_build_dir_include_args(target, compiler)
commands += compiler.get_compile_only_args()
# Add per-target compile args, f.ex, `c_args : ['-DFOO']`. We set these
# near the end since these are supposed to override everything else.
commands += self.escape_extra_args(target.get_extra_args(compiler.get_language()))
# Do not escape this one, it is interpreted by the build system
# (Xcode considers these as variables to expand at build time)
if extras is not None:
commands += extras
commands += [input]
return commands
def compiler_to_generator(self, target: build.BuildTarget, def compiler_to_generator(self, target: build.BuildTarget,
compiler: 'Compiler', compiler: 'Compiler',
sources: _ALL_SOURCES_TYPE, sources: _ALL_SOURCES_TYPE,
@ -2026,16 +2054,7 @@ class Backend:
exelist = compiler.get_exelist() exelist = compiler.get_exelist()
exe = programs.ExternalProgram(exelist[0]) exe = programs.ExternalProgram(exelist[0])
args = exelist[1:] args = exelist[1:]
# FIXME: There are many other args missing commands = self.compiler_to_generator_args(target, compiler)
commands = self.generate_basic_compiler_args(target, compiler)
commands += compiler.get_dependency_gen_args('@OUTPUT@', '@DEPFILE@')
commands += compiler.get_output_args('@OUTPUT@')
commands += compiler.get_compile_only_args() + ['@INPUT@']
commands += self.get_source_dir_include_args(target, compiler)
commands += self.get_build_dir_include_args(target, compiler)
# Add per-target compile args, f.ex, `c_args : ['-DFOO']`. We set these
# near the end since these are supposed to override everything else.
commands += self.escape_extra_args(target.get_extra_args(compiler.get_language()))
generator = build.Generator(exe, args + commands.to_native(), generator = build.Generator(exe, args + commands.to_native(),
[output_templ], depfile='@PLAINNAME@.d', [output_templ], depfile='@PLAINNAME@.d',
depends=depends) depends=depends)

@ -10,9 +10,12 @@ from . import backends
from .. import build from .. import build
from .. import mesonlib from .. import mesonlib
from .. import mlog from .. import mlog
from ..arglist import CompilerArgs
from ..mesonlib import MesonBugException, MesonException, OptionKey from ..mesonlib import MesonBugException, MesonException, OptionKey
if T.TYPE_CHECKING: if T.TYPE_CHECKING:
from ..build import BuildTarget
from ..compilers import Compiler
from ..interpreter import Interpreter from ..interpreter import Interpreter
INDENT = '\t' INDENT = '\t'
@ -33,10 +36,12 @@ XCODETYPEMAP = {'c': 'sourcecode.c.c',
'dylib': 'compiled.mach-o.dylib', 'dylib': 'compiled.mach-o.dylib',
'o': 'compiled.mach-o.objfile', 'o': 'compiled.mach-o.objfile',
's': 'sourcecode.asm', 's': 'sourcecode.asm',
'asm': 'sourcecode.asm', 'asm': 'sourcecode.nasm',
'metal': 'sourcecode.metal', 'metal': 'sourcecode.metal',
'glsl': 'sourcecode.glsl', 'glsl': 'sourcecode.glsl',
} }
NEEDS_CUSTOM_RULES = {'nasm': 'sourcecode.nasm',
}
LANGNAMEMAP = {'c': 'C', LANGNAMEMAP = {'c': 'C',
'cpp': 'CPLUSPLUS', 'cpp': 'CPLUSPLUS',
'objc': 'OBJC', 'objc': 'OBJC',
@ -271,6 +276,7 @@ class XCodeBackend(backends.Backend):
self.generate_native_target_map() self.generate_native_target_map()
self.generate_native_frameworks_map() self.generate_native_frameworks_map()
self.generate_custom_target_map() self.generate_custom_target_map()
self.generate_native_target_build_rules_map()
self.generate_generator_target_map() self.generate_generator_target_map()
self.generate_source_phase_map() self.generate_source_phase_map()
self.generate_target_dependency_map() self.generate_target_dependency_map()
@ -288,6 +294,9 @@ class XCodeBackend(backends.Backend):
objects_dict.add_comment(PbxComment('Begin PBXBuildFile section')) objects_dict.add_comment(PbxComment('Begin PBXBuildFile section'))
self.generate_pbx_build_file(objects_dict) self.generate_pbx_build_file(objects_dict)
objects_dict.add_comment(PbxComment('End PBXBuildFile section')) objects_dict.add_comment(PbxComment('End PBXBuildFile section'))
objects_dict.add_comment(PbxComment('Begin PBXBuildRule section'))
self.generate_pbx_build_rule(objects_dict)
objects_dict.add_comment(PbxComment('End PBXBuildRule section'))
objects_dict.add_comment(PbxComment('Begin PBXBuildStyle section')) objects_dict.add_comment(PbxComment('Begin PBXBuildStyle section'))
self.generate_pbx_build_style(objects_dict) self.generate_pbx_build_style(objects_dict)
objects_dict.add_comment(PbxComment('End PBXBuildStyle section')) objects_dict.add_comment(PbxComment('End PBXBuildStyle section'))
@ -401,6 +410,16 @@ class XCodeBackend(backends.Backend):
for t in self.build_targets: for t in self.build_targets:
self.native_targets[t] = self.gen_id() self.native_targets[t] = self.gen_id()
def generate_native_target_build_rules_map(self) -> None:
self.build_rules = {}
for name, target in self.build_targets.items():
languages = {}
for language in target.compilers:
if language not in NEEDS_CUSTOM_RULES:
continue
languages[language] = self.gen_id()
self.build_rules[name] = languages
def generate_custom_target_map(self) -> None: def generate_custom_target_map(self) -> None:
self.shell_targets = {} self.shell_targets = {}
self.custom_target_output_buildfile = {} self.custom_target_output_buildfile = {}
@ -720,6 +739,48 @@ class XCodeBackend(backends.Backend):
settings_dict.add_item('COPY_PHASE_STRIP', 'NO') settings_dict.add_item('COPY_PHASE_STRIP', 'NO')
styledict.add_item('name', f'"{name}"') styledict.add_item('name', f'"{name}"')
def to_shell_script(self, args: CompilerArgs) -> str:
quoted_cmd = []
for c in args:
quoted_cmd.append(c.replace('"', chr(92) + '"'))
cmd = ' '.join(quoted_cmd)
return f"\"#!/bin/sh\\n{cmd}\\n\""
def generate_pbx_build_rule(self, objects_dict: PbxDict) -> None:
for name, languages in self.build_rules.items():
target: BuildTarget = self.build_targets[name]
for language, idval in languages.items():
compiler: Compiler = target.compilers[language]
buildrule = PbxDict()
buildrule.add_item('isa', 'PBXBuildRule')
buildrule.add_item('compilerSpec', 'com.apple.compilers.proxy.script')
if compiler.get_id() != 'yasm':
# Yasm doesn't generate escaped build rules
buildrule.add_item('dependencyFile', '"$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).d"')
buildrule.add_item('fileType', NEEDS_CUSTOM_RULES[language])
inputfiles = PbxArray()
buildrule.add_item('inputFiles', inputfiles)
buildrule.add_item('isEditable', '0')
outputfiles = PbxArray()
outputfiles.add_item('"$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).o"')
buildrule.add_item('outputFiles', outputfiles)
# Do NOT use this parameter. Xcode will accept it from the UI,
# but the parser will break down inconsistently upon next
# opening. rdar://FB12144055
# outputargs = PbxArray()
# args = self.generate_basic_compiler_args(target, compiler)
# outputargs.add_item(self.to_shell_script(args))
# buildrule.add_item('outputFilesCompilerFlags', outputargs)
commands = CompilerArgs(compiler)
commands += compiler.get_exelist()
if compiler.get_id() == 'yasm':
# Yasm doesn't generate escaped build rules
commands += self.compiler_to_generator_args(target, compiler, output='"$SCRIPT_OUTPUT_FILE_0"', input='"$SCRIPT_INPUT_FILE"', depfile=None)
else:
commands += self.compiler_to_generator_args(target, compiler, output='"$SCRIPT_OUTPUT_FILE_0"', input='"$SCRIPT_INPUT_FILE"', depfile='"$(dirname "$SCRIPT_OUTPUT_FILE_0")/$(basename "$SCRIPT_OUTPUT_FILE_0" .o).d"', extras=['$OTHER_INPUT_FILE_FLAGS'])
buildrule.add_item('script', self.to_shell_script(commands))
objects_dict.add_item(idval, buildrule, 'PBXBuildRule')
def generate_pbx_container_item_proxy(self, objects_dict: PbxDict) -> None: def generate_pbx_container_item_proxy(self, objects_dict: PbxDict) -> None:
for t in self.build_targets: for t in self.build_targets:
proxy_dict = PbxDict() proxy_dict = PbxDict()
@ -1115,7 +1176,10 @@ class XCodeBackend(backends.Backend):
generator_id += 1 generator_id += 1
for bpname, bpval in t.buildphasemap.items(): for bpname, bpval in t.buildphasemap.items():
buildphases_array.add_item(bpval, f'{bpname} yyy') buildphases_array.add_item(bpval, f'{bpname} yyy')
ntarget_dict.add_item('buildRules', PbxArray()) build_rules = PbxArray()
for language, build_rule_idval in self.build_rules[tname].items():
build_rules.add_item(build_rule_idval, f'{language}')
ntarget_dict.add_item('buildRules', build_rules)
dep_array = PbxArray() dep_array = PbxArray()
ntarget_dict.add_item('dependencies', dep_array) ntarget_dict.add_item('dependencies', dep_array)
dep_array.add_item(self.regen_dependency_id) dep_array.add_item(self.regen_dependency_id)

Loading…
Cancel
Save