前言
最近在研究micropython的源码编译过程,简单记录下关于qstr部分内容,本篇文章基于micropython1.18版本源码,1.19版本及之后可能会略有差异。
标识符与相应对象的联系
Micropython中有很多标识符,例如lcd.py中出现的标识符有:import、lcd、init、print、“hello”。这些标识符最终都需要与某个对象或操作联系起来。那么这种联系是如何建立的呢?那就是通过QSTR。
// This file was automatically generated by makeqstrdata.py QDEF0(MP_QSTRnull, (const byte*)"\x00\x00\x00" "") QDEF0(MP_QSTR_, (const byte*)"\x05\x15\x00" "") QDEF0(MP_QSTR___dir__, (const byte*)"\x7a\x8f\x07" "__dir__") ...
其中是一系列的宏定义,格式为:
QDEF(MP_QSTR_xxx, (const byte*)"哈希值(2字节)长度(1字节)" "对应的字符串"
这个文件是由makeqstrdata.py生成的,该文件位于py/makeqstrdata.py,py目录下有几个python脚本用于代码预处理c代码,包括生成qstr池,注册c模组。
QSTR生成流程
- 首先通过
py/makeqstrdefs.py查找C源码中的MP_QSTR_XXX关键字,然后提取到ports/unix/build-standard/genhdr/qstr目录下建立新文件,增加条目Q(XXX)。 - 然后将qstr目录下若干文件整合成一个文件
ports/unix/build-standard/genhdr/qstrdefs.collected.h。 - py/makeqstrdata.py将根据
ports/unix/build-standard/genhdr/qstrdefs.collected.h生成QSTR池文件unix/build-standard/genhdr/qstrdefs.generated.h
QSTR的hash生成设置
C源码中计算qstr hash的位置位于qstr.c中
// this must match the equivalent function in makeqstrdata.py mp_uint_t qstr_compute_hash(const byte *data, size_t len) {
// djb2 algorithm; see http://www.cse.yorku.ca/~oz/hash.html mp_uint_t hash = 5381; for (const byte *top = data + len; data < top; data++) {
hash = ((hash << 5) + hash) ^ (*data); // hash * 33 ^ data } hash &= Q_HASH_MASK; // Make sure that valid hash is never zero, zero means "hash not computed" if (hash == 0) {
hash++; } return hash; }
hash长度设置
在qstr.c中能看到MICROPY_QSTR_BYTES_IN_HASH宏判断,该值可赋1或2,但如果不设置则通过其他方式确定,在py/mpconfig.h文件中通过设置MICROPY_CONFIG_ROM_LEVEL来控制hash 长度是1 还是2,参见
// Number of bytes used to store qstr hash #ifndef MICROPY_QSTR_BYTES_IN_HASH #if MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES #define MICROPY_QSTR_BYTES_IN_HASH (2) #else #define MICROPY_QSTR_BYTES_IN_HASH (1) #endif #endif
当MICROPY_QSTR_BYTES_IN_HASH未被定义时参考MICROPY_CONFIG_ROM_LEVEL的设置,micropython给目标机划分了6个级别,用于适应不同硬件资源的编译。
// Disable all optional features (i.e. minimal port). #define MICROPY_CONFIG_ROM_LEVEL_MINIMUM (0) // Only enable core features (constrained flash, e.g. STM32L072) #define MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES (10) // Enable most common features (small on-device flash, e.g. STM32F411) #define MICROPY_CONFIG_ROM_LEVEL_BASIC_FEATURES (20) // Enable convenience features (medium on-device flash, e.g. STM32F405) #define MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES (30) // Enable all common features (large/external flash, rp2, unix) #define MICROPY_CONFIG_ROM_LEVEL_FULL_FEATURES (40) // Enable everything (e.g. coverage) #define MICROPY_CONFIG_ROM_LEVEL_EVERYTHING (50) // Ports/boards should set this, but default to level=core. #ifndef MICROPY_CONFIG_ROM_LEVEL #define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES) #endif // Helper macros for "have at least this level". #define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES) #define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_BASIC_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_BASIC_FEATURES) #define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES) #define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_FULL_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_FULL_FEATURES) #define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EVERYTHING (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_EVERYTHING)
由此可以得知,MICROPY_CONFIG_ROM_LEVEL决定的hash长度,在6个级别中除了MINIMUM长度为1外其他都为2。
对象字符串长度字段的字节长度
前面我们分析过qstr宏定义的组成
QDEF(MP_QSTR_xxx, (const byte*)"哈希值(2字节)长度(1字节)" "对应的字符串"
// Number of bytes used to store qstr length // Dictates hard limit on maximum Python identifier length, but 1 byte // (limit of 255 bytes in an identifier) should be enough for everyone #ifndef MICROPY_QSTR_BYTES_IN_LEN #define MICROPY_QSTR_BYTES_IN_LEN (1) #endif
这样我们可以在mpconfigport.h中添加MICROPY_QSTR_BYTES_IN_LEN宏的设置就可以更改字节位长度。不过一般来说不会有超过256长度函数名,所以一般不用设置该项,只需留意有这个配置就行。
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/200117.html原文链接:https://javaforall.net
