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))
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,
compiler: 'Compiler',
sources: _ALL_SOURCES_TYPE,
@ -2026,16 +2054,7 @@ class Backend:
exelist = compiler.get_exelist()
exe = programs.ExternalProgram(exelist[0])
args = exelist[1:]
# FIXME: There are many other args missing
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()))
commands = self.compiler_to_generator_args(target, compiler)
generator = build.Generator(exe, args + commands.to_native(),
[output_templ], depfile='@PLAINNAME@.d',
depends=depends)

@ -10,9 +10,12 @@ from . import backends
from .. import build
from .. import mesonlib
from .. import mlog
from ..arglist import CompilerArgs
from ..mesonlib import MesonBugException, MesonException, OptionKey
if T.TYPE_CHECKING:
from ..build import BuildTarget
from ..compilers import Compiler
from ..interpreter import Interpreter
INDENT = '\t'
@ -33,10 +36,12 @@ XCODETYPEMAP = {'c': 'sourcecode.c.c',
'dylib': 'compiled.mach-o.dylib',
'o': 'compiled.mach-o.objfile',
's': 'sourcecode.asm',
'asm': 'sourcecode.asm',
'asm': 'sourcecode.nasm',
'metal': 'sourcecode.metal',
'glsl': 'sourcecode.glsl',
}
NEEDS_CUSTOM_RULES = {'nasm': 'sourcecode.nasm',
}
LANGNAMEMAP = {'c': 'C',
'cpp': 'CPLUSPLUS',
'objc': 'OBJC',
@ -271,6 +276,7 @@ class XCodeBackend(backends.Backend):
self.generate_native_target_map()
self.generate_native_frameworks_map()
self.generate_custom_target_map()
self.generate_native_target_build_rules_map()
self.generate_generator_target_map()
self.generate_source_phase_map()
self.generate_target_dependency_map()
@ -288,6 +294,9 @@ class XCodeBackend(backends.Backend):
objects_dict.add_comment(PbxComment('Begin PBXBuildFile section'))
self.generate_pbx_build_file(objects_dict)
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'))
self.generate_pbx_build_style(objects_dict)
objects_dict.add_comment(PbxComment('End PBXBuildStyle section'))
@ -401,6 +410,16 @@ class XCodeBackend(backends.Backend):
for t in self.build_targets:
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:
self.shell_targets = {}
self.custom_target_output_buildfile = {}
@ -720,6 +739,53 @@ class XCodeBackend(backends.Backend):
settings_dict.add_item('COPY_PHASE_STRIP', 'NO')
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:
for t in self.build_targets:
proxy_dict = PbxDict()
@ -1115,7 +1181,10 @@ class XCodeBackend(backends.Backend):
generator_id += 1
for bpname, bpval in t.buildphasemap.items():
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()
ntarget_dict.add_item('dependencies', dep_array)
dep_array.add_item(self.regen_dependency_id)

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

@ -1,15 +1,17 @@
project('nasm config file', 'c')
if host_machine.cpu_family() == 'x86' and host_machine.system() == 'windows'
asm_format = 'win32'
elif host_machine.cpu_family() == 'x86_64' and host_machine.system() == 'windows'
asm_format = 'win64'
elif host_machine.cpu_family() == 'x86' and host_machine.system() == 'linux'
if not host_machine.cpu_family().startswith('x86')
error('MESON_SKIP_TEST: nasm only supported for x86 and x86_64')
endif
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'
elif host_machine.cpu_family() == 'x86_64' and host_machine.system() == 'linux'
asm_format = 'elf64'
else
error('MESON_SKIP_TEST: skipping test on this platform')
asm_format = 'elf64'
endif
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')
endif
if host_machine.system() == 'windows'
error('MESON_SKIP_TEST: this test asm is not made for Windows')
elif host_machine.system() == 'sunos'
error('MESON_SKIP_TEST: this test asm is not made for Solaris or illumos')
if host_machine.system() != 'linux'
error('MESON_SKIP_TEST: this test asm is made for Linux')
endif
if meson.backend().startswith('vs')

@ -4,6 +4,10 @@ if not add_languages('nasm', required: false)
error('MESON_SKIP_TEST: nasm not found')
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')
error('MESON_SKIP_TEST: VS backend does not recognise NASM yet')
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