Xcode 常见 CLI 工具

3 篇文章 0 订阅

前言

Hi Coder,我是 CoderStar!

在新的一年里,祝小伙伴们工作顺利,升职加薪。

在咱们日常开发中,或多或少都会用到 Xcode 内置的一些CLI工具,但是大部分小伙伴可能只是会用到一些具体的命令,今天我们就一起来聊一聊 Xcode 内置的常见Command Lines Tool

介绍的可能不全,大家可以去文中出现的路径下查看更多的工具。

Command Line Tool本质是一个命令行工具包,内部有很多有用的工具,如Apple LLVM compilerMake等等。并且并不是只有开发 Apple 应用程序才需要用到这些工具包,当我们使用Homebrew在安装一些python库或者js库时,都会提示需要Command Line Tool

下文会对Command Line Tool直接缩写成 CLI,XXX 一般情况是指对应路径地址。

我们在开发者官网 Command Line Tool 对其单独下载,当然每个版本的 Xcode 安装包内也会包含这套工具包。

其实下列有一部分工具属于 LLVM 序列,比如dwarfdumpar,启动本质其实为llvm-dwarfdumpllvm-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 commandenv 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,得到:

(__TEXT,__text) section
_main:
0000000100003f63	pushq	%rbp
0000000100003f64	movq	%rsp, %rbp
0000000100003f67	pushq	%r14
0000000100003f69	pushq	%rbx
0000000100003f6a	movq	%rsi, %r14
0000000100003f6d	movl	%edi, %ebx
0000000100003f6f	callq	0x100003f88                     ## symbol stub for: __NSGetProgname
0000000100003f74	movq	(%rax), %rdi
0000000100003f77	leal	-0x1(%rbx), %esi
0000000100003f7a	leaq	0x8(%r14), %rdx
0000000100003f7e	movl	$0x1, %ecx
0000000100003f83	callq	0x100003f8e                     ## symbol stub for: _xcselect_invoke_xcrun
复制代码

我们可以发现该命令调用_xcselect_invoke_xcrun函数。

然后我们通过nm /usr/bin/xcodebuild查看其name list

                 U __NSGetProgname
0000000100008018 d __dyld_private
0000000100000000 T __mh_execute_header
0000000100003f63 t _main
0000000100008010 s _shim_marker
                 U _xcselect_invoke_xcrun
                 U dyld_stub_binder
复制代码

通过_xcselect_invoke_xcrun前面的U标识我们可以知道该函数是一个外部符号,是另外一个动态库去处理的。

后面我们通过 Swift-Swiftc 可以知道更详细流程,这里只说结论:

libxcselect.dylib
👇🏻
_xcselect_invoke_xcrun
👇🏻
libxcrun.dylib
👇🏻
xcrun_main
复制代码

我们后面最后实际上会调用到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

DWARFdSYM 的关系是,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

# 使用示例
dwarfdump -h

# 查看 xx.app 文件的 UUID
dwarfdump --uuid xx.app/xx

# 查看 xx.app.dSYM 文件的 UUID
dwarfdump --uuid xx.app.dSYM

# 导出debug_info 的信息到文件 debug_line.txt 中
dwarfdump --debug-info xx.app.dSYM > debug_info.txt

#  出debug_line 的信息到文件 debug_line.txt 中
dwarfdump --debug-line xx.app.dSYM > debug_line.txt

# 校验DWARF的有效性
dwarfdump --verify iOSTest.app.dSYM

# 查找指定地址的相关信息
# 一般用在Crash解析时
dwarfdump --arch arm64 --lookup 0x100006694 iOSTest.app.dSYM

复制代码

更多命令可见 llvm-dwarfdump

dsymutil

作用:可以使用 dsymutil 从 二进制中 中提取 dSYM 文件以及对 dSYM 文件进行一些操作; 使用场景:当dSYM文件丢失后,可以将其作为找回dSYM文件的一种方式; 路径:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/dsymutil


# 从二进制文件中还有`DSYM`信息的二进制包中抽取形成`.dysm`文件
dsymutil XXX

# 使用指定的符号映射更新现有的 dSYM
# 处理开启bitcode选项的dsym文件
dsymutil -symbol-map /Users/XXXXX/Library/Developer/Xcode/Archives/2019-09-27/YYYY.xcarchive/BCSymbolMaps 0f1e9458-9741-36fb-b47c-694546728ea1.dSYM
复制代码

symbolicatecrash

