评论

收藏

鸿蒙内核源码分析(GN应用篇) | GN语法及在鸿蒙的使用 | 百篇博客分析HarmonyOS源码 | v60.01

服务系统 服务系统 发布于:2021-07-21 13:19 | 阅读数:579 | 评论:0

OpenHarmony | 鸿蒙研究站 | WeHarmony < 国内 | 国外 >
DSC0000.png

百篇博客系列篇.本篇为:
v60.xx 鸿蒙内核源码分析(GN应用篇) | GN语法及在鸿蒙的使用  | 51 .c .h .o
编译模块相关篇为:
      
  • v59.xx 鸿蒙内核源码分析(构建工具篇) | 顺瓜摸藤调试鸿蒙构建过程  | 51 .c .h .o  
  • v58.xx 鸿蒙内核源码分析(环境脚本篇) | 有了它编译鸿蒙好简单  | 51 .c .h .o  
  • v57.xx 鸿蒙内核源码分析(编译过程篇) | 简单案例窥视GCC编译全过程  | 51 .c .h .o  
  • v50.xx 鸿蒙内核源码分析(编译环境篇) | docker编译鸿蒙真的很香  | 51 .c .h .o
GN是什么?
GN 是一个为 Ninja 生成构建文件的元构建系统。 为什么会有GN,说是有个叫even的谷歌负责构建系统的工程师在使用传统的makefile构建chrome时觉得太麻烦,不高效,所以设计了一套更简单,更高效新的构建工具,然后就被广泛的使用了.
GN语法和配置
gn 有大量的内置变量和库函数,熟悉这些库函数基本就知道gn能干什么,gn的官方文档很齐全,前往 GN参考手册翻看查找 . gn的语法很简单,了解以下几点基本就能看懂gn代码.重点了解下函数的调用方式,和其他高级语言不太一样. 字符串
a = "mypath"
b = "$a/foo.cc"  # b -> "mypath/foo.cc"
c = "foo${a}bar.cc"  # c -> "foomypathbar.cc"
列表
a = [ "first" ]
a += [ "second" ]  # [ "first", "second" ]
a += [ "third", "fourth" ]  # [ "first", "second", "third", "fourth" ]
b = a + [ "fifth" ]  # [ "first", "second", "third", "fourth", "fifth" ]
条件语句
if (is_linux || (is_win && target_cpu == "x86")) {
  sources -= [ "something.cc" ]
  }else {
  ...
  }
循环
foreach(i, mylist) {
  print(i)  # Note: i is a copy of each element, not a reference to it.
}
函数调用
print("hello, world")
assert(is_win, "This should only be executed on Windows") # 如果is_win为真,就打印后面的内容
static_library("mylibrary") { 
  sources = [ "a.cc" ]
}
解读:
      
  • print,assert,static_library都是库函数,或者叫内置函数.  
  • static_library的调用有点奇怪,它是个函数,函数内部会使用sources这个内置变量,sources = [ "a.cc" ]相当于先传参给这个函数的内置变量,并调用这个函数.学习ng得习惯这种语法方式,被大量的使用.
模板 | Templates gn提供了很多内置函数,使用偏傻瓜式,若不是太复杂的系统熟悉这些内置函数,往里填空写字就可以了,如果想自己定义函数怎么办? 答案是模板,模板就是自定义函数.
#定义模板, 例如:新建文件 //tools/idl_compiler.gni
template("idl") { #自定义一个名称为 "idl"的函数
  source_set(target_name) { #调用内置函数 source_set
  sources = invoker.sources #invoker为内置变量,含义为调用者内容 即:[ "a", "b" ]的内容
  }
}
#后缀.gni 代表这是一个 gn import file
import("//tools/idl_compiler.gni") #先import模板,类似 C语言的 #include
idl("my_interfaces") { #等同于调用 idl
  sources = [ "a", "b" ] #给idl传参, 参数的接收方是 invoker.sources
}
明白了模板的使用,阅读鸿蒙gn代码就不会有太大的障碍.
目标项 | Targets 目标是构建图中的一个节点。它通常表示将生成某种可执行文件或库文件。整个构建是由一个个的目标组成. 目标包含:
action: 运行脚本以生成文件
executable: 生成可执行文件
group: 生成依赖关系组
shared_library: 生成.dll或.so动态链接库
static_library: 生成.lib或.a 静态链接库
...
配置项 | Configs 记录完成目标项所需的配置信息,例如:
config("myconfig") {#创建一个标签为`myconfig`的配置项
  include_dirs = [ "include/common" ]
  defines = [ "ENABLE_DOOM_MELON" ]
  }
executable("mything") {#生成可执行文件
  configs = [ ":myconfig" ]#使用标签为`myconfig`的配置项来生成目标文件
}
GN在鸿蒙中的使用
有了以上基础铺垫,正式开始gn在openharomny的使用.
从哪开始
在构建工具篇中已经说清楚了 hb的python部分有个工作任务是生成gn参数,执行命令行.
/home/tools/gn gen /home/openharmony/code-v1.1.1-LTS/out/hispark_aries/ipcamera_hispark_aries \
  --root=/home/openharmony/code-v1.1.1-LTS \
  --dotfile=/home/openharmony/code-v1.1.1-LTS/build/lite/.gn \
  --script-executable=python3 \
  '--args=ohos_build_type="debug" ohos_build_compiler_specified="clang" ohos_build_compiler_dir="/home/tools/llvm" product_path="/home/openharmony/code-v1.1.1-LTS/vendor/hisilicon/hispark_aries" device_path="/home/openharmony/code-v1.1.1-LTS/device/hisilicon/hispark_aries/sdk_liteos" ohos_kernel_type="liteos_a" enable_ohos_appexecfwk_feature_ability = false ohos_full_compile=true'
解读
      
  • root,dotfile,script-executable是gn内置的固定参数,一切从dotfile指向的文件开始.即build/lite/.gn 相当于main()函数的作用,  
  • 打开 build/lite/.gn看下内容,只有两句,先配置好内部参数再工作.
    # The location of the build configuration file.
    buildconfig = "//build/lite/config/BUILDCONFIG.gn" #1.完成GN的配置工作
    # The source root location.
    root = "//build/lite" #2.完成GN的编译工作

  • args为用户自定义的参数,它们将会在解析BUILD.gn,BUILDCONFIG.gn过程中被使用.
