How to Cross Compile C Program for ARM
Table of Contents
1. 简介
本文介绍如何在 x86_64 Linux 平台(Ubuntu 22.04.1 LTS)上编译出可以在 ARM Linux 平台中运行的程序,也就是进行所谓的交叉编译。
2. ARM Linux 交叉编译器
2.1. GCC 三种 ARM 交叉编译器
GCC 有 ARM 三种架构的交叉编译器,如表 1 所示。
ARM Architecture | GCC 交叉编译器 | 说明 |
---|---|---|
ARM EABI (armel) | gcc-arm-linux-gnueabi | Older 32-bit ARM processors without hardware FPU |
ARM hard-float (armhf) | gcc-arm-linux-gnueabihf | Modern ARM 32-bit processors that implement at least the ARMv7 architecture |
64-bit ARM (arm64) | gcc-aarch64-linux-gnu | ARM 64-bit processors that implement at least the ARMv8 architecture |
2.2. 安装交叉编译器
在进行交叉编译前,需要先在 x86_64 Linux 中安装交叉编译器。
下面是 ARM 交叉编译器的安装方法(你可以根据自己的需要安装其中一个或多个):
$ sudo apt install gcc-arm-linux-gnueabi # 安装目标运行平台为 armel(older arm32 processor)的交叉编译器 $ sudo apt install gcc-arm-linux-gnueabihf # 安装目标运行平台为 armhf(modern arm32 processor)的交叉编译器 $ sudo apt install gcc-aarch64-linux-gnu # 安装目标运行平台为 arm64 的交叉编译器
安装完 gcc-arm-linux-gnueabi 后,会在目录 /usr/bin 中创建很多以 arm-linux-gnueabi- 开头的编译工具;在目录 /usr/arm-linux-gnueabi 中创建 armel 平台的头文件和动态库和静态库:
$ ls /usr/bin/arm-linux-gnueabi-* # /usr/bin/ 中有很多以 arm-linux-gnueabi- 开头的编译工具 /usr/bin/arm-linux-gnueabi-addr2line /usr/bin/arm-linux-gnueabi-gcc-nm /usr/bin/arm-linux-gnueabi-ld.bfd /usr/bin/arm-linux-gnueabi-ar /usr/bin/arm-linux-gnueabi-gcc-nm-11 /usr/bin/arm-linux-gnueabi-ld.gold /usr/bin/arm-linux-gnueabi-as /usr/bin/arm-linux-gnueabi-gcc-ranlib /usr/bin/arm-linux-gnueabi-lto-dump-11 /usr/bin/arm-linux-gnueabi-c++filt /usr/bin/arm-linux-gnueabi-gcc-ranlib-11 /usr/bin/arm-linux-gnueabi-nm /usr/bin/arm-linux-gnueabi-cpp /usr/bin/arm-linux-gnueabi-gcov /usr/bin/arm-linux-gnueabi-objcopy /usr/bin/arm-linux-gnueabi-cpp-11 /usr/bin/arm-linux-gnueabi-gcov-11 /usr/bin/arm-linux-gnueabi-objdump /usr/bin/arm-linux-gnueabi-dwp /usr/bin/arm-linux-gnueabi-gcov-dump /usr/bin/arm-linux-gnueabi-ranlib /usr/bin/arm-linux-gnueabi-elfedit /usr/bin/arm-linux-gnueabi-gcov-dump-11 /usr/bin/arm-linux-gnueabi-readelf /usr/bin/arm-linux-gnueabi-gcc /usr/bin/arm-linux-gnueabi-gcov-tool /usr/bin/arm-linux-gnueabi-size /usr/bin/arm-linux-gnueabi-gcc-11 /usr/bin/arm-linux-gnueabi-gcov-tool-11 /usr/bin/arm-linux-gnueabi-strings /usr/bin/arm-linux-gnueabi-gcc-ar /usr/bin/arm-linux-gnueabi-gprof /usr/bin/arm-linux-gnueabi-strip /usr/bin/arm-linux-gnueabi-gcc-ar-11 /usr/bin/arm-linux-gnueabi-ld $ ls /usr/arm-linux-gnueabi/ # armel 平台的头文件和动态库和静态库 bin include lib
类似地,安装完 gcc-arm-linux-gnueabihf 后,会在目录 /usr/bin 中会创建很多以 arm-linux-gnueabihf- 开头的编译工具;在目录 /usr/arm-linux-gnueabihf 中会创建 armhf 平台的头文件和动态库和静态库:
$ ls /usr/bin/arm-linux-gnueabihf-* # /usr/bin/ 中有很多以 arm-linux-gnueabihf- 开头的编译工具 /usr/bin/arm-linux-gnueabihf-addr2line /usr/bin/arm-linux-gnueabihf-gcc-nm /usr/bin/arm-linux-gnueabihf-ld.bfd /usr/bin/arm-linux-gnueabihf-ar /usr/bin/arm-linux-gnueabihf-gcc-nm-11 /usr/bin/arm-linux-gnueabihf-ld.gold /usr/bin/arm-linux-gnueabihf-as /usr/bin/arm-linux-gnueabihf-gcc-ranlib /usr/bin/arm-linux-gnueabihf-lto-dump-11 /usr/bin/arm-linux-gnueabihf-c++filt /usr/bin/arm-linux-gnueabihf-gcc-ranlib-11 /usr/bin/arm-linux-gnueabihf-nm /usr/bin/arm-linux-gnueabihf-cpp /usr/bin/arm-linux-gnueabihf-gcov /usr/bin/arm-linux-gnueabihf-objcopy /usr/bin/arm-linux-gnueabihf-cpp-11 /usr/bin/arm-linux-gnueabihf-gcov-11 /usr/bin/arm-linux-gnueabihf-objdump /usr/bin/arm-linux-gnueabihf-dwp /usr/bin/arm-linux-gnueabihf-gcov-dump /usr/bin/arm-linux-gnueabihf-ranlib /usr/bin/arm-linux-gnueabihf-elfedit /usr/bin/arm-linux-gnueabihf-gcov-dump-11 /usr/bin/arm-linux-gnueabihf-readelf /usr/bin/arm-linux-gnueabihf-gcc /usr/bin/arm-linux-gnueabihf-gcov-tool /usr/bin/arm-linux-gnueabihf-size /usr/bin/arm-linux-gnueabihf-gcc-11 /usr/bin/arm-linux-gnueabihf-gcov-tool-11 /usr/bin/arm-linux-gnueabihf-strings /usr/bin/arm-linux-gnueabihf-gcc-ar /usr/bin/arm-linux-gnueabihf-gprof /usr/bin/arm-linux-gnueabihf-strip /usr/bin/arm-linux-gnueabihf-gcc-ar-11 /usr/bin/arm-linux-gnueabihf-ld $ ls /usr/arm-linux-gnueabihf/ # armhf 平台的头文件和动态库和静态库 bin include lib
同样地,安装完 gcc-aarch64-linux-gnu 后,会在目录 /usr/bin 中会创建很多以 aarch64-linux-gnu- 开头的编译工具;在目录 /usr/aarch64-linux-gnu 中会创建 arm64 平台的头文件和动态库和静态库:
$ ls /usr/bin/aarch64-linux-gnu-* # /usr/bin/ 中有很多以 aarch64-linux-gnu- 开头的编译工具 /usr/bin/aarch64-linux-gnu-addr2line /usr/bin/aarch64-linux-gnu-gcc-nm /usr/bin/aarch64-linux-gnu-ld.bfd /usr/bin/aarch64-linux-gnu-ar /usr/bin/aarch64-linux-gnu-gcc-nm-11 /usr/bin/aarch64-linux-gnu-ld.gold /usr/bin/aarch64-linux-gnu-as /usr/bin/aarch64-linux-gnu-gcc-ranlib /usr/bin/aarch64-linux-gnu-lto-dump-11 /usr/bin/aarch64-linux-gnu-c++filt /usr/bin/aarch64-linux-gnu-gcc-ranlib-11 /usr/bin/aarch64-linux-gnu-nm /usr/bin/aarch64-linux-gnu-cpp /usr/bin/aarch64-linux-gnu-gcov /usr/bin/aarch64-linux-gnu-objcopy /usr/bin/aarch64-linux-gnu-cpp-11 /usr/bin/aarch64-linux-gnu-gcov-11 /usr/bin/aarch64-linux-gnu-objdump /usr/bin/aarch64-linux-gnu-dwp /usr/bin/aarch64-linux-gnu-gcov-dump /usr/bin/aarch64-linux-gnu-ranlib /usr/bin/aarch64-linux-gnu-elfedit /usr/bin/aarch64-linux-gnu-gcov-dump-11 /usr/bin/aarch64-linux-gnu-readelf /usr/bin/aarch64-linux-gnu-gcc /usr/bin/aarch64-linux-gnu-gcov-tool /usr/bin/aarch64-linux-gnu-size /usr/bin/aarch64-linux-gnu-gcc-11 /usr/bin/aarch64-linux-gnu-gcov-tool-11 /usr/bin/aarch64-linux-gnu-strings /usr/bin/aarch64-linux-gnu-gcc-ar /usr/bin/aarch64-linux-gnu-gprof /usr/bin/aarch64-linux-gnu-strip /usr/bin/aarch64-linux-gnu-gcc-ar-11 /usr/bin/aarch64-linux-gnu-ld $ ls /usr/aarch64-linux-gnu/ # aarch64 平台(arm64)的头文件和动态库和静态库 bin include lib
2.3. 交叉编译实例(无第 3 方库)
假设有下面 C 程序:
#include <stdio.h> int main() { printf("Hello, World!"); return 0; }
编译程序:
$ gcc hello.c -o hello # 这不是交叉编译,目标程序只能在当前平台(x86_64)运行 $ arm-linux-gnueabi-gcc hello.c -o hello.armel # 交叉编译,目标程序可在 armel 平台运行 $ arm-linux-gnueabihf-gcc hello.c -o hello.armhf # 交叉编译,目标程序可在 armhf 平台运行 $ aarch64-linux-gnu-gcc hello.c -o hello.aarch64 # 交叉编译,目标程序可在 arm64 平台运行
2.4. 交叉编译实例(依赖于 OpenSSL)
假设有下面使用了 OpenSSL 的 C 程序:
#include <stdio.h> #include <openssl/evp.h> int digest_message(const unsigned char *message, size_t message_len, const char *digest_name, unsigned char *digest, unsigned int *digest_len) { EVP_MD_CTX *mdctx; const EVP_MD *md; if ((mdctx = EVP_MD_CTX_new()) == NULL) { return -1; } if ((md = EVP_get_digestbyname(digest_name)) == NULL) { return -1; } EVP_DigestInit_ex(mdctx, md, NULL); EVP_DigestUpdate(mdctx, message, message_len); EVP_DigestFinal_ex(mdctx, digest, digest_len); EVP_MD_CTX_free(mdctx); return 0; } void dumphex(const unsigned char *src, size_t len) { size_t i; for (i = 0; i < len; i++) { fprintf(stderr, "%02x", src[i]); } printf("\n"); } int main() { unsigned char input[3] = {'a', 'b', 'c'}; unsigned char hash_outbuf[EVP_MAX_MD_SIZE]; unsigned int hash_len; digest_message(input, 3, "md5", hash_outbuf, &hash_len); fprintf(stderr, "md5(abc):\t"); dumphex(hash_outbuf, hash_len); // 900150983cd24fb0d6963f7d28e17f72 fprintf(stderr, "sha256(abc):\t"); digest_message(input, 3, "sha256", hash_outbuf, &hash_len); dumphex(hash_outbuf, hash_len); // ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad return 0; }
如果当前系统(x86_64 Linux)中安装了 OpenSSL 开发库(sudo apt install libssl-dev),这时我们能编译出能在当前平台(x86_64)运行的可执行程序;但还不能进行交叉编译,会报错:
$ gcc openssl_example.c -lcrypto -o openssl_example # 这不是交叉编译,目标程序只能在当前平台(x86_64)运行 $ arm-linux-gnueabi-gcc openssl_example.c -lcrypto -o openssl_example.armel # 交叉编译会失败,因为 /usr/arm-linux-gnueabi 中没有 OpenSSL 相关头文件和库文件 In file included from /usr/include/openssl/evp.h:14, from openssl_example.c:2: /usr/include/openssl/macros.h:14:10: fatal error: openssl/opensslconf.h: No such file or directory 14 | #include <openssl/opensslconf.h> | ^~~~~~~~~~~~~~~~~~~~~~~ compilation terminated $ arm-linux-gnueabihf-gcc openssl_example.c -lcrypto -o openssl_example.armhf # 交叉编译会失败,因为 /usr/arm-linux-gnueabihf 中没有 OpenSSL 相关头文件和库文件 In file included from /usr/include/openssl/evp.h:14, from openssl_example.c:2: /usr/include/openssl/macros.h:14:10: fatal error: openssl/opensslconf.h: No such file or directory 14 | #include <openssl/opensslconf.h> | ^~~~~~~~~~~~~~~~~~~~~~~ compilation terminated $ aarch64-linux-gnu-gcc openssl_example.c -lcrypto -o openssl_example.aarch64 # 交叉编译会失败,因为 /usr/aarch64-linux-gnu 中没有 OpenSSL 相关头文件和库文件 In file included from /usr/include/openssl/evp.h:14, from openssl_example.c:2: /usr/include/openssl/macros.h:14:10: fatal error: openssl/opensslconf.h: No such file or directory 14 | #include <openssl/opensslconf.h> | ^~~~~~~~~~~~~~~~~~~~~~~ compilation terminated
这是因为对于交叉编译器 arm-linux-gnueabi-gcc(或 arm-linux-gnueabihf-gcc 或 aarch64-linux-gnu-gcc)来说,它们读取头文件和库文件的目录是 /usr/arm-linux-gnueabi(或 /usr/arm-linux-gnueabihf 或 /usr/aarch64-linux-gnu)。我们需要把 OpenSSL 的头文件和库文件安装到这些目录中。
2.4.1. 交叉编译 OpenSSL
要交叉编译使用了 OpenSSL 的 C 程序,需要在 /usr/arm-linux-gnueabi(或 /usr/arm-linux-gnueabihf 或 /usr/aarch64-linux-gnu)中安装 OpenSSL 相关头文件和库文件。
下面介绍一下如何从 OpenSSL 源码开始,编译和安装 aarch64 平台(arm64)使用的 OpenSSL 头文件和库文件到目录 /usr/aarch64-linux-gnu 中:
$ curl -LO https://github.com/openssl/openssl/releases/download/OpenSSL_1_1_1w/openssl-1.1.1w.tar.gz $ tar -xzf openssl-1.1.1w.tar.gz $ cd openssl-1.1.1w $ ./Configure linux-aarch64 --cross-compile-prefix=aarch64-linux-gnu- --prefix=/usr/aarch64-linux-gnu Configuring OpenSSL version 1.1.1w (0x1010117fL) for linux-aarch64 Using os-specific seed configuration Creating configdata.pm Creating Makefile ********************************************************************** *** *** *** OpenSSL has been successfully configured *** *** *** *** If you encounter a problem while building, please open an *** *** issue on GitHub <https://github.com/openssl/openssl/issues> *** *** and include the output from the following command: *** *** *** *** perl configdata.pm --dump *** *** *** *** (If you are new to OpenSSL, you might want to consult the *** *** 'Troubleshooting' section in the INSTALL file first) *** *** *** ********************************************************************** $ make $ sudo make install
如果要编译和安装 armel 平台使用的 OpenSSL 头文件和库文件到目录 /usr/arm-linux-gnueabi 中,则可以指定不同参数重新执行 ./Configure 后再运行 make:
$ make distclean $ ./Configure linux-armv4 --cross-compile-prefix=arm-linux-gnueabi- --prefix=/usr/arm-linux-gnueabi $ make $ sudo make install
如果要编译和安装 armhf 平台使用的 OpenSSL 头文件和库文件到目录 /usr/arm-linux-gnueabihf 中,则可以指定不同参数重新执行 ./Configure 后再运行 make:
$ make distclean $ ./Configure linux-armv4 --cross-compile-prefix=arm-linux-gnueabihf- --prefix=/usr/arm-linux-gnueabihf -march=armv7-a $ make $ sudo make install
当 OpenSSL 相关头文件和库文件已经安装到交叉编译器的各个目录中后,现在可以成功编译前面的例子了:
$ arm-linux-gnueabi-gcc openssl_example.c -lcrypto -o openssl_example.armel # 交叉编译成功,目标程序可在 armel 平台运行 $ arm-linux-gnueabihf-gcc openssl_example.c -lcrypto -o openssl_example.armhf # 交叉编译成功,目标程序可在 armhf 平台运行 $ aarch64-linux-gnu-gcc openssl_example.c -lcrypto -o openssl_example.aarch64 # 交叉编译成功,目标程序可在 arm64 平台运行
2.5. 交叉编译实例(依赖于 GMP)
假设有下面使用了 GMP 的 C 程序:
#include <stdio.h> #include <gmp.h> #include <assert.h> int main(){ char inputStr[1024]; /* mpz_t is the type defined for GMP integers. It is a pointer to the internals of the GMP integer data structure */ mpz_t n; int flag; printf ("Enter your number: "); scanf("%1023s" , inputStr); /* NOTE: never every write a call scanf ("%s", inputStr); You are leaving a security hole in your code. */ /* 1. Initialize the number */ mpz_init(n); mpz_set_ui(n,0); /* 2. Parse the input string as a base 10 number */ flag = mpz_set_str(n,inputStr, 10); assert (flag == 0); /* If flag is not 0 then the operation failed */ /* Print n */ printf ("n = "); mpz_out_str(stdout,10,n); printf ("\n"); /* 3. Add one to the number */ mpz_add_ui(n,n,1); /* n = n + 1 */ /* 4. Print the result */ printf (" n +1 = "); mpz_out_str(stdout,10,n); printf ("\n"); /* 5. Square n+1 */ mpz_mul(n,n,n); /* n = n * n */ printf (" (n +1)^2 = "); mpz_out_str(stdout,10,n); printf ("\n"); /* 6. Clean up the mpz_t handles or else we will leak memory */ mpz_clear(n); }
如果当前系统(x86_64 Linux)中安装了 GMP 开发库(sudo apt install libgmp-dev),这时我们能编译出能在当前平台(x86_64)运行的可执行程序;但还不能进行交叉编译,会报错:
$ gcc gmp_example.c -lgmp -o gmp_example # 这不是交叉编译,目标程序只能在当前平台(x86_64)运行 $ arm-linux-gnueabi-gcc gmp_example.c -lgmp -o gmp_example.armel # 交叉编译会失败,因为 /usr/arm-linux-gnueabi 中没有 GMP 相关头文件和库文件 gmp_example.c:2:10: fatal error: gmp.h: No such file or directory 2 | #include <gmp.h> | ^~~~~~~ compilation terminated. $ arm-linux-gnueabihf-gcc gmp_example.c -lgmp -o gmp_example.armhf # 交叉编译会失败,因为 /usr/arm-linux-gnueabihf 中没有 GMP 相关头文件和库文件 gmp_example.c:2:10: fatal error: gmp.h: No such file or directory 2 | #include <gmp.h> | ^~~~~~~ compilation terminated. $ aarch64-linux-gnu-gcc gmp_example.c -lgmp -o gmp_example.aarch64 # 交叉编译会失败,因为 /usr/aarch64-linux-gnu 中没有 GMP 相关头文件和库文件 gmp_example.c:2:10: fatal error: gmp.h: No such file or directory 2 | #include <gmp.h> | ^~~~~~~ compilation terminated.
这是因为对于交叉编译器 arm-linux-gnueabi-gcc(或 arm-linux-gnueabihf-gcc 或 aarch64-linux-gnu-gcc)来说,它们读取头文件和库文件的目录是 /usr/arm-linux-gnueabi(或 /usr/arm-linux-gnueabihf 或 /usr/aarch64-linux-gnu)。我们需要把 GMP 的头文件和库文件安装到这些目录中。
2.5.1. 交叉编译 GMP
要交叉编译使用了 GMP 的 C 程序,需要在 /usr/arm-linux-gnueabi(或 /usr/arm-linux-gnueabihf 或 /usr/aarch64-linux-gnu)中安装 GMP 相关头文件和库文件。
下面介绍一下如何从 GMP 源码开始,编译和安装 aarch64 平台(arm64)使用的 OpenSSL 头文件和库文件到目录 /usr/aarch64-linux-gnu 中:
$ curl -LO https://gmplib.org/download/gmp/gmp-6.3.0.tar.xz $ tar -xJf gmp-6.3.0.tar.xz $ cd gmp-6.3.0 $ ./configure --prefix=/usr/aarch64-linux-gnu --build=x86_64-pc-linux-gnu --host=aarch64-linux-gnu $ make $ sudo make install
如果要安装 armel 平台使用的 GMP 头文件和库文件到目录 /usr/arm-linux-gnueabi 中,则可以指定不同参数重新执行 ./configure 后再运行 make:
$ make distclean $ ./configure --prefix=/usr/arm-linux-gnueabi --build=x86_64-pc-linux-gnu --host=arm-linux-gnueabi $ make $ sudo make install
如果要安装 armhf 平台使用的 GMP 头文件和库文件到目录 /usr/arm-linux-gnueabihf 中,则可以指定不同参数重新执行 ./configure 后再运行 make:
$ make distclean $ ./configure --prefix=/usr/arm-linux-gnueabihf --build=x86_64-pc-linux-gnu --host=arm-linux-gnueabihf $ make $ sudo make install
当 GMP 相关头文件和库文件已经安装到交叉编译器的各个目录中后,现在可以成功编译前面的例子了:
$ arm-linux-gnueabi-gcc gmp_example.c -lgmp -o gmp_example.armel # 交叉编译成功,目标程序可在 armel 平台运行 $ arm-linux-gnueabihf-gcc gmp_example.c -lgmp -o gmp_example.armhf # 交叉编译成功,目标程序可在 armhf 平台运行 $ aarch64-linux-gnu-gcc gmp_example.c -lgmp -o gmp_example.aarch64 # 交叉编译成功,目标程序可在 arm64 平台运行
3. ARM Android 交叉编译器
Android NDK 中包含有 ARM Android 的交叉编译器。MacOS 中安装 Android NDK 26.1.10909125 后,其交叉编译器位置如下:
$ ls $HOME/Library/Android/sdk/ndk/26.1.10909125/toolchains/llvm/prebuilt/darwin-x86_64/bin aarch64-linux-android21-clang clang llvm-dwp aarch64-linux-android21-clang++ clang++ llvm-ifs aarch64-linux-android22-clang clang-17 llvm-lib aarch64-linux-android22-clang++ clang-check llvm-link aarch64-linux-android23-clang clang-cl llvm-lipo aarch64-linux-android23-clang++ clang-format llvm-ml aarch64-linux-android24-clang clang-tidy llvm-modextract aarch64-linux-android24-clang++ clangd llvm-nm aarch64-linux-android25-clang dsymutil llvm-objcopy aarch64-linux-android25-clang++ git-clang-format llvm-objdump aarch64-linux-android26-clang i686-linux-android21-clang llvm-profdata aarch64-linux-android26-clang++ i686-linux-android21-clang++ llvm-ranlib aarch64-linux-android27-clang i686-linux-android22-clang llvm-rc aarch64-linux-android27-clang++ i686-linux-android22-clang++ llvm-readelf aarch64-linux-android28-clang i686-linux-android23-clang llvm-readobj aarch64-linux-android28-clang++ i686-linux-android23-clang++ llvm-size aarch64-linux-android29-clang i686-linux-android24-clang llvm-strings aarch64-linux-android29-clang++ i686-linux-android24-clang++ llvm-strip aarch64-linux-android30-clang i686-linux-android25-clang llvm-symbolizer aarch64-linux-android30-clang++ i686-linux-android25-clang++ llvm-windres aarch64-linux-android31-clang i686-linux-android26-clang merge-fdata aarch64-linux-android31-clang++ i686-linux-android26-clang++ sancov aarch64-linux-android32-clang i686-linux-android27-clang sanstats aarch64-linux-android32-clang++ i686-linux-android27-clang++ scan-build aarch64-linux-android33-clang i686-linux-android28-clang scan-view aarch64-linux-android33-clang++ i686-linux-android28-clang++ x86_64-linux-android21-clang aarch64-linux-android34-clang i686-linux-android29-clang x86_64-linux-android21-clang++ aarch64-linux-android34-clang++ i686-linux-android29-clang++ x86_64-linux-android22-clang armv7a-linux-androideabi21-clang i686-linux-android30-clang x86_64-linux-android22-clang++ armv7a-linux-androideabi21-clang++ i686-linux-android30-clang++ x86_64-linux-android23-clang armv7a-linux-androideabi22-clang i686-linux-android31-clang x86_64-linux-android23-clang++ armv7a-linux-androideabi22-clang++ i686-linux-android31-clang++ x86_64-linux-android24-clang armv7a-linux-androideabi23-clang i686-linux-android32-clang x86_64-linux-android24-clang++ armv7a-linux-androideabi23-clang++ i686-linux-android32-clang++ x86_64-linux-android25-clang armv7a-linux-androideabi24-clang i686-linux-android33-clang x86_64-linux-android25-clang++ armv7a-linux-androideabi24-clang++ i686-linux-android33-clang++ x86_64-linux-android26-clang armv7a-linux-androideabi25-clang i686-linux-android34-clang x86_64-linux-android26-clang++ armv7a-linux-androideabi25-clang++ i686-linux-android34-clang++ x86_64-linux-android27-clang armv7a-linux-androideabi26-clang ld x86_64-linux-android27-clang++ armv7a-linux-androideabi26-clang++ ld.lld x86_64-linux-android28-clang armv7a-linux-androideabi27-clang ld64.lld x86_64-linux-android28-clang++ armv7a-linux-androideabi27-clang++ lld x86_64-linux-android29-clang armv7a-linux-androideabi28-clang lld-link x86_64-linux-android29-clang++ armv7a-linux-androideabi28-clang++ lldb x86_64-linux-android30-clang armv7a-linux-androideabi29-clang lldb-argdumper x86_64-linux-android30-clang++ armv7a-linux-androideabi29-clang++ lldb.sh x86_64-linux-android31-clang armv7a-linux-androideabi30-clang llvm-addr2line x86_64-linux-android31-clang++ armv7a-linux-androideabi30-clang++ llvm-ar x86_64-linux-android32-clang armv7a-linux-androideabi31-clang llvm-as x86_64-linux-android32-clang++ armv7a-linux-androideabi31-clang++ llvm-bolt x86_64-linux-android33-clang armv7a-linux-androideabi32-clang llvm-cfi-verify x86_64-linux-android33-clang++ armv7a-linux-androideabi32-clang++ llvm-config x86_64-linux-android34-clang armv7a-linux-androideabi33-clang llvm-cov x86_64-linux-android34-clang++ armv7a-linux-androideabi33-clang++ llvm-cxxfilt yasm armv7a-linux-androideabi34-clang llvm-dis armv7a-linux-androideabi34-clang++ llvm-dwarfdump
3.1. 交叉编译 Android 平台 OpenSSL
假定 Android NDK 已经完成安装,下面介绍如何在 MacOS 中编译 Android ARM64 平台的 OpenSSL 库。
$ cd $HOME/test/ $ curl -LO https://github.com/openssl/openssl/releases/download/openssl-3.2.0/openssl-3.2.0.tar.gz $ tar -xzf openssl-3.2.0.tar.gz $ cd openssl-3.2.0 $ $ export ANDROID_NDK_ROOT=$HOME/Library/Android/sdk/ndk/26.1.10909125 $ export PATH=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/darwin-x86_64/bin:$PATH $ ./Configure android-arm64 -D__ANDROID_API__=29 --prefix=$HOME/test/openssl-3.2.0/output $ make $ make install
成功执行上面命令后,编译出来的 OpenSSL 库文件(包含静态库和动态库)会保存到 --prefix
参数所指定的目录中。
注意,在编译 Android 平台 OpenSSL 库时不需要设置参数 --cross-compile-prefix
,脚本会根据其它参数自动判断,参考:https://github.com/openssl/openssl/blob/openssl-3.2.0/NOTES-ANDROID.md