GNU Make: Build Xcode Project
Preface
Xcode 很垃圾, 但还好有很多开源工具可以帮我尽可能的避开 Xcode 带来的不便。
除了可以在 Xcode IDE 内构建工程外, 还可以使用 xcodebuild
来构建, 这就意味着我可以用 GNU
Make 来构建工程, 这样就能更好的与 CI/CD 整合了。
Makefile 入门
基本语法
之所以选择 Makefile 而不是其它构建工具或 plain-old shell script 是因为:
- Makefile 比 shell script 多了目标依赖和其它一些 Makefile 的便利语法;
- 其它构建工具或多或少有较高的学习曲线;
- macOS 自带一个 GNU Make 而其它构建工具还需要自行安装。
Makefile 的语法还是很简单的, 具体可以去 makefiletutorial.com 快速入门, 下面只做一个简单的例子:
# Comment starts with number sign(#).
# Run commands in bash shell.
SHELL=/bin/bash
# Define a variable.
my_variable:=my value, and spaces are ok.
target: dependency1 dependency2
# Add at sign(@) before the command to stop it from being printed.
@echo "Last"
dependency1: dependency2
@echo "Second"
dependency2:
@echo "First"
# Build `target` every time the user asked for.
.PHONY: target
复制上面的代码然后粘贴到一个文本文件内并将其命名为 Makefile
, 然后在 Makefile
文件所在
目录运行命令 make
, 运行完成后命令行的输出应该是:
First
Second
Last
需要注意一点的是: Makefile 用 tab 缩进而不是 spaces, 如果用 spaces 作为缩进的话会出现这样 的错误:
Makefile:<line number>: *** missing separator. Stop.
在 make 和 shell 之间传递变量
一个 Target 内逐个运行多个命令的时候每个命令都是在新的进程里运行, 也就意味着前一次运行的命令里 有设置变量或 export 变量的话在运行下一个命令时这些变量就不存在了, 因此需要一个方法在 shell 和 make 的环境之间交换数据。
default:
# Passing variable from shell to make
$(eval from_shell:=$(shell echo "from_shell"))
# Passing variable from make to shell
echo $(from_shell)
使用命令构建 Xcode 工程
xcodebuild
大致的用法是这样的:
xcodebuild -project ./<project>.xcodeproj \
-target <target> \
-destination platform=<iOS, macOS or something else> \
-configuration <Debug | Release> build
比如构建一个 debug 版的 hello world 工程运行在 iOS 上, 则使用如下命令:
xcodebuild -project ./HelloWorld.xcodeproj \
-target app \
-destination platform=iOS \
-configuration Debug build
整合 Makefile 和 xcodebuild
使用 GNU Make 的一个原因就是可以用不同条件构建工程, 比如提供一个参数来构建 Release 版软件:
SHELL=/bin/bash
is_release=false
.PHONY: build
build:
$(eval xcodebuild_conf:=Debug)
ifeq ($(is_release), true)
$(eval xcodebuild_conf:=Release)
endif
@xcodebuild -project ./HelloWorld.xcodeproj \
-target app \
-destination platform=iOS \
-configuration $(xcodebuild_conf) build
如果我使用命令:
make is_release=true build
来构建工程的话, 提供给 xcodebuild
的 -configuration
参数的值就会是 Release
, 也就
是要求 xcodebuild
构建 release 版的软件。