• 生成目标文件:
  • 目标文件包含了机器指令代码、数据、链接时需要的信息、符号表、调试信息、字符串表。
  • 我们需要记录一些clang指令:

1、不指定target时、默认是 Mach-O 64-bit object x86_64:

$ clang -x c -g -c main.c -o main.o
-x: 指定编译文件语言类型
-g: 生成调试信息
-c: 生成目标文件,只运行preprocess,compile,assemble,不链接
-o: 输出文件
-isysroot: 使用的SDK路径
-I<directory>:在指定目录寻找头文件  						Header Search Path
-L<library_name>:指定链接的库文件名称(.a/.dylib库文件)	Library Search Path
-l<library_name>: 指定链接的库文件名称(.a/ .dylib库文件)	Other Link Flags -lAFNetworking
-F<directory>: 在指定目录寻找framework					Framework Search Path
-framework <framework_name> :指定链接的framework名称		Other Link Flags -framework AFNetworking
生成相应的LLVM文件格式,来进行链接时间优化。
当我们配合着 -S使用时,生成汇编语言文件。否则生成bitcode格式的目标文件。
-flto=<value> 设置LTO模式: full or thin
-flto=full : 默认值,单片(monolithic)LTO通过将所有输入合并到单个模块中来实现此目的。
-flto=thin :使用thin LTO代替
-emit-llvm : 
-install-name : 指定动态库初次安装时的默认路径,向'LC_ID_DYLIB'添加安装路径,该路径为dyld定位该库。
  • clang -o 是将main.c源文件编译成为一个可执行的二进制代码(-o选项其实是指定输出文件文件名,如果不加 -c 选项,clang 默认会编译链接生成可执行文件,文件的名称由 -o选项指定)。
  • clang -c是使用LLVM汇编器将源文件转化为目标代码。

2、指定生成 Mach-O 64-bit x86_64目标文件格式

clang -x c -target x86_64-apple-macos11.1 -g -c main.c -o main.o

3、如果指定target不带 apple系统版本(包括 macOS,ipadOS,iOS,真机和模拟器)。例如 x86_64,那么生成的目标文件是 Linux的 ELF 64-bit

clang -x c -target x86_64 -g -c main.c -o main.o

4、编译.m (不包含其他头文件的文件)

clang -x objective-c -target x86_64-apple-macos11.1 -fobjc-arc -fmodules \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk -c main.m -o main.o
  • 在模拟器上编译:
clang -x objective-c -target x86_64-apple-ios14.3-simulator -fobjc-arc -fmodules \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator14.3.sdk -c main.m -o main.o

5、编译 .mm

  • 在mac上编译:
clang -x objective-c++ -target x86_64-apple-macos11.1 -std=c++11 -stdlib=libc++ -fobjc-arc -fmodules \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk -c main.m
  • 在模拟器上编译:
echo "----将 main.m 链接AFNetworking 编译为 main.o"
clang -target x86_64-apple-ios14.3-simulator \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk \
-I./AFNetworking \
-c main.m -o main.o
echo "----将 main.o 链接AFNetworking 编译为 main 可执行文件"
clang -target x86_64-apple-ios14.3-simulator \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk \
-L./AFNetworking \
-lAFNetworking \
main.o -o main

6、生成dSYM文件:

clang -x c -g1 main.c -o main.o
//-g1: 将调试信息写入'DWARF'格式文件
  • 查看调试信息:
dwarfdump a.o
dwarfdump a.dSYM
dwarfdump --lookup 0x100000f20 --arch=x86_64 a.dSYM
//--lookup 查看地址的调试信息。将显示出所在的目录,文件,函数等信息
  • 查看文件内容
  • otool用来查看Mach-O文件内部结构:
otool -l library.dylib
otool -h libTest.a
//-l: 显示解析后的mach header 和 load command
//-h: 显示未解析的mach header
//-L:打印所有链接的动态库路径
//-D:打印当前动态库的'install_name'
  • objdump用来查看文件内部结构,包括ELFMach-O
objdump --macho -h a.o
objdump --macho -x a.o
objdump --macho -s -d a.o
objdump --macho --syms a.o
/*
--macho : 指定Mach-O类型
-h: 打印各个段的基本信息
-x: 打印各个段更详细的信息
-d: 将所有包含指定的段反编译
-s: 将所有段的内容以16进制的方式打印出来。
--lazy-bind:打印 lazy binding info
--syms 打印符号表
*/
  • 静态库的压缩和解压缩
  • ar 压缩目标文件,并对其进行编号和索引,形成静态库。同时也可以解压缩静态库,查看有哪些目标文件
ar -rc a.a a.o
-r: 添加or替换文件
-c: 不输出任何信息
-t: 列出包含的目标文件
  • 创建静态库
  • 创建库命令: libtool 也可以创建静态库和动态库。
libtool -static -arch_only x86_64 a.o -o a.a
libtool -static -arch_only arm64 -D -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.3.sdk main.o -o libMain.a
  • 创建动态库
clang -dynamiclib -target arm64-apple-ios14.3 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.3.sdk a.o -o a.dylib
  • nm查看符号表
nm -pa a.o
-a: 显示符号表的所有内容
-g: 显示全局符号
-p: 不排序。显示符号表本来的顺序
-r: 逆转顺序
-u: 显示未定义符号
  • 生成dSYM文件
  • dsymutil可以被理解为是调试信息链接器。它按照下面的步骤执行:
  • 读取debug map
  • 从 .o文件中加载DWARF
  • 重新定位所有地址
  • 最后将全部的DWARF打包成 dSYM Bundle
  • 有了dSYM后,我们就拥有了最标准的DWARF的文件。任何可以dwarf读取工具(可以处理Mach-O二进制文件)都可以处理该标准DWARF。
  • dsymutil操作DWARF格式的 debug symbol。可以将可执行文件debug symbol生成DWARF格式的文件:
dsymutil -f a -o a.dSYM
//-f: .dwarf格式文件
//-o <filename>: 输出.dSYM格式文件
  • 移除符号
  • strip用来移除和修改符号表:
strip -S a.o
//-S 删除调试符号
//-X 移除本地符号,'L'开头的
//-x 移除全部的本地符号,只保留全局符号
  • 链接器 ld
-all_load 加载静态库包含的所有文件
-ObjC 加载静态库包含的所有的Objective-C类和Category
-force_load <path_to_archive> 加载静态库中指定的文件
  • 链接动态库和静态库
ld -dylib -arch x86_64 -macosx_version_min 10.13 a.dylib -o a 
ld -static -arch x86_64 -e _main a.a -o a
  • Xcode打印加载的库
Pre-main Time 指 main 函数执行之前的加载时间,包括 dylib 动态库加载,Mach-O 文件加载, Rebase/Binding ҅Objective-C Runtime 加载等。
Xcode 自身提供了一个在控制台打印这些时间的方法: 在Xcode中 Edit Scheme --> Run --> Arguments 添加环境变量 DYLD_PRINT_STATISTICS 并把值设为 1
DYLD_PRINT_LIBRARIES: 打印出所有被加载的库。
DYLD_PRINT_LIBRARIES_POST_LAUNCH:打印的是通过dlopen调用返回的库,包括动态库的依赖库,主要发生在main函数运行之后。