Você pode usar os conjuntos de ferramentas fornecidos com o Android NDK de forma independente ou como plug-ins com um ambiente de desenvolvimento integrado já existente. Essa flexibilidade pode ser útil se você já tem um sistema de compilação próprio e só precisa do recurso para invocar o compilador cruzado a fim de incluir a compatibilidade com o Android.
Selecionar o conjunto de ferramentas
Antes de tudo, é preciso escolher a que arquitetura de processador o
conjunto de ferramentas autônomo será destinado. Isso pode ser feito com a sinalização --arch
.
Selecionar o sysroot
O próximo passo é definir seu sysroot. O sysroot é um diretório que contém os cabeçalhos e as bibliotecas do sistema para seu destino. Para definir o sysroot, é necessário saber para qual nível da API do Android você oferecerá compatibilidade nativa. As APIs nativas disponíveis variam de acordo com o nível da API do Android.
As bibliotecas para APIs nativas dos respectivos níveis da API do Android (link em inglês) ficam em
$NDK/platforms/
. Cada diretório no nível da API contém subdiretórios
para as CPUs e arquiteturas diversas. Os cabeçalhos residem em $NDK/sysroot
.
Para saber mais sobre os níveis da API do Android e as respectivas APIs nativas compatíveis, consulte APIs nativas.
Criar o conjunto de ferramentas
O NDK oferece o script make_standalone_toolchain.py
para instalação de um
conjunto de ferramentas personalizado pela linha de comando.
Essa é uma nova ferramenta que substitui make-standalone-toolchain.sh
. Ela foi reimplementada em Python para que os usuários do Windows não precisem instalar o Cygwin ou MSYS (links em inglês) para executar a ferramenta.
O script está localizado no diretório $NDK/build/tools/
, em que $NDK
é a raiz da instalação do NDK.
Veja um exemplo do uso desse script:
$NDK/build/tools/make_standalone_toolchain.py \
--arch arm --api 21 --install-dir /tmp/my-android-toolchain
Esse comando cria um diretório chamado /tmp/my-android-toolchain/
, contendo uma cópia do sysroot android-21/arch-arm
e dos binários do conjunto de ferramentas para ARM de 32 bits.
Os binários do conjunto de ferramentas não dependem nem contêm caminhos específicos para o host. Em outras palavras, é possível instalá-los em qualquer local ou até movê-los, se necessário.
O argumento --arch
é obrigatório, mas o nível da API padrão será o mínimo compatível com a arquitetura (atualmente, 16 para arquiteturas de 32 bits e 21 para arquiteturas de 64 bits).
Desde a versão r18, todos os conjuntos de ferramentas autônomos usam Clang e libc++. Por padrão, a biblioteca compartilhada libc++ será usada, exceto durante a compilação de executáveis estáticos. Para forçar o uso da biblioteca estática, transmita -static-libstdc++
durante a vinculação. Esse
comportamento corresponde ao de um conjunto de ferramentas de host normal.
Como mencionado em Compatibilidade com a biblioteca C++, normalmente é necessário
transmitir -latomic
ao fazer vinculação com a libc++.
Se a opção --install-dir
for omitida, a ferramenta criará um tarball
chamado $TOOLCHAIN_NAME.tar.bz2
no diretório atual. É possível colocar o tarball em um diretório diferente usando a opção --package-dir
.
Para ver mais opções e detalhes, use --help
.
Trabalhar com Clang
Os binários do Clang são incluídos automaticamente nos conjuntos de ferramentas autônomos.
Há também dois scripts de wrapper chamados clang
e clang++
em <install-dir>/bin
. Esses scripts invocam o binário clang
com as sinalizações de arquitetura apropriadas. Em outras palavras, eles precisam funcionar sem exigir nenhuma modificação, e você poderá usá-los nas suas compilações simplesmente configurando as variáveis de ambiente CC
e CXX
para apontar para eles.
Há também os scripts de wrapper gcc
e g++
, que também chamam o Clang.
Eles fornecem certo nível de compatibilidade para arquivos de compilação que se referem explicitamente ao GCC, embora o NDK não contenha mais o GCC. Obviamente, se um arquivo de compilação usar opções de linha de comando não compatíveis com o Clang, será necessário removê-las ou substituí-las.
Alvos do Clang com ARM
Em compilações para ARM, o Clang altera o alvo com base na presença das sinalizações de compilador -march=armv7-a
e/ou -mthumb
:
Tabela 1. Valores -march
especificáveis e alvos resultantes.
Valor -march |
Alvo resultante |
---|---|
-march=armv7-a |
armv7-none-linux-androideabi |
-mthumb |
thumb-none-linux-androideabi |
-march=armv7-a e -mthumb |
thumbv7-none-linux-androideabi |
Se quiser, você também pode substituir por seu -target
.
clang
e clang++
precisam ser substituídos para gcc
e g++
em um makefile. Em caso de dúvida, use as seguintes opções ao invocar o compilador para verificar se eles estão funcionando corretamente:
-v
para fazer o despejo de comandos associados a problemas de driver do compilador.-###
-para fazer o despejo de opções de linha de comando, incluindo as predefinidas implicitamente.-x c < /dev/null -dM -E
para fazer o despejo de predefinições do pré-processador-save-temps
para comparar os arquivos pré-processados de*.i
ou*.ii
.
Compatibilidade com ABI
Por padrão, um conjunto de ferramentas autônomo Clang ARM terá como alvo a ABI armeabi-v7a.
Para modificar essa configuração, use a opção -march
ou -target
adequada.
É recomendável usar a sinalização do compilador -mthumb
para forçar a geração de instruções Thumb-2 de 16 bits. Caso essa sinalização seja omitida, o conjunto de ferramentas gerará instruções para ARM de 32 bits.
Para usar as instruções de NEON, use a seguinte sinalização do compilador -mfpu
: -mfpu=neon
.
Essa configuração força o uso de VFPv3-D32
de acordo com a especificação da ARM.
Além disso, forneça estas duas sinalizações ao vinculador: -march=armv7-a -Wl,--fix-cortex-a8
.
A primeira sinalização instrui o vinculador a selecionar as bibliotecas de conjunto de ferramentas adequadas para armv7-a. A segunda sinalização é necessária como uma alternativa a um bug da CPU em algumas implementações de Cortex-A8.
Não é necessário usar nenhum sinalizador de compilador específico para trabalhar com outros ABIs.
Para saber mais sobre a compatibilidade com ABIs, consulte ABIs do Android.
Avisos e limitações
Compatibilidade com Windows
Os binários do Windows não dependem do Cygwin. Essa falta de dependência faz com que eles sejam mais rápidos. No entanto, o ponto negativo é que eles não entendem especificações de caminho do Cygwin, como cygdrive/c/foo/bar
, ao contrário de C:/foo/bar
.
Exceções, RTTI e STL
Os binários do conjunto de ferramentas são compatíveis com exceções de C++ e RTTI por padrão. Para desativar as exceções de C++ e RTTI ao compilar fontes (para, por exemplo, gerar um código de máquina mais leve), use -fno-exceptions
e -fno-rtti
.
Compatibilidade com STL C++
O conjunto de ferramentas autônomo inclui uma implementação da Standard Template Library (STL) de C++.
Use
-static-libstdc++
para conseguir a versão da biblioteca estática da libc ++. Isso garante que todo código STL C++ necessário seja incluído no binário final. Esse método é o ideal para gerar um único executável ou biblioteca compartilhada, que é a nossa recomendação.A versão de biblioteca compartilhada do libc++ será usada por padrão. Nenhuma outra sinalização é necessária para fazer a vinculação com a biblioteca compartilhada. Você precisa incluir
libc++_shared.so
no seu app para que o código seja carregado.A Tabela 2 mostra a localização desse arquivo para cada arquitetura.
Tabela 2. Valores
-march
especificáveis e alvos resultantes.Conjunto de ferramentas Local 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/
Criar projetos de código aberto com conjuntos de ferramentas autônomos
Considere este exemplo de conjunto de ferramentas:
# Create an arm64 API 26 libc++ toolchain.
$NDK/build/tools/make_standalone_toolchain.py \
--arch arm64 \
--api 26 \
--install-dir=my-toolchain
Veja como configurar seu ambiente para usá-lo na criação de um projeto de código aberto tradicional:
# 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"
Projetos com sistemas de compilação personalizados
Veja um exemplo de como criar um toybox após realizar as etapas anteriores:
git clone https://github.com/landley/toybox.git
cd toybox
make defconfig && make
Projetos com autoconf
Como alternativa, os projetos baseados em autoconf teriam a seguinte aparência:
tar zxvf make-4.2.tar.gz
cd make-4.2
./configure --host=$target_host && make
Os projetos baseados em autoconf variam consideravelmente quanto à compatibilidade com a compilação cruzada. Além disso, se você usar git clone
em um projeto baseado em autoconf, provavelmente não haverá um script configure
registrado. Por isso, você precisará seguir a documentação do projeto para descobrir como fazer a inicialização.