<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>wong2.me</title><link>https://wong2.me/</link><description>Recent content on wong2.me</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Thu, 21 Oct 2021 19:58:11 +0800</lastBuildDate><atom:link href="https://wong2.me/index.xml" rel="self" type="application/rss+xml"/><item><title>Emscripten的文件系统</title><link>https://wong2.me/posts/emscripten-file-system/</link><pubDate>Thu, 21 Oct 2021 19:58:11 +0800</pubDate><guid>https://wong2.me/posts/emscripten-file-system/</guid><description>&lt;h2 id="intro">Intro&lt;/h2>
&lt;p>我们知道Emscripten可以将C/C++代码编译到WebAssembly，从而在浏览器中运行。为了实现这个目标，除了代码层面的编译外，Emscripten还需要在Web环境下提供大量对native runtime的模拟，如文件系统、底层图形库、网络等。今天重点看一下文件系统部分。&lt;/p>
&lt;h2 id="overview">Overview&lt;/h2>
&lt;p>由于浏览器中的JavaScript无法直接访问操作系统的文件系统，Emscripten提供了一套虚拟文件系统来模拟一个POSIX FS。&lt;/p>
&lt;p>&lt;img src="overview.png" alt="Overview">&lt;/p>
&lt;p>如上面的架构图所示，原生代码编写的应用使用libc/libxx中API进行文件系统操作，经Emscripten编译后，调用JavaScript编写的虚拟文件系统API。&lt;/p>
&lt;p>默认的虚拟文件系统实现为&lt;code>MEMFS&lt;/code>，顾名思义它是在内存里实现的，页面刷新后数据就会丢失。如果需要持久化，在浏览器里可以使用基于IndexedDB的&lt;code>IDBFS&lt;/code>。&lt;/p>
&lt;h2 id="使用示例">使用示例&lt;/h2>
&lt;p>下面我们通过一个例子来展示文件系统的使用，并为后续实验提供一个基础。&lt;/p>
&lt;h3 id="c程序">C程序&lt;/h3>
&lt;p>首先我们编写一个如下含有文件操作的C程序：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#include&lt;/span> &lt;span style="color:#75715e">&amp;lt;stdio.h&amp;gt;&lt;/span>&lt;span style="color:#75715e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">void&lt;/span> &lt;span style="color:#a6e22e">append_line&lt;/span>(&lt;span style="color:#66d9ef">char&lt;/span> &lt;span style="color:#f92672">*&lt;/span>filename, &lt;span style="color:#66d9ef">char&lt;/span> &lt;span style="color:#f92672">*&lt;/span>line) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> FILE &lt;span style="color:#f92672">*&lt;/span>fp &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">fopen&lt;/span>(filename, &lt;span style="color:#e6db74">&amp;#34;a&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">fprintf&lt;/span>(fp, &lt;span style="color:#e6db74">&amp;#34;%s&lt;/span>&lt;span style="color:#ae81ff">\n&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>, line);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">fclose&lt;/span>(fp);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">int&lt;/span> &lt;span style="color:#a6e22e">main&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这段程序中定义了 &lt;code>append_line&lt;/code> 函数，它的作用就是往一个文件里添加一行新内容。我们在&lt;code>main&lt;/code>中并没有调用它，而是准备暴露给JS代码调用。&lt;/p>
&lt;h3 id="编译">编译&lt;/h3>
&lt;p>接下来我们用下面的命令编译这段C代码到WebAssembly，在选项中指定export &lt;code>append_line&lt;/code> 函数。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>emcc fs.c &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -o fs.js &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span>	-s EXPORTED_RUNTIME_METHODS&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;[cwrap, FS]&amp;#34;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span>	-s EXPORTED_FUNCTIONS&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;[_append_line]&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>编译后会得到 &lt;code>fs.js&lt;/code> 和 &lt;code>fs.wasm&lt;/code> 两个文件，其中 &lt;code>fs.js&lt;/code> 是 Emscripten提供的 wrapper 文件，它会自动处理 wasm 文件的加载等等。我们写一段极其简单的HTML来使用它：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-html" data-lang="html">&lt;span style="display:flex;">&lt;span>&amp;lt;&lt;span style="color:#f92672">body&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&amp;lt;&lt;span style="color:#f92672">script&lt;/span> &lt;span style="color:#a6e22e">src&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;fs.js&amp;#34;&lt;/span>&amp;gt;&amp;lt;/&lt;span style="color:#f92672">script&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&amp;lt;&lt;span style="color:#f92672">script&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">appendLine&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">Module&lt;/span>.&lt;span style="color:#a6e22e">cwrap&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;append_line&amp;#39;&lt;/span>, &lt;span style="color:#66d9ef">null&lt;/span>, [&lt;span style="color:#e6db74">&amp;#39;string&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;string&amp;#39;&lt;/span>])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&amp;lt;/&lt;span style="color:#f92672">script&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;/&lt;span style="color:#f92672">body&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>除了引入 &lt;code>fs.js&lt;/code> 外，我们还通过 &lt;code>cwrap&lt;/code> 把 &lt;code>append_line&lt;/code> 转成了可以在JS中调用的函数。（C和JS代码如何互操作不是本文的重点，想了解更多可以阅读&lt;a href="https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html">相关文档&lt;/a>。&lt;/p></description></item><item><title/><link>https://wong2.me/travel/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://wong2.me/travel/</guid><description>&lt;h2 id="我去过的地方">我去过的地方&lt;/h2>
&lt;h3 id="中国">中国&lt;/h3>
&lt;ul>
&lt;li>北京&lt;/li>
&lt;li>上海&lt;/li>
&lt;li>香港&lt;/li>
&lt;li>台北&lt;/li>
&lt;li>重庆&lt;/li>
&lt;li>天津&lt;/li>
&lt;li>四川（成都，都江堰，乐山）&lt;/li>
&lt;li>江苏（南京，苏州，扬州，无锡，徐州，高邮）&lt;/li>
&lt;li>浙江（杭州，宁波，绍兴，湖州，台州，金华，衢州，嘉兴，嵊泗）&lt;/li>
&lt;li>山东（济南，济宁，曲阜，青岛，日照，菏泽）&lt;/li>
&lt;li>安徽（黄山，芜湖）&lt;/li>
&lt;li>陕西（西安）&lt;/li>
&lt;li>山西（平遥）&lt;/li>
&lt;li>湖北（武汉，荆州，襄阳）&lt;/li>
&lt;li>湖南（长沙）&lt;/li>
&lt;li>广东（广州，顺德，深圳）&lt;/li>
&lt;li>广西（南宁，柳州）&lt;/li>
&lt;li>福建（福州，厦门，泉州，武夷山，平潭）&lt;/li>
&lt;li>贵州（贵阳，黄果树，凯里，千户苗寨）&lt;/li>
&lt;li>云南（昆明，西双版纳，丽江，泸沽湖）&lt;/li>
&lt;li>海南（三亚）&lt;/li>
&lt;li>待补充&lt;/li>
&lt;/ul>
&lt;h3 id="日本">日本&lt;/h3>
&lt;p>东京，大阪，京都，神户，姬路，横滨，镰仓，奈良，冲绳，札幌，小樽，箱根，名古屋，下吕，白川乡，金泽，富山，福冈，佐贺，熊本，松山，今治，高松，直岛，仓敷，冈山，广岛&lt;/p>
&lt;h3 id="韩国">韩国&lt;/h3>
&lt;p>济州岛&lt;/p>
&lt;h3 id="越南">越南&lt;/h3>
&lt;p>胡志明市，美奈，芽庄&lt;/p></description></item><item><title/><link>https://wong2.me/use/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://wong2.me/use/</guid><description>&lt;h2 id="things-i-use">Things I use&lt;/h2>
&lt;h3 id="devices">Devices&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>iPhone 15 Pro&lt;/strong>&lt;/li>
&lt;li>&lt;strong>Macbook Pro M4 (2024)&lt;/strong>&lt;/li>
&lt;li>&lt;strong>AirPods Pro&lt;/strong>&lt;/li>
&lt;li>&lt;strong>HHKB Professional HYBRID Type-S 雪&lt;/strong>&lt;/li>
&lt;li>&lt;strong>微信读书墨水屏&lt;/strong>&lt;/li>
&lt;/ul>
&lt;h3 id="mac-apps">Mac Apps&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>&lt;a href="https://arc.net">Arc&lt;/a>&lt;/strong>: daily browser&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://www.cursor.com">Cursor&lt;/a>&lt;/strong>: IDE&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://raycast.com">Raycast&lt;/a>&lt;/strong>: best Mac launcher&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://read.readwise.io">Readwise Reader&lt;/a>&lt;/strong>: best Read-it-later and RSS reader&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://ghostty.zerebos.com">Ghostty&lt;/a>&lt;/strong>: terminal&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://shottr.cc">Shottr&lt;/a>&lt;/strong>: screenshot tool&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://proxyman.io">Proxyman&lt;/a>&lt;/strong>: HTTP requests debugging tool&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://github.com/MonitorControl/MonitorControl">MonitorControl&lt;/a>&lt;/strong>: controls external display brightness and volume&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://www.mowglii.com/itsycal/">Itsycal&lt;/a>&lt;/strong>: tiny menubar calendar&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://screen.studio/">Screen Studio&lt;/a>&lt;/strong>: screen recording&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://lemon.qq.com/">Lemon&lt;/a>&lt;/strong>: clean your mac&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://rectangleapp.com/">Rectangle&lt;/a>&lt;/strong>: window manager&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://github.com/dwarvesf/hidden">Hidden Bar&lt;/a>&lt;/strong>: hide menubar items&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://eggerapps.at/postico2/">Postico 2&lt;/a>&lt;/strong>: postgresql client&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://apps.apple.com/us/app/tadama-workflow-timer/id1415817706?mt=12">Tadama&lt;/a>&lt;/strong>: relax timer&lt;/li>
&lt;/ul>
&lt;h3 id="browser-extensions">Browser Extensions&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>&lt;a href="https://chromewebstore.google.com/detail/hover-zoom+/pccckmaobkjjboncdfnnofkonhgpceea">Hover Zoom+&lt;/a>&lt;/strong>&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://bitwarden.com">Bitwarden&lt;/a>&lt;/strong>&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://chromewebstore.google.com/detail/vimium/dbepggeogbaibhgnhhndojpepiihcmeb">Vimium&lt;/a>&lt;/strong>&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://chromewebstore.google.com/detail/cjpalhdlnbpafiamejdnhcphjbkeiagm">uBlock Origin&lt;/a>&lt;/strong>&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://chromewebstore.google.com/detail/json-formatter/bcjindcccaagfpapjjmafapmmgkkhgoa">JSON Formatter&lt;/a>&lt;/strong>&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://clearurls.xyz/">ClearURLs&lt;/a>&lt;/strong>&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://github.com/refined-github/refined-github">Refined GitHub&lt;/a>&lt;/strong>&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://chromewebstore.google.com/detail/immersive-translate-web-p/bpoadfkcbjbfhfodiogcnhhhpibjhbnh">沉浸式翻译&lt;/a>&lt;/strong>&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://chathub.gg">ChatHub&lt;/a>&lt;/strong>&lt;/li>
&lt;/ul>
&lt;h3 id="saas">SaaS&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>&lt;a href="https://supabase.com">Supabase&lt;/a>&lt;/strong>&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://railway.com?referralCode=aDYnxe">Railway&lt;/a>&lt;/strong>&lt;/li>
&lt;/ul></description></item></channel></rss>