BUILDCONFIG.gn | 构建配置项
BUILDCONFIG.gn为BUILD.gn做准备,填充好编译所需的配置信息.即生成配置项 详细请查看 build/lite/config/BUILDCONFIG.gn 文件全部内容,本篇只贴出部分.
import("//build/lite/ohos_var.gni")
import("${device_path}/config.gni")
....
arch = "arm"
if (ohos_kernel_type == "liteos_a") {
  target_triple = "$arch-liteos"
} else if (ohos_kernel_type == "linux") {
  target_triple = "$arch-linux-ohosmusl"
}
...
template("executable") { #生成可执行文件
  executable(target_name) {
  forward_variables_from(invoker, Variables_Executable)
  if (!defined(invoker.deps)) {
    deps = [ "//build/lite:prebuilts" ]
  } else {
    deps += [ "//build/lite:prebuilts" ]
  }
  if (defined(invoker.configs)) {
    configs = []
    configs += invoker.configs
  }
  }
}
set_defaults("executable") {#设置目标类型的默认值
  configs = default_executable_configs
  configs += [ "//build/lite/config:board_exe_ld_flags" ]
}
...
解读
      
  • ${device_path}为命令行参数,本篇为home/openharmony/code-v1.1.1-LTS/device/hisilicon/hispark_aries/sdk_liteos  
  • 查看构建-配置内容,BUILDCONFIG主要任务就是对其中的内置变量赋值.例如:
         
    • 指定编译器 clang,   
    • 如何生成可执行文件的方法   
      
BUILD.gn | 启动构建
查看 build/lite/BUILD.gn 文件
#目的是要得到项目各个模块的编译入口
group("ohos") {
  deps = []
  if (ohos_build_target == "") {
  # Step 1: Read product configuration profile.
  # 第一步:读取配置文件product_path的值来源于根目录的ohos_config.json,如下,内容由 hb set 命令生成
  # {
  #  "root_path": "/home/openharmony",
  #  "board": "hispark_aries",
  #  "kernel": "liteos_a",
  #  "product": "ipcamera_hispark_aries",
  #  "product_path": "/home/openharmony/vendor/hisilicon/hispark_aries",
  #  "device_path": "/home/openharmony/device/hisilicon/hispark_aries/sdk_liteos",
  #  "patch_cache": null
  #}
  product_cfg = read_file("${product_path}/config.json", "json")
  # Step 2: Loop subsystems configured by product.
  # 第二步:循环处理各自子系统,config.json中子系统部分格式如下hb
  #"subsystems": [
  #  {
  #  "subsystem": "aafwk",
  #  "components": [
  #    { "component": "ability", "features":[ "enable_ohos_appexecfwk_feature_ability = false" ] }
  #  ]
  #  },
  #  ...
  #  {
  #  "subsystem": "distributed_schedule",
  #  "components": [
  #  { "component": "system_ability_manager", "features":[] },
  #  { "component": "foundation", "features":[] },
  #  { "component": "distributed_schedule", "features":[] }
  #  ]
  #  },
  #  {
  #    "subsystem": "kernel",
  #    "components": [
  #    { "component": "liteos_a", "features":[] }
  #    ]
  #   },
  #]
  foreach(product_configed_subsystem, product_cfg.subsystems) {#对子系统数组遍历操作
    subsystem_name = product_configed_subsystem.subsystem#读取一个子系统 aafwk,hiviewdfx,security ==
    subsystem_info = {
    }
    # Step 3: Read OS subsystems profile.
  # 第三步: 读取各个子系统的配置文件
    subsystem_info =
      read_file("//build/lite/components/${subsystem_name}.json", "json")
    # Step 4: Loop components configured by product.
    # 第四步: 循环读取子系统内各控件的配置信息
    # 此处以内核为例://build/lite/components/kernel.json"
    # "components": [
    #   {
    #   "component": "liteos_a",        # 组件名称
    #   "description": "liteos-a kernel",   # 组件一句话功能描述
    #   "optional": "false",          # 组件是否为最小系统必选
    #   "dirs": [               # 组件源码路径
    #     "kernel/liteos_a"
    #   ],
    #   "targets": [              # 组件编译入口
    #     "//kernel/liteos_a:kernel"
    #   ],
    #   "rom": "1.98MB",            # 组件ROM值
    #   "ram": "",              # 组件RAM估值
    #   "output": [               # 组件编译输出
    #     "liteos.bin"
    #   ],
    #   "adapted_board": [          # 组件已适配的主板
    #     "hispark_aries",
    #     "hispark_taurus",
    #     "hi3518ev300",
    #   "hi3516dv300",
    #   ],
    #   "adapted_kernel": [ "liteos_a" ],   # 组件已适配的内核
    #   "features": [],             # 组件可配置的特性
    #   "deps": {
    #     "components": [],           # 组件依赖的其他组件
    #     "third_party": [          # 组件依赖的三方开源软件
    #     "FreeBSD",
    #     "musl",
    #     "zlib",
    #     "FatFs",
    #     "Linux_Kernel",
    #     "lwip",
    #     "NuttX",
    #     "mtd-utils"
    #     ]
    #   }
    #   },
    # ]
    foreach(product_configed_component,
        product_configed_subsystem.components) { #遍历项目控件数组
    # Step 5: Check whether the component configured by product is exist.
  # 第五步: 检查控件配置信息是否存在
    component_found = false #初始为不存在
    foreach(system_component, subsystem_info.components) {#项目控件和子系统中的控件遍历对比
      if (product_configed_component.component ==
        system_component.component) { #找到了liteos_a
      component_found = true
      }
    }
  #如果没找到的信息,则打印项目控件查找失败日志
    assert(
      component_found,
      "Component "${product_configed_component.component}" not found" +
        ", please check your product configuration.")
    # Step 6: Loop OS components and check validity of product configuration.
# 第六步: 检查子系统控件的有效性并遍历控件组,处理各个控件
    foreach(component, subsystem_info.components) {
      kernel_valid = false#检查内核
      board_valid = false#检查开发板
      # Step 6.1: Skip component which not configured by product.
      if (component.component == product_configed_component.component) {
      # Step 6.1.1: Loop OS components adapted kernel type.
      foreach(component_adapted_kernel, component.adapted_kernel) {
        if (component_adapted_kernel == product_cfg.kernel_type && 
          kernel_valid == false) { #内核检测是否已适配
        kernel_valid = true
        }
      }
# 如果内核未适配,则打印未适配日志
      assert(
        kernel_valid,
        "Invalid component configed, ${subsystem_name}:${product_configed_component.component} " + "not available for kernel: ${product_cfg.kernel_type}!")
      # Step 6.1.2: Add valid component for compiling.
# 添加有效组件进行编译
      foreach(component_target, component.targets) {//遍历组件的编译入口
        deps += [ component_target ] #添加到编译列表中
      }
      }
    }
    }
  }
  # Step 7: Add device and product target by default.
  # 第七步: 添加设备和项目的编译单元
  # "product_path": "/home/openharmony/vendor/hisilicon/hispark_aries",
  # "device_path": "/home/openharmony/device/hisilicon/hispark_aries/sdk_liteos",
    deps += [
    "${device_path}/../", #添加 //device/hisilicon/hispark_aries 进入编译项
    "${product_path}"#添加 //vendor/hisilicon/hispark_aries 进入编译项
  ]
  } else {#编译指定的组件,例如 hb build -T targetA&&targetB
  deps += string_split(ohos_build_target, "&&")
  }
}
解读
      
  • 有三个概念贯彻整个鸿蒙系统,子系统(subsystems),组件(components),功能(features).理解它们的定位和特点是解读鸿蒙的关键所在.  
  • 先找到product_path下的 配置文件 config.json,里面配置了项目所要使用的子系统和组件.  
  • 再遍历项目所使用的组件是否能再 //build/lite/components/*.json组件集中能找到.  
  • 将找到的组件targets加入到编译列表deps中.targets指向了要编译的组件目录.例如内核组件时指向了://kernel/liteos_a:kernel,
    import("//build/lite/config/component/lite_component.gni") #组件模板函数
    import("//build/lite/config/subsystem/lite_subsystem.gni") #子系统模板函数
    lite_subsystem("kernel") {#编译内核子系统/组件入口
      subsystem_components = []
      if (enable_ohos_kernel_liteos_a_ext_build == false) {
      subsystem_components += [
        "//kernel/liteos_a/kernel",
        "//kernel/liteos_a/net",
        "//kernel/liteos_a/lib",
        "//kernel/liteos_a/compat",
        "//kernel/liteos_a/fs",
        "//kernel/liteos_a/arch:platform_cpu",
      ]
      if (LOSCFG_SHELL) {
        subsystem_components += [ "//kernel/liteos_a/shell" ]
      }
      } else {
      deps = [ ":make" ]
      }
    }
    lite_subsystem是个模板函数(自定义函数),再查看lite_subsystem.gni函数原型,它的目的只有一个填充 deps,deps是私有链接依赖关系,最终会形成一颗依赖树.gn会根据这些依赖关系生成最终的.ninja文件.
    # 定义一个子系统
    # lite_subsystem template模板定义了子系统中包含的所有模块
    # 参数
    #   subsystem_components (必须))
    #   [范围列表] 定义子系统的所有模块.
    template("lite_subsystem") {
      assert(defined(invoker.subsystem_components), "subsystem_components in required.")
      lite_subsystem_components = invoker.subsystem_components
      group(target_name) {
        deps = []
        if(defined(invoker.deps)) {
          deps += invoker.deps
        }
        # add subsystem packages
        foreach(pkg_label, lite_subsystem_components) {
          deps += [ pkg_label ]
        }
      }
    }