作用:是一个perl脚本,里面整合了逐步解析的操作(可以将命令拷贝出来,直接进行调用); 场景:Crash 文件符号化; 路径:/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash

# 需要先运行该命令,不然下面 symbolicatecrash命令会出现
# Error: "DEVELOPER_DIR" is not defined at ./symbolicatecrash line 69.
export DEVELOPER_DIR="/Applications/XCode.App/Contents/Developer"

# 运行命令前需要将崩溃日志、 dSYM 以及 symbolicatecrash 复制到同一个目录下
symbolicatecrash log.crash -d xxx.app.dSYM > symbol.log
复制代码

atos

作用:Crash 符号化; 路径:/Applications/Xcode.app/Contents/Developer/usr/bin/atos

# 0x0000000100298000为 load address; 0x000000010029e694为 symbol address
# 最后一个i表示显示内联函数
atos -arch arm64  -o iOSTest.app.dSYM/Contents/Resources/DWARF/iOSTest -l 0x0000000100298000 0x000000010029e694 -i
复制代码

构建相关

xcodebuild

作用:我们可以使用其对 Xcode 工程进行清理,分析,构建,测试,存档; 场景:CI 构建等; 路径:/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild

可以通过man xcodebuild查看手册。

其中man命令就是用来查看指定命令的使用手册。

# 清理
xcodebuild clean -workspace ${WORKSPACE_PATH} -scheme ${SCHEME_NAME} -configuration ${BUILD_TYPE}

# 构建
xcodebuild archive -workspace ${WORKSPACE_PATH} -scheme ${SCHEME_NAME} -archivePath ${ARCHIVE_PATH}

## 存档
xcodebuild -exportArchive -archivePath $ARCHIVE_PATH -exportPath ${IPA_PATH} -exportOptionsPlist ${EXPORTOPTIONSPLIST_PATH}
复制代码
  • xctoolxctoolfacebook 推出的用于替换 xcodebuild 的更易于测试 iOS 和 mac 应用程序的命令行工具,特别适用于 iOS App 的持续集成;
  • xcbuildxcbuild 是一个兼容 Xcode 的编译工具,它能使编译更快快速,更友好的编译过程日志,可以运行在多个平台(主要指 OS X 和 Linux);

altool

作用:使用其验证 ipa 以及上传 ipa 到 Store; 路径:/Applications/Xcode.app/Contents/Developer/usr/bin/altool

# 验证
# version、build号是否正确等case
xcrun altool --validate-app -f xxx.ipa -t ios --apiKey xxx --apiIssuer xxx --verbose

# 上传
xcrun altool --upload-app -f xxx.ipa -t ios --apiKey xxx --apiIssuer xxx --verbose
复制代码

工具链相关

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。其实两个方法实现大家可以通过以下链接查看,

manglecopySwiftV1MangledName 函数

demanglecopySwiftV1DemangledName

当然 Apple 本身也为我们特意准备了一个 CLI 工具 --swift-demangle来方便我们。

命令:xcrun swift-demangle  _TtC7iOSTest27PickImageDemoViewController
结果:_TtC7iOSTest27PickImageDemoViewController ---> iOSTest.PickImageDemoViewController

命令:xcrun swift-demangle --compact _TtC7iOSTest27PickImageDemoViewController
结果:iOSTest.PickImageDemoViewController
复制代码

我们还可以在 SwiftDemangle.h 看到 swift 底层该函数名称 -- swift_demangle_getDemangledName,项目中需要加入libswiftDemangle.tbd

Mach-O 操作相关

其实关于 Mach-O 操作的大部分工具都是 LLVM 下面的,包括otoolobjdumpnmdwarfdump等等,其命令本质上都是一个替身,背后实际上都是llvm-XXX命令的原身。

nm

作用:nm 命令是 linux 下自带的特定文件分析工具,一般用来检查分析二进制文件、库文件、可执行文件中的符号表,返回二进制文件中各段的信息,查看二进制目标文件的符号,主要就是函数名称以及全局变量; 路径:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/nm

# 得到XXX中的程序符号表
nm XXX

# 查看所有符号,会打印出符号来源哪个地方
nm -nm XXX

# 找到未定义的符号,也就是外部符号
nm -u XXX
复制代码

前面我们曾经查看过xcodebuild的符号,输出如下。

                 U __NSGetProgname
0000000100008018 d __dyld_private
0000000100000000 T __mh_execute_header
0000000100003f63 t _main
0000000100008010 s _shim_marker
                 U _xcselect_invoke_xcrun
                 U dyld_stub_binder
复制代码

