Chuỗi công cụ độc lập (lỗi thời)

Bạn có thể sử dụng các chuỗi công cụ được cung cấp kèm theo Android NDK một cách độc lập hoặc dưới dạng trình bổ trợ với một IDE hiện có. Khả năng linh hoạt này có thể hữu ích nếu bạn đã có hệ thống xây dựng riêng và chỉ cần khả năng gọi trình biên dịch chéo để thêm sự hỗ trợ vào Android cho hệ thống này.

Chọn chuỗi công cụ

Trước hết, bạn cần quyết định cấu trúc bộ xử lý mà chuỗi công cụ độc lập sẽ nhắm mục tiêu. Việc này được thực hiện bằng cờ --arch.

Chọn sysroot

Việc tiếp theo bạn cần làm là xác định sysroot. Sysroot là một thư mục chứa các tiêu đề hệ thống và thư viện đối với mục tiêu của bạn. Để xác định sysroot, bạn phải biết cấp độ Android API mà bạn muốn nhắm mục tiêu cho khả năng hỗ trợ gốc; API gốc có sẵn khác nhau tuỳ theo cấp độ Android API.

Thư viện dành cho API gốc của cấp độ Android API tương ứng nằm trong $NDK/platforms/; lần lượt, mỗi thư mục cấp API sẽ chứa các thư mục con cho nhiều CPU và cấu trúc. Các tiêu đề này nằm ở $NDK/sysroot.

Để biết thêm thông tin chi tiết về các cấp độ Android API và API gốc tương ứng mà những API này hỗ trợ, hãy xem phần API gốc.

Tạo chuỗi công cụ

NDK cung cấp tập lệnh make_standalone_toolchain.py để cho phép bạn cài đặt chuỗi công cụ được tuỳ chỉnh từ dòng lệnh.

Đây là công cụ mới thay thế cho make-standalone-toolchain.sh cũ. Công cụ này đã được tái triển khai trong Python sao cho người dùng Windows không cần cài đặt Cygwin hoặc MSYS để chạy.

Tập lệnh nằm trong thư mục $NDK/build/tools/, trong đó $NDK là thư mục cài đặt gốc của NDK.

Dưới đây là ví dụ về cách sử dụng tập lệnh này:

$NDK/build/tools/make_standalone_toolchain.py \
    --arch arm --api 21 --install-dir /tmp/my-android-toolchain

Lệnh này tạo một thư mục có tên /tmp/my-android-toolchain/, chứa một bản sao của sysroot android-21/arch-arm và các tệp nhị phân của chuỗi công cụ cho mục tiêu ARM 32 bit.

Lưu ý: Các tệp nhị phân của chuỗi công cụ không phụ thuộc hoặc chứa các đường dẫn dành riêng cho từng máy chủ. Nói cách khác, bạn có thể cài đặt các tệp này ở bất kỳ vị trí nào hoặc thậm chí di chuyển nếu cần.

Đối số --arch là bắt buộc, nhưng cấp độ API sẽ mặc định là cấp được hỗ trợ tối thiểu cho cấu trúc đã cho (hiện là 16 đối với cấu trúc 32 bit và 21 đối với cấu trúc 64 bit).

Kể từ r18, tất cả các chuỗi công cụ độc lập đều sử dụng Clang và libc++. Thư viện dùng chung libc++ sẽ được sử dụng theo mặc định trừ khi tạo một tệp thực thi tĩnh. Để buộc sử dụng thư viện tĩnh, hãy truyền -static-libstdc++ khi liên kết. Hành vi này khớp với hành vi của một chuỗi công cụ máy chủ lưu trữ thông thường.

Như đã đề cập trong phần Hỗ trợ thư viện C++, bạn thường sẽ cần truyền -latomic khi liên kết dựa trên libc++.

Xin lưu ý rằng nếu bạn bỏ qua tuỳ chọn --install-dir, công cụ sẽ tạo một tệp tar (tarball) trong thư mục hiện tại có tên là $TOOLCHAIN_NAME.tar.bz2. Bạn có thể đặt tệp tar này trong một thư mục khác bằng cách sử dụng --package-dir.

