iOS工程07hmap及vfs探索

423 阅读1分钟

一、hmap

工程产物headermap等于 hmap

配置 header.json (学习工程化,确实很枯燥,但是坚持就是胜利!!!)

{

    "Dog.h": [
            "/user/module/include/",
            "Dog.h"
        ]
}

//根据命令编译,生成 .hmap
hmapfile writer --json-path=./header.json

image.png

1、OC&Swift

我们用Realmswift框架了分析: image.png 为什么已经用module * {export *} 还要声明 Private 呢?

因为特定的头文件并没有放入umbrella散头文件里。

image.png xcode中配置MODULEMAP_PRIVATE_FILE 文件路径跟module 文件配置私有库目录是一样的。

SwiftLibrary 的二进制库

swift.a 库的生成:先看下编译产物: image.png SwiftLibrary.swiftmodule 就是提供swift.a库的信息。

  1. Product 文件夹存储刚刚生成的3个产物
  2. 然后创建SwiftLibrary.modulemap文件
  3. 在通过命令生成对应

SwiftLibrary.modulemap:

module SwiftLibrary {
}

// -Swift.h系统自动生成 framework(子带module)

module SwiftLibrary.Swift {
    header "SwiftLibrary-Swift.h"
    //编译的语
    requires objc
}

然后在项目中配置对SwiftLibrary.modulemap 的使用。

OTHER_CFLAGS = -fmodules -fmodule-map-file="${SRCROOT}/../Product/SwiftLibrary.modulemap"  
// SwiftC --> SwiftLibrary-Swift.h 头文件 (module) 
SWIFT_INCLUDE_PATHS = "${SRCROOT}/../Product"
OTHER_SWIFT_FLAGS = -Xclang -fmodule-map-file="${SRCROOT}/zoo.modulemap"

编译通过! image.png SwiftLibrary.a库在当前的cocoapods可以使用module header 来配置二进制库.a 需要配置modulemap文件

2、hmap

传统的目录搜索,依赖目录。如果当前.h和.m不在同一个目录的话,第二次循环才能找到相关的头文件

  • hmap[key]-> 对应完整的头文件路径-module定义
  • hmap改变头文件的引入方式 (完整路径/module)
  • hmap也是二进制文件 (exec格式:mach-o ELF) header+二进制存储key和value
  • process-->exec 依赖了什么第三方库,代码存在什么地方,需要配置文件
  • 这个配置文件就是macho header

通过 file 命令查看DumpHeaderMap exec格式文件信息: image.png

//查看objdump 命令
man objdump

objdump --macho --private-header   /xxxx/你的exec文件

image.png

image.png --private-headers 加s打印更加详细的信息 image.png

struct HMapHeader {
  uint32_t Magic;          // Magic word, also indicatession;
  uint16_t Version;        // Version number -- currently 1.
  uint16_t Reserved;       // Reserved for future use - zero for now.
  uint32_t StringsOffset;  // Offset to start of string pool.
  uint32_t NumEntries;     // Number of entries in the string table.
  uint32_t NumBuckets;     // Number of buckets (always a power of 2).
  uint32_t MaxValueLength; // Length of longest result path (excluding nul).
  // An array of 'NumBuckets' HMapBucket objects follows this header.
  // Strings follow the buckets, at StringsOffset.
};
// hmap = header + [NumBuckets buckets] + [StringsOffset]string table hmap位置
// bucket --> 具体的key Prefix suffix。在string table什么位置

struct HMapBucket {
   uint32_t Key;    // Offset (into strings) of key.
   uint32_t Prefix; // Offset (into strings) of value prefix.
   uint32_t Suffix; // Offset (into strings) of value suffix.
};

所以hmap 等于header加一堆buckets在加上StringsOffset table hmap位置(偏移量) ,主要用到StringsOffsetNumEntriesNumBuckets 三个参数。

小结:

  1. hmap 优化的点,会进行模块映射需要自己编写modulemap文件
  2. hmap xcode 生成耗时是可以加快的(cocoapods-hmap)

二、vfs

vfs是虚拟文件系统,作用于framework(APP)。编译.m文件会先去当前所在的目录找.h文件。但是xcode编译生成产物的时候会生成一个Headers的文件来存放public级别的.h文件。如果是私有就会生成PrivateHeaders文件夹存放私有.h文件。

如果设置完:#import "/app包目录//PrivateHeaders/xx.h" 后在配置:

HEADER_SEARCH_PATHS = "/Users/ws/Library/Developer/Xcode/DerivedData/LGApp-dflcoivumjxanrbflpqkkzqfbmpz/Build/Products/Debug-iphonesimulator/LGApp.app/PrivateHeaders"

编译生成查看产物:发现all-product-headers.yaml是一个json文件, image.png

{
    "case-sensitive": "false",
    "roots": [
        {
            "contents": [
                {
                    "external-contents": "LGApp/Zoo/LGCat.h",
                    "name": "LGCat.h",
                    "type": "file"
                }
            ],
            "name": "/Debug-iphoneos/LGApp.app/Headers",
            "type": "directory"
        },
        {
            "contents": [
                {
                    "external-contents": "/LGApp/Zoo/LGDog.h",
                    "name": "LGDog.h",
                    "type": "file"
                }
            ],
            "name": "/LGApp.app/PrivateHeaders",
            "type": "directory"
        }
    ],
    "version": 0
}

把包里面的文件和源码里的文件进行一一映射。

vfs相关命令:

`vfs yamlwriter` lets you create clang opt "-ivfsoverlay" ymal file, map virtual path to real path.

# write the VFS YAML file to --output-path=<path>
$ vfs yamlwriter --framework-path=<path> --real-headers-dir=<path> --real-modules-dir=<path> --output-path=<path>

# write the VFS YAML file to .
$ vfs yamlwriter --framework-path=<path> --real-headers-dir=<path> --real-modules-dir=<path>