<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:"Yu Gothic";
        panose-1:2 11 4 0 0 0 0 0 0 0;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:"\@Yu Gothic";
        panose-1:2 11 4 0 0 0 0 0 0 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0in;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:#0563C1;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:#954F72;
        text-decoration:underline;}
p.msonormal0, li.msonormal0, div.msonormal0
        {mso-style-name:msonormal;
        mso-margin-top-alt:auto;
        margin-right:0in;
        mso-margin-bottom-alt:auto;
        margin-left:0in;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
span.EmailStyle18
        {mso-style-type:personal-compose;
        font-family:"Calibri",sans-serif;
        color:windowtext;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-size:10.0pt;
        font-family:"Calibri",sans-serif;}
@page WordSection1
        {size:8.5in 11.0in;
        margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
        {page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="EN-US" link="#0563C1" vlink="#954F72">
<div class="WordSection1">
<p class="MsoNormal">Hi all,<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">For about two years now, we have been using Emscripten together with Yocto, via an emscripten.bbclass that I wrote. In a nutshell, it works by conducting the actual build in a Docker container, whose image is where Emscripten is actually
installed. I mount all the necessary directories (e.g. ${B}, ${S}, etc.) into the container, and I’ve got some Python scripting that ensures that containers get cleaned up even if the build is aborted with Ctrl+C or otherwise dies. All of our Emscripten-enabled
recipes happen to be using CMake, so emscripten.bbclass is CMake specific. It’s basically a reimplementation of cmake.bbclass (from Poky) that happens to run in a container.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">For the time being the specifics of how the Emscripten part works isn’t relevant (1). I provide it as background for what I really want to ask about, which is the Yocto-specific plumbing. Here’s a snippet of it:
<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">-------<o:p></o:p></p>
<p class="MsoNormal"> # Copyright (C) 2020 Agilent Technologies, Inc.<o:p></o:p></p>
<p class="MsoNormal"> # SPDX-License-Identifier: GPL-2.0-only<o:p></o:p></p>
<p class="MsoNormal"> CLASSOVERRIDE = "class-emscripten"<o:p></o:p></p>
<p class="MsoNormal"> SPECIAL_PKGSUFFIX_class-emscripten += "-emscripten"<o:p></o:p></p>
<p class="MsoNormal"> BASEDEPENDS_class-emscripten = ""<o:p></o:p></p>
<p class="MsoNormal"> FILES_${PN} =+ "${libdir}/*.js"<o:p></o:p></p>
<p class="MsoNormal"> export prefix = "/usr/js"<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> python emscripten_virtclass_handler() {<o:p></o:p></p>
<p class="MsoNormal"> pn = e.data.getVar("PN")<o:p></o:p></p>
<p class="MsoNormal"> if not pn.endswith("-emscripten"):<o:p></o:p></p>
<p class="MsoNormal"> return<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> classextend = e.data.getVar('BBCLASSEXTEND') or ""<o:p></o:p></p>
<p class="MsoNormal"> if "emscripten" not in classextend:<o:p></o:p></p>
<p class="MsoNormal"> return<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> def map_dependencies(varname, d, suffix = ""):<o:p></o:p></p>
<p class="MsoNormal"> if suffix:<o:p></o:p></p>
<p class="MsoNormal"> varname = varname + "_" + suffix<o:p></o:p></p>
<p class="MsoNormal"> deps = d.getVar(varname)<o:p></o:p></p>
<p class="MsoNormal"> if not deps:<o:p></o:p></p>
<p class="MsoNormal"> return<o:p></o:p></p>
<p class="MsoNormal"> deps = bb.utils.explode_deps(deps)<o:p></o:p></p>
<p class="MsoNormal"> newdeps = []<o:p></o:p></p>
<p class="MsoNormal"> for dep in deps:<o:p></o:p></p>
<p class="MsoNormal"> if dep == pn:<o:p></o:p></p>
<p class="MsoNormal"> continue<o:p></o:p></p>
<p class="MsoNormal"> elif dep in ["cmake-native"]:<o:p></o:p></p>
<p class="MsoNormal"> continue<o:p></o:p></p>
<p class="MsoNormal"> elif dep.endswith("-emscripten"):<o:p></o:p></p>
<p class="MsoNormal"> newdeps.append(dep)<o:p></o:p></p>
<p class="MsoNormal"> elif dep.endswith("-native"):<o:p></o:p></p>
<p class="MsoNormal"> bb.warn("emscripten.bbclass: Native dependency {0} will not be usable from within Emscripten Docker container".format(dep))<o:p></o:p></p>
<p class="MsoNormal"> newdeps.append(dep)<o:p></o:p></p>
<p class="MsoNormal"> d.setVar(varname, " ".join(newdeps))<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> e.data.setVar("OVERRIDES", e.data.getVar("OVERRIDES", False) + ":virtclass-emscripten")<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> map_dependencies("DEPENDS", e.data)<o:p></o:p></p>
<p class="MsoNormal"> for pkg in [e.data.getVar("PN"), "", "${PN}"]:<o:p></o:p></p>
<p class="MsoNormal"> map_dependencies("RDEPENDS", e.data, pkg)<o:p></o:p></p>
<p class="MsoNormal"> map_dependencies("RRECOMMENDS", e.data, pkg)<o:p></o:p></p>
<p class="MsoNormal"> map_dependencies("RSUGGESTS", e.data, pkg)<o:p></o:p></p>
<p class="MsoNormal"> map_dependencies("RPROVIDES", e.data, pkg)<o:p></o:p></p>
<p class="MsoNormal"> map_dependencies("RREPLACES", e.data, pkg)<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> provides = e.data.getVar("PROVIDES")<o:p></o:p></p>
<p class="MsoNormal"> nprovides = []<o:p></o:p></p>
<p class="MsoNormal"> for prov in provides.split():<o:p></o:p></p>
<p class="MsoNormal"> if prov.find(pn) != -1:<o:p></o:p></p>
<p class="MsoNormal"> nprovides.append(prov)<o:p></o:p></p>
<p class="MsoNormal"> elif not prov.endswith("-emscripten"):<o:p></o:p></p>
<p class="MsoNormal"> nprovides.append(prov.replace(prov, prov + "-emscripten"))<o:p></o:p></p>
<p class="MsoNormal"> else:<o:p></o:p></p>
<p class="MsoNormal"> nprovides.append(prov)<o:p></o:p></p>
<p class="MsoNormal"> e.data.setVar("PROVIDES", ' '.join(nprovides))<o:p></o:p></p>
<p class="MsoNormal"> } <o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> addhandler emscripten_virtclass_handler<o:p></o:p></p>
<p class="MsoNormal"> emscripten_virtclass_handler[eventmask] = "bb.event.RecipePreFinalise"<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> do_populate_sysroot[stamp-extra-info] = ""<o:p></o:p></p>
<p class="MsoNormal"> do_packagedata[stamp-extra-info] = ""<o:p></o:p></p>
<p class="MsoNormal">-------<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">There are two main goals of this code. First, it sets up dependencies between -emscripten recipes. Second, it sets ‘prefix’ to be ‘/usr/js/’ so that, for example, a “foo” and “foo-emscripten” recipe that both install development headers
won’t collide. I call this the “sub-sysroot”.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">I have a few concerns/questions:<o:p></o:p></p>
<p class="MsoNormal">[a] Is the basic premise of a custom CLASSOVERRIDE supported by Yocto? Our situation seems a bit weird, because our emscripten recipes are still sort of “target” recipes, so I feel a bit funny completely wiping CLASSOVERRIDE.<o:p></o:p></p>
<p class="MsoNormal">[b] At the very least, I know I did something wrong, because sometimes we get weird warnings like:<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-family:"Arial",sans-serif">WARNING: app-emscripten-1.0+gitAUTOINC+1d1073e7c4-r0 do_compile: Manifest /home/user/yocto/build/tmp/sstate-control/manifest-x86_64_x86_64-nativesdk-library-emscripten.populate_sysroot
not found in my_mach cortexa9t2hf-neon cortexa9t2hf-vfp cortexa9hf-neon cortexa9hf-vfp armv7at2hf-neon armv7ahf-neon armv7at2hf-vfp armv7ahf-vfp armv6thf-vfp armv6hf-vfp armv5tehf-vfp armv5ehf-vfp armv5thf-vfp armv5hf-vfp allarch x86_64_x86_64-nativesdk (variant
'')?<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><o:p> </o:p></p>
<p class="MsoNormal" style="margin-bottom:10.0pt;line-height:115%;text-autospace:none">
<span lang="EN">... usually followed by a build failure in “app-emscripten” because “library-emscripten:do_populate_sysroot” indeed didn’t run. Related to [a] or perhaps the stamp-extra-info lines?<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN">[c] Is there a better way to do the “sub-sysroot” (/usr/js)? Would multilib cover this whole use case? (2)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN">I appreciate any comments/help.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN">Chris<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN"><o:p> </o:p></span></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">(1) I’m happy to cover it in a separate thread if people are interested. I hope to rewrite the class using Clang’s WebAssembly backend, rather than call out to the Emscripten container which has always seemed like a hack. Regardless, I
will make what we have public on poky-contrib soon anyway.<o:p></o:p></p>
<p class="MsoNormal">(2) I suppose one option is to have Emscripten flavors of all the MACHINEs we are building for, but I’d like to avoid that. We only have a handful of Emscripten recipes, so a separate MACHINE at this time would be overkill.
<o:p></o:p></p>
</div>
</body>
</html>