Merge pull request #11737 from amyspark/amyspark/add-nasm-building-rules-to-xcode

backends: Add Nasm build rules to Xcode
pull/13087/head
Jussi Pakkanen 8 months ago committed by GitHub
commit 1dcffb635f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 39
      mesonbuild/backend/backends.py
  2. 73
      mesonbuild/backend/xcodebackend.py
  3. 11
      mesonbuild/compilers/asm.py
  4. 18
      test cases/nasm/1 configure file/meson.build
  5. 6
      test cases/nasm/2 asm language/meson.build
  6. 4
      test cases/nasm/3 nasm only/meson.build
  7. 4
      test cases/nasm/4 through configure/dummy.asm.in
  8. 2
      test cases/nasm/4 through configure/dummy.def
  9. 30
      test cases/nasm/4 through configure/meson.build

@ -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,53 @@ 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 +1181,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)

@ -42,8 +42,10 @@ class NasmCompiler(Compiler):
linker: T.Optional['DynamicLinker'] = None, linker: T.Optional['DynamicLinker'] = None,
full_version: T.Optional[str] = None, is_cross: bool = False): full_version: T.Optional[str] = None, is_cross: bool = False):
super().__init__(ccache, exelist, version, for_machine, info, linker, full_version, is_cross) super().__init__(ccache, exelist, version, for_machine, info, linker, full_version, is_cross)
self.links_with_msvc = False
if 'link' in self.linker.id: if 'link' in self.linker.id:
self.base_options.add(OptionKey('b_vscrt')) self.base_options.add(OptionKey('b_vscrt'))
self.links_with_msvc = True
def needs_static_linker(self) -> bool: def needs_static_linker(self) -> bool:
return True return True
@ -83,9 +85,7 @@ class NasmCompiler(Compiler):
def get_debug_args(self, is_debug: bool) -> T.List[str]: def get_debug_args(self, is_debug: bool) -> T.List[str]:
if is_debug: if is_debug:
if self.info.is_windows(): return ['-g']
return []
return ['-g', '-F', 'dwarf']
return [] return []
def get_depfile_suffix(self) -> str: def get_depfile_suffix(self) -> str:
@ -138,8 +138,11 @@ class YasmCompiler(NasmCompiler):
def get_debug_args(self, is_debug: bool) -> T.List[str]: def get_debug_args(self, is_debug: bool) -> T.List[str]:
if is_debug: if is_debug:
if self.info.is_windows(): if self.info.is_windows() and self.links_with_msvc:
return ['-g', 'cv8']
elif self.info.is_darwin():
return ['-g', 'null'] return ['-g', 'null']
else:
return ['-g', 'dwarf2'] return ['-g', 'dwarf2']
return [] return []

@ -1,15 +1,17 @@
project('nasm config file', 'c') project('nasm config file', 'c')
if host_machine.cpu_family() == 'x86' and host_machine.system() == 'windows' if not host_machine.cpu_family().startswith('x86')
asm_format = 'win32' error('MESON_SKIP_TEST: nasm only supported for x86 and x86_64')
elif host_machine.cpu_family() == 'x86_64' and host_machine.system() == 'windows' endif
asm_format = 'win64'
elif host_machine.cpu_family() == 'x86' and host_machine.system() == 'linux' if host_machine.system() != 'linux'
error('MESON_SKIP_TEST: this test asm is made for Linux')
endif
if host_machine.cpu_family() == 'x86'
asm_format = 'elf32' asm_format = 'elf32'
elif host_machine.cpu_family() == 'x86_64' and host_machine.system() == 'linux'
asm_format = 'elf64'
else else
error('MESON_SKIP_TEST: skipping test on this platform') asm_format = 'elf64'
endif endif
nasm = find_program('nasm', required: false) nasm = find_program('nasm', required: false)

@ -5,10 +5,8 @@ if not host_machine.cpu_family().startswith('x86')
error('MESON_SKIP_TEST: nasm only supported for x86 and x86_64') error('MESON_SKIP_TEST: nasm only supported for x86 and x86_64')
endif endif
if host_machine.system() == 'windows' if host_machine.system() != 'linux'
error('MESON_SKIP_TEST: this test asm is not made for Windows') error('MESON_SKIP_TEST: this test asm is made for Linux')
elif host_machine.system() == 'sunos'
error('MESON_SKIP_TEST: this test asm is not made for Solaris or illumos')
endif endif
if meson.backend().startswith('vs') if meson.backend().startswith('vs')

@ -4,6 +4,10 @@ if not add_languages('nasm', required: false)
error('MESON_SKIP_TEST: nasm not found') error('MESON_SKIP_TEST: nasm not found')
endif endif
if not ['linux', 'windows'].contains(host_machine.system())
error('MESON_SKIP_TEST: this test asm is made for Windows and Linux')
endif
if meson.backend().startswith('vs') if meson.backend().startswith('vs')
error('MESON_SKIP_TEST: VS backend does not recognise NASM yet') error('MESON_SKIP_TEST: VS backend does not recognise NASM yet')
endif endif

@ -0,0 +1,4 @@
global dummy
section .rodata align=16
dummy:
dd 0x00010203

@ -0,0 +1,30 @@
project('through configure')
if not add_languages('nasm', required: false)
error('MESON_SKIP_TEST: nasm not found')
endif
if not host_machine.cpu_family().startswith('x86')
assert(not add_languages('nasm', required: false))
error('MESON_SKIP_TEST: nasm only supported for x86 and x86_64')
endif
if meson.backend().startswith('vs')
error('MESON_SKIP_TEST: VS backend does not recognise NASM yet')
endif
section = host_machine.system() == 'macos' ? '.rodata' : '.rdata'
sources = configure_file(
input: 'dummy.asm.in',
output: 'dummy.asm',
configuration: {
'section': section
}
)
dummy = library(
'dummy',
sources,
vs_module_defs: 'dummy.def',
)
Loading…
Cancel
Save