㈠ 如何编译 dotnet/runtime 源代码
编译 dotnet/runtime 源代码的步骤如下:
环境准备:
安装Python 3:
解决下载问题:
生成和运行编译命令:
指定编译框架版本:
验证编译结果:
重点注意事项: 编译过程中可能会遇到由于访问国外服务器网速较慢导致的下载问题,需要耐心解决。 确保按照官方文档和实际需求正确配置编译环境。 在编译过程中遇到问题时,查阅相关文档和社区资源,寻求解决方案。
㈡ 编译型框架 SvelteJS
在2016年,Svelte框架由Rollup等工具的作者Rich Harris推出,旨在解决React等框架存在的问题,虽然它没有像其他框架那样大红大紫,但从State of JS的统计来看,它一直保持着持久的热度。本文将深入浅出地介绍Svelte,希望更多人在适合的场景下可以考虑使用它。
Svelte的诞生源于Rich对前端库和框架的深入思考。他非常欣赏React等框架带来的更声明式、低心智负担的开发方式,这使得前端工程师能够更好地控制复杂度、提升开发效率和质量。然而,他也敏锐地洞察到了一些不那么尽如人意之处。
Rich注意到,尽管React、Vue等框架引入了Virtual DOM的概念,从而能够进行现有DOM与期望DOM的对比,并执行较重的DOM操作以保持两者一致,但这其实更多是一种实现声明式、状态驱动UI开发的手段,并非不可或缺。Virtual DOM的主要问题在于有很多不必要的Diff操作。例如,假设我们有一个React App,点击一次按钮后,新旧Virtual DOM对比如下:虽然只有p节点下的文本需要更新,但React实际上会遍历所有节点,造成不必要的额外开销。尽管人们可能觉得纯粹的JS运算不会有显着的开销,但在页面内容和逻辑足够复杂的情况下,这个问题会变得更加明显。因此,React提供了useMemo、useCallback等Hooks来避免一些耗时操作的重复执行或不必要的重复渲染,但这些其实可以视为错误设计的副作用,让开发者需要关注一些本应是实现原理层面的技巧,增加了额外的心智负担。
那么,是否有一种新的方式,可以在count变化时仅仅更新引用它的DOM文本节点?如果能够做到这一点,那岂不是更加响应式?
Rich还质疑了运行时在前端框架中的必要性。React、Angular、Vue等框架都有运行时,用于处理用户操作或数据请求引起组件状态变化时的高效更新DOM节点。然而,运行时代码会被打包到最终产物中。以典型的TodoMVC应用为例,我们来看几种方案下的JS包体积:如果我们以JavaScript ES6为基准衡量其他方案因为运行时而带来的额外包体积,那么Vue大约是10倍,React约为18倍,Angular则接近27倍。诚然,这些优秀的框架为开发者提供了更为便捷和高效的开发方式,而且现在动辄上兆的中大型前端应用比比皆是,几十K压缩后的JS包并不是那么关键。不过,退一步想,如果有一个新的方案可以提供与主流框架相媲美的特性,同时最终包体积接近原生JS,那岂不是更好?
基于以上两点洞见,Rich开始从一个全新的角度理解和思考前端框架:前端框架应该是主要用来结构化想法而非代码,它们使得应用的复杂度能够受到合理的控制。如果我们有办法在提供结构化想法的种种功能的同时,在编译阶段将应用源代码转换为接近原生JS实现的最终代码,那么就不再需要浏览器和源代码之间的中间抽象层,我们的应用也会运行得更快。
虽然有了一个崭新的思路,但落实在实现层面还会有众多挑战。接下来,我们将简要介绍Svelte的具体实现。
Svelte采用了模板为先的组件封装方案,每个组件都存储在.svelte文件中,语法是HTML的超集。一个示例将前面的计数器App用Svelte重新实现,看起来非常像Vue,组件的JS、CSS、HTML都在同一文件中集中管理。因此,从开发者的角度来看,Svelte的编程方式十分熟悉、自然。选择模板而非灵活的JSX的原因也体现在这个例子中,编译器很容易发现结构化的视图中p元素有一部分文本需要使用count,以及点击按钮时需要调用一个回调函数,其他部分都是确定的。因此,只需在count变化时刷新相应的DOM文本节点即可。为了在有一定约束的情况下提供足够多的功能,Svelte也提供了一系列模板语法。
在介绍Svelte编译器如何工作之前,我们不妨设想:如果让我们自己使用原生JS实现上面的计数器App的话,会是什么样的呢?一个可供参考的实现如下(暂时忽略CSS)。
Svelte生成的JS结果如下,可以运行的完整示例见NaiveCompiledApp。可以看出,虽然细节上有些许不同,但是整体的代码结构与我们前面人肉编译的版本非常相像。令人惊叹的是,Svelte也能在count变化时精准地更新对应的文本节点,十分高效。这里的回调函数中的$$invalidate可以理解成一种更具效率的数据变更处理机制,具体实现运用了位掩码(bitmask)来标记脏数据的变量索引,然后安排一个microtask异步进行批量更新。
此外,除了一些简单的append、element、set_data等工具方法和SvelteComponent基类以外,最终构建的应用几乎没有使用任何额外的框架代码,所有的框架工作都基本在编译阶段完成,这真所谓是“编译器即框架”!
在编译器内部,可以细分为解析模板、分析代码、构建产物三个步骤。在编译过程中,Svelte将.svelte文件编译成一个JS文件和一个可选的CSS文件,这些产物可以在浏览器中直接运行。
在介绍完基本原理后,让我们看下Svelte的具体表现。从生成最终代码的体积来看,同样以TodoMVC为例,Svelte代码的最终体积是:JS包13K,Gzip压缩后5.3K。以下是与其他框架对照的图表。Svelte构建JS包的体积是Vue的1/6,React的1/9,Angular的1/12,已经非常接近于原生JS。可以说是非常精巧的。
从运行速度来看,JSFrameworkBenchmark的测试结果如下。从最后一行的加权结果来看,Svelte的性能非常接近原生JS,与同类型编译型框架Solid以及以快着称的类React框架Inferno相当,优于Vue、Angular,更是大幅领先React。
了解完基本原理后,我们将介绍几个常用的进阶特性,如显式声明响应性。在实际开发中,我们常常遇到一些场景:一个变量依赖了另一个或多个变量,且这种依赖关系非常确定。例如:
得益于编译器即框架的优势,Svelte使用$标签来更为显式地声明这类依赖关系,建立更具效率的响应性:依赖的变量有变化则需要重新执行赋值操作。下面是一个示例。
实现这一特性的思路并不复杂:遇到有标签$的赋值语句时,则在等号右侧变量变化的时候执行$$invalidate将左侧变量标记为脏数据,进而触发后续的更新逻辑。进一步地,Svelte还支持使用$标签来声明任意变量的依赖关系。
㈢ linux Kbuild详解系列(3) - Kbuild系统框架概览
深入探索Kbuild系统框架概览,揭示其背后机制,本系列博客从本章节开始,逐步揭秘Kbuild系统。Linux内核的Makefile主要用于编译源码,生成目标文件,实现内核的简洁高效编译。Make和Makefile是Linux下用于编译工具和配置文件,执行make命令时,系统会自动寻找Makefile文件并按配置进行编译。Linux内核源码的编译采用了扩展的make工具和Makefile,形成kbuild系统,专为内核编译设计。
Linux内核的编译文件形式多样,包括vmlinux、vmlinux.bin、vmlinuz、zImage、bzImage等。Kbuild系统中的Makefile文件分布于各个目录,对模块进行分离编译,降低耦合性,实现灵活的编译方式。Makefile主要分为五部分:配置文件、模块编译、链接、模块排列和链接顺序。
内核模块的编译流程包括将模块编译进内核、生成vmlinux镜像。配置文件控制模块的编译行为,通过make的自动推导原则,模块自动编译。链接顺序决定了模块执行的顺序,优先级相同的模块按编译顺序依次执行。所有配置为-m的模块将被编译为可加载模块.ko文件。
驱动模块依赖多个文件时,通过指定依赖文件进行编译。Makefile中定义的目录层次关系处理原则是一个Makefile只负责处理本目录的编译关系。顶层Makefile中定义的变量如KERNELRELEASE、ARCH、INSTALL_PATH等在编译内核时发挥关键作用。变量定义影响编译选项、安装目录等。
编译选项在不同版本中进行了调整,如ccflags-y、asflags-y和ldflags-y分别对应编译、汇编和链接时的参数。subdir-ccflags-y和subdir-asflags-y针对本目录及其子目录有效。CFLAGS_\$@和AFLAGS_\$@允许为模块提供单独的编译参数。
Kbuild系统中的变量在顶层Makefile中定义,全局有效,影响整个编译流程。驱动开发者在编译单一模块时,顶层Makefile中的变量未被定义,只有调用顶层Makefile后,子目录的Makefile中才可能被赋值。生成header文件为开发者提供内核接口,便于模块集成。通过指定DIR目录和架构,build工具生成对应的头文件,供开发者使用。
理解Kbuild系统的执行流程是内核开发和维护的关键。通过官方文档和源码参考,开发者能更深入地掌握Kbuild系统的工作原理,优化内核编译过程,提升开发效率。本系列博客旨在提供全面的指导,帮助开发者全面了解Kbuild系统框架,实现高效、稳定的内核开发。