Patchwork [RFC/RFT] build: replace weak symbols with a static library

login
register
mail settings
Submitter Paolo Bonzini
Date Nov. 16, 2012, 3:50 p.m.
Message ID <1353081001-12568-1-git-send-email-pbonzini@redhat.com>
Download mbox | patch
Permalink /patch/199668/
State New
Headers show

Comments

Paolo Bonzini - Nov. 16, 2012, 3:50 p.m.
Weak symbols were a nice idea, but they turned out not to be
a good one.  Toolchain support is just too sparse.

This patch uses a surprisingly low-tech approach, i.e. static
libraries.  Symbols in a static library are always overridden
by symbols in an object file.  Furthermore, if you place each
function in a separate source file, object files for unused
functions will not be taken in.  This means that each function
can use all the dependencies that it needs (especially QAPI
stuff such as error_setg).

All stubs are placed in separate object files and put together
in a static library.  The library then is linked to all
programs.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 Makefile                   | 14 ++++++++++----
 Makefile.objs              |  5 +++++
 Makefile.target            |  4 ++--
 compiler.h                 | 11 -----------
 osdep.c                    | 32 --------------------------------
 oslib-win32.c              |  7 -------
 qemu-sockets.c             | 22 ----------------------
 qmp.c                      |  9 ---------
 rules.mak                  |  2 +-
 stubs/Makefile.objs        |  8 ++++++++
 stubs/arch-query-cpu-def.c |  9 +++++++++
 stubs/fd-register.c        |  6 ++++++
 stubs/fdset-add-fd.c       |  7 +++++++
 stubs/fdset-find-fd.c      |  7 +++++++
 stubs/fdset-get-fd.c       |  7 +++++++
 stubs/fdset-remove-fd.c    |  7 +++++++
 stubs/get-fd.c             |  8 ++++++++
 stubs/set-fd-handler.c     | 11 +++++++++++
 18 file modificati, 88 inserzioni(+), 88 rimozioni(-)
 create mode 100644 stubs/Makefile.objs
 create mode 100644 stubs/arch-query-cpu-def.c
 create mode 100644 stubs/fd-register.c
 create mode 100644 stubs/fdset-add-fd.c
 create mode 100644 stubs/fdset-find-fd.c
 create mode 100644 stubs/fdset-get-fd.c
 create mode 100644 stubs/fdset-remove-fd.c
 create mode 100644 stubs/get-fd.c
 create mode 100644 stubs/set-fd-handler.c
Peter Maydell - Nov. 16, 2012, 4:54 p.m.
On 16 November 2012 15:50, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Weak symbols were a nice idea, but they turned out not to be
> a good one.  Toolchain support is just too sparse.
>
> This patch uses a surprisingly low-tech approach, i.e. static
> libraries.  Symbols in a static library are always overridden
> by symbols in an object file.  Furthermore, if you place each
> function in a separate source file, object files for unused
> functions will not be taken in.  This means that each function
> can use all the dependencies that it needs (especially QAPI
> stuff such as error_setg).
>
> All stubs are placed in separate object files and put together
> in a static library.  The library then is linked to all
> programs.

I think this is definitely a better approach; thanks for taking
the time to implement it. That said, this patch doesn't build on
MacOS:

manooth$ make V=1
make  BUILD_DIR=/Users/pm215/src/qemu -C libdis V="1" TARGET_DIR="libdis/" all
make  BUILD_DIR=/Users/pm215/src/qemu -C arm-softmmu V="1"
TARGET_DIR="arm-softmmu/" all
rm -f libqemustub.a && ar rcs libqemustub.a
ar: no archive members specified
usage:  ar -d [-TLsv] archive file ...
        ar -m [-TLsv] archive file ...
        ar -m [-abiTLsv] position archive file ...
        ar -p [-TLsv] archive [file ...]
        ar -q [-cTLsv] archive file ...
        ar -r [-cuTLsv] archive file ...
        ar -r [-abciuTLsv] position archive file ...
        ar -t [-TLsv] archive [file ...]
        ar -x [-ouTLsv] archive [file ...]
make[1]: *** [libqemustub.a] Error 1
make: *** [subdir-arm-softmmu] Error 2


