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 所示。

Table 1: ARM 三种架构对应的 GCC 交叉编译器
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

参考:https://www.debian.org/ports/arm/index.en.html

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

4. 参考

Author: cig01

Created: <2023-11-24 Fri>

Last updated: <2023-11-29 Wed>

Creator: Emacs 27.1 (Org mode 9.4)