什么是交叉编译
在一个平台上编译生成其他平台可运行的程序, 我们称之为交叉编译
以c
语言为例, 在Mac
平台编译出来的程序只能在Mac
平台运行, 将其拷贝到Windows
平台则无法识别, 解决这个问题的办法就是将源代码移至Windows
平台 然后重新编译一次 这种做法属于原始的常规编译
那能不能在Mac
平台编译生成能在Windows
平台运行的程序呢, 可以, 只要借助交叉编译工具即可实现, 而这种非常规编译手段也叫做交叉编译
关于交叉编译实操, 详见之前的文章《android设备上如何运行C语言原生程序》
针对C/C++
语言目前主流的交叉编译有:
- GCC:
GNU
旗下的一款编译工具 - CLANG: 苹果主导编写的一款基于
LLVM
的编译工具 - MSVC: 微软旗下的一款编译工具
为什么使用Clang
相较之下, Clang
编译速度更快, 占用内存更小, 错误提示更加人性化
Clang常规使用
我们先以一个C
语言小程序来示范clang
的编译流程
编写
c
程序代码 文件名为main,c
1
2
3
4
5
6
7
int main(int argc, char** argv){
printf("Hello World!\n");
return 0;
}编译程序源码为当前平台可执行文件
1
clang main.c -o main
-o
:指定输出执行文件路径和程序名称编译时顺带打印编译日志
添加一个
-v
即可1
clang main.c -o main -v
编译生成预处理文件
使用
-E
, 区分大小写1
clang -E main.c -o main
编译生成汇编代码
使用
-s
, 区分大小写1
clang -S main.c -o main
编译生成obj文件
使用
-c
, 区分大小写1
clang -c main.c -o main
Clang交叉编译
指定
cpu
架构使用
-arch
, 比如我们要编译生成arm64
位架构平台可执行的程序1
clang main.c -o main -arch arm64
正常情况下 上述指令会执行失败, 那是因为
clang
默认会使用本平台的SDK
进行链接编译, 而本平台的SDK
如果不支持arm
的话自然无法编译 目前大部分电脑用的cpu
依然还是x86
架构的既然如此 倘若我们需要编译能在
iPhone
上运行的程序, 那么就需要指定可以支持arm
的SDK
来进行编译, 比如iphoneOS_SDK
指定编译SDK
在
clang
中, 通过来-isysroot
指定编译SDK
, 如下:1
clang -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.5.sdk main.c -o main -arch arm64
编译成功后 生成的可执行文件即可在苹果手机上运行
指定操作系统
1
clang main.c -o main -target x86_64-apple-darwin-eabi
这里使用
-target
同时指定cpu
架构和操作系统,-target
的参数一共分为四部分:- arch:
cpu
架构 比如arm
,x86_64
- vendor: 工具连提供厂商 比如
pc
,apple
,nvidia
,ibm
,等 - os: 操作系统 比如
darwin
,linux
,win32
- abi:应用程序二进制接口, 描述了程序在目标平台的运行规则, 比如
eabi
,androidabi
,gnueabi
等
每部分用横杆隔开, 合起来就是
arch-vendor-os-abi
- arch:
示例
Mac
编译android
平台程序这里我使用的是
ndk
包下的clang
进行编译1
ndk/21.0.6113669/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang --target=armv7-none-linux-androideabi16 --sysroot=/Users/songjian/Library/Android/sdk/ndk/21.0.6113669/toolchains/llvm/prebuilt/darwin-x86_64/sysroot main.c -o androidExc
Mac
编译iphone
平台程序1
clang -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.5.sdk main.c -o main -arch arm64
lua源码交叉编译
接下来 我们在Mac
平台上编译生成android
上可执行的lua
程序
由于lua
源码文件比较多, 手敲命令编译太过繁琐, 因此我这里使用gradle
+cmake
构建工具进行快速编译
其中build.gradle
配置如下:
1 | apply plugin: 'c' |
这里 我将所有lua
源码放置在了lua
目录当中
CMakeLists.txt
配置如下:
1 | # 限定cmake最小版本号 当前使用的版本必须在这个之上 |
编译工程后我们在build
目录可以查看到生成的程序:
将其push
到root
过的android
设备上即可正常运行
关于工程配置, 如有疑问 可参考文章《使用Android Studio进行C/C++的开发》
附加
Mac
平台上查看可执行文件的架构1
file 程序名 或 lipo –info 程序名
如果你的电脑安装了
xcode
, 那么可以使用xcrun
来查看sdk
路径查看当前平台
SDK
路径:1
xcrun --show-sdk-path
查看
iphone
平台SDK
路径:1
xcrun --sdk iphoneos --show-sdk-path
甚至可以用
xcrun
配合clang
简化编译指令:1
2
3xcrun -sdk iphoneos clang -arch arm64 -o main main.c
或者
clang -isysroot `xcrun --sdk iphoneos --show-sdk-path` main.c -o main -arch arm64以及本机平台
1
clang -isysroot `xcrun --show-sdk-path` main.c -o main -arch x86_64
目前
iphoneOS_SDK
支持的cpu
架构有1
2
3
4arm64
armv7s
armv7
armv6x86
系列处理器暂不支持
总结
关于GCC和Clang的使用对比:
GCC
会针对每一个编译主机和目标架构提供一套完整的套件,包含了二进制、头文件和库等。所以通常使用起来比较简单
而Clang
是复用一套编译系统去负责多个目标的编译任务,通过 -target
选项来区分, 各个平台对应的头文件和库需要自己单独准备 编译的时候将路径通过参数告知给Clang
, 使用起来相对会麻烦一些
本文为作者原创转载时请注明出处 谢谢