Để biết thêm tuỳ chọn và thông tin chi tiết, hãy sử dụng --help.

Làm việc với Clang

Tệp nhị phân Clang được tự động đưa vào các chuỗi công cụ độc lập.

Ngoài ra, còn có hai tập lệnh trình bao bọc tên là clangclang++ trong <install-dir>/bin. Các tập lệnh này gọi tệp nhị phân clang với các cờ cấu trúc mục tiêu chính xác. Nói cách khác, các tập lệnh này sẽ hoạt động mà không cần điều chỉnh và bạn có thể sử dụng chúng trong các bản dựng của riêng mình chỉ bằng cách đặt các biến môi trường CCCXX để trỏ đến các tập lệnh đó.

Ngoài ra, còn có các tập lệnh trình bao bọc tên là gccg++ cũng gọi là Clang. Điều này là để cung cấp một số mức độ tương thích cho các tệp xây dựng có đề cập rõ ràng đến GCC mặc dù NDK không còn chứa GCC. Rõ ràng là nếu một tệp bản dựng sử dụng các tuỳ chọn dòng lệnh mà Clang không hỗ trợ, bạn sẽ cần loại bỏ hoặc thay thế các tuỳ chọn đó.

Clang nhắm mục tiêu bằng ARM

Khi tạo cho ARM, Clang thay đổi mục tiêu dựa trên sự hiện diện của các cờ trình biên dịch -march=armv7-a và/hoặc -mthumb:

Bảng 1. Các giá trị -march có thể chỉ định và mục tiêu thu được.

Giá trị -march Mục tiêu thu được
-march=armv7-a armv7-none-linux-androideabi
-mthumb thumb-none-linux-androideabi
Cả -march=armv7-a-mthumb thumbv7-none-linux-androideabi

Bạn cũng có thể ghi đè bằng -target của riêng mình nếu muốn.

clangclang++ nên là bản thay thế bất chợt cho gccg++ trong một tệp makefile. Nếu nghi ngờ, hãy sử dụng các tuỳ chọn sau đây khi gọi trình biên dịch để xác minh rằng chúng đang hoạt động đúng cách:

  • -v để kết xuất các lệnh liên quan đến vấn đề về trình điều khiển của trình biên dịch
  • -### để kết xuất các tuỳ chọn dòng lệnh, bao gồm cả tuỳ chọn được xác định hoàn toàn từ trước.
  • -x c < /dev/null -dM -E để kết xuất định nghĩa của bộ xử lý trước được xác định trước
  • -save-temps để so sánh *.i hoặc tệp đã xử lý trước*.ii.

Khả năng tương thích với ABI

Theo mặc định, một chuỗi công cụ độc lập ARM Clang sẽ nhắm mục tiêu đến armeabi-v7a ABI. Bạn có thể ghi đè tuỳ chọn này bằng cách truyền tuỳ chọn -march hoặc -target thích hợp.

Bạn nên sử dụng cờ trình biên dịch -mthumb để buộc tạo hướng dẫn Thumb-2 16 bit. Nếu bạn bỏ qua, chuỗi công cụ sẽ phát hướng dẫn ARM 32 bit.

Để sử dụng hướng dẫn NEON, bạn phải sử dụng cờ trình biên dịch -mfpu: -mfpu=neon.

Lưu ý: Chế độ cài đặt này bắt buộc sử dụng VFPv3-D32 theo thông số kỹ thuật ARM.

Ngoài ra, hãy nhớ cung cấp hai cờ sau cho trình liên kết: -march=armv7-a -Wl,--fix-cortex-a8.

Cờ đầu tiên hướng dẫn trình liên kết chọn các thư viện chuỗi công cụ được tạo riêng cho armv7-a. Cờ thứ 2 là bắt buộc để khắc phục lỗi CPU trong một số hoạt động triển khai Cortex-A8.

Bạn không phải sử dụng bất kỳ cờ trình biên dịch cụ thể nào khi nhắm mục tiêu đến ABI khác.

Để tìm hiểu thêm về khả năng hỗ trợ ABI, hãy xem bài viết ABI Android.

