Conjuntos de ferramentas autônomos

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á tiver um sistema de compilação próprio e só precisar do recurso para invocar o compilador cruzado a fim de incluir a compatibilidade com o Android.

Selecionar 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 o sinalizador --arch.

Selecionar o sysroot

O próximo passo é definir seu sysroot. O sysroot é um diretório que contém os cabeçalhos e bibliotecas do sistema para seu destino. Para definir o sysroot, é necessário saber para qual nível de API do Android você oferecerá compatibilidade nativa. As APIs nativas disponíveis variam de acordo com o nível de API do Android.

As bibliotecas para APIs nativas dos respectivos níveis de API do Android ficam em $NDK/platforms/. Cada diretório em nível de API contém subdiretórios para as CPUs e arquiteturas diversas. Os cabeçalhos são localizados em $NDK/sysroot.

Para saber mais sobre os níveis de 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 por meio da 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 para executar a ferramenta.

O script se localiza no diretório $NDK/build/tools/, em que $NDK é a raiz da instalação do NDK.

Veja abaixo 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 de 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++. A biblioteca compartilhada libc++ será usada por padrão, 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.

Além disso, há dois scripts de wrapper, chamados clang e clang++, em <install-dir>/bin. Esses scripts invocam o binário clang com os sinalizadores de arquitetura apropriados. Em outras palavras, eles precisam funcionar sem exigir nenhuma modificação, e você precisa poder usá-los em 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 dos sinalizadores 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 com seu próprio -target.

clang e clang++ precisam ser substitutos para gcc e g++ no makefile. Em caso de dúvida, use as seguintes opções ao invocar o compilador para verificar se estão funcionando corretamente:

  • -v para copiar comandos associados a problemas de driver do compilador.
  • -### para copiar opções de linha de comando, incluindo as predefinidas implicitamente.
  • -x c < /dev/null -dM -E para despejar definições de pré-processador predefinidas.
  • -save-temps para comparar arquivos pré-processados *.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 o sinalizador 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 o seguinte sinalizador 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 os dois sinalizadores a seguir ao vinculador: -march=armv7-a -Wl,--fix-cortex-a8.

O primeiro sinalizador instrui o vinculador a selecionar as bibliotecas de conjunto de ferramentas adequadas para armv7-a. O segundo sinalizador é necessário 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.

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 utilizar a versão de biblioteca estática do 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. Nenhum outro sinalizador é necessário para fazer a vinculação com a biblioteca compartilhada. Você precisa incluir libc++_shared.so no seu app, ou o código não será 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 usando 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 que usam 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.