Extract common_ss, system_ss, and family-common objects into one
qemu-system binary. Only arm, aarch64, microblaze-softmmu are
listed; a new target must have arch_srcs equal to target_info_def
only (target-info-def.c). Config headers stay in arch_genh.

- Union non-TARGET_* keys with y taking precedence
- Reject leftover arch_srcs on participating targets
- Reject TARGET_* conditions on common_ss and system_ss
- Link SDL, install the binary, and apply Darwin entitlements

Adding a target that still has per-target sources fails meson, for
example:

  combined qemu-system leftover for :
  expected:
  target-info-def.c
  arch_srcs:
  target/microblaze/mmu.c
  target/microblaze/machine.c
  target-info-def.c

Signed-off-by: Yonggang Luo <[email protected]>
---
 meson.build | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 147 insertions(+), 4 deletions(-)

diff --git a/meson.build b/meson.build
index d5639a2d676..7ab5c7971a8 100644
--- a/meson.build
+++ b/meson.build
@@ -4288,15 +4288,30 @@ if host_os == 'darwin'
 endif
 
 traceable = []
+single_binary_target_info_objects = []
+single_binary_config = {}
+single_binary_bases = {}
+single_binary_deps = []
+single_binary_crates = []
+single_binary_available = false
+
+single_binary_supported_targets = [
+  'aarch64-softmmu',
+  'arm-softmmu',
+  'microblaze-softmmu',
+]
+
 emulators = {}
-target_info_def = files('target-info-def.c')
+target_info_def_src = 'target-info-def.c'
+target_info_def = files(target_info_def_src)
 target_info_def_objects = {}
 foreach target : target_dirs
   config_target = config_target_mak[target]
   target_name = config_target['TARGET_NAME']
   target_base_arch = config_target['TARGET_BASE_ARCH']
-  arch_srcs = [config_target_h[target]]
+  arch_srcs = []
   arch_deps = []
+  arch_genh = [config_target_h[target]]
   c_args = ['-DCOMPILING_PER_TARGET',
             '-DCONFIG_TARGET="@[email protected]"'.format(target),
   ]
@@ -4322,7 +4337,7 @@ foreach target : target_dirs
     endif
 
     c_args += ['-DCONFIG_DEVICES="@[email protected]"'.format(target)]
-    arch_srcs += config_devices_h[target]
+    arch_genh += config_devices_h[target]
     link_args += enable_modules ? ['@block.syms', '@qemu.syms'] : []
   else
     abi = config_target['TARGET_ABI_DIR']