Cảnh báo và giới hạn

Hỗ trợ Windows

Các tệp nhị phân trên Windows không phụ thuộc vào Cygwin. Việc thiếu phần phụ thuộc này làm cho các tệp nhị phân này nhanh hơn. Tuy nhiên, cái giá kèm theo các tệp này không hiểu được các thông số kỹ thuật của đường dẫn Cygwin như cygdrive/c/foo/bar, chứ không phải C:/foo/bar.

Ngoại lệ, RTTI và STL

Các tệp nhị phân của chuỗi công cụ hỗ trợ ngoại lệ đối với C++ và RTTI theo mặc định. Để tắt các trường hợp ngoại lệ C++ và RTTI khi tạo nguồn (ví dụ: để tạo mã máy nhẹ hơn), hãy sử dụng -fno-exceptions-fno-rtti.

Hỗ trợ STL C++

Chuỗi công cụ độc lập bao gồm hoạt động triển khai Thư viện mẫu chuẩn (STL) C++.

  • Sử dụng -static-libstdc++ để tải phiên bản thư viện tĩnh của libc++. Làm như vậy để đảm bảo rằng tất cả mã STL C++ bắt buộc đều được đưa vào tệp nhị phân cuối cùng. Đây là phương thức lý tưởng nếu bạn chỉ đang tạo một thư viện dùng chung hoặc tệp thực thi, cũng là đề xuất của chúng tôi.

  • Phiên bản thư viện dùng chung của libc++ sẽ được dùng theo mặc định. Bạn không cần gắn cờ nào khác để liên kết dựa trên thư viện dùng chung. Bạn phải đóng gói libc++_shared.so trong ứng dụng. Nếu không, mã của bạn sẽ không tải được.

    Bảng 2 cho thấy vị trí của tệp này cho từng cấu trúc.

    Bảng 2. Các giá trị -march có thể chỉ định và mục tiêu thu được.

    Chuỗi công cụ Vị trí
    arm $TOOLCHAIN/arm-linux-androideabi/lib/
    arm64 $TOOLCHAIN/aarch64-linux-android/lib/
    x86 $TOOLCHAIN/i686-linux-android/lib/
    x86_64 $TOOLCHAIN/x86_64-linux-android/lib/

Xây dựng các dự án nguồn mở bằng chuỗi công cụ độc lập

Cho chuỗi công cụ ví dụ sau:

# Create an arm64 API 26 libc++ toolchain.
$NDK/build/tools/make_standalone_toolchain.py \
  --arch arm64 \
  --api 26 \
  --install-dir=my-toolchain

Dưới đây là cách bạn sẽ thiết lập môi trường để sử dụng chuỗi công cụ nhằm xây dựng một dự án nguồn mở truyền thống:

# Add the standalone toolchain to the search path.
export PATH=$PATH:`pwd`/my-toolchain/bin

# Tell configure what tools to use.
target_host=aarch64-linux-android
export AR=$target_host-ar
export AS=$target_host-clang
export CC=$target_host-clang
export CXX=$target_host-clang++
export LD=$target_host-ld
export STRIP=$target_host-strip

# Tell configure what flags Android requires.
export CFLAGS="-fPIE -fPIC"
export LDFLAGS="-pie"

Các dự án có hệ thống xây dựng tuỳ chỉnh

Ví dụ: Dưới đây là cách xây dựng toybox sau khi thực hiện các bước trước đó:

git clone https://github.com/landley/toybox.git
cd toybox
make defconfig && make

Các dự án có autoconf

Ngoài ra, một dự án dựa trên autoconf sẽ có dạng như sau:

tar zxvf make-4.2.tar.gz
cd make-4.2
./configure --host=$target_host && make

Lưu ý: Các dự án dựa trên autoconf rất khác nhau về khả năng hỗ trợ biên dịch chéo. Ngoài ra, xin lưu ý rằng nếu bạn git clone một dự án dựa trên autoconf, thì rất ít khả năng sẽ có tập lệnh configure được đăng ký, vì vậy bạn sẽ phải làm theo tài liệu của dự án đó để biết cách tự khởi động.