当前位置: 首页 > news >正文

域名解析玉林网站优化

域名解析,玉林网站优化,龙岗免费的网站制作,免费家装设计网站背景介绍 书接上回《Monorepo 解决方案 — Bazel 在头条 iOS 的实践》#xff0c;在头条工程切换至 Bazel 构建系统后#xff0c;为了支持用户使用 Xcode 开发的习惯#xff0c;我们使用了开源项目 Tulsi 作为生成工具#xff0c;用于将 Bazel 工程转换为 Xcode 工程。但是… 背景介绍 书接上回《Monorepo 解决方案 — Bazel 在头条 iOS 的实践》在头条工程切换至 Bazel 构建系统后为了支持用户使用 Xcode 开发的习惯我们使用了开源项目 Tulsi 作为生成工具用于将 Bazel 工程转换为 Xcode 工程。但是在使用的过程中我们发现了一些问题其中影响较大的是 Xcode 工程卡顿对于头条这种大型项目来说Xcode 卡顿一直是本地研发的痛点问题在切换 Bazel 构建系统之后卡顿现象明显加剧。Xcode 功能支持受限Tulsi 支持的功能有限很多功能都年久失修并未持续适配 Bazel 与 rules 的更新。 在做了一些前期调研后我们发现 rules_xcodeproj 提供了更好的解决方案。rules_xcodeproj 是一个由一系列 Bazel rules 组成的开源项目使用它可以从一个 Bazel 工程生成对应的 Xcode 工程实现在 Xcode 中写代码同时使用 Bazel 进行真正的构建任务相比于 Tulsirules_xcodeproj 在以下几个方面有着更为明显的优势。 Xcode 工程更加流畅 头条工程迁移到 rules_xcodeproj 后工程首次冷启、二次启动和文件增删操作的时间有了明显缩短工程卡顿情况也明显好转。Xcode 功能支持度更高 rules_xcodeproj 对 Xcode 的支持更全面包括单元测试、SwiftUI Previews能够更好地满足我们的需求。社区更加活跃随着 rules_xcodeproj 在 2023 年 2 月份发布正式版Tulsi 项目也正式宣布停止维护这意味着对于新版本的 BazelTulsi 将不再提供适配和支持同时 rules_xcodeproj 几乎每月都会更新一个中版本对于后续适配 Bazel 更新的成本会更低。更符合 BitSky 的演进路线由 Bazel 驱动的工程生成方式更符合 BitSky 的 Bazel Native 演进路线可以完全在 Bazel 环境下生成工程。 因此我们将 Xcode 生成工具从 Tulsi 迁移到了 rules_xcodeproj并对 BitSky 工具链进行了适配。适配过程中我们在修复 rules_xcodeproj 索引问题的同时对工程结构进行了一些优化进一步提升了工程流畅度。头条 iOS 工程的测试数据如下 测试设备 MacBook Pro芯片 M1 Pro内存 32GB ps. 本文介绍均基于 rules_xcodeproj 1.4.0 版本build with bazel 模式 pps. 由于 Xcode 主线程的卡顿较难监测此处用主动操作的执行时间衡量流畅度 Tulsirules_xcodeproj工程首次冷启47s16s二次启动33s12s文件操作新增 20s删除 23s新增 8s删除 6s 下面来看下我们具体做的适配工作。 适配过程 从 Tulsi 迁移到 rules_xcodeproj 后我们发现 Xcode 卡顿有明显改善仔细分析发现 Tulsi 工程的卡顿主要有两方面原因 头条工程中组件数量多、依赖关系复杂Tulsi 的索引方案需要 Xcode Target 之间保留这些依赖关系但这些依赖关系并不会被 Xcode 构建消费却增加了 Xcode 对工程进行解析和计算的成本。 图中 Pod X_A 与 Pod X_B 为 Pod X 分别在 App A 与 App B 下被引用的 Target 全源码构建我们在切换 Bazel 时还推进了工程的全源码构建源码数量大幅增加也给索引任务带来更大的压力。 接下来详细说明整个分析和适配过程带大家更全面地了解我们结合 rules_xcodeproj 在 Xcode 背后做了什么。 在 Xcode 中开发时主要会用到三部分功能构建、索引和调试。而 Xcode 并不能直接理解 Bazel 项目的工程文件BUILD 和 WORKSPACE所以我们需要通过工具rules_xcodeproj 或 Tulsi将 Bazel 的工程文件转换为 Xcode 可以理解的 .xcodeproj来支持这些功能正常工作。 各功能的适配点如下表所示。 rules_xcodeproj 原生方案的调试模块基本能正常工作而索引和构建两个模块中我们对原生方案的改造较大因此本文主要对这两个模块进行展开介绍。 索引 前面提到支持 Xcode 索引功能需要提供各个源文件的编译参数rules_xcodeproj 实现这一点的工作流程是 rules_xcodeproj 在 Bazel 的分析阶段获取到源码文件和编译参数用这些信息创建 Xcode Target 的 Compile Sources 和 Build Setting 产出工程文件 .xcodeprojXcode 加载工程文件获取源码文件对应的索引参数调用 clang 或 swiftc 执行索引命令。 迁移过程中我们注意到 rules_xcodeproj 工程的索引在多 Target 共用源文件的场景存在语法高亮异常的问题对比 Tulsi 工程的处理方式后我们得出两个结论 索引异常是由于 rules_xcodeproj 移除了所有 Library Target 间的依赖导致的Tulsi 工程中 Library Target 间的依赖关系正是导致 Tulsi 工程更为卡顿的关键原因。 后文会先分析依赖关系在索引中发挥的作用以及 rules_xcodeproj 如何处理依赖关系移除带来的问题然后介绍我们如何通过源码合并方案解决 rules_xcodeproj 索引方面的缺陷。 依赖关系在索引中的作用 这里提到的“依赖关系”主要是指 Xcode 工程文件.xcodeproj准确来说是其中的project.pbxproj文件中记录的 Xcode Target 之间的依赖关系。 需要明确的是这部分依赖关系只会在 Xcode 索引过程被用到被移除后也只会影响 Xcode 的索引功能。构建时用到依赖关系 Bazel 会从 BUILD 文件中获取不会关心 .xcodeproj 中的信息。 这些依赖关系在 Xcode 中的表现形式如下图所示既有直接在 Build Phases 的 Target Dependencies 中声明的依赖也会对声明在 Link Binary With Libraries 中 Target 产生依赖。 概括来说依赖关系在 Xcode 的索引过程中发挥着以下两方面作用 正确的中间产物生成顺序clang/Swift Module 中间产物的生成需要依赖关系来确定构建顺序正确的多 Target 编译参数多 Target 共用源文件时应用正确的编译参数以便于正确地高亮代码。 下面分别对其进行展开介绍。 中间产物生成顺序 以一个 Swift 组件为例当它被 OC 组件引用时需要生成一个 XX-Swift.h 文件把方法和声明暴露给 OC 组件当它被其他 Swift 组件引用时也需要生成一个 swiftmodule 文件供其他 Swift 组件引用。XX-Swift.h 和 swiftmodule 并不是原始的源码文件也不是最终的二进制产物是构建时的中间产物。在 Xcode 对一个组件的源代码索引时需要这个组件的依赖组件已经准备好中间产物供索引时消费。这里我们先分析下 Xcode 是怎样解决这个问题的。 首先Xcode 通过 Target 来描述产物是如何构建出来的每个 Target 拥有自己的 Build Phases 和 Build Settings通常一个组件对应一个 Target。Build Phases 中的 Compile Sources 记录了构建这个 Target 需要编译哪些源码文件。Build Settings 里记录了构建这个 Target 时的各种配置这其中就包括了编译参数。Xcode 可以从 Build Settings 里去获取编译参数然后对 Compile Sources 中记录的源码文件进行索引编译。 一个 Target 引用另外一个 Target 时需要将依赖关系添加到 Build Phases 的 Target Dependencies 中。Xcode 在构建时会根据这些依赖关系来决定构建 Target 的顺序保证一个 Target 构建时它依赖的 Target 已经完成构建。 索引时也是类似的处理Xcode 有一个 Index Build 的阶段在这个阶段也会根据依赖关系按照顺序去触发 Target 的 Build Phase完成之后才会开始索引这个 Target 的源码文件。 这里有一个例子SwiftDemo 依赖了 HelloLib两个 Target 均为 Swift 组件。 在对 SwiftDemo 的源码文件进行索引编译之前会先触发 Index Build。Index Build 时根据依赖关系先 Build HelloLib这个时候会进行 Compile Swift source files参数中包含 -emit-module -emit-module-path /path最终会生成 swiftmodule 。 如果将 HelloLib 从 SwiftDemo 的 Target Dependencies 中移除在 SwiftDemo 的 Index Build 时不会先 Build HelloLib并且在 HelloLib 的 Index Build 中也不会生成 swiftmodule。 可以看出Xcode 正是通过依赖关系来保证构建时的顺序索引也依赖构建顺序来保证 Module 中间产物的生成时机。 在 Tulsi 生成的 Xcode 工程中依然保留了 Target 之间的依赖关系用于解决索引的中间产物生成问题。这里就不做过多介绍。 而在 rules_xcodeproj 生成的工程中Target 之间的依赖关系是完全去掉的每个 Target 都有且仅有一个额外添加的依赖 BazelDependencies。对于 Module 中间产物的处理在生成的 Xcode Target 中我们可以看到这样一条 Build Phase。 原理是在 Index Build 阶段执行到这 Target 时去跑一个 shell 脚本。 以 NewsInHouse 这个 Target 为例这个脚本里经过一系列的处理最终会去调用这样一条 Bazel Build 命令 在这条命令中有一些关键信息 rules_xcodeproj_generated//generator/xcodeproj:xcodeproj Bazel Build 的 Target可以认为是我们使用 rules_xcodeproj 定义的生成工程的 Bazel Target。 bc //Article:NewsInHouse applebin_ios-* 在上述 Target 里 rules_xcodeproj 添加了一些 OutputGroupInfo。Bazel Build 时可以通过 --output_groups 参数指定输出产物。 这一条 output group 对应的是 //Article:NewsInHouse 及其依赖 Target 的产物中 swiftmodule 之类的编译依赖部分。 bg //Article:NewsInHouse applebin_ios-* 这一条 output group 对应的是 //Article:NewsInHouse 及其依赖 Target 的输入文件中的非源文件的部分比如编译时依赖的 hmap 。 这样的 Bazel Build 命令可以在 Index Build 时将 hmap 和 swiftmodule 之类的索引中间产物生成出来然后再索引具体文件时就不会因为缺少这些中间产物而失败。 并且这里的依赖关系是由 Bazel 去处理的不是必须像 Xcode 原生机制那样按照依赖关系来决定 Index Build 中 Target 的顺序。 所以仅从 Module 中间产物 这方面来说Xcode 中的依赖关系并不是必需的。 多 Target 编译参数 除了中间产物生成之外依赖关系在多个 Target 共用源文件时的编译参数计算也发挥着作用。这里的“编译参数计算”是指当一个源文件被不同 Target 引用时应用的编译参数可能不同的情况。这么介绍比较抽象来看下具体的例子 下面 Demo 工程中有两个 App TargetAppA 和 AppB 在两个 App Target 的 Build Settings 中分别注入了宏IS_APP_A和IS_APP_B。 有一份公共的代码文件 public.m 分别被添加到两个 App Target 的 Compile Sources 中。 public.m 内用预编译宏隔离了存在差异的逻辑随着我们切换构建的 App Scheme由于编译参数的差异宏作用域中高亮的代码区域也会随之变化如下图。 此时的工程结构如下图所示Xcode 可以通过选中的 AppA Scheme 获取到 AppA Target 的 Build Settings图中红线路径正确地传递编译参数-DIS_APP_A1。 实际的情况会复杂一些因为工程的组件化建设将代码下沉到了一个个组件内而非直接与 App Target 关联。此时同一份代码文件在不同 App Target 内的索引参数计算则是通过 Target 之间的依赖关系实现的。 对应到 Xcode 中Xcode 可以通过 App Target - Library Target 的依赖关系应用对应的 Build Settings 生成索引。 此时的工程结构则变成了下图的模式Xcode 依然可以通过 AppA Target 与 PublicLibraryA Target 的依赖关系应用正确的编译参数图中红线路径。 Xcode 原生工程和 Tulsi 生成的 Xcode 工程都是通过这种依赖关系来保证编译参数的正确计算的。 而 rules_xcodeproj 生成的工程完全移除了 Target 之间的依赖关系转而给所有 Target 都添加了对 BazelDependencies 的依赖如下图所示。 从图中可以看到在缺少 AppA Target 对 PublicLibraryA Target 依赖的情况下对于同时被 PublicLibraryA 和 PublicLibraryB 引用的 public.m Xcode 无法感知应该应用哪个 Target 中的编译参数图中红线路径无法关联 AppA Scheme 与 public.m。此时 Xcode 触发索引时应用的 Build Settings 是固定的不会随着构建 App Scheme 切换而更改。 具体的表现当构建目标从 AppB 切换到 AppA 时IS_APP_B宏中的代码仍然会展示为高亮而不会随之切换从而给开发者带来困惑。 对于这个问题rules_xcodeproj 可以通过构建索引解决因为依赖信息在 Bazel 侧BUILD 文件中是完整的所以触发构建后可以让代码高亮正确展示。 但由于编辑索引使用的参数是 Xcode 从文件所属的 Library Target 的 Build Settings 中获取的因此在代码编辑过程中仍然会出现高亮错误的问题。 构建索引指在构建过程中输出索引产物需要通过 index-import 导入 Xcode 缓存目录Derived Data下供 Xcode 消费。 编辑索引在代码编辑过程中实时生成的索引在内存中消费索引结果不会将产物写入磁盘。 在这个场景下rules_xcodeproj 移除依赖的做法是有缺陷的。 那么我们要在 rules_xcodeproj 恢复 Target 间的依赖关系么 答案是不需要。首先前文有提及大量复杂的依赖关系会导致 Xcode 卡顿不应恢复其次要解决这类代码高亮错误的问题需要的其实并不是所有 Target 之间的依赖关系而是源码文件与当前构建 App Target 的关系。 回顾一下 Demo 工程最简单的结构当源码文件直接被对应 App Target 引用时是不需要 Library Target 间的依赖关系来建立联系的。 基于这一思路我们将所有 Library Target 的源码合并到了对应 App Target。当然直接合并源码以后索引并不能正常工作需要对受影响的功能点进行适配这些适配将在下一节源码合并方案中展开介绍。 源码合并方案 索引参数接管 将所有源码合并至 App Target 虽然能解决文件与 App 的关联问题但各个 Library Target 编译参数是不同的聚合之后不同 Target 下源文件的参数就无法通过 Build Settings 区分了。 对于这个问题我们是通过 XCBBuildServiceProxy 接管索引参数计算解决的。 索引构建时Xcode 会先将文件所属 Target 的 Build Settings 发送给 XCBBuildService 处理成编译器理解的参数再交给 SKAgent 触发编译器进行实际编译行为。而我们在 XCBBuildServiceProxy 的基础上实现了 BitSkyXCBBuildService可以拦截 Xcode 发给 XCBBuildService 的请求通过 Bazel aquery 查询到具体文件的编译参数直接返回给 Xcode 完成后续的索引构建行为。 完成源码合并与索引参数接管这两步改造以后工程结构如下图所示。可以看到 AppA Scheme 能够直接通过 AppA Target 关联到  public.m图中红线从而正确地应用编译参数高亮对应代码块。rules_xcodeproj 移除依赖关系的副作用也完全被修复。 Library Target 移除 完成源码合并以及索引参数的接管之后Library Target 中的主要信息 Build Settings 和源码都不再有意义了是否能将这些 Target 信息直接移除呢 经过梳理Library Target 主要有以下三个作用在完成源码合并以及索引参数接管后仅需对“Module 中间产物生成”进行一些改造即可将几百个 Library Target 的信息进行移除大幅精简工程文件的内容。 Library Target 作用说明适配方案触发 Xcode 索引Xcode 只会对添加到 Build Phase - Compile Sources 中的源码文件生成索引将源码添加到 App Target 的 Compile Sources 中有相同的效果按 Target 维度隔离 Build SettingsXcode 原生的索引功能会通过 Build Settings 生成文件的编译参数通过 XCBBuildServiceProxy 接管索引参数请求交由 Bazel aquery 查询具体文件的编译参数Module 中间产物生成在 Library Target 的 Build Phase 触发各个 Target 维度的中间产物生成将所需产物聚合到各个 App Target 的 Build Phase 触发生成 最终的工程结构如下图所示。 整体方案上线后头条工程文件project.pbxproj行数从 45w 减少至 35w工程启动与文件操作耗时也比原来的 Tulsi 工程减少了 60% 以上。 Tulsirules_xcodeproj原生rules_xcodeproj源码合并工程首次冷启47s22s16s二次启动33s16s12s文件操作新增 20s删除 23s新增 13s删除 11s新增 8s删除 6s p.s. 源码合并后存在一个副作用是 Xcode Build Phase 页面加载时间会增加很多但考虑到使用 bazel 构建后我们并不需要在 Build Phase 修改配置这个副作用是可以接受的。 构建 rules_xcodeproj 目前提供了两种 Build 模式分别是 Build with Xcode 和 Build with Bazel。 Build with Xcode 模式下构建行为是由 Xcode 接管的。Build with Bazel 模式下构建行为是由 Bazel 接管的。 据 rules_xcodeproj 官方介绍Build with Xcode 模式在 Bazel 7 下将很难支持并且即将到来的新的增量生成模式也会放弃 Build with Xcode 。 所以这里主要看一下 Build with Bazel 这个模式生成的工程中宿主 Target 对应一个 XCScheme这个 Scheme 的 Build Pre-actions 里生成一个 SCHEME_Target_IDS_FILE 用于记录 Target 的 Bazel Label。然后宿主 Target 依赖了 Target BazelDependenciesXcode 在构建宿主 Target 之前会先构建 BazelDependencies。BazelDependencies 通过 Build Phase 去调用 Bazel Build这个时候会解析 SCHEME_Target_IDS_FILE 获取需要构建的 Bazel Target。BazelDependencies 构建完成后宿主 Target 的 Build Phase 里会去把相应的 Bazel 的产物拷贝到 Xcode Derivedata 目录下。 另外在 rules_xcodeproj 的规划中未来还会提供一种新的模式叫做 Build with Proxy在这个模式下会通过 XCBBuildServiceProxy 完全绕过 Xcode build system由 Bazel 控制整个 build 过程。相比 Build with Bazel 这个模式可以带来一些更贴近原生的 Xcode 使用体验比如 无需添加 BazelDependencies Target可以去掉重复的 warnings/errors可以有更稳定的索引效果可以在进度条展示更多信息可以有更详细的 Build 报告 当然这种模式也存在比较大的问题 在不同 Xcode 版本之间Xcode 和 XCBBuildService 交互的 API 可能会有一些破坏性的变更需要逐一适配需要在 Xcode 启动时注入环境变量将 XCBBuildService 指向自定义的 XCBBuildServiceProxy BitSky 目前采用的方案和 Build with Proxy 是类似的通过 BitSkyXCBBuildService 接管 Xcode 的 build 行为。在用户点击 Build 时BitSkyXCBBuildService 里可以从宿主 Target 的 Build Settings 里解析获取对应的 Bazel Target然后再由 BitSky 生成调用 Bazel Build 的命令这样可以保证 Bazel Build 的参数完全由 BitSky 控制同时可以通过 Bazel 的 Build Event Protocol 来更好的提供 Xcode 的进度 和 Build 日志展示。 同时为了保证在打开生成的 Xcode 工程时都能够使用 BitSkyXCBBuildServiceBitSky 在生成工程同时会生成一个 Xcode 的影子分身 BitSkyXcode。使用这个 BitSkyXcode 打开工程无需手动注入环境变量体验上和使用原生 Xcode 打开工程基本一致。 总结 本文主要介绍了我们将 Xcode 工程生成工具切换到 rules_xcodeproj 过程中做的一些适配和优化工作 索引方面 在分析 Tulsi 与 rules_xcodeproj 工程文件的过程中我们注意到最大的差异在于 rules_xcodeproj 移除了 Library Target 间的依赖关系这也是 Tulsi 工程更加卡顿的罪魁祸首。rules_xcodeproj 移除依赖关系后会导致多 Target 共用的源文件语法高亮异常我们通过源码合并方案解决了这个问题并且精简了工程文件信息提升了 Xcode 流畅度。构建方面 我们通过 BitSkyXCBBuildService 接管了 Xcode 的 build 行为能够更好地管理构建参数并在 Xcode 提供构建进度和日志的展示。 在完成切换之后虽然 Xcode 代码编辑过程中的卡顿得到了明显的缓解但本地研发的调试过程仍然存在 Xcode 卡顿/卡死等现象对研发同学的开发工作存在较大困扰。后续我们将针对调试体验从生成工程的角度做一些优化工作。 目前考虑基于 Focus Mode 的理念从底层能力上支持研发同学仅关注与当前需求开发相关联的部分代码比如 裁剪 Xcode 工程中需要索引的源代码裁剪构建过程中需要执行编译源代码裁剪调试时调试器需要加载调试信息 另外在用户侧通过策略智能帮助研发同学选择和添加需要 Focus 的源码。 参考文档 Tulsi (https://github.com/bazelbuild/tulsi) rules_xcodeproj (https://github.com/MobileNativeFoundation/rules_xcodeproj) Migrating from Xcode to Bazel (https://bazel.build/migrate/xcode) Monorepo 解决方案 — Bazel 在头条 iOS 的实践 哔哩哔哩 iOS Bazel 进化之路 用VSCode基于Bazel打造Apple生态开发环境
http://www.zqtcl.cn/news/181621/