@@ -4433,7 +4448,7 @@ foreach target : target_dirs
   endforeach
 
   lib = static_library('qemu-' + target,
-                 sources: arch_srcs + genh,
+                 sources: arch_srcs + arch_genh + genh,
                  dependencies: lib_deps,
                  objects: objects,
                  include_directories: target_inc,
@@ -4443,6 +4458,45 @@ foreach target : target_dirs
   target_info_def_objects += {target: lib.extract_objects(target_info_def)}
 
   if target.endswith('-softmmu')
+    if target in single_binary_supported_targets
+      arch_src_rels = []
+      foreach src : arch_srcs
+        arch_src_rels += fs.relative_to(src, meson.project_source_root())
+      endforeach
+      if arch_src_rels != [target_info_def_src]
+        error('combined qemu-system leftover for ' + target + ':\n'
+              + 'expected:\n' + target_info_def_src + '\n'
+              + 'arch_srcs:\n' + '\n'.join(arch_src_rels))
+      endif
+      single_target_config = {}
+      foreach k, v : config_target
+        if not k.startswith('TARGET_')
+          single_target_config += {k: v}
+          if k not in single_binary_config or v == 'y'
+            single_binary_config += {k: v}
+          endif
+        endif
+      endforeach
+      target_common_no_target = common_ss.apply(
+        single_target_config, strict: false)
+      if (target_common.sources() != target_common_no_target.sources() or
+          target_common.dependencies() != 
target_common_no_target.dependencies())
+        error('common_ss must not use TARGET_* conditions')
+      endif
+      target_system = system_ss.apply(config_target, strict: false)
+      target_system_no_target = system_ss.apply(
+        single_target_config, strict: false)
+      if (target_system.sources() != target_system_no_target.sources() or
+          target_system.dependencies() != 
target_system_no_target.dependencies())
+        error('system_ss must not use TARGET_* conditions')
+      endif
+      single_binary_target_info_objects += lib.extract_objects(target_info_def)
+      single_binary_bases += {target_base_arch: true}
+      single_binary_deps += arch_deps
+      single_binary_deps += target_stubs
+      single_binary_crates += main_rs
+      single_binary_available = true
+    endif
     execs = [{
       'name': 'qemu-system-' + target_name,
       'win_subsystem': 'console',
@@ -4524,6 +4578,95 @@ foreach target : target_dirs
   endforeach
 endforeach
 
+# Combined qemu-system: one apply + extract, same sources as
+# qemu-system-$target.
+#
+# common_ss / system_ss use single_binary_config, the non-TARGET_* union where
+# 'y' takes precedence.
+# Do not use when: 'TARGET_*' on these sets; those keys are dropped and the 
file
+# would vanish from qemu-system.
+#
+# Family common/system libs use config_base_arch_mak[base] (every target of 
that
+# TARGET_BASE_ARCH, including user-mode if enabled).
+#
+# Each qemu-* lib contributes target-info-def.c. Participating targets must 
have
+# arch_srcs equal to target_info_def only.
+if single_binary_available
+  single_binary_objects = []
+  target_common = common_ss.apply(single_binary_config, strict: false)
+  single_binary_objects += common_all.extract_objects(target_common.sources())
+  single_binary_deps += target_common.dependencies()
+
+  target_system = system_ss.apply(single_binary_config, strict: false)
+  single_binary_objects += libsystem.extract_objects(target_system.sources())
+  single_binary_deps += target_system.dependencies()
+
+  foreach base, _ : single_binary_bases
+    config_base = config_base_arch_mak[base]
+    if base in target_common_arch_libs
+      src = target_common_arch[base].apply(config_base, strict: false)
+      single_binary_objects += target_common_arch_libs[base].extract_objects(
+        src.sources())
+      single_binary_deps += src.dependencies()
+    endif
+    if base in target_common_system_arch_libs
+      src = target_common_system_arch[base].apply(config_base, strict: false)
+      single_binary_objects += 
target_common_system_arch_libs[base].extract_objects(
+        src.sources())
+      single_binary_deps += src.dependencies()
+    endif
+  endforeach
+  single_binary_objects += single_binary_target_info_objects
+
+  single_binary_link_args = emulator_link_args
+  single_binary_link_args += enable_modules ? ['@block.syms', '@qemu.syms'] : 
[]
+  qemu_system_name = 'qemu-system'
+  if host_os == 'darwin'
+    qemu_system_name += '-unsigned'
+  endif
+  qemu_system = executable(qemu_system_name,
+                           sources: [single_binary_crates, 
files('system/main.c')],
+                           dependencies: single_binary_deps + [sdl],
+                           objects: single_binary_objects,
+                           link_depends: [block_syms, qemu_syms],
+                           link_args: single_binary_link_args,
+                           build_by_default: true,
+                           install: true)
+  if host_os == 'darwin'
+    icon = 'pc-bios/qemu.rsrc'
+    build_input = [qemu_system, files(icon)]
+    install_input = [
+      get_option('bindir') / qemu_system_name,
+      meson.current_source_dir() / icon
+    ]
+    if 'CONFIG_HVF' in single_binary_config
+      entitlements = 'accel/hvf/entitlements.plist'
+      build_input += files(entitlements)
+      install_input += meson.current_source_dir() / entitlements
+    endif
+    emulators += {'qemu-system': custom_target('qemu-system',
+                 input: build_input,
+                 output: 'qemu-system',
+                 build_by_default: true,
+                 command: [entitlement, '@OUTPUT@', '@INPUT@'])
+    }
+    meson.add_install_script(entitlement, '--install',
+                             get_option('bindir') / 'qemu-system',
+                             install_input)
+  else
+    emulators += {'qemu-system': qemu_system}
+  endif
+else
+  error_str = f'''qemu-system only support targets:
+@single_binary_supported_targets@
+
+use ./configure --target-list= to choose at least one of them'''
+  t = custom_target(command: ['sh', '-c', 'echo "' + error_str + '" && exit 
1'],
+                    output: 'none',
+                    build_by_default: false)
+  alias_target('qemu-system', t)
+endif
+
 # Other build targets
 
 if get_option('plugins')
-- 
2.52.0.windows.1


Reply via email to