I am using MV BlueFox3 camera on a RaspberryPi4 and I am trying to write a .bb recipe which is going to install the necessary software for the camera. A quick setup guide is on the manufacturer website, but I can not get the first part to work. So far, this is how my recipe looks:
SUMMARY = "Installs mvIMPACT Acquire base libraries"
DESCRIPTION = "This recipe installs mvIMPACT Acquire base libraries for all MATRIX VISION devices."
HOMEPAGE = "http://www.matrix-vision.de"
LICENSE_FLAGS = "EULA"
LICENSE_FLAGS_WHITELIST = "EULA"
LICENSE = "EULA"
LIC_FILES_CHKSUM = "file://${WORKDIR}/mvIMPACT_Acquire-ARM64-2.45.0/doc/EULA.txt;md5=f6f99507036166a5604b38e6df10f004"
PACKAGE_ARCH = "${MACHINE_ARCH}"
S = "${WORKDIR}"
SRC_URI = "file://mvGenTL_Acquire-ARM64_gnu-2.45.0.tgz"
TARGET = "arm64"
MVIA_SUBDIR = "opt/mvIMPACT_Acquire"
MVIA_LIB_SUBDIR = "lib"
TOOLKITS_LIB_SUBDIR = "Toolkits"
MV_DATA_DIR = "opt/mvIMPACT_Acquire/data"
do_install() {
# install mvIMPACT Acquire runtime binaries
install -m 0755 -d ${D}${base_prefix}/${MVIA_SUBDIR}/${MVIA_LIB_SUBDIR}
install -m 0755 -d ${D}${base_prefix}/${MVIA_SUBDIR}/${TOOLKITS_LIB_SUBDIR}
install -m 0755 -d ${D}${base_prefix}/${MVIA_SUBDIR}/${TOOLKITS_LIB_SUBDIR}/FreeImage3160/bin/Release/FreeImage/${TARGET}
oe_soinstall ${S}/mvIMPACT_Acquire-ARM64-${PV}/lib/${TARGET}/libmvDeviceManager.so.${PV} ${D}${base_prefix}/${MVIA_SUBDIR}/${MVIA_LIB_SUBDIR}
oe_soinstall ${S}/mvIMPACT_Acquire-ARM64-${PV}/lib/${TARGET}/libmvPropHandling.so.${PV} ${D}${base_prefix}/${MVIA_SUBDIR}/${MVIA_LIB_SUBDIR}
oe_soinstall ${S}/mvIMPACT_Acquire-ARM64-${PV}/Toolkits/expat/bin/${TARGET}/lib/*.so.* ${D}${base_prefix}/${MVIA_SUBDIR}/${TOOLKITS_LIB_SUBDIR}
install -m 0755 ${S}/mvIMPACT_Acquire-ARM64-${PV}/Toolkits/FreeImage3160/bin/Release/FreeImage/${TARGET}/*.so ${D}${base_prefix}/${MVIA_SUBDIR}/${TOOLKITS_LIB_SUBDIR}/FreeImage3160/bin/Release/FreeImage/${TARGET}
# set environment variables for mvIMPACT Acquire
install -m 0755 -d ${D}${sysconfdir}/profile.d
echo 'export MVIMPACT_ACQUIRE_DIR=/opt/mvIMPACT_Acquire' >> ${D}${sysconfdir}/profile.d/acquire.sh
echo 'export MVIMPACT_ACQUIRE_DATA_DIR=/opt/mvIMPACT_Acquire/data' >> ${D}${sysconfdir}/profile.d/acquire.sh
# set library search paths for the dynamic linker
install -m 0755 -d ${D}${sysconfdir}/ld.so.conf.d
echo '/opt/mvIMPACT_Acquire/lib' >> ${D}${sysconfdir}/ld.so.conf.d/acquire.conf
echo '/opt/mvIMPACT_Acquire/Toolkits' >> ${D}${sysconfdir}/ld.so.conf.d/acquire.conf
# set up logfiles
install -m 0755 -d ${D}${base_prefix}/${MV_DATA_DIR}/logs
install -m 0755 ${S}/mvIMPACT_Acquire-ARM64-${PV}/apps/mvDebugFlags.mvd ${D}${base_prefix}/${MV_DATA_DIR}/logs/
}
INHIBIT_PACKAGE_STRIP = "1"
INSANE_SKIP_${PN} += "dev-so \
already-stripped \
ldflags"
PACKAGES = "${PN} ${PN}-dev ${PN}-doc"
FILES_${PN} += "${base_prefix}/${MVIA_SUBDIR}/${MVIA_LIB_SUBDIR}/lib*.so.* \
${base_prefix}/${MVIA_SUBDIR}/${TOOLKITS_LIB_SUBDIR}/lib*.so.* \
${base_prefix}/${MVIA_SUBDIR}/${TOOLKITS_LIB_SUBDIR}/FreeImage3160/bin/Release/FreeImage/${TARGET}/lib*.so \
${sysconfdir}/profile.d/*.sh \
${sysconfdir}/ld.so.conf.d/*.conf"
FILES_${PN}-dev += "${base_prefix}/${MVIA_SUBDIR}/${MVIA_LIB_SUBDIR}/lib*.so \
${base_prefix}/${MVIA_SUBDIR}/${TOOLKITS_LIB_SUBDIR}/lib*.so"
FILES_${PN}-doc += "${base_prefix}/${MV_DATA_DIR}/logs"
but I am getting the following error:
NOTE: Executing Tasks
ERROR: mvimpact-acquire-base-2.45.0-r0 do_package: QA Issue: File '/opt/mvIMPACT_Acquire/Toolkits/FreeImage3160/bin/Release/FreeImage/arm64/libfreeimage-3.16.0.so' from mvimpact-acquire-base was already stripped, this will prevent future debugging! [already-stripped]
ERROR: mvimpact-acquire-base-2.45.0-r0 do_package: QA Issue: File '/opt/mvIMPACT_Acquire/Toolkits/libexpat.so.1.6.0' from mvimpact-acquire-base was already stripped, this will prevent future debugging! [already-stripped]
ERROR: mvimpact-acquire-base-2.45.0-r0 do_package: QA Issue: File '/opt/mvIMPACT_Acquire/lib/libmvDeviceManager.so.2.45.0' from mvimpact-acquire-base was already stripped, this will prevent future debugging! [already-stripped]
ERROR: mvimpact-acquire-base-2.45.0-r0 do_package: QA Issue: File '/opt/mvIMPACT_Acquire/lib/libmvPropHandling.so.2.45.0' from mvimpact-acquire-base was already stripped, this will prevent future debugging! [already-stripped]
ERROR: mvimpact-acquire-base-2.45.0-r0 do_package: QA Issue: mvimpact-acquire-base: Files/directories were installed but not shipped in any package:
/opt
/opt/mvIMPACT_Acquire
/opt/mvIMPACT_Acquire/Toolkits
/opt/mvIMPACT_Acquire/lib
/opt/mvIMPACT_Acquire/data
/opt/mvIMPACT_Acquire/Toolkits/libexpat.so
/opt/mvIMPACT_Acquire/Toolkits/libexpat.so.1.6.0
/opt/mvIMPACT_Acquire/Toolkits/libexpat.so.1
/opt/mvIMPACT_Acquire/Toolkits/FreeImage3160
/opt/mvIMPACT_Acquire/Toolkits/FreeImage3160/bin
/opt/mvIMPACT_Acquire/Toolkits/FreeImage3160/bin/Release
/opt/mvIMPACT_Acquire/Toolkits/FreeImage3160/bin/Release/FreeImage
/opt/mvIMPACT_Acquire/Toolkits/FreeImage3160/bin/Release/FreeImage/arm64
/opt/mvIMPACT_Acquire/Toolkits/FreeImage3160/bin/Release/FreeImage/arm64/libfreeimage-3.16.0.so
/opt/mvIMPACT_Acquire/lib/libmvPropHandling.so
/opt/mvIMPACT_Acquire/lib/libmvDeviceManager.so.2.45.0
/opt/mvIMPACT_Acquire/lib/libmvDeviceManager.so.2
/opt/mvIMPACT_Acquire/lib/libmvDeviceManager.so
/opt/mvIMPACT_Acquire/lib/libmvPropHandling.so.2.45.0
/opt/mvIMPACT_Acquire/lib/libmvPropHandling.so.2
/opt/mvIMPACT_Acquire/data/logs
/opt/mvIMPACT_Acquire/data/logs/mvDebugFlags.mvd
Please set FILES such that these items are packaged. Alternatively if they are unneeded, avoid installing them or delete them within do_install.
mvimpact-acquire-base: 22 installed and not shipped files. [installed-vs-shipped]
ERROR: mvimpact-acquire-base-2.45.0-r0 do_package: Fatal QA errors found, failing task.
ERROR: Logfile of failure stored in: /home/stefan/Projects/raspberrypiOS/build/tmp/work/raspberrypi4_64-poky-linux/mvimpact-acquire-base/2.45.0-r0/temp/log.do_package.2280592
ERROR: Task (/home/stefan/Projects/raspberrypiOS/meta-mvimpact-acquire/recipes-mvimpactacquire/mvimpact-acquire/mvimpact-acquire-base_2.45.0.bb:do_package) failed with exit code '1'
I am guessing that I should change the FILES variable to ensure proper package splitting but I do not know how. I have tried adding the directories and files from the error message, but no matter what I do, the error message seems to be the same (22 packages).
In the workdir, the image and package folders seem to be identical, and the package-split folder contains mvimpact-acquire-base (with only the /etc folder inside, but no /opt), while the mvimpact-acquire-base-dev, mvimpact-acquire-base-doc, mvimpact-acquire-base-src folders are all empty.
Can anyone help me understand this problem better or suggest a potential solution regarding the FILES variable and the error message.
I think the other error messages about stripping are not at issue here, but if you can share additional info it would be great.
Below are the contents of some WORKDIR(/work/raspberrypi4_64-poky-linux/mvimpact-acquire-base/2.45.0-r0) subdirectories.
image/
├── etc
│ ├── ld.so.conf.d
│ │ └── acquire.conf
│ └── profile.d
│ └── acquire.sh
└── opt
└── mvIMPACT_Acquire
├── data
│ └── logs
│ └── mvDebugFlags.mvd
├── lib
│ ├── libmvDeviceManager.so -> libmvDeviceManager.so.2.45.0
│ ├── libmvDeviceManager.so.2 -> libmvDeviceManager.so.2.45.0
│ ├── libmvDeviceManager.so.2.45.0
│ ├── libmvPropHandling.so -> libmvPropHandling.so.2.45.0
│ ├── libmvPropHandling.so.2 -> libmvPropHandling.so.2.45.0
│ └── libmvPropHandling.so.2.45.0
└── Toolkits
├── FreeImage3160
│ └── bin
│ └── Release
│ └── FreeImage
│ └── arm64
│ └── libfreeimage-3.16.0.so
├── libexpat.so -> libexpat.so.1.6.0
├── libexpat.so.1 -> libexpat.so.1.6.0
└── libexpat.so.1.6.0
14 directories, 13 files
package/
├── etc
│ ├── ld.so.conf.d
│ │ └── acquire.conf
│ └── profile.d
│ └── acquire.sh
└── opt
└── mvIMPACT_Acquire
├── data
│ └── logs
│ └── mvDebugFlags.mvd
├── lib
│ ├── libmvDeviceManager.so -> libmvDeviceManager.so.2.45.0
│ ├── libmvDeviceManager.so.2 -> libmvDeviceManager.so.2.45.0
│ ├── libmvDeviceManager.so.2.45.0
│ ├── libmvPropHandling.so -> libmvPropHandling.so.2.45.0
│ ├── libmvPropHandling.so.2 -> libmvPropHandling.so.2.45.0
│ └── libmvPropHandling.so.2.45.0
└── Toolkits
├── FreeImage3160
│ └── bin
│ └── Release
│ └── FreeImage
│ └── arm64
│ └── libfreeimage-3.16.0.so
├── libexpat.so -> libexpat.so.1.6.0
├── libexpat.so.1 -> libexpat.so.1.6.0
└── libexpat.so.1.6.0
14 directories, 13 files
packages-split/
├── mvimpact-acquire-base
│ └── etc
│ ├── ld.so.conf.d
│ │ └── acquire.conf
│ └── profile.d
│ └── acquire.sh
├── mvimpact-acquire-base-dev
├── mvimpact-acquire-base-doc
└── mvimpact-acquire-base-src
7 directories, 2 files
The issue was new BitBake syntax. I changed the following lines:
INSANE_SKIP_${PN} += "dev-so
FILES_${PN} += "${base_prefix}/${MVIA_SUBDIR}/${MVIA_LIB_SUBDIR}/lib*.so.* \
${base_prefix}/${MVIA_SUBDIR}/${TOOLKITS_LIB_SUBDIR}/lib*.so.* \
${base_prefix}/${MVIA_SUBDIR}/${TOOLKITS_LIB_SUBDIR}/FreeImage3160/bin/Release/FreeImage/${TARGET}/lib*.so \
${sysconfdir}/profile.d/*.sh \
${sysconfdir}/ld.so.conf.d/*.conf"
to
INSANE_SKIP:${PN} += "dev-so
FILES:${PN} += "${base_prefix}/${MVIA_SUBDIR}/${MVIA_LIB_SUBDIR}/lib*.so.* \
${base_prefix}/${MVIA_SUBDIR}/${TOOLKITS_LIB_SUBDIR}/lib*.so.* \
${base_prefix}/${MVIA_SUBDIR}/${TOOLKITS_LIB_SUBDIR}/FreeImage3160/bin/Release/FreeImage/${TARGET}/lib*.so \
${sysconfdir}/profile.d/*.sh \
${sysconfdir}/ld.so.conf.d/*.conf"
So basically, instead of underscores it now uses colons.
Related
During experiments with Yocto's Advanced Kernel Metadata I got into a situation where I would like to have the .scc, .patch and .cfg files organized into a directory structure as mentioned in the syntax section, and to keep that structure in all the layers (consider 2 layers here - meta-main_layer and meta-bsp_layer):
meta-main_layer
└── recipes-kernel
└── linux
└── linux-yocto.bb
└── linux-yocto
├── cfg
│ ├── main_frag_1.cfg
│ └── main_frag_1.scc
├── features
│ ├── main_feature_1.cfg
│ ├── main_feature_1.patch
│ └── main_feature_1.scc
└── patches
├── main_patch_1.patch
└── main_patch_1.scc
meta-bsp_layer
└── recipes-kernel
└── linux
└── linux-yocto.bbappend
└── linux-yocto
├── bsp
│ └── bsp_definition.scc
├── cfg
│ ├── bsp_frag_1.cfg
│ └── bsp_frag_1.scc
├── features
│ ├── bsp_feature_1.cfg
│ ├── bsp_feature_1.patch
│ └── bsp_feature_1.scc
└── patches
├── bsp_patch_1.patch
└── bsp_patch_1.scc
meta-main_layer/recipes-kernel/linux/linux-yocto.bb contains:
FILESEXTRAPATHS_prepend := "${THISDIR}:"
...
SRC_URI = "file://linux-yocto;type=kmeta \
"
Edit:
And meta-bsp_layer/recipes-kernel/linux/linux-yocto.bbappend:
FILESEXTRAPATHS_prepend := "${THISDIR}:"
...
SRC_URI += " file://linux-yocto;type=kmeta \
"
... end of edit
This means that after parsing the recipes, the SRC_URI will contain file://linux-yocto;type=kmeta twice, and FILESEXTRAPATHS=meta-bsp_layer/recipes-kernel/linux:meta-main_layer/recipes-kernel/linux:. The way I understand it, the do_unpack() task goes through the files in SRC_URI and for each of them, it searches FILESEXTRAPATHS for that file, and it takes the first one it finds. That means that in my case, only the files from meta-bsp_layer are taken, as its path is the first in FILESEXTRAPATHS, and the files from the meta-main_layer are ignored.
What I would like to achieve is that instead of taking the files from only the first path found in FILESEXTRAPATHS, do_unpack() would go through all of the paths in FILESEXTRAPATHS and merge the directories of the same name (cfg, features and patches) from both layers. Without that, I don't see any big benefits of using the Advanced Kernel Metadata mechanism. Could anyone advise how to get this done?
PS: I'm using Yocto Zeus.
I have a project that uses akka in version 2.11_2.5.21 which is assembly in my fat jar.
I have download the scala binary 2.11.12 and it is shipped with a lib/akka-actor_2.11-2.3.16.jar (next to bin/scala)
When I run my project : scala -cp target/scala-2.11/project-assembly-2.4.0.jar foo.MyClass I get
java.lang.NoSuchMethodError: akka.actor.OneForOneStrategy.withMaxNrOfRetries(I)Lakka/actor/OneForOneStrategy;
If i remove lib/akka-actor_2.11-2.3.16.jar in my scala directory it works.
Of course it also works with sbt run as sbt used its own scala version.
Why does scala binary use its own akka version instead of the one shipped in the fat jar?
Assuming by "Scala binary" you are referring to the decompressed structure of say https://downloads.lightbend.com/scala/2.11.12/scala-2.11.12.tgz
➜ scala-2.11.12 tree -L 2
.
├── bin
│ ├── fsc
│ ├── fsc.bat
│ ├── scala
│ ├── scala.bat
│ ├── scalac
│ ├── scalac.bat
│ ├── scaladoc
│ ├── scaladoc.bat
│ ├── scalap
│ └── scalap.bat
├── doc
│ ├── LICENSE.md
│ ├── License.rtf
│ ├── README
│ ├── licenses
│ └── tools
├── lib
│ ├── akka-actor_2.11-2.3.16.jar
│ ├── config-1.2.1.jar
│ ├── jline-2.14.3.jar
│ ├── scala-actors-2.11.0.jar
│ ├── scala-actors-migration_2.11-1.1.0.jar
│ ├── scala-compiler.jar
│ ├── scala-continuations-library_2.11-1.0.2.jar
│ ├── scala-continuations-plugin_2.11.12-1.0.2.jar
│ ├── scala-library.jar
│ ├── scala-parser-combinators_2.11-1.0.4.jar
│ ├── scala-reflect.jar
│ ├── scala-swing_2.11-1.0.2.jar
│ ├── scala-xml_2.11-1.0.5.jar
│ └── scalap-2.11.12.jar
└── man
└── man1
then everything inside lib/ will take precedence over what you specify with -cp. To see this analyse the following snippet of bin/scala runner script
execCommand \
"${JAVACMD:=java}" \
$JAVA_OPTS \
"${java_args[#]}" \
"${classpath_args[#]}" \
-Dscala.home="$SCALA_HOME" \
$OVERRIDE_USEJAVACP \
"$EMACS_OPT" \
$WINDOWS_OPT \
scala.tools.nsc.MainGenericRunner "$#"
Note that "${classpath_args[#]}" which holds jars from lib precedes the last "$#" which holds your arguments such as -cp. Finally JVM will pick the first matching class it finds on the classpath which in your case will be the one from lib/akka-actor_2.11-2.3.16.jar. For example
scala -cp target/scala-2.11/project-assembly-2.4.0.jar
would expand to something like
java -Xbootclasspath/a:/scala-2.11.12/lib/akka-actor_2.11-2.3.16.jar ... scala.tools.nsc.MainGenericRunner -cp target/scala-2.11/project-assembly-2.4.0.jar
hence Xbootclasspath would take precedence over -cp.
I want to create a small application image. That image installed at a separate partition shall be mounted to /usr/local. I created a recipe like this:
inherit image
IMAGE_BASENAME = "appfs"
IMAGE_NAME_SUFFIX = ".appfs"
IMAGE_INSTALL_append = " app_lib "
IMAGE_INSTALL_append = " app_prog1 "
IMAGE_INSTALL_append = " app_prog2 "
IMAGE_INSTALL_append = " app_prog3 "
The result looks not bad, I can control the installation of the files by the prefix-Variable in the recipes of the application programms. So the will be installed in /bin, which means /usr/local/bin in the device.
But the image contains the whole directory structure of a root filesystem. Is there any comfortable way to generate the reduced directory structure of the /usr/local directory? Or do I need to clean it up by myself in a IMAGE_POSTPROCESS_COMMAND?
Kind regards
It sounds like what you want is a package or package group and not an image.
An image is a full distribution installation, usually using the poky distro.
This is built-in to yocto and unavoidable, as all dependencies of your app will need to be in the image. (runtimes, supporting libs, basic linux env, etc.)
In your tmp/deploy/rpm or tmp/deploy/deb directory you should have packages related to your apps.
Something that may help organize is to create a package group to aggregate your applications.
If you look at your tmp/deploy/images/<machine>/<imagename>.manifest file you will notice that in addition to the packages you specified, some additional ones such as libc6 and base-files are included.
You can remove them by naming the packages in ROOTFS_RO_UNNEEDED. This variable is used to remove recipes such as shadow and run-postinsts which are processed when creating a read-only image. You can add the other undesirable recipes to this list until your manifest matches exactly the packages you want included.
For example:
# tested with Yocto 2.6
IMAGE_FSTYPES = "ext4"
IMAGE_INSTALL = "my-go-app"
inherit image
# Don't run ldconfig on the rootfs
LDCONFIGDEPEND = ""
# If not building an RO filesystem, you can force use of ROOTFS_RO_UNNEEDED
# but be aware of the other packages included in the variable by image.bbclass
FORCE_RO_REMOVE = "1"
# Use _append because image.bbclass includes other packages
ROOTFS_RO_UNNEEDED_append = "base-files base-files-lic \
bash bash-lic \
libc6 libc6-lic \
ncurses-libtinfo libtinfo5 \
opkg-utils-lic \
ncurses-terminfo-base ncurses-lic \
run-postinsts-lic \
"
The resulting filesystem I get looks like this:
tmp
├── etc
│ ├── shells.rpmsave
│ ├── timestamp
│ └── version
├── lost+found [error opening dir]
├── usr
│ ├── bin
│ │ └── my-go-app
│ ├── lib
│ │ └── go
│ │ └── pkg
│ │ └── linux_arm64_dynlink
│ │ └── libstd.so
│ └── share
│ ├── common-licenses
│ │ └── license.manifest
│ └── licenses
│ ├── go-runtime
│ │ ├── generic_BSD-3-Clause
│ │ └── LICENSE
│ └── my-go-app
└── var
├── cache
└── lib
There may still be a few files left to clean up using a postprocess function:
postprocess_partial_image() {
rm -f ${IMAGE_ROOTFS}/etc/shells.rpmsave
rm -rf ${IMAGE_ROOTFS}/var
}
ROOTFS_POSTPROCESS_COMMAND += "postprocess_partial_image; "
I have downloaded a rpm in my ansible-playbook:
(djangoenv)~/P/c/apache-installer ❯❯❯ tree .
.
├── defaults
│ └── main.yml
├── files
│ ├── apache2latest.tar
│ ├── httpd_final.conf
│ ├── httpd_temp.conf
│ └── sshpass-1.05-9.1.i686.rpm
├── handlers
│ └── main.yml
├── hosts
├── meta
│ └── main.yml
├── README.md
├── tasks
│ └── main.yml
├── templates
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml
My question is why can't I just install it using:
- yum: name=files/sshpass-1.05-9.1.i686.rpm
? It complains that files/sshpass-1.05-9.1.i686.rpm is not found in the system. Now I am doing it in two steps:
- copy: src=files/sshpass-1.05-9.1.i686.rpm dest=/tmp/sshpass-1.05-9.1.i686.rpm force=no
- yum: name=/tmp/sshpass-1.05-9.1.i686.rpm state=present
No, there is no simple way around coping the package to the remote host before installing. Ansible yum module expects a local file when you define a file in the name parameter.
IMHO it is not a good idea to keep packages inside the Ansible code base. Because they are binary and not exactly part of the actual Ansible code. It would be cleaner to setup a private repository and store those files there. That is the only way around coping a package in this situation I'm aware of.
I'm trying to use HTTrack or Wget do download some .docx files from a website. I want to do this only for a folder and it's subfolders. Ex: www.examplewebsite.com/doc (this goes down 5 more levels)
How would be a good way to do this?
The previous proposed answer is ludicrous considering the "spider" option has ALWAYS specifically NOT DOWNLOADED, but instead followed.
Better late than never, but here is the command you seek to both mirror the desired file extension files locally, but then as a bonus pull down the target html and auto-adjust it so that if you open it locally and click the links, they will have been altered and adjusted accordingly to now point to the local drive.
wget -e robots=off -r -k -A docx,doc "https://<url>"
If this works for you, I would appreciate the answer points!
You can use --spider with -r (recursive option ) and have --accept to filter the files of your intrest
wget --spider -r --accept "*.docx" <url>
Usage
wget -r -np -A pdf,doc https://web.cs.ucla.edu/~harryxu/
Result
tree
└── web.cs.ucla.edu
├── ~harryxu
│ ├── papers
│ │ ├── chianina-pldi21.pdf
│ │ ├── dorylus-osdi21.pdf
│ │ ├── genc-pldi20.pdf
│ │ ├── jaaru-asplos21.pdf
│ │ ├── jportal-pldi21.pdf
│ │ ├── li-sigcomm20.pdf
│ │ ├── trimananda-fse20.pdf
│ │ ├── vigilia-sec18.pdf
│ │ ├── vora-asplos17.pdf
│ │ ├── wang-asplos17.pdf
│ │ ├── wang-osdi18.pdf
│ │ ├── wang-osdi20.pdf
│ │ ├── wang-pldi19.pdf
│ │ └── zuo-eurosys19.pdf