前言
Hi Coder,我是 CoderStar!
在新的一年里,祝小伙伴们工作顺利,升职加薪。
在咱们日常开发中,或多或少都会用到 Xcode 内置的一些 CLI
工具,但是大部分小伙伴可能只是会用到一些具体的命令,今天我们就一起来聊一聊 Xcode 内置的常见 Command Line Tool
。
介绍的可能不全,大家可以去文中出现的路径下查看更多的工具。
Command Line Tool
本质是一个命令行工具包,内部有很多有用的工具,如 Apple LLVM compiler
、Make
等等。并且并不是只有开发 Apple 应用程序才需要用到这些工具包,当我们下载 Homebrew
时,在安装过程中也会下载 Command Line Tool
。
下文会对
Command Line Tool
直接缩写成 CLI,XXX 一般情况是指对应路径地址。
我们在开发者官网 Command Line Tool 对其单独下载,当然每个版本的 Xcode 安装包内也会包含这套工具包。
其实下列有一部分工具属于 LLVM 序列,比如 dwarfdump
、ar
,启动本质其实为 llvm-dwarfdump
、llvm-ar
,都属于 LLVM
工具链中的一部分。
前置工具
在我来介绍这套工具包其他工具之前,我先来介绍两个工具,我称它们为前置工具,因为有了这两个工具,我们才能更好的使用其他的工具。
xcode-select
这个工具可以帮助我们下载及安装 CLI,比手动下载更便捷。并且还能解决另外问题,就是如果我们装有多个 Xcode,我们在使用 CLI 相关工具时,系统就会不知道该去使用哪个版本或者哪个位置的 CLI,使用这个工具可以帮助我们设置及切换当前默认使用的 CLI。
介绍该工具常见的命令:
xcode-select --install
: 安装 CLI,会安装到/Library/Developer/CommandLineTools/
xcode-select -p
: 显示当前指定的工具包所在 Xcode 路径xcode-select -s <path>
: 切换默认工具包所在 Xcode 路径xcode-select -r
: 重置工具包所在 Xcode 路径
xcode-select
提供了一个环境变量,让你能临时使用其他环境来执行xcode command
,env DEVELOPER_DIR="/Applications/Xcode-beta.app" /usr/bin/xcodebuild
xcode-select 选择路径不是直接选择的 CLI 路径,而是选择所在 Xcode 的路径,继而使用该 Xcode 对应的 CLI,默认情况会选择到该 Xcode 包内包含的 CLI,但是如果我们通过 Xcode Preferences 调整过该 Xcode 对应的 CLI,就会使用调整后的 CLI。
这个工具应该是 Mac 自带的工具,位于 /usr/bin/xcode-select
,并不是跟随 CLI 工具包一块下载下来的。
xcrun
回想我们过去在使用一些 CLI 命令的时候,会直接在终端上执行 xcodebuild ...
这样的方式,没有指定具体的 CLI 路径,并且我们执行 which xcodebuild
得到的结果是 /usr/bin/xcodebuild
。那这个命令是怎么执行到我们通过 xcode-select
设置的默认 CLI 路径下呢?那就得提到我们马上要介绍的这个工具了 – xcrun
。
我们就以 xcodebuild
举例,我们通过 which xcodebuild
得到的结果是 /usr/bin/xcodebuild
,也就是说我们在执行 xcodebuild
的时候实际上在执行 usr/bin/xcodebuild
,那再让我们看看 /usr/bin/xcodebuild
下的指令是怎么配合 xcode-select
找到 /Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild
的?
我们先通过 otool -tV /usr/bin/xcodebuild
查看其 textsection
,得到:
|
|
我们可以发现该命令调用 _xcselect_invoke_xcrun
函数。
然后我们通过 nm /usr/bin/xcodebuild
查看其 name list
|
|
通过 _xcselect_invoke_xcrun
前面的 U
标识我们可以知道该函数是一个外部符号,是另外一个动态库去处理的。
后面我们通过 Swift-Swiftc 可以知道更详细流程,这里只说结论:
|
|
我们后面最后实际上会调用到 xcrun_main
函数,其内部就会根据 xcode-select
等设置的情况选择合适的 CLI 路径,具体执行的顺序可见 Developer Binaries on OS X, xcode-select and xcrun 。
xcrun(Xcode Command Line Tool Runner
) 是 Xcode 基本的命令行工具,使用它来调用其他 CLI 工具,这时候你应该就知道为啥需要它来调用其他 CLI 工具了。
我们执行 xcrun
命令时实际上也是走的 /usr/bin/xcrun
,其内部也是上面一套流程,准确而言,在这套 CLI 工具包中位于 /usr/bin
路径下的命令都是上面那个流程,也就是说下面几个命令是等价的:
- xcodebuild
- /usr/bin/xcodebuild
- xcrun xcodebuild
- Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild
当然这套工具包有些命令不在 /usr/bin
路径下,我们就需要在命令前加上 xcrun
了,如 swift-demangle
,如果我们直接使用 swift-demangle
就会出现命令找不到的错误,使用 xcrun swift-demangle
这种方式即可。
相关命令:
- xcrun –find clang // 找到指定工具路径
- xcrun –sdk iphoneos –find pngcrush
- xcrun –sdk macosx –show-sdk-path
通过 xcode-select
安装的 CLI 路径位于:/Library/Developer/CommandLineTools/
。
Xcode 内嵌的 CLI 路径位于:/Applications/Xcode.app/Contents/Developer/usr/bin
还有一点需要注意的是,xcrun 并不是只会寻找 xcode-select
设置下的路径,还会寻找 Xcode 另外的一些路径来执行命令,包括
- Developer/usr
- Developer/Platforms
- Developer/ToolChain
例子如下:
xcodebuild:/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild
swift-demangle:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-demangle
深入浅出 Xcode Command Lines Tool - 初探 深入浅出 Xcode 命令列 - libxcselect.dylib 深入浅出 Xcode 命令列 - xcrun
关于这两个工具有开源的实现 xcode-tools。
符号表相关
先简单介绍一下 DWARF
以及 dSYM
。
DWARF
与 dSYM
的关系是,DWARF
是文件格式,而 dSYM
往往指一个单独的文件。在 Xcode 中如果不做特殊指定,debug information
是被保存在 executable
文件中。因为 DWARF
的存在我们才可以在 debug
时看到函数名称等信息,因为 dSYM
文件的存在,我们才可以符号化,解 Crash。
关于符号解析之前有过一篇文章 iOS符号化解析。
dwarfdump
作用:解析目标文件,存档和 .dSYM
包中的 DWARF
节,并以人类可读的形式打印其内容;
使用场景:Crash 符号化;
路径:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/dwarfdump
;
|
|
更多命令可见 llvm-dwarfdump。
dsymutil
作用:可以使用 dsymutil
从 二进制中 中提取 dSYM
文件以及对 dSYM
文件进行一些操作;
使用场景:当 dSYM
文件丢失后,可以将其作为找回 dSYM
文件的一种方式;
路径:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/dsymutil
;
|
|
symbolicatecrash
作用:是一个 perl
脚本,里面整合了逐步解析的操作(可以将命令拷贝出来,直接进行调用);
场景:Crash 文件符号化;
路径:/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash
;
|
|
iOS 15 之后,崩溃日志的格式为 JSON 形式,新的脚本地址为 /Applications/Xcode.app/Contents/SharedFrameworks/CoreSymbolicationDT.framework/Versions/A/Resources/CrashSymbolicator.py
这个 py 脚本为 python3 写的,所有也需要 python3 环境下去调用,命令为
|
|
解析之后的结果也是 JSON 形式的。
当然我们也可以将其拷贝出来使用,但是需要在首行加上下列代码
|
|
atos
作用:Crash 符号化;
路径:/Applications/Xcode.app/Contents/Developer/usr/bin/atos
;
|
|
构建相关
xcodebuild
作用:我们可以使用其对 Xcode 工程进行清理,分析,构建,测试,存档;
场景:CI 构建等;
路径:/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild
;
可以通过 man xcodebuild
查看手册。
其中
man
命令就是用来查看指定命令的使用手册。
|
|
xctool
:xctool
是facebook
推出的用于替换xcodebuild
的更易于测试 iOS 和 mac 应用程序的命令行工具,特别适用于 iOS App 的持续集成;xcbuild
:xcbuild
是一个兼容Xcode
的编译工具,它能使编译更快快速,更友好的编译过程日志,可以运行在多个平台(主要指 OS X 和 Linux);
altool
作用:使用其验证 ipa 以及上传 ipa 到 Store;
路径:/Applications/Xcode.app/Contents/Developer/usr/bin/altool
|
|
工具链相关
swiftc
作用:swift 语言的编译前端;
路径:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc
;
swiftc
只是一个替身,原身是swift-frontend
。
clang
作用:oc 语言的编译前端;
路径:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang
;
sourcekit-lsp
LSP(Language-Server-Protocol)开源的语言服务器协定。由红帽、微软和 Codenvy 联合推出,可以让不同的程序编辑器与集成开发环境(IDE)方便嵌入各种程序语言,允许开发人员在最喜爱的工具中使用各种语言来撰写程序,SourceKit-LSP
是 Apple 维护的用于 Swift 的 LSP;其的存在允许我们使用其他 IDE 开发 Swift,如 VSCode;
路径:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/sourcekit-lsp
工具相关
actool
作用:对 项目中 Assets 的文件进行压缩、处理,生成 .car
文件;
路径:/Applications/Xcode.app/Contents/Developer/usr/bin/actool
;
actool
并非一个脚本,而是一个编译完成的二进制文件,所以 compile asset catalog
的过程是一个黑盒。
swift-demangle
在 Swift 中因为命名空间的原因,需要对类名进行 mangle
,如果需要显示正确名称,自然也需要 demangle
。其实两个方法实现大家可以通过以下链接查看,
mangle
:copySwiftV1MangledName函数,
demangle
:copySwiftV1DemangledName
当然 Apple 本身也为我们特意准备了一个 CLI 工具 –swift-demangle
来方便我们。
|
|
我们还可以在 SwiftDemangle.h 看到 swift 底层该函数名称 – swift_demangle_getDemangledName
,项目中需要加入 libswiftDemangle.tbd
。
genstrings & ibtool
genstrings
作用:genstrings
工具从指定的 C 或者 Objective-C 源文件生成 .strings
文件;
命令:genstrings -a /path/to/source/files/*.m
ibtool
正如 genstrings
作用于源代码,而 ibtool
作用于 XIB
文件;
命令:$ ibtool --generate-strings-file Localizable.strings en.lpoj/Interface.xib
本地化是它的主要功能,ibtool 还拥有对 Interface Builder 文档有效的其他几个功能。
- –convert: 更改所有对类名的引用
- –upgrade: 将文档升级到最新版
- –enable-auto-layout:启用自动布局
- –update-frames:更新框架
- –update-constraints:更新约束
xed
作用:这个命令可以简单地打开 Xcode,可以用在 CLI 程序内;
命令:xed XXX.xcworkspace
agvtool
作用:读取以及写入 Xcode 工程 Info.plist
中的版本号等信息。
agvtool what-version
:返回 build 号;agvtool next-versio
:build 号加上,写入Info.plist
;
plutil
plutil
多用于处理 plist 文件的校验和修改,其还可以用用于校验多语言文件 .strings
的格式问题。
plutil -lint path/Localizable.strings
模拟器
open -a Simulator
: 打开一个模拟器(会是最近打开过的那一个)xcrun simctl list
:列出安装的所有设备xcrun simctl boot XXX
: XXX 为设备唯一标识(长这样:413E2CA2-420B-4074-BD64-47333E167A20
),xcrun simctl list
结果里面会有。
Mach-O 操作相关
其实关于 Mach-O 操作的大部分工具都是 LLVM 下面的,包括 otool
、objdump
、nm
、dwarfdump
等等,其命令本质上都是一个替身,背后实际上都是 llvm-XXX
命令的原身。
nm
作用:nm
命令是 linux 下自带的特定文件分析工具,一般用来检查分析二进制文件、库文件、可执行文件中的符号表,返回二进制文件中各段的信息,查看二进制目标文件的符号,主要就是函数名称以及全局变量;
路径:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/nm
;
|
|
前面我们曾经查看过 xcodebuild
的符号,输出如下。
|
|
上述中间的大写字母就是后面对应符号的类型,其中全部的类型包括:
- A 该符号的值在今后的链接中将不再改变;
- B 该符号放在 BSS 段中,通常是那些未初始化的全局变量;
- D 该符号放在普通的数据段中,通常是那些已经初始化的全局变量;
- T 该符号放在代码段中,通常是那些全局非静态函数;
- U 该符号未定义过,需要自其他对象文件中链接进来;
- W 未明确指定的弱链接符号;同链接的其他对象文件中有它的定义就用上,否则就用一个系统特别指定的默认值。
otool & objdump
为什么要把这两个工具放到一起说呢?因为这两个工具之间有一定的关系。其实 otool
本质上就是 objdump
的一层 wrapper,底层其实都是使用 objdump
的实现。
比如 otool -L XXX
本质就等价 objdump --macho -dylibs-used XXX
,更多详细的转换规则可见 otool.html。
两者作用: 针对目标文件的展示工具,用来发现应用中使用到了哪些系统库,调用了其中哪些方法,使用了库中哪些对象及属性。
otool
路径:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/otool
还有一个比这个更方便的工具,jtool
MachOView 算是这个 CLI 工具的 GUI 工具了。
|
|
objdump
Linux 的文件也可以使用这个工具。
路径:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/objdump
|
|
其实
objdump
的功能之一可以代替nm
命令,其中objdump --macho --syms XXX
也可以输出符号表。
strings
作用:查看二进制文件中的字符串;
路径:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/strings
;
|
|
lipo
lipo
源于 mac
系统要制作兼容 powerpc
平台和 intel 平台的程序,lipo
是一个在 Mac OS X
中处理通用程序(Universal Binaries)的工具。
|
|
ar
作用:建立、修改静态库;
路径:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool
;
|
|
file
我们可以使用 file
命令来区分动态库与静态库。
如 file Flutter
得到,我们可以很容易看到 dynamically
关键字,其为一个动态库
|
|
如 file CSPickerView
,得到结果如下:CSPickerView 为一个静态库
|
|
class-dump
这是一个命令行实用程序,用于检查存储在 Mach-O
文件中的 Objective-C
运行时信息。它为类、类别和协议生成声明。这与使用 ‘otool -ov’ 提供的信息相同,但呈现为普通的 Objective-C 声明,因此更加紧凑和可读。
如果安装了
MonkeyDev
,内置了class-dump
,就不用再特意去安装了。
dyldinfo
|
|
最后
当然,CLI 命令还有很多,这里只是列举了一些常见的,对于其他的,大家可以直接通过开头提到的一些路径去查找。
要更加努力呀!
Let’s be CoderStar!