上述中间的大写字母就是后面对应符号的类型,其中全部的类型包括:

  • 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

MachOView 算是这个 CLI 工具的 GUI 工具了。

# 查看使用到哪些动态库,一般是涉及到 	/usr/lib/ 	/System/Library/Frameworks/  @rpath 这三个位置,如果没有自己的动态库,就没有后面的 @rpath
otool -L XXX

# 筛选是否链接了xxx库
otool -L XXX | grep "xxx"

# 查看汇编码
otool -tV XXX

# 输出Object-C类结构以及定义的方法
otool -ov XXX

# 查看头部内容
otool -h XXX

# 查看 load commands
otool -l XXX

# 查看该应用是否砸壳
# 看输出结果的cryptid参数,其中0:砸壳、1:未砸壳。
otool -l XXX | grep -B 2 crypt

# 查看代码段起始地址
otool -l iOSTest.app.dSYM/Contents/Resources/DWARF/iOSTest | grep __TEXT -C 5

# 查看重定位符号表
otool -r XXX
复制代码

objdump

路径:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/objdump

# 查看mach-header
objdump --macho -private-header XXX

# 查看text段
objdump --macho -d XXX

# 查看符号表
objdump --macho --syms XXX

# 查看导出符号表
objdump --macho --exports-trie XXX

# 查看间接符号表
objdump --macho --indirect-symbols XXX

# 查看重定位符号表
objdump --macho --reloc XXX
复制代码

其实objdump的功能之一可以代替nm命令,其中objdump --macho --syms XXX也可以输出符号表。

strings

作用:查看二进制文件中的字符串; 路径:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/strings

# 查看指定字符串
strings XXX | grep "xxx"
复制代码

lipo

lipo 源于 mac 系统要制作兼容 powerpc 平台和 intel 平台的程序,lipo 是一个在 Mac OS X 中处理通用程序(Universal Binaries)的工具。

### 查看查看静态库支持的 CPU 架构
lipo -info frameworkName.framework/frameworkName
lipo -info frameworkName.a

### 合并静态库
lipo -create 静态库存放路径 1 静态库存放路径 2 ... -output 整合后存放的路径

lipo -create frameworkName-armv7.a frameworkName-armv7s.a frameworkName-i386.a -output frameworkName.a
lipo -create frameworkNameOne.framework/frameworkNameOne frameworkNameTwo.framework/frameworkNameTwo -output frameworkName.framework

### 静态库拆分
lipo 静态库源文件路径 -thin CPU 架构名称 -output 拆分后文件存放路径
lipo libname.a -thin armv7 -output libname-armv7.a

### 擦除指定架构
lipo -remove XXX.a arm64 -output XXX.a
复制代码

ar

作用:建立、修改静态库; 路径:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool

ar -x XXX

-d 删除备存文件中的成员文件。
-m 变更成员文件在备存文件中的次序。
-p 显示备存文件中的成员文件内容。
-q 将问家附加在备存文件末端。
-r 将文件插入备存文件中。
-t 显示备存文件中所包含的文件。
-x 自备存文件中取出成员文件。
复制代码

file

我们可以使用file命令来区分动态库与静态库。

file Flutter得到,我们可以很容易看到dynamically关键字,其为一个动态库

Flutter: Mach-O 64-bit dynamically linked shared library arm64
复制代码

file CSPickerView,得到结果如下:CSPickerView 为一个静态库

CSPickerView: Mach-O universal binary with 5 architectures: [i386:current ar archive] [arm_v7] [arm_v7s] [x86_64] [arm64]
CSPickerView (for architecture i386):	current ar archive
CSPickerView (for architecture armv7):	current ar archive
CSPickerView (for architecture armv7s):	current ar archive
CSPickerView (for architecture x86_64):	current ar archive
CSPickerView (for architecture arm64):	current ar archive
复制代码

class-dump

下载地址

这是一个命令行实用程序,用于检查存储在 Mach-O 文件中的 Objective-C 运行时信息。它为类、类别和协议生成声明。这与使用 'otool -ov' 提供的信息相同,但呈现为普通的 Objective-C 声明,因此更加紧凑和可读。

如果安装了MonkeyDev,内置了class-dump,就不用再特意去安装了。

最后

当然,CLI 命令还有很多,这里只是列举了一些常见的,对于其他的,大家可以直接通过开头提到的一些路径去查找。

要更加努力呀!

Let's be CoderStar!


作者:CoderStar
链接:https://juejin.cn/post/7060142847609012255
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值