And it doesn't build on Linux:

ccache gcc -Wl,--warn-common -Wl,-z,relro -Wl,-z,now -pie -m64 -g  -o
vscclient libcacard/cac.o libcacard/event.o libcacard/vcard.o
libcacard/vreader.o libcacard/vcard_emul_nss.o
libcacard/vcard_emul_type.o libcacard/card_7816.o osdep.o cutils.o
qemu-timer-common.o oslib-posix.o qemu-thread-posix.o trace.o
trace/default.o trace/control.o libcacard/vscclient.o -lnss3
-lnssutil3 -lsmime3 -lssl3 -lplds4 -lplc4 -lnspr4 -lpthread -ldl
-pthread -lgthread-2.0 -lrt -lglib-2.0   -lrt -pthread -lgthread-2.0
-lrt -lglib-2.0    -lz -lrbd -lrados -lcurl   -lvdeplug -luuid  -laio
osdep.o: In function `qemu_open':
/home/petmay01/linaro/qemu-from-laptop/qemu/osdep.c:166: undefined
reference to `monitor_fdset_get_fd'
/home/petmay01/linaro/qemu-from-laptop/qemu/osdep.c:176: undefined
reference to `monitor_fdset_dup_fd_add'
osdep.o: In function `qemu_close':
/home/petmay01/linaro/qemu-from-laptop/qemu/osdep.c:212: undefined
reference to `monitor_fdset_dup_fd_find'
/home/petmay01/linaro/qemu-from-laptop/qemu/osdep.c:218: undefined
reference to `monitor_fdset_dup_fd_remove'
collect2: ld returned 1 exit status
make: *** [vscclient] Error 1



-- PMM
Peter Maydell - Nov. 16, 2012, 5:06 p.m.
On 16 November 2012 16:54, Peter Maydell <peter.maydell@linaro.org> wrote:
> And it doesn't build on Linux:

Adding libqemustub.a to the vscclient$(EXESUF) prerequisites fixes
that, and then it fails on qemu-system-arm:

  LINK  arm-softmmu/qemu-system-arm
../qmp.o: In function `qmp_query_cpu_definitions':
/home/petmay01/linaro/qemu-from-laptop/qemu/qmp.c:476: undefined
reference to `arch_query_cpu_definitions'
collect2: ld returned 1 exit status

This turns out to be the same problem as the MacOS failure:
as well as building the libqemustub.a in the root directory
we also try to create an empty libqemustub.a in arm-softmmu/
(or whatever the target subdir is). On MacOS this fails
because ar doesn't allow an empty list of objects. On Linux
it succeeds, but then the final link of the qemu executable
fails because we use the emtpy archive rather than the one
with all the stub objects.

-- PMM
Peter Maydell - Nov. 16, 2012, 5:15 p.m.
On 16 November 2012 17:06, Peter Maydell <peter.maydell@linaro.org> wrote:
> This turns out to be the same problem as the MacOS failure:
> as well as building the libqemustub.a in the root directory
> we also try to create an empty libqemustub.a in arm-softmmu/
> (or whatever the target subdir is). On MacOS this fails
> because ar doesn't allow an empty list of objects. On Linux
> it succeeds, but then the final link of the qemu executable
> fails because we use the emtpy archive rather than the one
> with all the stub objects.

Changing all the references to libqemustub.a in Makefile.target
to read "../libqemustub.a" instead fixes this and we seem to
build OK on both MacOS and Linux.

-- PMM

Patch

diff --git a/Makefile b/Makefile
index 81c660f..686efe7 100644
--- a/Makefile
+++ b/Makefile
@@ -157,6 +157,12 @@  version.o: $(SRC_PATH)/version.rc config-host.h
 	$(call quiet-command,$(WINDRES) -I. -o $@ $<,"  RC    $(TARGET_DIR)$@")
 
 version-obj-$(CONFIG_WIN32) += version.o
+
+######################################################################
+# Build library with stubs
+
+libqemustub.a: $(stub-obj-y)
+
 ######################################################################
 # Support building shared library libcacard
 
