Add a workaround for an Android NDK compiler bug. On certain NDK build configurations, one of the innermost parts of the Schur eliminator would get compiled incorrectly. The compiler changed a -= to a +=. The normal Ceres unit tests caught the problem; however, since it is not possible to build the tests with the NDK (only with the standalone toolchain) this was difficult to track down. Finding the issue involved pasting the schur eliminator unit test inside of solver_impl.cc and other such hacks. Change-Id: Ie91bb545d74fe39f0c8cbd1a6eb69ee4d8b25fb2
diff --git a/CMakeLists.txt b/CMakeLists.txt index 73893bd..4152ecc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -479,9 +479,10 @@ ENDIF ("${UNIX}" AND NOT ${BUILD_ANDROID}) # Disable threads in mutex.h. Someday, after there is OpenMP support in -# Android, this can get removed. +# Android, this can get removed. Also turn on a workaround for an NDK bug. IF (${BUILD_ANDROID}) ADD_DEFINITIONS(-DCERES_NO_THREADS) + ADD_DEFINITIONS(-DCERES_WORK_AROUND_ANDROID_NDK_COMPILER_BUG) ENDIF (${BUILD_ANDROID}) OPTION(DISABLE_TR1
diff --git a/internal/ceres/schur_eliminator_impl.h b/internal/ceres/schur_eliminator_impl.h index a916de0..6120db9 100644 --- a/internal/ceres/schur_eliminator_impl.h +++ b/internal/ceres/schur_eliminator_impl.h
@@ -532,7 +532,29 @@ // like the Matrix class does. Eigen::Block<MatrixRef, kFBlockSize, kFBlockSize> block(m, r, c, block1_size, block2_size); - block.noalias() -= b1_transpose_inverse_ete * b2; +#ifdef CERES_WORK_AROUND_ANDROID_NDK_COMPILER_BUG + // Removing the ".noalias()" annotation on the following statement is + // necessary to produce a correct build with the Android NDK, including + // versions 6, 7, 8, and 8b, when built with STLPort and the + // non-standalone toolchain (i.e. ndk-build). This appears to be a + // compiler bug; if the workaround is not in place, the line + // + // block.noalias() -= b1_transpose_inverse_ete * b2; + // + // gets compiled to + // + // block.noalias() += b1_transpose_inverse_ete * b2; + // + // which breaks schur elimination. Introducing a temporary by removing the + // .noalias() annotation causes the issue to disappear. Tracking this + // issue down was tricky, since the test suite doesn't run when built with + // the non-standalone toolchain. + // + // TODO(keir): Make a reproduction case for this and send it upstream. + block -= b1_transpose_inverse_ete * b2; +#else + block.noalias() -= b1_transpose_inverse_ete * b2; +#endif // CERES_WORK_AROUND_ANDROID_NDK_COMPILER_BUG } } }
diff --git a/jni/Android.mk b/jni/Android.mk index dcd247e..eaccb29 100644 --- a/jni/Android.mk +++ b/jni/Android.mk
@@ -87,7 +87,8 @@ -DCERES_NO_GFLAGS \ -DCERES_NO_THREADS \ -DCERES_NO_CXSPARSE \ - -DCERES_NO_TR1 + -DCERES_NO_TR1 \ + -DCERES_WORK_AROUND_ANDROID_NDK_COMPILER_BUG LOCAL_SRC_FILES := $(CERES_SRC_PATH)/array_utils.cc \ $(CERES_SRC_PATH)/block_evaluate_preparer.cc \