MacOSX APP使用x264动态库
作者:罗上文,微信:Loken1,公众号:FFmpeg弦外之音
在MacOSX上使用x264是非常简单的,本文以Objective-C为例。
在编译 x264 代码之前,我们需要设置一下汇编器(AS)、编译器(CC)的环境变量,如下:
export PATH="$PATH:/Users/loken/Documents/x264/tools/"
export AS="gas-preprocessor.pl -arch powerpc -- xcrun -sdk macosx clang"
export CC="xcrun -sdk macosx clang"
gas-preprocessor.pl 是 x264 项目的 tools 目录下的一个 Perl 脚本,如下:

这个脚本已经有10年的历史了,早期他应该是为了扩展苹果的 gas 命令的,也就是用 perl 在 gas 上包了一层,使用起来更加方便。
然后现在已经是2024年了,苹果系统的 gas 命令应该是被删除了,目前用来编译汇编代码,把汇编代码转成机器码的是 clang 命令。
所以 clang 命令,它即是 汇编器,也是 编译器。
gas-preprocessor.pl -arch powerpc -- xcrun -sdk macosx clang
上面这条命令是比较复杂的,我们需要仔细研究它的具体的用法,需要弄清楚以下几个问题。
1,-arch 参数
-arch 顾名思义是指定计算机架构,也是确定生成的机器码是什么CPU架构的,我的是旧版 Mac Mini,采用的是 intel i5 芯片,所以 arch 肯定是 powerpc。
如果是别的CPU芯片呢?gas-preprocessor.pl 一共支持几种架构,如何查看?
答:需要翻 gas-preprocessor.pl 的源代码,如下:
my %canonical_arch = ("aarch64" => "aarch64", "arm64" => "aarch64",
"arm" => "arm",
"powerpc" => "powerpc", "ppc" => "powerpc");
可以看到,它一共支持 3 种架构,aarch64、arm、powerpc。
2,-- 参数
-- 参数其实是它这个 perl 脚本自己实现的功能,-- 后面必须接汇编器的命令。作者的注释如下:
Options for this program needs to be separated with ' -- ' from the assembler
command. Following options are currently supported:
3,xcrun 命令
xcrun 其实是 MacOSX 系统的命令,全称是 Xcode Run。简单来说,它相当于 python 的虚拟环境 anaconda。
xcrun -sdk macosx clang
上面的命令其实是分为两个部分的,如下:

你可以这样理解上面这条命令,xcrun 会设置编译环境为 macosx,什么是编译环境?
就是编译的时候需要引入一些头文件,链接一些系统库等等。-sdk macosx 的作用就是告诉 clang 命令,需要的头文件、系统库、命令工具、等等都去 macosx sdk 的环境拿。
macosx sdk 的环境是什么呢?实际上它就是一个路径,如下:
xcrun -sdk macosx --show-sdk-path
上面的命令会打印出来 macosx 环境的路径
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk
那 xcrun 一共支持几种 SDK 环境呢?如下:
- iphoneos,手机SDK
- iphonesimulator,手机模拟器SDK
- macosx,PC-SDK
- watchos,手表SDK
- watchtv,苹果电视SDK
配置完 汇编器、编译器 的环境变量,我们就可以编译 x264 的代码了,命令如下:
./configure \
--enable-static \
--disable-asm \
--enable-pic \
--enable-shared \
--enable-debug \
--host=x86_64-apple-darwin \
--extra-cflags="-arch x86_64 -mmacosx-version-min=12.0" \
--extra-asflags="-arch x86_64 -mmacosx-version-min=12.0" \
--extra-ldflags="-arch x86_64 -mmacosx-version-min=12.0" \
--prefix="/Users/loken/Documents/x264/thin/x86_64"
make -j4
make install
--prefix 一定要设置成绝对路径,如果设置成相对目录,你运行的时候可能会遇到下面的报错。
--prefix="./thin/x86_64"
dyld[23683]: Library not loaded: ./thin/x86_64/lib/libx264.157.dylib
Referenced from: /Users/loken/Library/Developer/Xcode/DerivedData/test-gvcajfcsyrvpwxapjscewdhnqemd/Build/Products/Debug/test
Reason: tried: '/Users/loken/Library/Developer/Xcode/DerivedData/test-gvcajfcsyrvpwxapjscewdhnqemd/Build/Products/Debug/libx264.157.dylib' (no such file), '/usr/lib/system/introspection/libx264.157.dylib' (no such file), './thin/x86_64/lib/libx264.157.dylib' (no such file), '/usr/local/lib/libx264.157.dylib' (no such file), '/usr/lib/libx264.157.dylib' (no such file)
Program ended with exit code: 9
这个错误其实也可以设置 RunPath Search Path 来解决,但是有点麻烦。
-arch x86_64 这个参数也比较重要,这个其实就是 clang 命令的参数,那 clang 支持多少种架构呢?我们可以通过下面的命令查看
clang -print-targets
编译完成之后,就能在 ./thin/x86_64 目录下看到 x264 的动态库与静态库了,如下:

下面介绍一下如何在 Objective-C 里面调用 x264 的动态库。
其实在 Xcode 里面引入动态库 跟在 VS2019 里引入动态库是非常类似的,无非就是指定头文件的搜索路径、指定动态库的搜索路径、指定链接器要去链接哪些动态库、等等。如下:

然后我们在 Build Phases 里面添加一下 libx264.157.dylib 动态库到项目里,如下:

现在我们就可以修改 main.m 的代码,使用 libx264 动态库里面的函数了,如下:
#import <Foundation/Foundation.h>
#include "x264_config.h"
#include "x264.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
x264_param_t xp;
x264_param_default(&xp);
}
return 0;
}
上面的代码很简单,我就设置了一个 xp 变量,然后给他赋予默认值。读者可以自行断点调试,如下:

因为我编译的时候开启了 --enable-debug,所以是可以跳进去 x264_param_default 函数的源代码的。
扩展知识:
我们可以打开 Xcode 的编译构建日志,可以看到,我们设置的 x264 路径以及库名称已经传递给了 clang 命令了,如下:

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -x objective-c 省略 -I/Users/loken/Documents/x264/thin/x86_64/include -c /Users/loken/Documents/test/test/main.m 省略
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -target x86_64-apple-macos12.3 省略 -fobjc-link-runtime -lx264.157 -Xlinker -no_adhoc_codesign -Xlinker -dependency_info -Xlinker /Users/loken/Library/Developer/Xcode/DerivedData/test-gvcajfcsyrvpwxapjscewdhnqemd/Build/Intermediates.noindex/test.build/Debug/test.build/Objects-normal/x86_64/test_dependency_info.dat -o /Users/loken/Library/Developer/Xcode/DerivedData/test-gvcajfcsyrvpwxapjscewdhnqemd/Build/Products/Debug/test
参考资料: