aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.objs2
-rw-r--r--Makefile.target14
-rw-r--r--chardev/Makefile.objs5
-rw-r--r--chardev/char.c2
-rw-r--r--hw/Makefile.objs2
-rw-r--r--hw/core/qdev.c6
-rw-r--r--hw/display/Makefile.objs30
-rw-r--r--hw/usb/Makefile.objs13
-rw-r--r--include/qemu/module.h2
-rw-r--r--include/qom/object.h12
-rw-r--r--qdev-monitor.c5
-rw-r--r--qom/object.c14
-rw-r--r--qom/qom-qmp-cmds.c3
-rw-r--r--softmmu/vl.c4
-rw-r--r--util/module.c67
15 files changed, 156 insertions, 25 deletions
diff --git a/Makefile.objs b/Makefile.objs
index 98383972ee..d22b3b45d7 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -59,6 +59,7 @@ common-obj-y += migration/
common-obj-y += audio/
common-obj-m += audio/
common-obj-y += hw/
+common-obj-m += hw/
common-obj-y += replay/
@@ -70,6 +71,7 @@ common-obj-$(CONFIG_TPM) += tpm.o
common-obj-y += backends/
common-obj-y += chardev/
+common-obj-m += chardev/
common-obj-$(CONFIG_SECCOMP) += qemu-seccomp.o
qemu-seccomp.o-cflags := $(SECCOMP_CFLAGS)
diff --git a/Makefile.target b/Makefile.target
index 8ed1eba95b..02bd9d7117 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -179,6 +179,20 @@ endif # CONFIG_SOFTMMU
dummy := $(call unnest-vars,,obj-y)
all-obj-y := $(obj-y)
+#
+# common-obj-m has some crap here, probably as side effect from
+# unnest-vars recursing into target directories to fill obj-y and not
+# properly handling the -m case.
+#
+# Clear common-obj-m as workaround. Fixes suspious dependency errors
+# when building devices as modules. A bit hackish, but should be ok
+# as long as we do not have any target-specific modules.
+#
+# The meson-based build system currently in development doesn't need
+# unnest-vars and will obsolete this workaround.
+#
+common-obj-m :=
+
include $(SRC_PATH)/Makefile.objs
dummy := $(call unnest-vars,.., \
authz-obj-y \
diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs
index d68e1347f9..3a58c9d329 100644
--- a/chardev/Makefile.objs
+++ b/chardev/Makefile.objs
@@ -18,8 +18,11 @@ chardev-obj-$(CONFIG_WIN32) += char-win.o
chardev-obj-$(CONFIG_WIN32) += char-win-stdio.o
common-obj-y += msmouse.o wctablet.o testdev.o
-common-obj-$(CONFIG_BRLAPI) += baum.o
+
+ifeq ($(CONFIG_BRLAPI),y)
+common-obj-m += baum.o
baum.o-cflags := $(SDL_CFLAGS)
baum.o-libs := $(BRLAPI_LIBS)
+endif
common-obj-$(CONFIG_SPICE) += spice.o
diff --git a/chardev/char.c b/chardev/char.c
index e3051295ac..df697f3ce9 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -527,7 +527,7 @@ static const ChardevClass *char_get_class(const char *driver, Error **errp)
const ChardevClass *cc;
char *typename = g_strdup_printf("chardev-%s", driver);
- oc = object_class_by_name(typename);
+ oc = module_object_class_by_name(typename);
g_free(typename);
if (!object_class_dynamic_cast(oc, TYPE_CHARDEV)) {
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 4cbe5e4e57..14b7ea4eb6 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -43,4 +43,6 @@ devices-dirs-y += smbios/
endif
common-obj-y += $(devices-dirs-y)
+common-obj-m += display/
+common-obj-m += usb/
obj-y += $(devices-dirs-y)
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 2131c7f951..9de16eae05 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -137,6 +137,9 @@ void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
*/
DeviceState *qdev_new(const char *name)
{
+ if (!object_class_by_name(name)) {
+ module_load_qom_one(name);
+ }
return DEVICE(object_new(name));
}
@@ -147,10 +150,9 @@ DeviceState *qdev_new(const char *name)
*/
DeviceState *qdev_try_new(const char *name)
{
- if (!object_class_by_name(name)) {
+ if (!module_object_class_by_name(name)) {
return NULL;
}
-
return DEVICE(object_new(name));
}
diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
index 77a7d622bd..e907f3182b 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -44,18 +44,24 @@ common-obj-$(CONFIG_ARTIST) += artist.o
obj-$(CONFIG_VGA) += vga.o
-common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o
-
-obj-$(CONFIG_VIRTIO_GPU) += virtio-gpu-base.o virtio-gpu.o virtio-gpu-3d.o
-obj-$(CONFIG_VHOST_USER_GPU) += vhost-user-gpu.o
-obj-$(call land,$(CONFIG_VIRTIO_GPU),$(CONFIG_VIRTIO_PCI)) += virtio-gpu-pci.o
-obj-$(call land,$(CONFIG_VHOST_USER_GPU),$(CONFIG_VIRTIO_PCI)) += vhost-user-gpu-pci.o
-obj-$(CONFIG_VIRTIO_VGA) += virtio-vga.o
-obj-$(CONFIG_VHOST_USER_VGA) += vhost-user-vga.o
-virtio-gpu.o-cflags := $(VIRGL_CFLAGS)
-virtio-gpu.o-libs += $(VIRGL_LIBS)
-virtio-gpu-3d.o-cflags := $(VIRGL_CFLAGS)
-virtio-gpu-3d.o-libs += $(VIRGL_LIBS)
+ifeq ($(CONFIG_QXL),y)
+common-obj-m += qxl.mo
+qxl.mo-objs = qxl.o qxl-logger.o qxl-render.o
+endif
+
+ifeq ($(CONFIG_VIRTIO_GPU),y)
+common-obj-m += virtio-gpu.mo
+virtio-gpu-obj-$(CONFIG_VIRTIO_GPU) += virtio-gpu-base.o virtio-gpu.o virtio-gpu-3d.o
+virtio-gpu-obj-$(CONFIG_VHOST_USER_GPU) += vhost-user-gpu.o
+virtio-gpu-obj-$(call land,$(CONFIG_VIRTIO_GPU),$(CONFIG_VIRTIO_PCI)) += virtio-gpu-pci.o
+virtio-gpu-obj-$(call land,$(CONFIG_VHOST_USER_GPU),$(CONFIG_VIRTIO_PCI)) += vhost-user-gpu-pci.o
+virtio-gpu-obj-$(CONFIG_VIRTIO_VGA) += virtio-vga.o
+virtio-gpu-obj-$(CONFIG_VHOST_USER_VGA) += vhost-user-vga.o
+virtio-gpu.mo-objs := $(virtio-gpu-obj-y)
+virtio-gpu.mo-cflags := $(VIRGL_CFLAGS)
+virtio-gpu.mo-libs := $(VIRGL_LIBS)
+endif
+
common-obj-$(CONFIG_DPCD) += dpcd.o
common-obj-$(CONFIG_XLNX_ZYNQMP_ARM) += xlnx_dp.o
diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs
index fa5c3fa1b8..e342ff59fa 100644
--- a/hw/usb/Makefile.objs
+++ b/hw/usb/Makefile.objs
@@ -29,11 +29,13 @@ common-obj-$(CONFIG_USB_NETWORK) += dev-network.o
ifeq ($(CONFIG_USB_SMARTCARD),y)
common-obj-y += dev-smartcard-reader.o
-common-obj-$(CONFIG_SMARTCARD) += smartcard.mo
+ifeq ($(CONFIG_SMARTCARD),y)
+common-obj-m += smartcard.mo
smartcard.mo-objs := ccid-card-passthru.o ccid-card-emulated.o
smartcard.mo-cflags := $(SMARTCARD_CFLAGS)
smartcard.mo-libs := $(SMARTCARD_LIBS)
endif
+endif
ifeq ($(CONFIG_POSIX),y)
common-obj-$(CONFIG_USB_STORAGE_MTP) += dev-mtp.o
@@ -41,9 +43,12 @@ endif
# usb redirection
ifeq ($(CONFIG_USB),y)
-common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o
-redirect.o-cflags = $(USB_REDIR_CFLAGS)
-redirect.o-libs = $(USB_REDIR_LIBS)
+ifeq ($(CONFIG_USB_REDIR),y)
+common-obj-m += redirect.mo
+redirect.mo-objs = redirect.o quirks.o
+redirect.mo-cflags = $(USB_REDIR_CFLAGS)
+redirect.mo-libs = $(USB_REDIR_LIBS)
+endif
endif
# usb pass-through
diff --git a/include/qemu/module.h b/include/qemu/module.h
index 011ae1ae76..9121a475c1 100644
--- a/include/qemu/module.h
+++ b/include/qemu/module.h
@@ -70,5 +70,7 @@ void register_dso_module_init(void (*fn)(void), module_init_type type);
void module_call_init(module_init_type type);
bool module_load_one(const char *prefix, const char *lib_name);
+void module_load_qom_one(const char *type);
+void module_load_qom_all(void);
#endif
diff --git a/include/qom/object.h b/include/qom/object.h
index 94a61ccc3f..51f188137f 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -994,6 +994,18 @@ bool object_class_is_abstract(ObjectClass *klass);
*/
ObjectClass *object_class_by_name(const char *typename);
+/**
+ * module_object_class_by_name:
+ * @typename: The QOM typename to obtain the class for.
+ *
+ * For objects which might be provided by a module. Behaves like
+ * object_class_by_name, but additionally tries to load the module
+ * needed in case the class is not available.
+ *
+ * Returns: The class for @typename or %NULL if not found.
+ */
+ObjectClass *module_object_class_by_name(const char *typename);
+
void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
const char *implements_type, bool include_abstract,
void *opaque);
diff --git a/qdev-monitor.c b/qdev-monitor.c
index e3083fae39..648b8ac4fa 100644
--- a/qdev-monitor.c
+++ b/qdev-monitor.c
@@ -149,6 +149,7 @@ static void qdev_print_devinfos(bool show_no_user)
int i;
bool cat_printed;
+ module_load_qom_all();
list = object_class_get_list_sorted(TYPE_DEVICE, false);
for (i = 0; i <= DEVICE_CATEGORY_MAX; i++) {
@@ -217,13 +218,13 @@ static DeviceClass *qdev_get_device_class(const char **driver, Error **errp)
DeviceClass *dc;
const char *original_name = *driver;
- oc = object_class_by_name(*driver);
+ oc = module_object_class_by_name(*driver);
if (!oc) {
const char *typename = find_typename_by_alias(*driver);
if (typename) {
*driver = typename;
- oc = object_class_by_name(*driver);
+ oc = module_object_class_by_name(*driver);
}
}
diff --git a/qom/object.c b/qom/object.c
index 6ece96bc2b..34daaf1280 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -985,6 +985,20 @@ ObjectClass *object_class_by_name(const char *typename)
return type->class;
}
+ObjectClass *module_object_class_by_name(const char *typename)
+{
+ ObjectClass *oc;
+
+ oc = object_class_by_name(typename);
+#ifdef CONFIG_MODULES
+ if (!oc) {
+ module_load_qom_one(typename);
+ oc = object_class_by_name(typename);
+ }
+#endif
+ return oc;
+}
+
ObjectClass *object_class_get_parent(ObjectClass *class)
{
TypeImpl *type = type_get_parent(class->type);
diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
index c5249e44d0..5e2c8cbf33 100644
--- a/qom/qom-qmp-cmds.c
+++ b/qom/qom-qmp-cmds.c
@@ -116,6 +116,7 @@ ObjectTypeInfoList *qmp_qom_list_types(bool has_implements,
{
ObjectTypeInfoList *ret = NULL;
+ module_load_qom_all();
object_class_foreach(qom_list_types_tramp, implements, abstract, &ret);
return ret;
@@ -130,7 +131,7 @@ ObjectPropertyInfoList *qmp_device_list_properties(const char *typename,
ObjectPropertyIterator iter;
ObjectPropertyInfoList *prop_list = NULL;
- klass = object_class_by_name(typename);
+ klass = module_object_class_by_name(typename);
if (klass == NULL) {
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
"Device '%s' not found", typename);
diff --git a/softmmu/vl.c b/softmmu/vl.c
index ecbc18ba75..3f58ffd4dc 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -1772,8 +1772,8 @@ static bool vga_interface_available(VGAInterfaceType t)
assert(t < VGA_TYPE_MAX);
return !ti->class_names[0] ||
- object_class_by_name(ti->class_names[0]) ||
- object_class_by_name(ti->class_names[1]);
+ module_object_class_by_name(ti->class_names[0]) ||
+ module_object_class_by_name(ti->class_names[1]);
}
static const char *
diff --git a/util/module.c b/util/module.c
index e48d9aacc0..32b0547b82 100644
--- a/util/module.c
+++ b/util/module.c
@@ -245,3 +245,70 @@ bool module_load_one(const char *prefix, const char *lib_name)
#endif
return success;
}
+
+/*
+ * Building devices and other qom objects modular is mostly useful in
+ * case they have dependencies to external shared libraries, so we can
+ * cut down the core qemu library dependencies. Which is the case for
+ * only a very few devices & objects.
+ *
+ * So with the expectation that this will be rather the exception than
+ * to rule and the list will not gain that many entries go with a
+ * simple manually maintained list for now.
+ */
+static struct {
+ const char *type;
+ const char *prefix;
+ const char *module;
+} const qom_modules[] = {
+ { "ccid-card-passthru", "hw-", "usb-smartcard" },
+ { "ccid-card-emulated", "hw-", "usb-smartcard" },
+ { "usb-redir", "hw-", "usb-redirect" },
+ { "qxl-vga", "hw-", "display-qxl" },
+ { "qxl", "hw-", "display-qxl" },
+ { "virtio-gpu-device", "hw-", "display-virtio-gpu" },
+ { "virtio-gpu-pci", "hw-", "display-virtio-gpu" },
+ { "virtio-vga", "hw-", "display-virtio-gpu" },
+ { "vhost-user-gpu-device", "hw-", "display-virtio-gpu" },
+ { "vhost-user-gpu-pci", "hw-", "display-virtio-gpu" },
+ { "vhost-user-vga", "hw-", "display-virtio-gpu" },
+ { "chardev-braille", "chardev-", "baum" },
+};
+
+static bool module_loaded_qom_all;
+
+void module_load_qom_one(const char *type)
+{
+ int i;
+
+ if (module_loaded_qom_all) {
+ return;
+ }
+ for (i = 0; i < ARRAY_SIZE(qom_modules); i++) {
+ if (strcmp(qom_modules[i].type, type) == 0) {
+ module_load_one(qom_modules[i].prefix,
+ qom_modules[i].module);
+ return;
+ }
+ }
+}
+
+void module_load_qom_all(void)
+{
+ int i;
+
+ if (module_loaded_qom_all) {
+ return;
+ }
+ for (i = 0; i < ARRAY_SIZE(qom_modules); i++) {
+ if (i > 0 && (strcmp(qom_modules[i - 1].module,
+ qom_modules[i].module) == 0 &&
+ strcmp(qom_modules[i - 1].prefix,
+ qom_modules[i].prefix) == 0)) {
+ /* one module implementing multiple types -> load only once */
+ continue;
+ }
+ module_load_one(qom_modules[i].prefix, qom_modules[i].module);
+ }
+ module_loaded_qom_all = true;
+}