logo头像

小玉的技术博客

Clang常用命令介绍

前言

iOS 开发中 Objective-C 是 Clang / LLVM 来编译的。学习Clang有助于我们对Objective-C编译过程的理解

Clang常用命令介绍

clang -ccc-print-phases main.m

功能:查看编译的步骤
输出结果:

1
2
3
4
5
6
7
0: input, "main.m", objective-c
1: preprocessor, {0}, objective-c-cpp-output
2: compiler, {1}, ir
3: backend, {2}, assembler
4: assembler, {3}, object
5: linker, {4}, image
6: bind-arch, "x86_64", {5}, image

clang -rewrite-objc main.m

功能:查看编译结果
输出结果:main.cpp文件

clang -### main.m -o main

功能:查看操作内部命令
输出结果

1
2
3
4
5
6
Apple LLVM version 10.0.1 (clang-1001.0.46.3)
Target: x86_64-apple-darwin18.2.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
"/Library/Developer/CommandLineTools/usr/bin/clang" "-cc1" "-triple" "x86_64-apple-macosx10.14.0" "-Wdeprecated-objc-isa-usage" "-Werror=deprecated-objc-isa-usage" "-emit-obj" "-mrelax-all" "-disable-free" "-disable-llvm-verifier" "-discard-value-names" "-main-file-name" "main.m" "-mrelocation-model" "pic" "-pic-level" "2" "-mthread-model" "posix" "-mdisable-fp-elim" "-fno-strict-return" "-masm-verbose" "-munwind-tables" "-target-sdk-version=10.14" "-target-cpu" "penryn" "-dwarf-column-info" "-debugger-tuning=lldb" "-target-linker-version" "450.3" "-resource-dir" "/Library/Developer/CommandLineTools/usr/lib/clang/10.0.1" "-isysroot" "/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk" "-I/usr/local/include" "-Wno-atomic-implicit-seq-cst" "-Wno-framework-include-private-from-public" "-Wno-atimport-in-framework-header" "-Wno-quoted-include-in-framework-header" "-fdebug-compilation-dir" "/Users/ZLY/Desktop" "-ferror-limit" "19" "-fmessage-length" "238" "-stack-protector" "1" "-fblocks" "-fencode-extended-block-signature" "-fregister-global-dtors-with-atexit" "-fobjc-runtime=macosx-10.14.0" "-fobjc-exceptions" "-fexceptions" "-fmax-type-align=16" "-fdiagnostics-show-option" "-fcolor-diagnostics" "-o" "/var/folders/kj/svm6s3rn6kdcvmbhds_grhvm0000gp/T/main-1301a5.o" "-x" "objective-c" "main.m"
"/Library/Developer/CommandLineTools/usr/bin/ld" "-demangle" "-lto_library" "/Library/Developer/CommandLineTools/usr/lib/libLTO.dylib" "-no_deduplicate" "-dynamic" "-arch" "x86_64" "-macosx_version_min" "10.14.0" "-syslibroot" "/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk" "-o" "main" "/var/folders/kj/svm6s3rn6kdcvmbhds_grhvm0000gp/T/main-1301a5.o" "-L/usr/local/lib" "-lSystem" "/Library/Developer/CommandLineTools/usr/lib/clang/10.0.1/lib/darwin/libclang_rt.osx.a"

clang基本语法介绍

命令 功能
-fmodules 允许modules的语言特性
-fsyntax-only 防止编译器生成代码,只是语法级别的说明和修改
-Xclang 向clang编译器传递参数
-dump-tokens 运行预处理器,拆分内部代码段为各种token
-ast-dump 构建抽象语法树AST,然后对其进行拆解和调试
-S 只运行预处理和编译步骤
-fobjc-arc 为OC对象生成retain和release的调用
-emit-llvm 使用LLVM描述汇编和对象文件
-o 输出到目标文件
-c 只运行预处理,编译和汇编步骤

代码编译的执行步骤拆解

下面我们对iOS代码编译的步骤进行一个简单的拆解,看看内部是如何实现的.
预处理完成后就会进行词法分析,这里会把代码切成一个个 Token,比如大小括号,等于号还有字符串等。

1
clang -fmodules -fsyntax-only -Xclang -dump-tokens main.m

然后是语法分析,验证语法是否正确,然后将所有节点组成抽象语法树 AST 。

1
clang -fmodules -fsyntax-only -Xclang -ast-dump main.m

完成这些步骤后就可以开始IR中间代码的生成了,CodeGen 会负责将语法树自顶向下遍历逐步翻译成 LLVM IR,IR 是编译过程的前端的输出后端的输入。

1
clang -S -fobjc-arc -emit-llvm main.m -o main.ll

这里 LLVM 会去做些优化工作,在 Xcode 的编译设置里也可以设置优化级别-01,-03,-0s,还可以写些自己的 Pass,官方有比较完整的 Pass 教程: Writing an LLVM Pass — LLVM 5 documentation

1
clang -O3 -S -fobjc-arc -emit-llvm main.m -o main.ll

Pass 是 LLVM 优化工作的一个节点,一个节点做些事,一起加起来就构成了 LLVM 完整的优化和转化。
如果开启了 bitcode 苹果会做进一步的优化,有新的后端架构还是可以用这份优化过的 bitcode 去生成。

1
clang -emit-llvm -c main.m -o main.bc

生成汇编

1
clang -S -fobjc-arc main.m -o main.s

生成目标文件

1
clang -fmodules -c main.m -o main.o

生成可执行文件,这样就能够执行看到输出结果

1
2
3
4
5
clang main.o -o main
执行
./main
输出
starming rank 14

下面是完整步骤:

  1. 编译信息写入辅助文件,创建文件架构 .app 文件
  2. 处理文件打包信息
  3. 执行 CocoaPod 编译前脚本,checkPods Manifest.lock
  4. 编译.m文件,使用 CompileC 和 clang 命令
  5. 链接需要的 Framework
  6. 编译 xib
  7. 拷贝 xib ,资源文件
  8. 编译 ImageAssets
  9. 处理 info.plist
  10. 执行 CocoaPod 脚本
  11. 拷贝标准库
  12. 创建 .app 文件和签名
支付宝打赏 微信打赏

赞赏是不耍流氓的鼓励