@@ -183,9 +189,9 @@  tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \
 	main-loop.o iohandler.o error.o
 tools-obj-$(CONFIG_POSIX) += compatfd.o
 
-qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y)
-qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y)
-qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y)
+qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y) libqemustub.a
+qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y) libqemustub.a
+qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y) libqemustub.a
 
 qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
 
@@ -232,7 +238,7 @@  $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
 QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
 $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
 
-qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(oslib-obj-y) $(trace-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y)
+qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(oslib-obj-y) $(trace-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y) libqemustub.a
 
 QEMULIBS=libuser libdis libdis-user
 
diff --git a/Makefile.objs b/Makefile.objs
index 37be7e2..5f112dc 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -1,4 +1,8 @@ 
 #######################################################################
+# Stub library, linked in tools
+stub-obj-y = stubs/
+
+#######################################################################
 # Target-independent parts used in system and user emulation
 universal-obj-y =
 universal-obj-y += qemu-log.o
@@ -237,6 +241,7 @@  vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
 QEMU_CFLAGS+=$(GLIB_CFLAGS)
 
 nested-vars += \
+	stub-obj-y \
 	qga-obj-y \
 	qom-obj-y \
 	qapi-obj-y \
diff --git a/Makefile.target b/Makefile.target
index 3822bc5..2794dd4 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -162,12 +162,12 @@  endif #CONFIG_LINUX_USER
 
 ifdef QEMU_PROGW
 # The linker builds a windows executable. Make also a console executable.
-$(QEMU_PROGW): $(all-obj-y)
+$(QEMU_PROGW): $(all-obj-y) libqemustub.a
 	$(call LINK,$^)
 $(QEMU_PROG): $(QEMU_PROGW)
 	$(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG),"  GEN   $(TARGET_DIR)$(QEMU_PROG)")
 else
-$(QEMU_PROG): $(all-obj-y)
+$(QEMU_PROG): $(all-obj-y) libqemustub.a
 	$(call LINK,$^)
 endif
 
diff --git a/compiler.h b/compiler.h
index 55d7d74..2f7998b 100644
--- a/compiler.h
+++ b/compiler.h
@@ -50,20 +50,9 @@ 
 #   define __printf__ __gnu_printf__
 #  endif
 # endif
