blob: 16b2b6961d9428ccee2b84db98a81a84a301c873 [file] [log] [blame] [view]
# Clang Migration Notes
The Android OS switched to clang several years ago. Future versions of
the NDK will remove GCC, so the sooner you start testing your project
with clang the better!
## How to switch to clang
For `ndk-build`, remove lines setting `NDK_TOOLCHAIN` or
`NDK_TOOLCHAIN_VERSION`.
For cmake, remove lines setting `ANDROID_TOOLCHAIN`.
For standalone toolchains, use the `clang`/`clang++` binaries instead of
`gcc`/`g++`.
For other build systems, ask the owners of that build system.
## How to fix common problems
When moving to Clang from GCC, you may notice some differences.
### `-Oz` versus `-Os`
Warning: Do not use `-Oz` until [Issue 573] is resolved if you use exceptions.
[Issue 573]: https://github.com/android-ndk/ndk/issues/573
[Clang Optimization Flags](https://clang.llvm.org/docs/CommandGuide/clang.html#code-generation-options)
has the full details, but if you used `-Os` to optimize your
code for size with GCC, you probably want `-Oz` when using
Clang. Although `-Os` attempts to make code small, it still
enables some optimizations that will increase code size (based on
https://stackoverflow.com/a/15548189/632035). For the smallest possible
code with Clang, prefer `-Oz`. With `-Oz`, Chromium actually saw both
size *and* performance improvements when moving to Clang compared to
`-Os` with GCC.
### `__attribute__((__aligned__))`
Normally the `__aligned__` attribute is given an explicit alignment,
but with no value means maximum alignment”. The interpretation of
maximum differs between GCC and Clang: Clang includes vector types
too so for ARM GCC thinks the maximum alignment is 8 (for `uint64_t`), but
Clang thinks its 16 (because there are NEON instructions that require
16-byte alignment). Normally this shouldnt matter because malloc is
always at least 16-byte aligned, and mmap regions are page (4096-byte)
aligned. Most code should either specify an explicit alignment or use
[alignas](http://en.cppreference.com/w/cpp/language/alignas) instead.
### `-Bsymbolic`
When targeting Android (but no other platform), GCC passed
[-Bsymbolic](ftp://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_3.html)
to the linker by default. This is not a good default, so Clang does not
do that. `-Bsymbolic` causes the following behavior change:
```c++
// foo.cpp
#include <iostream>
void foo() {
std::cout << "Goodbye, world" << std::endl;
}
void bar() {
foo();
}
```
```c++
// main.cpp
#include <iostream>
extern void bar();
void foo() {
std::cout << "Hello, world\n";
}
int main(int, char**) {
foo(); // Prints “Hello, world!”
bar(); // Without -Bsymbolic, prints “Hello, world!” With -Bsymbolic, prints “Goodbye, world!”
}
```
In addition to not being the "expected" default behavior on all other
platforms, this prevents symbol interposition (used by tools such
as asan).
You might however wish to add manually `-Bsymbolic` back because it can
result in smaller ELF files because fewer relocations are needed. If you
do want the non-`-Bsymbolic` behavior but would like fewer relocations,
that can be achieved via `-fvisibility=hidden` (and manually exporting
the symbols you want to be public, using the `JNI_EXPORT` macro in JNI
code or `__attribute__ ((visibility("default")))` otherwise. Linker
version scripts are an even more powerful mechanism for controlling
exported symbols, but harder to use.
### `-fno-integrated-as`
Especially for ARM and ARM64, Clang is much stricter about assembler
rules than GCC/GAS. Use `-fno-integrated-as` if Clang reports errors in
inline assembly or assembly files that you don't wish to modernize.