相关文章:

  • 网站建设优化托管跨境电商怎么做流程
  • 昆明网站建站平台在线阅读网站开发教程
  • pv3d 优秀网站18种最有效推广的方式
  • 一站式网站建设顾问网站建设公司专业网站科技开发
  • python做网站比php好网站开发财务费用
  • 图片上传网站变形的处理北京网站建设有哪些公司
  • 昆山品牌网站建设wordpress 浮动二维码
  • 网站网页建设论文cms免费源码
  • wordpress登录的图片不显示seo竞价网站建设
  • 邢台做移动网站找谁网上推广平台哪个好
  • 做网站准备广州短视频拍摄公司
  • 网站建设学什么软件做电影资源网站有哪些
  • 怎么样让百度搜到自己的网站wordpress的短代码
  • 聊城专业网站建设公司电子商务网站建设与维护李建忠下载
  • icp备案网站接入信息怎么写长兴县网站建设
  • 如何在网上注册公司网站网站不想让百度收录
  • 服务器做jsp网站教程视频免费的舆情网站app下载
  • 肇庆网站建设方案优化家居定制类网站建设
  • 自助建站加盟备案的网站有什么好处
  • 科技公司企业网站建设重庆seo优化
  • 空间站天宫vr全景尚层装饰
  • 有没有专门做中考卷子的网站网络公司推广公司
  • 网站建设费用如何列支wordpress页面构建
  • 用dw做网站怎么做出下拉菜单企业进行网站建设的方式有( )
  • 纯静态网站索引怎么做如何用wampp 做网站
  • 怎样做网站吸引人wordpress数据可视化插件
  • 网站运营管理教材中国设计之窗官方网站
  • 高端网站设计高端网站制作P2P网站怎么建设
  • 一般网站建设的流程故事app怎么制作
  • 一般在什么网站上做电子请帖国外产品设计网