生成了哪些文件
执行后ng gen 会生成如下文件和目录
turing@ubuntu:/home/openharmony/code-v1.1.1-LTS/out/hispark_aries/ipcamera_hispark_aries$ ls
args.gn  build.ninja  build.ninja.d  NOTICE_FILE  obj  test_info  toolchain.ninja
build.ninja.d中记录依赖的 BUILD.gn文件路径
build.ninja: ../../../base/global/resmgr_lite/frameworks/resmgr_lite/BUILD.gn \
       ../../../base/hiviewdfx/hilog_lite/frameworks/featured/BUILD.gn \
       ../../../base/hiviewdfx/hilog_lite/services/apphilogcat/BUILD.gn \
       ....
ng根据这些组件的BUILD.gn在obj目录下对应生成了每个组件的.ninja文件.此处列出鸿蒙L1所有的 .ninja文件, 具体ninja是如何编译成最终的库和可执行文件的,将在后续篇中详细介绍其语法和应用.
turing@ubuntu:/home/openharmony/code-v1.1.1-LTS/out/hispark_aries/ipcamera_hispark_aries/obj$ tree
├── base
│   ├── global
│   │   └── resmgr_lite
│   │     └── frameworks
│   │       └── resmgr_lite
│   │         └── global_resmgr.ninja
│   ├── hiviewdfx
│   │   └── hilog_lite
│   │     ├── frameworks
│   │     │   └── featured
│   │     │     ├── hilog_shared.ninja
│   │     │     └── hilog_static.ninja
│   │     └── services
│   │       ├── apphilogcat
│   │       │   ├── apphilogcat.ninja
│   │       │   └── apphilogcat_static.ninja
│   │       └── hilogcat
│   │         ├── hilogcat.ninja
│   │         └── hilogcat_static.ninja
│   ├── security
│   │   ├── appverify
│   │   │   └── interfaces
│   │   │     └── innerkits
│   │   │       └── appverify_lite
│   │   │         ├── products
│   │   │         │   └── ipcamera
│   │   │         │     └── verify_base.ninja
│   │   │         ├── unittest
│   │   │         │   └── app_verify_test.ninja
│   │   │         └── verify.ninja
│   │   ├── deviceauth
│   │   │   └── frameworks
│   │   │     └── deviceauth_lite
│   │   │       └── source
│   │   │         └── hichainsdk.ninja
│   │   ├── huks
│   │   │   └── frameworks
│   │   │     └── huks_lite
│   │   │       └── source
│   │   │         └── huks.ninja
│   │   └── permission
│   │     └── services
│   │       └── permission_lite
│   │         ├── ipc_auth
│   │         │   └── ipc_auth_target.ninja
│   │         ├── pms
│   │         │   └── pms_target.ninja
│   │         ├── pms_base
│   │         │   └── pms_base.ninja
│   │         └── pms_client
│   │           └── pms_client.ninja
│   └── startup
│     ├── appspawn_lite
│     │   └── services
│     │     ├── appspawn.ninja
│     │     └── test
│     │       └── unittest
│     │         └── common
│     │           └── appspawn_test.ninja
│     ├── bootstrap_lite
│     │   └── services
│     │     └── source
│     │       └── bootstrap.ninja
│     ├── init_lite
│     │   └── services
│     │     ├── init.ninja
│     │     └── test
│     │       └── unittest
│     │         └── common
│     │           └── init_test.ninja
│     └── syspara_lite
│       └── frameworks
│         ├── parameter
│         │   └── src
│         │     └── sysparam.ninja
│         ├── token
│         │   └── token_shared.ninja
│         └── unittest
│           └── parameter
│             └── ParameterTest.ninja
├── build
│   └── lite
│     └── config
│       └── component
│         ├── cJSON
│         │   ├── cjson_shared.ninja
│         │   └── cjson_static.ninja
│         ├── openssl
│         │   ├── openssl_shared.ninja
│         │   └── openssl_static.ninja
│         └── zlib
│           ├── zlib_shared.ninja
│           └── zlib_static.ninja
├── drivers
│   ├── adapter
│   │   └── uhdf
│   │     ├── manager
│   │     │   └── hdf_core.ninja
│   │     ├── platform
│   │     │   └── hdf_platform.ninja
│   │     ├── posix
│   │     │   └── hdf_posix_osal.ninja
│   │     └── test
│   │       └── unittest
│   │         ├── common
│   │         │   └── hdf_test_common.ninja
│   │         ├── config
│   │         │   └── hdf_adapter_uhdf_test_config.ninja
│   │         ├── manager
│   │         │   ├── hdf_adapter_uhdf_test_door.ninja
│   │         │   ├── hdf_adapter_uhdf_test_ioservice.ninja
│   │         │   ├── hdf_adapter_uhdf_test_manager.ninja
│   │         │   └── hdf_adapter_uhdf_test_sbuf.ninja
│   │         ├── osal
│   │         │   └── hdf_adapter_uhdf_test_osal.ninja
│   │         └── platform
│   │           └── hdf_adapter_uhdf_test_platform.ninja
│   └── peripheral
│     ├── input
│     │   └── hal
│     │     └── hdi_input.ninja
│     └── wlan
│       ├── client
│       │   └── wifi_driver_client.ninja
│       ├── hal
│       │   └── wifi_hal.ninja
│       └── test
│         ├── performance
│         │   └── hdf_peripheral_wlan_test_performance.ninja
│         └── unittest
│           └── hdf_peripheral_wlan_test.ninja
├── foundation
│   ├── aafwk
│   │   └── aafwk_lite
│   │     ├── frameworks
│   │     │   ├── ability_lite
│   │     │   │   └── ability.ninja
│   │     │   ├── abilitymgr_lite
│   │     │   │   └── abilitymanager.ninja
│   │     │   └── want_lite
│   │     │     └── want.ninja
│   │     └── services
│   │       └── abilitymgr_lite
│   │         ├── abilityms.ninja
│   │         ├── tools
│   │         │   └── aa.ninja
│   │         └── unittest
│   │           └── test_lv0
│   │             └── page_ability_test
│   │               └── ability_test_pageAbilityTest_lv0.ninja
│   ├── ai
│   │   └── engine
│   │     ├── services
│   │     │   ├── client
│   │     │   │   ├── ai_client.ninja
│   │     │   │   ├── client_executor
│   │     │   │   │   └── client_executor.ninja
│   │     │   │   └── communication_adapter
│   │     │   │     └── ai_communication_adapter.ninja
│   │     │   ├── common
│   │     │   │   ├── platform
│   │     │   │   │   ├── dl_operation
│   │     │   │   │   │   └── dlOperation.ninja
│   │     │   │   │   ├── event
│   │     │   │   │   │   └── event.ninja
│   │     │   │   │   ├── lock
│   │     │   │   │   │   └── lock.ninja
│   │     │   │   │   ├── os_wrapper
│   │     │   │   │   │   └── ipc
│   │     │   │   │   │     └── aie_ipc.ninja
│   │     │   │   │   ├── semaphore
│   │     │   │   │   │   └── semaphore.ninja
│   │     │   │   │   ├── threadpool
│   │     │   │   │   │   └── threadpool.ninja
│   │     │   │   │   └── time
│   │     │   │   │     └── time.ninja
│   │     │   │   ├── protocol
│   │     │   │   │   └── data_channel
│   │     │   │   │     └── data_channel.ninja
│   │     │   │   └── utils
│   │     │   │     └── encdec
│   │     │   │       └── encdec.ninja
│   │     │   └── server
│   │     │     ├── ai_server.ninja
│   │     │     ├── communication_adapter
│   │     │     │   └── ai_communication_adapter.ninja
│   │     │     ├── plugin_manager
│   │     │     │   └── plugin_manager.ninja
│   │     │     └── server_executor
│   │     │       └── server_executor.ninja
│   │     └── test
│   │       ├── common
│   │       │   ├── ai_test_common.ninja
│   │       │   └── dl_operation
│   │       │     └── dl_operation_so
│   │       │       └── dlOperationSo.ninja
│   │       ├── function
│   │       │   ├── ai_test_function.ninja
│   │       │   └── death_callback
│   │       │     ├── testDeathCallbackLibrary.ninja
│   │       │     └── testDeathCallback.ninja
│   │       ├── performance
│   │       │   └── ai_test_performance_unittest.ninja
│   │       └── sample
│   │         ├── asyncDemoPluginCode.ninja
│   │         ├── sample_plugin_1.ninja
│   │         ├── sample_plugin_2.ninja
│   │         └── syncDemoPluginCode.ninja
│   ├── appexecfwk
│   │   └── appexecfwk_lite
│   │     ├── frameworks
│   │     │   └── bundle_lite
│   │     │     └── bundle.ninja
│   │     └── services
│   │       └── bundlemgr_lite
│   │         ├── bundle_daemon
│   │         │   └── bundle_daemon.ninja
│   │         ├── bundlems.ninja
│   │         └── tools
│   │           └── bm.ninja
│   ├── communication
│   │   ├── ipc_lite
│   │   │   └── liteipc_adapter.ninja
│   │   └── softbus_lite
│   │     └── softbus_lite.ninja
│   ├── distributedschedule
│   │   ├── dmsfwk_lite
│   │   │   ├── dmslite.ninja
│   │   │   └── moduletest
│   │   │     └── dtbschedmgr_lite
│   │   │       └── distributed_schedule_test_dms.ninja
│   │   ├── safwk_lite
│   │   │   └── foundation.ninja
│   │   └── samgr_lite
│   │     ├── communication
│   │     │   └── broadcast
│   │     │     └── broadcast.ninja
│   │     ├── samgr
│   │     │   ├── adapter
│   │     │   │   └── samgr_adapter.ninja
│   │     │   ├── samgr.ninja
│   │     │   └── source
│   │     │     └── samgr_source.ninja
│   │     ├── samgr_client
│   │     │   └── client.ninja
│   │     ├── samgr_endpoint
│   │     │   ├── endpoint_source.ninja
│   │     │   └── store_source.ninja
│   │     └── samgr_server
│   │       └── server.ninja
│   ├── graphic
│   │   ├── surface
│   │   │   ├── surface.ninja
│   │   │   └── test
│   │   │     └── lite_surface_unittest.ninja
│   │   ├── ui
│   │   │   └── ui.ninja
│   │   ├── utils
│   │   │   ├── graphic_hals.ninja
│   │   │   ├── graphic_utils.ninja
│   │   │   └── test
│   │   │     ├── graphic_test_color.ninja
│   │   │     ├── graphic_test_container.ninja
│   │   │     ├── graphic_test_geometry2d.ninja
│   │   │     ├── graphic_test_math.ninja
│   │   │     └── graphic_test_style.ninja
│   │   └── wms
│   │     ├── wms_client.ninja
│   │     └── wms_server.ninja
│   └── multimedia
│     ├── audio_lite
│     │   └── frameworks
│     │     └── audio_capturer_lite.ninja
│     ├── camera_lite
│     │   └── frameworks
│     │     └── camera_lite.ninja
│     ├── media_lite
│     │   ├── frameworks
│     │   │   ├── player_lite
│     │   │   │   └── player_lite.ninja
│     │   │   └── recorder_lite
│     │   │     └── recorder_lite.ninja
│     │   ├── interfaces
│     │   │   └── kits
│     │   │     └── player_lite
│     │   │       └── js
│     │   │         └── builtin
│     │   │           └── audio_lite_api.ninja
│     │   └── services
│     │     └── media_server.ninja
│     └── utils
│       └── lite
│         └── media_common.ninja
├── test
│   ├── developertest
│   │   ├── examples
│   │   │   └── lite
│   │   │     └── cxx_demo
│   │   │       └── test
│   │   │         └── unittest
│   │   │           └── common
│   │   │             └── CalcSubTest.ninja
│   │   └── third_party
│   │     └── lib
│   │       └── cpp
│   │         ├── gtest_main.ninja
│   │         └── gtest.ninja
│   └── xts
│     ├── acts
│     │   ├── aafwk_lite
│     │   │   └── ability_posix
│     │   │     └── module_ActsAbilityMgrTest.ninja
│     │   ├── ai_lite
│     │   │   └── ai_engine_posix
│     │   │     └── base
│     │   │       ├── module_ActsAiEngineTest.ninja
│     │   │       └── src
│     │   │         └── sample
│     │   │           ├── asyncDemoPluginCode.ninja
│     │   │           ├── sample_plugin_1_sync.ninja
│     │   │           ├── sample_plugin_2_async.ninja
│     │   │           └── syncDemoPluginCode.ninja
│     │   ├── appexecfwk_lite
│     │   │   └── bundle_mgr_posix
│     │   │     └── module_ActsBundleMgrTest.ninja
│     │   ├── communication_lite
│     │   │   ├── lwip_posix
│     │   │   │   └── module_ActsLwipTest.ninja
│     │   │   └── softbus_posix
│     │   │     └── module_ActsSoftBusTest.ninja
│     │   ├── distributed_schedule_lite
│     │   │   └── samgr_posix
│     │   │     └── module_ActsSamgrTest.ninja
│     │   ├── graphic_lite
│     │   │   ├── graphic_utils
│     │   │   │   ├── a
│     │   │   │   │   └── module_ActsUiInterfaceTest1.ninja
│     │   │   │   ├── color_posix
│     │   │   │   │   └── module_ActsColorTest.ninja
│     │   │   │   ├── geometry2d_posix
│     │   │   │   │   └── module_ActsGeometyr2dTest.ninja
│     │   │   │   ├── graphic_math_posix
│     │   │   │   │   └── module_ActsGraphicMathTest.ninja
│     │   │   │   ├── heap_base_posix
│     │   │   │   │   └── module_ActsHeapBaseTest.ninja
│     │   │   │   ├── list_posix
│     │   │   │   │   └── module_ActsListTest.ninja
│     │   │   │   ├── mem_api_posix
│     │   │   │   │   └── module_ActsGraphMemApiTest.ninja
│     │   │   │   ├── rect_posix
│     │   │   │   │   └── module_ActsRectTest.ninja
│     │   │   │   ├── transform_posix
│     │   │   │   │   └── module_ActsTransformTest.ninja
│     │   │   │   └── version_posix
│     │   │   │     └── module_ActsGraphVersionTest.ninja
│     │   │   ├── surface
│     │   │   │   └── surface_posix
│     │   │   │     └── module_ActsSurfaceTest.ninja
│     │   │   └── ui
│     │   │     ├── a
│     │   │     │   └── module_ActsUiInterfaceTest.ninja
│     │   │     ├── animator_posix
│     │   │     │   └── module_ActsAnimatorTest.ninja
│     │   │     ├── easing_equation_posix
│     │   │     │   └── module_ActsEasingEquationTest.ninja
│     │   │     ├── events_posix
│     │   │     │   └── module_ActsEventsTest.ninja
│     │   │     ├── flexlayout_posix
│     │   │     │   └── module_ActsFlexlaoutTest.ninja
│     │   │     ├── gridlayout_posix
│     │   │     │   └── module_ActsGridLayoutTest.ninja
│     │   │     ├── image_posix
│     │   │     │   └── module_ActsImageTest.ninja
│     │   │     ├── interpolation_posix
│     │   │     │   └── module_ActsInterpoliationTest.ninja
│     │   │     ├── layout_posix
│     │   │     │   └── module_ActsLayoutTest.ninja
│     │   │     ├── listlayout_posix
│     │   │     │   └── module_ActsListlayoutTest.ninja
│     │   │     ├── screen_posix
│     │   │     │   └── module_ActsScreenTest.ninja
│     │   │     ├── style_posix
│     │   │     │   └── module_ActsStyleTest.ninja
│     │   │     ├── theme_posix
│     │   │     │   └── module_ActsThemeTest.ninja
│     │   │     ├── ui_abstract_progress_posix
│     │   │     │   └── module_ActsUIAbstractProgressTest.ninja
│     │   │     ├── ui_analog_clock_posix
│     │   │     │   └── module_ActsUIAnalogClockTest.ninja
│     │   │     ├── uianimator_posix
│     │   │     │   └── module_ActsUIAnimatorTest.ninja
│     │   │     ├── ui_arc_lable_posix
│     │   │     │   └── module_ActsUIArcLabelTest.ninja
│     │   │     ├── ui_axis_posix
│     │   │     │   └── module_ActsUIAxisTest.ninja
│     │   │     ├── ui_box_porgress_posix
│     │   │     │   └── module_ActsUIBoxProgressTest.ninja
│     │   │     ├── ui_button_posix
│     │   │     │   └── module_ActsUIButtonTest.ninja
│     │   │     ├── ui_canvas_posix
│     │   │     │   └── module_ActsUICanvasTest.ninja
│     │   │     ├── ui_chart_posix
│     │   │     │   └── module_ActsUIChartTest.ninja
│     │   │     ├── ui_checbox_posix
│     │   │     │   └── module_ActsUICheckboxTest.ninja
│     │   │     ├── ui_circle_progress_posix
│     │   │     │   └── module_ActsUICircleProgressTest.ninja
│     │   │     ├── ui_digital_clock_posix
│     │   │     │   └── module_ActsUIDigitalClockTest.ninja
│     │   │     ├── ui_image_animator_posix
│     │   │     │   └── module_ActsUIImageAnimatorTest.ninja
│     │   │     ├── ui_image_posix
│     │   │     │   └── module_ActsUIImageTest.ninja
│     │   │     ├── ui_label_button_posix
│     │   │     │   └── module_ActsUILabelButtonTest.ninja
│     │   │     ├── ui_label_posix
│     │   │     │   └── module_ActsUILabelTest.ninja
│     │   │     ├── ui_list_posix
│     │   │     │   └── module_ActsUIListTest.ninja
│     │   │     ├── ui_picker_posix
│     │   │     │   └── module_ActsUIPickerTest.ninja
│     │   │     ├── ui_radio_button_posix
│     │   │     │   └── module_ActsUIRadioButtonTest.ninja
│     │   │     ├── ui_repeat_button_posix
│     │   │     │   └── module_ActsUIRepeatButtonTest.ninja
│     │   │     ├── ui_screenshot_posix
│     │   │     │   └── module_ActsUIScreenshotTest.ninja
│     │   │     ├── ui_scroll_view_posix
│     │   │     │   └── module_ActsUIScrollViewTest.ninja
│     │   │     ├── ui_slider_posix
│     │   │     │   └── module_ActsUISliderTest.ninja
│     │   │     ├── ui_surface_view_posix
│     │   │     │   └── module_ActsUISurfaceViewTest.ninja
│     │   │     ├── ui_swipe_view_posix
│     │   │     │   └── module_ActsUISwipeViewTest.ninja
│     │   │     ├── ui_text_posix
│     │   │     │   └── module_ActsUITextTest.ninja
│     │   │     ├── ui_texture_mapper_posix
│     │   │     │   └── module_ActsUITextureMapperTest.ninja
│     │   │     ├── ui_time_picker_posix
│     │   │     │   └── module_ActsUITimePickerTest.ninja
│     │   │     ├── ui_toggle_button_posix
│     │   │     │   └── module_ActsUIToggleButtonTest.ninja
│     │   │     ├── ui_view_group_posix
│     │   │     │   └── module_ActsUIViewGroupTest.ninja
│     │   │     └── ui_view_posix
│     │   │       └── module_ActsUIViewTest.ninja
│     │   ├── hiviewdfx_lite
│     │   │   └── hilog_posix
│     │   │     └── module_ActsHilogTest.ninja
│     │   ├── kernel_lite
│     │   │   ├── dyload_posix
│     │   │   │   └── module_ActsDyloadTest.ninja
│     │   │   ├── fs_posix
│     │   │   │   ├── jffs
│     │   │   │   │   └── module_ActsJFFS2Test.ninja
│     │   │   │   ├── nfs
│     │   │   │   │   └── module_ActsNFSTest.ninja
│     │   │   │   ├── vfat
│     │   │   │   │   └── module_ActsVFATTest.ninja
│     │   │   │   └── vfat_storage
│     │   │   │     └── module_ActsVFATstorageTest.ninja
│     │   │   ├── futex_posix
│     │   │   │   └── module_ActsFutexApiTest.ninja
│     │   │   ├── io_posix
│     │   │   │   └── module_ActsIoApiTest.ninja
│     │   │   ├── ipc_posix
│     │   │   │   ├── message_queue
│     │   │   │   │   └── module_ActsIpcMqTest.ninja
│     │   │   │   ├── pipe_fifo
│     │   │   │   │   └── module_ActsIpcPipeTest.ninja
│     │   │   │   ├── semaphore
│     │   │   │   │   └── module_ActsIpcSemTest.ninja
│     │   │   │   ├── shared_memory
│     │   │   │   │   └── module_ActsIpcShmTest.ninja
│     │   │   │   └── signal
│     │   │   │     └── module_ActsIpcSignalTest.ninja
│     │   │   ├── math_posix
│     │   │   │   ├── complexTest.ninja
│     │   │   │   └── module_ActsMathApiTest.ninja
│     │   │   ├── mem_posix
│     │   │   │   └── module_ActsMemApiTest.ninja
│     │   │   ├── net_posix
│     │   │   │   └── module_ActsNetTest.ninja
│     │   │   ├── process_posix
│     │   │   │   └── module_ActsProcessApiTest.ninja
│     │   │   ├── sched_posix
│     │   │   │   └── module_ActsSchedApiTest.ninja
│     │   │   ├── sys_posix
│     │   │   │   └── module_ActsSysApiTest.ninja
│     │   │   ├── time_posix
│     │   │   │   └── module_ActsTimeApiTest.ninja
│     │   │   ├── util_posix
│     │   │   │   └── module_ActsUtilApiTest.ninja
│     │   │   └── utils
│     │   │     ├── libfs.ninja
│     │   │     ├── libmt_utils.ninja
│     │   │     └── libutils.ninja
│     │   ├── multimedia_lite
│     │   │   └── media_lite_posix
│     │   │     └── recorder_native
│     │   │       └── module_ActsMediaRecorderTest.ninja
│     │   ├── security_lite
│     │   │   ├── datahuks_posix
│     │   │   │   └── module_ActsSecurityDataTest.ninja
│     │   │   └── permission_posix
│     │   │     ├── capability
│     │   │     │   ├── capability_shared.ninja
│     │   │     │   ├── jffs
│     │   │     │   │   └── module_ActsJFFS2CapabilityTest.ninja
│     │   │     │   └── vfat
│     │   │     │     └── module_ActsVFATCapabilityTest.ninja
│     │   │     ├── dac
│     │   │     │   ├── jffs
│     │   │     │   │   └── module_ActsJFFS2DACTest.ninja
│     │   │     │   └── vfat
│     │   │     │     └── module_ActsVFATDACTest.ninja
│     │   │     └── pms
│     │   │       └── module_ActsPMSTest.ninja
│     │   ├── startup_lite
│     │   │   ├── bootstrap_posix
│     │   │   │   └── module_ActsBootstrapTest.ninja
│     │   │   └── syspara_posix
│     │   │     └── module_ActsParameterTest.ninja
│     │   └── utils_lite
│     │     └── kv_store_posix
│     │       └── module_ActsKvStoreTest.ninja
│     └── tools
│       └── lite
│         ├── hcpptest
│         │   ├── gmock_main.ninja
│         │   ├── gmock.ninja
│         │   ├── hcpptest_main.ninja
│         │   └── hcpptest.ninja
│         └── others
│           └── query
│             └── query.ninja
├── third_party
│   ├── bounds_checking_function
│   │   ├── libsec_shared.ninja
│   │   └── libsec_static.ninja
│   ├── freetype
│   │   └── freetype.ninja
│   ├── giflib
│   │   └── libgif.ninja
│   ├── iniparser
│   │   └── iniparser.ninja
│   ├── libjpeg
│   │   └── libjpeg.ninja
│   ├── libpng
│   │   └── libpng.ninja
│   ├── mbedtls
│   │   ├── mbedtls_gt.ninja
│   │   ├── mbedtls_shared.ninja
│   │   └── mbedtls_static.ninja
│   └── qrcodegen
│     └── qrcodegen.ninja
├── utils
│   └── native
│     └── lite
│       ├── kv_store
│       │   └── src
│       │     └── utils_kv_store.ninja
│       └── os_dump
│         └── os_dump.ninja
└── vendor
  └── hisilicon
    └── hispark_aries
      └── hals
        ├── security
        │   └── permission_lite
        │     └── hal_pms.ninja
        └── utils
          ├── sys_param
          │   └── hal_sysparam.ninja
          └── token
            └── haltoken_shared.ninja