-# if defined(__APPLE__)
-#  define QEMU_WEAK_ALIAS(newname, oldname) \
-        static typeof(oldname) weak_##newname __attribute__((unused, weakref(#oldname)))
-#  define QEMU_WEAK_REF(newname, oldname) (weak_##newname ? weak_##newname : oldname)
-# else
-#  define QEMU_WEAK_ALIAS(newname, oldname) \
-        typeof(oldname) newname __attribute__((weak, alias (#oldname)))
-#  define QEMU_WEAK_REF(newname, oldname) newname
-# endif
 #else
 #define GCC_ATTR /**/
 #define GCC_FMT_ATTR(n, m)
-#define QEMU_WEAK_ALIAS(newname, oldname) \
-        _Pragma("weak " #newname "=" #oldname)
 #endif
 
 #endif /* COMPILER_H */
diff --git a/osdep.c b/osdep.c
index 2f7a491..3a63d26 100644
--- a/osdep.c
+++ b/osdep.c
@@ -54,38 +54,6 @@  static bool fips_enabled = false;
 
 static const char *qemu_version = QEMU_VERSION;
 
-static int default_fdset_get_fd(int64_t fdset_id, int flags)
-{
-    return -1;
-}
-QEMU_WEAK_ALIAS(monitor_fdset_get_fd, default_fdset_get_fd);
-#define monitor_fdset_get_fd \
-    QEMU_WEAK_REF(monitor_fdset_get_fd, default_fdset_get_fd)
-
-static int default_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
-{
-    return -1;
-}
-QEMU_WEAK_ALIAS(monitor_fdset_dup_fd_add, default_fdset_dup_fd_add);
-#define monitor_fdset_dup_fd_add \
-    QEMU_WEAK_REF(monitor_fdset_dup_fd_add, default_fdset_dup_fd_add)
-
-static int default_fdset_dup_fd_remove(int dup_fd)
-{
-    return -1;
-}
-QEMU_WEAK_ALIAS(monitor_fdset_dup_fd_remove, default_fdset_dup_fd_remove);
-#define monitor_fdset_dup_fd_remove \
-    QEMU_WEAK_REF(monitor_fdset_dup_fd_remove, default_fdset_dup_fd_remove)
-
-static int default_fdset_dup_fd_find(int dup_fd)
-{
-    return -1;
-}
-QEMU_WEAK_ALIAS(monitor_fdset_dup_fd_find, default_fdset_dup_fd_find);
-#define monitor_fdset_dup_fd_find \
-    QEMU_WEAK_REF(monitor_fdset_dup_fd_remove, default_fdset_dup_fd_find)
-
 int socket_set_cork(int fd, int v)
 {
 #if defined(SOL_TCP) && defined(TCP_CORK)
diff --git a/oslib-win32.c b/oslib-win32.c
index 326a2bd..51b33e8 100644
--- a/oslib-win32.c
+++ b/oslib-win32.c
@@ -32,13 +32,6 @@ 
 #include "trace.h"
 #include "qemu_socket.h"
 
-static void default_qemu_fd_register(int fd)
-{
-}
-QEMU_WEAK_ALIAS(qemu_fd_register, default_qemu_fd_register);
-#define qemu_fd_register \
-    QEMU_WEAK_REF(qemu_fd_register, default_qemu_fd_register)
-
 void *qemu_oom_check(void *ptr)
 {
     if (ptr == NULL) {
diff --git a/qemu-sockets.c b/qemu-sockets.c
index abcd791..cfed9c5 100644
--- a/qemu-sockets.c
+++ b/qemu-sockets.c
@@ -61,28 +61,6 @@  static QemuOptsList dummy_opts = {
     },
 };
 
-static int default_monitor_get_fd(Monitor *mon, const char *name, Error **errp)
-{
-    error_setg(errp, "only QEMU supports file descriptor passing");
-    return -1;
-}
-QEMU_WEAK_ALIAS(monitor_get_fd, default_monitor_get_fd);
-#define monitor_get_fd \
-    QEMU_WEAK_REF(monitor_get_fd, default_monitor_get_fd)
-
-static int default_qemu_set_fd_handler2(int fd,
-                                        IOCanReadHandler *fd_read_poll,
-                                        IOHandler *fd_read,
-                                        IOHandler *fd_write,
-                                        void *opaque)
-
-{
-    abort();
-}
-QEMU_WEAK_ALIAS(qemu_set_fd_handler2, default_qemu_set_fd_handler2);
-#define qemu_set_fd_handler2 \
-    QEMU_WEAK_REF(qemu_set_fd_handler2, default_qemu_set_fd_handler2)
-
 static int inet_getport(struct addrinfo *e)
 {
     struct sockaddr_in *i4;
diff --git a/qmp.c b/qmp.c
index 13e83a5..e3a7f0b 100644
--- a/qmp.c
+++ b/qmp.c
@@ -471,15 +471,6 @@  DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
     return prop_list;
 }
 
-static CpuDefinitionInfoList *default_arch_query_cpu_definitions(Error **errp)
-{
-    error_set(errp, QERR_NOT_SUPPORTED);
-    return NULL;
-}
-QEMU_WEAK_ALIAS(arch_query_cpu_definitions, default_arch_query_cpu_definitions);
-#define arch_query_cpu_definitions \
-    QEMU_WEAK_REF(arch_query_cpu_definitions, default_arch_query_cpu_definitions)
-
 CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
 {
     return arch_query_cpu_definitions(errp);
diff --git a/rules.mak b/rules.mak
index 1b173aa..d0b04e4 100644
--- a/rules.mak
+++ b/rules.mak
@@ -31,7 +31,7 @@  endif
 %.o: %.m
 	$(call quiet-command,$(OBJCC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<,"  OBJC  $(TARGET_DIR)$@")
 
-LINK = $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(sort $(1)) $(LIBS),"  LINK  $(TARGET_DIR)$@")
+LINK = $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(sort $(filter %.o, $1)) $(filter-out %.o, $1) $(LIBS),"  LINK  $(TARGET_DIR)$@")
 
 %$(EXESUF): %.o
 	$(call LINK,$^)
diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs
new file mode 100644
index 0000000..035b29a
--- /dev/null
+++ b/stubs/Makefile.objs
@@ -0,0 +1,8 @@ 
+stub-obj-y += arch-query-cpu-def.o
+stub-obj-y += fdset-add-fd.o
+stub-obj-y += fdset-find-fd.o
+stub-obj-y += fdset-get-fd.o
+stub-obj-y += fdset-remove-fd.o
+stub-obj-y += get-fd.o
+stub-obj-y += set-fd-handler.o
+stub-obj-$(CONFIG_WIN32) += fd-register.o
diff --git a/stubs/arch-query-cpu-def.c b/stubs/arch-query-cpu-def.c
new file mode 100644
index 0000000..47b5246
--- /dev/null
+++ b/stubs/arch-query-cpu-def.c
@@ -0,0 +1,9 @@ 
+#include "qemu-common.h"
+#include "arch_init.h"
+#include "qerror.h"
+
+CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
+{
+    error_set(errp, QERR_NOT_SUPPORTED);
+    return NULL;
+}
diff --git a/stubs/fd-register.c b/stubs/fd-register.c
new file mode 100644
index 0000000..813b6dd
--- /dev/null
+++ b/stubs/fd-register.c
@@ -0,0 +1,6 @@ 
+#include "qemu-common.h"
+#include "main-loop.h"
+
+void qemu_fd_register(int fd)
+{
+}
diff --git a/stubs/fdset-add-fd.c b/stubs/fdset-add-fd.c
new file mode 100644
index 0000000..09fe2a8
--- /dev/null
+++ b/stubs/fdset-add-fd.c
@@ -0,0 +1,7 @@ 
+#include "qemu-common.h"
+#include "monitor.h"
+
+int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
+{
+    return -1;
+}
diff --git a/stubs/fdset-find-fd.c b/stubs/fdset-find-fd.c
new file mode 100644
index 0000000..f82baa0
--- /dev/null
+++ b/stubs/fdset-find-fd.c
@@ -0,0 +1,7 @@ 
+#include "qemu-common.h"
+#include "monitor.h"
+
+int monitor_fdset_dup_fd_find(int dup_fd)
+{
+    return -1;
+}
diff --git a/stubs/fdset-get-fd.c b/stubs/fdset-get-fd.c
new file mode 100644
index 0000000..4106cf9
--- /dev/null
+++ b/stubs/fdset-get-fd.c
@@ -0,0 +1,7 @@ 
+#include "qemu-common.h"
+#include "monitor.h"
+
+int monitor_fdset_get_fd(int64_t fdset_id, int flags)
+{
+    return -1;
+}
diff --git a/stubs/fdset-remove-fd.c b/stubs/fdset-remove-fd.c
new file mode 100644
index 0000000..861b312
--- /dev/null
+++ b/stubs/fdset-remove-fd.c
@@ -0,0 +1,7 @@ 
+#include "qemu-common.h"
+#include "monitor.h"
+
+int monitor_fdset_dup_fd_remove(int dupfd)
+{
+    return -1;
+}
diff --git a/stubs/get-fd.c b/stubs/get-fd.c
new file mode 100644
index 0000000..3561ab6
--- /dev/null
+++ b/stubs/get-fd.c
@@ -0,0 +1,8 @@ 
+#include "qemu-common.h"
+#include "monitor.h"
+
+int monitor_get_fd(Monitor *mon, const char *name, Error **errp)
+{
+    error_setg(errp, "only QEMU supports file descriptor passing");
+    return -1;
+}
diff --git a/stubs/set-fd-handler.c b/stubs/set-fd-handler.c
new file mode 100644
index 0000000..4807b5d
--- /dev/null
+++ b/stubs/set-fd-handler.c
@@ -0,0 +1,11 @@ 
+#include "qemu-common.h"
+#include "main-loop.h"
+
+int qemu_set_fd_handler2(int fd,
+                         IOCanReadHandler *fd_read_poll,
+                         IOHandler *fd_read,
+                         IOHandler *fd_write,
+                         void *opaque)
+{
+    abort();
+}