The issue about code coverage for libguestfs
Hi, I tried to do code coverage testing for libguestfs with gcov. The steps are shown as follows: 1. Download and install the source package(libguestfs-1.36.5-1.el7.src.rpm) 2. Modify libguestfs.spec file #diff -u libguestfs.spec libguestfs.spec.modify --------------------------------------------------------------------------------------- --- libguestfs.spec 2017-08-29 02:44:35.623751541 -0400 +++ libguestfs.spec.modify 2017-08-29 06:09:49.650654223 -0400 @@ -14,7 +14,7 @@ Name: libguestfs Epoch: 1 Version: 1.36.5 -Release: 1%{?dist} +Release: 1.gcov%{?dist} License: LGPLv2+ # Source and patches. @@ -69,7 +69,7 @@ Patch0034: 0034-RHEL-7-v2v-disable-unconfig-of-manually-installed-VM.patch Patch0035: 0035-v2v-i-ova-Prefer-pigz-or-pxz-for-uncompressing-OVA-f.patch Patch0036: 0036-resize-handle-empty-UUIDs-for-swap-partitions-RHBZ-1.patch - +Patch0037: 0037-possible-link-fix.patch # Use git for patch management. BuildRequires: git @@ -815,6 +815,8 @@ %build +CFLAGS="-fprofile-arcs -ftest-coverage -g -O0"; export CFLAGS +LDFLAGS="-fprofile-arcs -ftest-coverage -lgcov"; export LDFLAGS # Test if network is available. ip addr list ||: ip route list ||: @@ -852,6 +854,7 @@ --disable-golang \ $extra +sed -i 's/^CFLAGS = -fprofile-arcs -ftest-coverage -g -O0/CFLAGS = /g' /home/mockbuild/rpmbuild/BUILD/libguestfs-1.36.5/ocaml/Makefile # Building index-parse.c by hand works around a race condition in the # autotools cruft, where two or more copies of yacc race with each # other, resulting in a corrupted file. ------------------------------------------------------------------------------------------ 3.Execute rpmbuild command, but it failed with some errors. #rpmbuild -ba SPECS/libguestfs.spec ------------------------------------------------------------------------------------------ ... gcc -std=gnu99 -std=gnu99 -DHAVE_CONFIG_H -I. -I.. -DGUESTFS_PRIVATE=1 -I.. -I/usr/lib64/ocaml -I../ocaml -I../common/utils -I../common/utils -I../lib -I../lib -I../gnulib/lib -I../gnulib/lib -fno-common -W -Wabi -Waddress -Waggressive-loop-optimizations -Wall -Wattributes -Wbad-function-cast -Wbuiltin-macro-redefined -Wchar-subscripts -Wclobbered -Wcomment -Wcomments -Wcoverage-mismatch -Wcpp -Wdeprecated -Wdeprecated-declarations -Wdisabled-optimization -Wdiv-by-zero -Wdouble-promotion -Wempty-body -Wendif-labels -Wenum-compare -Wextra -Wformat-contains-nul -Wformat-extra-args -Wformat-nonliteral -Wformat-security -Wformat-y2k -Wformat-zero-length -Wfree-nonheap-object -Wignored-qualifiers -Wimplicit -Wimplicit-function-declaration -Wimplicit-int -Winit-self -Wint-to-pointer-cast -Winvalid-memory-model -Winvalid-pch -Wjump-misses-init -Wlogical-op -Wmain -Wmaybe-uninitialized -Wmissing-braces -Wmissing-declarations -Wmissing-field-initializers -Wmissing-include-dirs -Wmissing-parameter-type -Wmissing-prototypes -Wmultichar -Wnarrowing -Wnested-externs -Wnonnull -Wold-style-declaration -Wold-style-definition -Woverflow -Woverride-init -Wpacked-bitfield-compat -Wparentheses -Wpointer-arith -Wpointer-sign -Wpointer-to-int-cast -Wpragmas -Wreturn-local-addr -Wreturn-type -Wsequence-point -Wsizeof-pointer-memaccess -Wstrict-aliasing -Wstrict-overflow -Wstrict-prototypes -Wsuggest-attribute=format -Wsuggest-attribute=noreturn -Wswitch -Wsync-nand -Wtrampolines -Wtrigraphs -Wtype-limits -Wuninitialized -Wunknown-pragmas -Wunused -Wunused-but-set-parameter -Wunused-but-set-variable -Wunused-function -Wunused-label -Wunused-local-typedefs -Wunused-macros -Wunused-parameter -Wunused-result -Wunused-value -Wunused-variable -Wvarargs -Wvariadic-macros -Wvector-operation-performance -Wvolatile-register-var -Wwrite-strings -Wnormalized=nfc -Wno-unused-parameter -Wno-missing-field-initializers -fdiagnostics-show-option -Wframe-larger-than=5000 -Wstack-usage=10000 -fPIC -fno-strict-overflow -Wno-strict-overflow -c -o ../common/utils/libguestfsocaml_a-utils.o `test -f '../common/utils/utils.c' || echo './'`../common/utils/utils.c ocamlfind ocamlc -g -annot -warn-error CDEFLMPSUVYZX-3 -package unix -c guestfs.ml -o guestfs.cmo ocamlfind ocamlopt -g -annot -warn-error CDEFLMPSUVYZX-3 -package unix -c guestfs.ml -o guestfs.cmx rm -f libguestfsocaml.a ar cr libguestfsocaml.a libguestfsocaml_a-guestfs-c.o libguestfsocaml_a-guestfs-c-actions.o libguestfsocaml_a-guestfs-c-errnos.o ../common/utils/libguestfsocaml_a-utils.o ../gnulib/lib/libgnu.la ranlib libguestfsocaml.a ocamlmklib -o mlguestfs \ libguestfsocaml_a-guestfs-c.o libguestfsocaml_a-guestfs-c-actions.o libguestfsocaml_a-guestfs-c-errnos.o ../common/utils/libguestfsocaml_a-utils.o guestfs.cmo \ -fprofile-arcs -ftest-coverage -lgcov \ \ -L../lib/.libs -lguestfs Unknown option -fprofile-arcs Unknown option -ftest-coverage ocamlmklib -o mlguestfs \ libguestfsocaml_a-guestfs-c.o libguestfsocaml_a-guestfs-c-actions.o libguestfsocaml_a-guestfs-c-errnos.o ../common/utils/libguestfsocaml_a-utils.o guestfs.cmx \ -fprofile-arcs -ftest-coverage -lgcov \ \ -L../lib/.libs -lguestfs Unknown option -fprofile-arcs Unknown option -ftest-coverage touch stamp-mlguestfs Warning: Element Unix.error not found make[2]: Leaving directory `/home/mockbuild/rpmbuild/BUILD/libguestfs-1.36.5/ocaml' Making all in ocaml/examples make[2]: Entering directory `/home/mockbuild/rpmbuild/BUILD/libguestfs-1.36.5/ocaml/examples' ocamlfind ocamlopt -cclib -L../../lib/.libs -package unix -linkpkg \ -warn-error A -I .. mlguestfs.cmxa create_disk.ml -o create_disk ocamlfind ocamlopt -cclib -L../../lib/.libs -package unix -linkpkg \ -warn-error A -I .. mlguestfs.cmxa debug_logging.ml -o debug_logging ../libmlguestfs.a(libguestfsocaml_a-utils.o): In function `guestfs_int_string_is_valid': utils.c:(.text+0xb99): undefined reference to `c_isalpha' utils.c:(.text+0xbbf): undefined reference to `c_isdigit' collect2: error: ld returned 1 exit status File "caml_startup", line 1: Error: Error during linking make[2]: *** [debug_logging] Error 2 make[2]: *** Waiting for unfinished jobs.... ../libmlguestfs.a(libguestfsocaml_a-utils.o): In function `guestfs_int_string_is_valid': utils.c:(.text+0xb99): undefined reference to `c_isalpha' utils.c:(.text+0xbbf): undefined reference to `c_isdigit' collect2: error: ld returned 1 exit status File "caml_startup", line 1: Error: Error during linking make[2]: *** [create_disk] Error 2 make[2]: Leaving directory `/home/mockbuild/rpmbuild/BUILD/libguestfs-1.36.5/ocaml/examples' make[1]: *** [all-recursive] Error 1 make[1]: Leaving directory `/home/mockbuild/rpmbuild/BUILD/libguestfs-1.36.5' make: *** [all] Error 2 error: Bad exit status from /var/tmp/rpm-tmp.JoY6TA (%build) RPM build errors: Bad exit status from /var/tmp/rpm-tmp.JoY6TA (%build) --------------------------------------------------------------------------------------- The patch in attachment added in libguestfs.spec aims to resolve the above issue. But it seems to have no effect. Any idea how to resolve this issue? Thanks. Best Regards Yongkui Guo IRC: yoguo Tel: 15010777318
On Thu, Aug 31, 2017 at 05:45:38AM -0400, Yongkui Guo wrote:
Hi,
I tried to do code coverage testing for libguestfs with gcov.
The steps are shown as follows: 1. Download and install the source package(libguestfs-1.36.5-1.el7.src.rpm)
Probably best to try building this from git instead of using RPMs, so we can get the changes working upstream first. Make sure to read this page first: http://libguestfs.org/guestfs-building.1.html
+CFLAGS="-fprofile-arcs -ftest-coverage -g -O0"; export CFLAGS +LDFLAGS="-fprofile-arcs -ftest-coverage -lgcov"; export LDFLAGS
+sed -i 's/^CFLAGS = -fprofile-arcs -ftest-coverage -g -O0/CFLAGS = /g' /home/mockbuild/rpmbuild/BUILD/libguestfs-1.36.5/ocaml/Makefile
../libmlguestfs.a(libguestfsocaml_a-utils.o): In function `guestfs_int_string_is_valid': utils.c:(.text+0xb99): undefined reference to `c_isalpha' utils.c:(.text+0xbbf): undefined reference to `c_isdigit'
I suppose that we need to link the OCaml bindings to -lgnu, which your patch attempts:
+libguestfsocaml_a_LIBADD = \ + $(top_builddir)/gnulib/lib/libgnu.la +
... but the problem is that libguestfsocaml.a isn't really used for anything. See the comment in the same Makefile.am: # Build the C part into a library, so that automake handles the C # compilation step for us. Note that we don't directly use this # library; we link with the object files that it generates. noinst_LIBRARIES = libguestfsocaml.a You'll need to change all the places where $(libguestfsocaml_a_OBJECTS) is used instead, eg something like this untested change: stamp-mlguestfs: libguestfsocaml.a $(guestfs_cmm) $(OCAMLMKLIB) -o mlguestfs \ $(libguestfsocaml_a_OBJECTS) guestfs.cmo \ $(LDFLAGS) \ $(LTLIBINTL) \ - -L../lib/.libs -lguestfs + -L../lib/.libs -lguestfs \ + -L../gnulib/lib/.libs -lgnu if HAVE_OCAMLOPT $(OCAMLMKLIB) -o mlguestfs \ $(libguestfsocaml_a_OBJECTS) guestfs.cmx \ $(LDFLAGS) \ $(LTLIBINTL) \ - -L../lib/.libs -lguestfs + -L../lib/.libs -lguestfs \ + -L../gnulib/lib/.libs -lgnu endif touch $@ Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com libguestfs lets you edit virtual machines. Supports shell scripting, bindings from many languages. http://libguestfs.org
----- Original Message -----
On Thu, Aug 31, 2017 at 05:45:38AM -0400, Yongkui Guo wrote:
Hi,
I tried to do code coverage testing for libguestfs with gcov.
The steps are shown as follows: 1. Download and install the source package(libguestfs-1.36.5-1.el7.src.rpm)
Probably best to try building this from git instead of using RPMs, so we can get the changes working upstream first. Make sure to read this page first:
I will read it later. And I need to think about how to do code coverage in this way. Thanks.
+CFLAGS="-fprofile-arcs -ftest-coverage -g -O0"; export CFLAGS +LDFLAGS="-fprofile-arcs -ftest-coverage -lgcov"; export LDFLAGS
+sed -i 's/^CFLAGS = -fprofile-arcs -ftest-coverage -g -O0/CFLAGS = /g' /home/mockbuild/rpmbuild/BUILD/libguestfs-1.36.5/ocaml/Makefile
../libmlguestfs.a(libguestfsocaml_a-utils.o): In function `guestfs_int_string_is_valid': utils.c:(.text+0xb99): undefined reference to `c_isalpha' utils.c:(.text+0xbbf): undefined reference to `c_isdigit'
I suppose that we need to link the OCaml bindings to -lgnu, which your patch attempts:
+libguestfsocaml_a_LIBADD = \ + $(top_builddir)/gnulib/lib/libgnu.la +
... but the problem is that libguestfsocaml.a isn't really used for anything. See the comment in the same Makefile.am:
# Build the C part into a library, so that automake handles the C # compilation step for us. Note that we don't directly use this # library; we link with the object files that it generates. noinst_LIBRARIES = libguestfsocaml.a
You'll need to change all the places where $(libguestfsocaml_a_OBJECTS) is used instead, eg something like this untested change:
stamp-mlguestfs: libguestfsocaml.a $(guestfs_cmm) $(OCAMLMKLIB) -o mlguestfs \ $(libguestfsocaml_a_OBJECTS) guestfs.cmo \ $(LDFLAGS) \ $(LTLIBINTL) \ - -L../lib/.libs -lguestfs + -L../lib/.libs -lguestfs \ + -L../gnulib/lib/.libs -lgnu if HAVE_OCAMLOPT $(OCAMLMKLIB) -o mlguestfs \ $(libguestfsocaml_a_OBJECTS) guestfs.cmx \ $(LDFLAGS) \ $(LTLIBINTL) \ - -L../lib/.libs -lguestfs + -L../lib/.libs -lguestfs \ + -L../gnulib/lib/.libs -lgnu endif touch $@
I added the above changes as a patch. But it failed with the following error: --------------------------------------------------------- ... ocamlmklib -o mlguestfs \ libguestfsocaml_a-guestfs-c.o libguestfsocaml_a-guestfs-c-actions.o libguestfsocaml_a-guestfs-c-errnos.o ../common/utils/libguestfsocaml_a-utils.o guestfs.cmo \ -Wl,-z,relro -specs=/usr/lib/rpm/redhat/redhat-hardened-ld \ \ -L../lib/.libs -lguestfs \ -L../gnulib/lib/.libs -lgnu Unknown option -Wl,-z,relro Unknown option -specs=/usr/lib/rpm/redhat/redhat-hardened-ld ocamlmklib -o mlguestfs \ libguestfsocaml_a-guestfs-c.o libguestfsocaml_a-guestfs-c-actions.o libguestfsocaml_a-guestfs-c-errnos.o ../common/utils/libguestfsocaml_a-utils.o guestfs.cmx \ -Wl,-z,relro -specs=/usr/lib/rpm/redhat/redhat-hardened-ld \ \ -L../lib/.libs -lguestfs \ -L../gnulib/lib/.libs -lgnu Unknown option -Wl,-z,relro Unknown option -specs=/usr/lib/rpm/redhat/redhat-hardened-ld touch stamp-mlguestfs make[2]: Leaving directory `/home/mockbuild/rpmbuild/BUILD/libguestfs-1.36.5/ocaml' Making all in ocaml/examples make[2]: Entering directory `/home/mockbuild/rpmbuild/BUILD/libguestfs-1.36.5/ocaml/examples' ocamlfind ocamlopt -cclib -L../../lib/.libs -package unix -linkpkg \ -warn-error A -I .. mlguestfs.cmxa create_disk.ml -o create_disk ocamlfind ocamlopt -cclib -L../../lib/.libs -package unix -linkpkg \ -warn-error A -I .. mlguestfs.cmxa debug_logging.ml -o debug_logging /usr/bin/ld: cannot find -lgnu collect2: error: ld returned 1 exit status --------------------------------------------------------- Then I removed the '-lgnu' option. The error was still the same as before: --------------------------------------------------------- ... ocamlmklib -o mlguestfs \ libguestfsocaml_a-guestfs-c.o libguestfsocaml_a-guestfs-c-actions.o libguestfsocaml_a-guestfs-c-errnos.o ../common/utils/libguestfsocaml_a-utils.o guestfs.cmo \ -fprofile-arcs -ftest-coverage -lgcov \ \ -L../lib/.libs -lguestfs \ -L../gnulib/lib/.libs Unknown option -fprofile-arcs Unknown option -ftest-coverage ocamlmklib -o mlguestfs \ libguestfsocaml_a-guestfs-c.o libguestfsocaml_a-guestfs-c-actions.o libguestfsocaml_a-guestfs-c-errnos.o ../common/utils/libguestfsocaml_a-utils.o guestfs.cmx \ -fprofile-arcs -ftest-coverage -lgcov \ \ -L../lib/.libs -lguestfs \ -L../gnulib/lib/.libs Unknown option -fprofile-arcs Unknown option -ftest-coverage touch stamp-mlguestfs Warning: Element Unix.error not found make[2]: Leaving directory `/home/mockbuild/rpmbuild/BUILD/libguestfs-1.36.5/ocaml' Making all in ocaml/examples make[2]: Entering directory `/home/mockbuild/rpmbuild/BUILD/libguestfs-1.36.5/ocaml/examples' ocamlfind ocamlopt -cclib -L../../lib/.libs -package unix -linkpkg \ -warn-error A -I .. mlguestfs.cmxa create_disk.ml -o create_disk ocamlfind ocamlopt -cclib -L../../lib/.libs -package unix -linkpkg \ -warn-error A -I .. mlguestfs.cmxa debug_logging.ml -o debug_logging ../libmlguestfs.a(libguestfsocaml_a-utils.o): In function `guestfs_int_string_is_valid': utils.c:(.text+0xb99): undefined reference to `c_isalpha' utils.c:(.text+0xbbf): undefined reference to `c_isdigit' collect2: error: ld returned 1 exit status File "caml_startup", line 1: Error: Error during linking make[2]: *** [debug_logging] Error 2 make[2]: *** Waiting for unfinished jobs.... ../libmlguestfs.a(libguestfsocaml_a-utils.o): In function `guestfs_int_string_is_valid': utils.c:(.text+0xb99): undefined reference to `c_isalpha' utils.c:(.text+0xbbf): undefined reference to `c_isdigit' collect2: error: ld returned 1 exit status File "caml_startup", line 1: Error: Error during linking make[2]: *** [create_disk] Error 2 make[2]: Leaving directory `/home/mockbuild/rpmbuild/BUILD/libguestfs-1.36.5/ocaml/examples' make[1]: *** [all-recursive] Error 1 make[1]: Leaving directory `/home/mockbuild/rpmbuild/BUILD/libguestfs-1.36.5' make: *** [all] Error 2 error: Bad exit status from /var/tmp/rpm-tmp.FM2viv (%build) --------------------------------------------------------- Best wishes Yongkui Guo IRC: yoguo Tel: 15010777318
On Fri, Sep 01, 2017 at 04:28:52AM -0400, Yongkui Guo wrote:
stamp-mlguestfs: libguestfsocaml.a $(guestfs_cmm) $(OCAMLMKLIB) -o mlguestfs \ $(libguestfsocaml_a_OBJECTS) guestfs.cmo \ $(LDFLAGS) \ $(LTLIBINTL) \ - -L../lib/.libs -lguestfs + -L../lib/.libs -lguestfs \ + -L../gnulib/lib/.libs -lgnu [...] ocamlmklib -o mlguestfs \ libguestfsocaml_a-guestfs-c.o libguestfsocaml_a-guestfs-c-actions.o libguestfsocaml_a-guestfs-c-errnos.o ../common/utils/libguestfsocaml_a-utils.o guestfs.cmo \ -Wl,-z,relro -specs=/usr/lib/rpm/redhat/redhat-hardened-ld \
The problem is unrelated to the patch. $(LDFLAGS) are added to the ocamlmklib command, but ocamlmklib only understands a limited subset of linker flags, including -L but not including -Wl. Possibly something like this might work: stamp-mlguestfs: libguestfsocaml.a $(guestfs_cmm) $(OCAMLMKLIB) -o mlguestfs \ $(libguestfsocaml_a_OBJECTS) guestfs.cmo \ - $(LDFLAGS) \ + -ldopt '$(LDFLAGS)' \ $(LTLIBINTL) \ -L../lib/.libs -lguestfs (in all the places where $(LDFLAGS) is passed to ocamlmklib). Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-df lists disk usage of guests without needing to install any software inside the virtual machine. Supports Linux and Windows. http://people.redhat.com/~rjones/virt-df/
On Fri, Sep 01, 2017 at 04:28:52AM -0400, Yongkui Guo wrote:
stamp-mlguestfs: libguestfsocaml.a $(guestfs_cmm) $(OCAMLMKLIB) -o mlguestfs \ $(libguestfsocaml_a_OBJECTS) guestfs.cmo \ $(LDFLAGS) \ $(LTLIBINTL) \ - -L../lib/.libs -lguestfs + -L../lib/.libs -lguestfs \ + -L../gnulib/lib/.libs -lgnu [...] ocamlmklib -o mlguestfs \ libguestfsocaml_a-guestfs-c.o libguestfsocaml_a-guestfs-c-actions.o libguestfsocaml_a-guestfs-c-errnos.o ../common/utils/libguestfsocaml_a-utils.o guestfs.cmo \ -Wl,-z,relro -specs=/usr/lib/rpm/redhat/redhat-hardened-ld \
The problem is unrelated to the patch.
$(LDFLAGS) are added to the ocamlmklib command, but ocamlmklib only understands a limited subset of linker flags, including -L but not including -Wl.
Possibly something like this might work:
stamp-mlguestfs: libguestfsocaml.a $(guestfs_cmm) $(OCAMLMKLIB) -o mlguestfs \ $(libguestfsocaml_a_OBJECTS) guestfs.cmo \ - $(LDFLAGS) \ + -ldopt '$(LDFLAGS)' \ $(LTLIBINTL) \ -L../lib/.libs -lguestfs
(in all the places where $(LDFLAGS) is passed to ocamlmklib).
Unfortunately, it still didn't work well. Should I need to modify Makefile.am in /home/mockbuild/rpmbuild/BUILD/libguestfs-1.36.5/ocaml/examples? ------------------------------------------------- ocamlfind ocamlc -g -annot -warn-error CDEFLMPSUVYZX-3 -package unix -c guestfs.ml -o guestfs.cmo ocamlfind ocamlopt -g -annot -warn-error CDEFLMPSUVYZX-3 -package unix -c guestfs.ml -o guestfs.cmx rm -f libguestfsocaml.a ar cr libguestfsocaml.a libguestfsocaml_a-guestfs-c.o libguestfsocaml_a-guestfs-c-actions.o libguestfsocaml_a-guestfs-c-errnos.o ../common/utils/libguestfsocaml_a-utils.o ranlib libguestfsocaml.a ocamlmklib -o mlguestfs \ libguestfsocaml_a-guestfs-c.o libguestfsocaml_a-guestfs-c-actions.o libguestfsocaml_a-guestfs-c-errnos.o ../common/utils/libguestfsocaml_a-utils.o guestfs.cmo \ -ldopt '-fprofile-arcs -ftest-coverage -lgcov' \ \ -L../lib/.libs -lguestfs \ -L../gnulib/lib/.libs -lgnu ocamlmklib -o mlguestfs \ libguestfsocaml_a-guestfs-c.o libguestfsocaml_a-guestfs-c-actions.o libguestfsocaml_a-guestfs-c-errnos.o ../common/utils/libguestfsocaml_a-utils.o guestfs.cmx \ -ldopt '-fprofile-arcs -ftest-coverage -lgcov' \ \ -L../lib/.libs -lguestfs \ -L../gnulib/lib/.libs -lgnu touch stamp-mlguestfs Warning: Element Unix.error not found make[2]: Leaving directory `/home/mockbuild/rpmbuild/BUILD/libguestfs-1.36.5/ocaml' Making all in ocaml/examples make[2]: Entering directory `/home/mockbuild/rpmbuild/BUILD/libguestfs-1.36.5/ocaml/examples' ocamlfind ocamlopt -cclib -L../../lib/.libs -package unix -linkpkg \ -warn-error A -I .. mlguestfs.cmxa create_disk.ml -o create_disk ocamlfind ocamlopt -cclib -L../../lib/.libs -package unix -linkpkg \ -warn-error A -I .. mlguestfs.cmxa debug_logging.ml -o debug_logging /usr/bin/ld: cannot find -lgnu collect2: error: ld returned 1 exit status File "caml_startup", line 1: Error: Error during linking make[2]: *** [debug_logging] Error 2 make[2]: *** Waiting for unfinished jobs.... -------------------------------------------------
participants (2)
-
Richard W.M. Jones -
Yongkui Guo