百篇博客.往期回顾
在加注过程中,整理出以下文章。内容立足源码,常以生活场景打比方尽可能多的将内核知识点置入某种场景,具有画面感,容易理解记忆。说别人能听得懂的话很重要! 百篇博客绝不是百度教条式的在说一堆诘屈聱牙的概念,那没什么意思。更希望让内核变得栩栩如生,倍感亲切.确实有难度,自不量力,但已经出发,回头已是不可能的了。:P
与代码有bug需不断debug一样,文章和注解内容会存在不少错漏之处,请多包涵,但会反复修正,持续更新,.xx代表修改的次数,精雕细琢,言简意赅,力求打造精品内容。
      
  • v60.xx 鸿蒙内核源码分析(GN应用篇) | GN语法及在鸿蒙的使用  | 51 .c .h .o
      
  • v59.xx 鸿蒙内核源码分析(构建工具篇) | 顺瓜摸藤调试鸿蒙构建过程  | 51 .c .h .o
      
  • v58.xx 鸿蒙内核源码分析(环境脚本篇) | 有了它编译鸿蒙好简单  | 51 .c .h .o
      
  • v57.xx 鸿蒙内核源码分析(编译过程篇) | 简单案例窥视GCC编译全过程  | 51 .c .h .o
      
  • v56.xx 鸿蒙内核源码分析(进程映像篇) | ELF是如何被加载运行的?  | 51 .c .h .o
      
  • v55.xx 鸿蒙内核源码分析(重定位篇) | 与国际接轨的对外部发言人  | 51 .c .h .o
      
  • v54.xx 鸿蒙内核源码分析(静态链接篇) | 完整小项目看透静态链接过程  | 51 .c .h .o
      
  • v53.xx 鸿蒙内核源码分析(ELF解析篇) | 你要忘了她姐俩你就不是银  | 51 .c .h .o
      
  • v52.xx 鸿蒙内核源码分析(静态站点篇) | 五一哪也没去就干了这事  | 51 .c .h .o
      
  • v51.xx 鸿蒙内核源码分析(ELF格式篇) | 应用程序入口并不是main  | 51 .c .h .o
      
  • v50.xx 鸿蒙内核源码分析(编译环境篇) | docker编译鸿蒙真的很香  | 51 .c .h  .o
      
  • v49.xx 鸿蒙内核源码分析(信号消费篇) | 谁让CPU连续四次换栈运行  | 51 .c .h  .o
      
  • v48.xx 鸿蒙内核源码分析(信号生产篇) | 年过半百,依然活力十足  | 51 .c .h  .o
      
  • v47.xx 鸿蒙内核源码分析(进程回收篇) | 临终前如何向老祖宗托孤  | 51 .c .h  .o
      
  • v46.xx 鸿蒙内核源码分析(特殊进程篇) | 龙生龙凤生凤老鼠生儿会打洞  | 51 .c .h  .o
      
  • v45.xx 鸿蒙内核源码分析(Fork篇) | 一次调用,两次返回  | 51 .c .h  .o
      
  • v44.xx 鸿蒙内核源码分析(中断管理篇) | 江湖从此不再怕中断  | 51 .c .h  .o
      
  • v43.xx 鸿蒙内核源码分析(中断概念篇) | 海公公的日常工作  | 51 .c .h  .o
      
  • v42.xx 鸿蒙内核源码分析(中断切换篇) | 系统因中断活力四射 | 51 .c .h  .o
      
  • v41.xx 鸿蒙内核源码分析(任务切换篇) | 看汇编如何切换任务  | 51 .c .h  .o
      
  • v40.xx 鸿蒙内核源码分析(汇编汇总篇) | 汇编可爱如邻家女孩  | 51 .c .h  .o
      
  • v39.xx 鸿蒙内核源码分析(异常接管篇) | 社会很单纯,复杂的是人  | 51 .c .h  .o
      
  • v38.xx 鸿蒙内核源码分析(寄存器篇) | 小强乃宇宙最忙存储器  | 51 .c .h  .o
      
  • v37.xx 鸿蒙内核源码分析(系统调用篇) | 开发者永远的口头禅  | 51 .c .h  .o
      
  • v36.xx 鸿蒙内核源码分析(工作模式篇) | CPU是韦小宝,七个老婆  | 51 .c .h  .o
      
  • v35.xx 鸿蒙内核源码分析(时间管理篇) | 谁是内核基本时间单位  | 51 .c .h  .o
      
  • v34.xx 鸿蒙内核源码分析(原子操作篇) | 谁在为原子操作保驾护航  | 51 .c .h  .o
      
  • v33.xx 鸿蒙内核源码分析(消息队列篇) | 进程间如何异步传递大数据  | 51 .c .h  .o
      
  • v32.xx 鸿蒙内核源码分析(CPU篇) | 整个内核就是一个死循环  | 51 .c .h  .o
      
  • v31.xx 鸿蒙内核源码分析(定时器篇) | 哪个任务的优先级最高  | 51 .c .h  .o
      
  • v30.xx 鸿蒙内核源码分析(事件控制篇) | 任务间多对多的同步方案  | 51 .c .h  .o
      
  • v29.xx 鸿蒙内核源码分析(信号量篇) | 谁在负责解决任务的同步  | 51 .c .h  .o
      
  • v28.xx 鸿蒙内核源码分析(进程通讯篇) | 九种进程间通讯方式速揽  | 51 .c .h  .o
      
  • v27.xx 鸿蒙内核源码分析(互斥锁篇) | 比自旋锁丰满的互斥锁  | 51 .c .h  .o
      
  • v26.xx 鸿蒙内核源码分析(自旋锁篇) | 自旋锁当立贞节牌坊  | 51 .c .h  .o
      
  • v25.xx 鸿蒙内核源码分析(并发并行篇) | 听过无数遍的两个概念  | 51 .c .h  .o
      
  • v24.xx 鸿蒙内核源码分析(进程概念篇) | 进程在管理哪些资源  | 51 .c .h  .o
      
  • v23.xx 鸿蒙内核源码分析(汇编传参篇) | 如何传递复杂的参数  | 51 .c .h  .o
      
  • v22.xx 鸿蒙内核源码分析(汇编基础篇) | CPU在哪里打卡上班  | 51 .c .h  .o
      
  • v21.xx 鸿蒙内核源码分析(线程概念篇) | 是谁在不断的折腾CPU  | 51 .c .h  .o
      
  • v20.xx 鸿蒙内核源码分析(用栈方式篇) | 程序运行场地由谁提供  | 51 .c .h  .o
      
  • v19.xx 鸿蒙内核源码分析(位图管理篇) | 谁能一分钱分两半花  | 51 .c .h  .o
      
  • v18.xx 鸿蒙内核源码分析(源码结构篇) | 内核每个文件的含义  | 51 .c .h  .o
      
  • v17.xx 鸿蒙内核源码分析(物理内存篇) | 怎么管理物理内存  | 51 .c .h  .o
      
  • v16.xx 鸿蒙内核源码分析(内存规则篇) | 内存管理到底在管什么  | 51 .c .h  .o
      
  • v15.xx 鸿蒙内核源码分析(内存映射篇) | 虚拟内存虚在哪里  | 51 .c .h  .o
      
  • v14.xx 鸿蒙内核源码分析(内存汇编篇) | 谁是虚拟内存实现的基础  | 51 .c .h  .o
      
  • v13.xx 鸿蒙内核源码分析(源码注释篇) | 鸿蒙必定成功,也必然成功  | 51 .c .h  .o
      
  • v12.xx 鸿蒙内核源码分析(内存管理篇) | 虚拟内存全景图是怎样的  | 51 .c .h  .o
      
  • v11.xx 鸿蒙内核源码分析(内存分配篇) | 内存有哪些分配方式  | 51 .c .h  .o
      
  • v10.xx 鸿蒙内核源码分析(内存主奴篇) | 皇上和奴才如何相处  | 51 .c .h  .o
      
  • v09.xx 鸿蒙内核源码分析(调度故事篇) | 用故事说内核调度过程  | 51 .c .h  .o
      
  • v08.xx 鸿蒙内核源码分析(总目录) | 百万汉字注解 百篇博客分析  | 51 .c .h  .o
      
  • v07.xx 鸿蒙内核源码分析(调度机制篇) | 任务是如何被调度执行的  | 51 .c .h  .o
      
  • v06.xx 鸿蒙内核源码分析(调度队列篇) | 内核有多少个调度队列  | 51 .c .h  .o
      
  • v05.xx 鸿蒙内核源码分析(任务管理篇) | 任务池是如何管理的  | 51 .c .h  .o
      
  • v04.xx 鸿蒙内核源码分析(任务调度篇) | 任务是内核调度的单元  | 51 .c .h  .o
      
  • v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度谁的贡献最大  | 51 .c .h  .o
      
  • v02.xx 鸿蒙内核源码分析(进程管理篇) | 谁在管理内核资源  | 51 .c .h  .o
      
  • v01.xx 鸿蒙内核源码分析(双向链表篇) | 谁是内核最重要结构体  | 51 .c .h  .o

关于 51 .c .h .o
看系列篇文章会常看到 51 .c .h .o,希望这对大家阅读不会造成影响. 分别对应以下四个站点的首个字符,感谢这些站点一直以来对系列篇的支持和推荐,尤其是 oschina gitee ,很喜欢它的界面风格,简洁大方,让人感觉到开源的伟大!
      
  • 51cto  
  • csdn  
  • harmony  
  • oschina
而巧合的是.c .h .o是C语言的头/源/目标文件,这就很有意思了,冥冥之中似有天数,将这四个宝贝以这种方式融合在一起. 51 .c .h .o , 我要CHO ,嗯嗯,hin 顺口 : )
百万汉字注解.百篇博客分析
百万汉字注解 >> 精读鸿蒙源码,中文注解分析, 深挖地基工程,大脑永久记忆,四大码仓每日同步更新< gitee | github | csdn | coding >
百篇博客分析 >> 故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,主流站点定期更新中< 51cto | csdn | harmony  | osc >
关注不迷路.代码即人生
DSC0001.png

热爱是所有的理由和答案 - turing
原创不易,欢迎转载,但麻烦请注明出处.

关注下面的标签,发现更多相似文章