Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] -DCMAKE_CXX_FLAGS overrides default Android compiler flags with new toolchain file #1693

Closed
rprichard opened this issue Mar 31, 2022 · 6 comments
Labels

Comments

@rprichard
Copy link
Collaborator

Description

The NDK automatically switches from the legacy CMake toolchain file to the new toolchain file if the CMake version is new enough. There are some differences in the way the two modes operate regarding the -DCMAKE_${LANG}_FLAGS variable that may have been unintentional.

With the legacy toolchain file, the CMAKE_${LANG}_FLAGS were appended to a set of default flags. With the new toolchain file, setting CMAKE_${LANG}_FLAGS instead overrides the default flags.

The result is that projects that upgrade to a newer CMake (or which start passing -DCMAKE_${LANG}_FLAGS) lose the default compiler flags.

This situation is made worse with Gradle. The Android Studio template for a new NDK project adds these build.gradle lines:

        externalNativeBuild {
            cmake {
                cppFlags ''
            }
        }

cppFlags is turned into a command-line argument setting CMAKE_CXX_FLAGS. However, when it's empty, the Android Gradle Plugin (AGP) instead omits the -DCMAKE_CXX_FLAGS=... argument. That's fine for the legacy toolchain, but with the new toolchain file, it means that adding a new argument to the cppFlags '' also suppresses many default flags. (With the new toolchain file, passing -DCMAKE_CXX_FLAGS= also overrides the defaults, but AGP isn't passing that.)

This behavioral change broke a project that was passing -std=... in cppFlags to set the C++ dialect. After upgrading CMake, the compiler stopped building with -ffunction-sections and -fdata-sections, which bloated the app's shared object. (For this particular project, -std=... was the only thing in cppFlags, so I think it was fixed by switching to CXX_STANDARD.)

Example:

# Test project
cat >CMakeLists.txt <<EOF
project(hello)
cmake_minimum_required(VERSION 3.18.1)
add_executable(hello hello.cpp)
EOF
cat >hello.cpp <<EOF
int main() {}
EOF

Legacy toolchain file (without -DCMAKE_CXX_FLAGS):

$ rm -fr out && cmake -GNinja -Bout \
  -DCMAKE_BUILD_TYPE=MinSizeRel \
  -DCMAKE_TOOLCHAIN_FILE=/x/android-ndk-r24/build/cmake/android.toolchain.cmake \
  -DANDROID_USE_LEGACY_TOOLCHAIN_FILE=ON \
  && ninja -Cout -v
...
/x/android-ndk-r24/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ \
  --target=armv7-none-linux-androideabi19 \
  --sysroot=/x/android-ndk-r24/toolchains/llvm/prebuilt/linux-x86_64/sysroot \
  -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables \
  -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 \
  -march=armv7-a -mthumb -Wformat -Werror=format-security \
  -Os -DNDEBUG -fPIE \
  -MD -MT CMakeFiles/hello.dir/hello.cpp.o \
  -MF CMakeFiles/hello.dir/hello.cpp.o.d \
  -o CMakeFiles/hello.dir/hello.cpp.o \
  -c /x/cmaketest/hello.cpp

Legacy toolchain file (with -DCMAKE_CXX_FLAGS):

$ rm -fr out && cmake -GNinja -Bout \
  -DCMAKE_BUILD_TYPE=MinSizeRel \
  -DCMAKE_TOOLCHAIN_FILE=/x/android-ndk-r24/build/cmake/android.toolchain.cmake \
  -DANDROID_USE_LEGACY_TOOLCHAIN_FILE=ON \
  -DCMAKE_CXX_FLAGS=-std=c++17 \
  && ninja -Cout -v
...
/x/android-ndk-r24/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ \
  --target=armv7-none-linux-androideabi19 \
  --sysroot=/x/android-ndk-r24/toolchains/llvm/prebuilt/linux-x86_64/sysroot \
  -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables \
  -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 \
  -march=armv7-a -mthumb -Wformat -Werror=format-security \
  -std=c++17 -Os -DNDEBUG -fPIE \
  -MD -MT CMakeFiles/hello.dir/hello.cpp.o \
  -MF CMakeFiles/hello.dir/hello.cpp.o.d \
  -o CMakeFiles/hello.dir/hello.cpp.o \
  -c /x/cmaketest/hello.cpp

These default flags come from ANDROID_COMPILER_FLAGS in $NDKr24/build/cmake/android-legacy.toolchain.cmake:

  -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables \
  -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 \
  -march=armv7-a -mthumb -Wformat -Werror=format-security`

New toolchain file (without -DCMAKE_CXX_FLAGS):

$ rm -fr out && cmake -GNinja -Bout \
  -DCMAKE_BUILD_TYPE=MinSizeRel \
  -DCMAKE_TOOLCHAIN_FILE=/x/android-ndk-r24/build/cmake/android.toolchain.cmake \
  -DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF \
  && ninja -Cout -v
...
/x/android-ndk-r24/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ \
  --target=armv7-none-linux-androideabi19 \
  --sysroot=/x/android-ndk-r24/toolchains/llvm/prebuilt/linux-x86_64/sysroot \
  -DANDROID -fdata-sections -ffunction-sections -funwind-tables \
  -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 \
  -march=armv7-a -mthumb -Wformat -Werror=format-security \
  -fexceptions -frtti -stdlib=libc++ -Os -DNDEBUG -fPIE \
  -MD -MT CMakeFiles/hello.dir/hello.cpp.o \
  -MF CMakeFiles/hello.dir/hello.cpp.o.d \
  -o CMakeFiles/hello.dir/hello.cpp.o \
  -c /x/cmaketest/hello.cpp

New toolchain file (with -DCMAKE_CXX_FLAGS):

$ rm -fr out && cmake -GNinja -Bout \
  -DCMAKE_BUILD_TYPE=MinSizeRel \
  -DCMAKE_TOOLCHAIN_FILE=/x/android-ndk-r24/build/cmake/android.toolchain.cmake \
  -DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF \
  -DCMAKE_CXX_FLAGS=-std=c++17 \
  && ninja -Cout -v
...
/x/android-ndk-r24/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ \
  --target=armv7-none-linux-androideabi19 \
  --sysroot=/x/android-ndk-r24/toolchains/llvm/prebuilt/linux-x86_64/sysroot \
  -std=c++17 -Os -DNDEBUG -fPIE \
  -MD -MT CMakeFiles/hello.dir/hello.cpp.o \
  -MF CMakeFiles/hello.dir/hello.cpp.o.d \
  -o CMakeFiles/hello.dir/hello.cpp.o \
  -c /x/cmaketest/hello.cpp

Adding -DCMAKE_CXX_FLAGS suppresses these flags:

  -DANDROID -fdata-sections -ffunction-sections -funwind-tables \
  -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 \
  -march=armv7-a -mthumb -Wformat -Werror=format-security \
  -fexceptions -frtti -stdlib=libc++

Using the new toolchain file results in explicit -fexceptions and -frtti arguments, which were not passed with the legacy toolchain file. This also means that:

  • With the new toolchain file, passing -DCMAKE_CXX_FLAGS=... suppresses the flags produced by -DANDROID_CPP_FEATURES="no-exceptions no-rtti"
  • With the legacy toolchain file, the -DCMAKE_CXX_FLAGS=... flags are appended to those resulting from ANDROID_CPP_FEATURES.

Affected versions

r23, r24, r25, Canary

Canary version

n/a

Host OS

Linux, Mac, Windows

Host OS version

any

Affected ABIs

armeabi-v7a, arm64-v8a, x86, x86_64

Build system

CMake

Other build system

No response

minSdkVersion

n/a

Device API level

n/a

@rprichard rprichard added the bug label Mar 31, 2022
@rprichard
Copy link
Collaborator Author

@jomof

@DanAlbert proposed having new versions of AGP pass -DANDROID_USE_LEGACY_TOOLCHAIN_FILE=ON to avoid this behavior change on CMake upgrade.

@rprichard
Copy link
Collaborator Author

I opened https://gitlab.kitware.com/cmake/cmake/-/issues/23378 against upstream CMake.

@DanAlbert
Copy link
Member

Not actually in the r25 branch, but we'll do a full update of r25 from master so marking done for that release.

@DanAlbert
Copy link
Member

https://android-review.googlesource.com/c/platform/ndk/+/2064269 is the "fix". We're back to the legacy toolchain by default until CMake can support this.

@DanAlbert
Copy link
Member

Workaround is in r23 build 8486889.

r24 still needs a cherry-pick.

@DanAlbert DanAlbert mentioned this issue May 31, 2022
@DanAlbert
Copy link
Member

r24 is not an LTS so it will lose support when r25 ships in early July. Due to a lack of bandwidth in our dependencies, it won't be possible to ship r24b before the end of the support window. Closing since this is already fixed in r25 and r23c.

If you are using r24 and do not want to encounter this bug, do not upgrade to CMake 3.21 or newer (or pass -DANDROID_USE_LEGACY_TOOLCHAIN_FILE=TRUE to CMake).

MaoHan001 pushed a commit to riscv-android-src/platform-ndk that referenced this issue Jun 22, 2022
Previously, the NDK used the new toolchain file for CMake 3.21 and up.
With the new toolchain file, CMAKE_CXX_FLAGS overrides the set of flags
the NDK provides, but we want the flags to be appended instead, which
is the legacy toolchain file's behavior.

Bug: android/ndk#1693
Test: checkbuild.py && run_tests.py
Change-Id: I241bcfbccc0b71a84616d78d68992c3856e42b85
(cherry picked from commit 61b77040e2cf383acef2d17c500a6196a9a35e48)
Merged-In: I241bcfbccc0b71a84616d78d68992c3856e42b85
MaoHan001 pushed a commit to riscv-android-src/platform-ndk that referenced this issue Jun 22, 2022
Bug: android/ndk#1693
Test: n/a
Change-Id: Ic785a42e414c5976c027b62075d382047620090b
(cherry picked from commit 341f8f600c25990ccdf0abfc1fa213a7e017f2e3)
Merged-In: Ic785a42e414c5976c027b62075d382047620090b
kichikuou added a commit to kichikuou/xsystem4-android that referenced this issue Oct 8, 2022
Android NDK r25 defaults to legacy toolchain file which does not work
for xsystem4 build.
android/ndk#1693
juan-lunarg added a commit to KhronosGroup/Vulkan-ValidationLayers that referenced this issue Apr 11, 2023
tnovak added a commit to tnovak/ExtendedAndroidTools that referenced this issue May 8, 2023
Includes a few tweaks needed to build bpftools with a recent NDK:

- Libcxx prebuilts are no longer included in sources/cxx-stl [1], so
  use the sysroot path instead.
- NDK now defaults to android-legacy.toolchain.cmake [2], irrespective of
  CMake version. With the legacy toolchain some env variables we set such
  as LDFLAGS aren't used, leading to build errors. Force the use of new
  toolchain file and switch to CXXFLAGS as opposed to CMAKE_CXX_FLAGS
  to avoid overriding toolchain defaults [3].

Test: make NDK_PATH=/opt/ndk/android-ndk-r25c bpftools-min

[1] https://android-review.googlesource.com/c/platform/ndk/+/2051541
[2] https://android-review.googlesource.com/c/platform/ndk/+/2064269
[3] android/ndk#1693
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants