Очередные андроедопроблемы.
Решил настроить кросс-компиляцию и запуск под Windows 7.
Компиляция работает, а вот юнит-тесты на эмуляторе не стартуют - ехешник валится с "Illegal instruction".
Под линуксом я с таким не сталкивался.
Что это может быть? Бага эмулятора под виндой, или я что-то не так настраиваю?
Цитата:
INFO: Running unit test bundles in "android\jni"...
INFO: Pushing content to device...
libdedicated.so: 1 file pushed. 5.4 MB/s (1591228 bytes in 0.282s)
libfilesystem.so: 1 file pushed. 6.8 MB/s (87908 bytes in 0.012s)
libgame.so: 1 file pushed. 6.0 MB/s (1982808 bytes in 0.317s)
libogg.so: 1 file pushed. 1.8 MB/s (20804 bytes in 0.011s)
libphysics.so: 1 file pushed. 7.6 MB/s (770412 bytes in 0.096s)
libplatform.so: 1 file pushed. 4.1 MB/s (48548 bytes in 0.011s)
libref_gles1.so: 1 file pushed. 5.5 MB/s (655044 bytes in 0.114s)
libref_null.so: 1 file pushed. 5.8 MB/s (626236 bytes in 0.103s)
libvgui.so: 1 file pushed. 5.7 MB/s (418140 bytes in 0.069s)
libvmdlib.so: 1 file pushed. 1.1 MB/s (6540 bytes in 0.006s)
libvorbis.so: 1 file pushed. 5.5 MB/s (175448 bytes in 0.030s)
libvorbisenc.so: 1 file pushed. 7.8 MB/s (989212 bytes in 0.122s)
libvorbisfile.so: 1 file pushed. 3.1 MB/s (35052 bytes in 0.011s)
libvsound.so: 1 file pushed. 5.2 MB/s (169588 bytes in 0.031s)
libvstdlib.so: 1 file pushed. 3.1 MB/s (79664 bytes in 0.024s)
libvtxlib.so: 1 file pushed. 2.5 MB/s (25272 bytes in 0.010s)
INFO: Running: "base_unittest"...
base_unittest: 1 file pushed. 7.8 MB/s (964288 bytes in 0.118s)
Illegal instruction
ERROR: Unit tests in bundle "base_unittest" failed!
INFO: Running: "platform_unittest"...
platform_unittest: 1 file pushed. 5.2 MB/s (850872 bytes in 0.155s)
Illegal instruction
ERROR: Unit tests in bundle "platform_unittest" failed!
INFO: Running: "vstdlib_unittest"...
vstdlib_unittest: 1 file pushed. 7.2 MB/s (1163836 bytes in 0.154s)
Illegal instruction
ERROR: Unit tests in bundle "vstdlib_unittest" failed!
INFO: Running: "filesystem_unittest"...
filesystem_unittest: 1 file pushed. 8.6 MB/s (1054080 bytes in 0.117s)
Illegal instruction
ERROR: Unit tests in bundle "filesystem_unittest" failed!
INFO: Running: "vtxlib_unittest"...
vtxlib_unittest: 1 file pushed. 7.4 MB/s (808280 bytes in 0.105s)
Illegal instruction
ERROR: Unit tests in bundle "vtxlib_unittest" failed!
INFO: Running: "vmdlib_unittest"...
vmdlib_unittest: 1 file pushed. 7.9 MB/s (788292 bytes in 0.096s)
Illegal instruction
ERROR: Unit tests in bundle "vmdlib_unittest" failed!
INFO: Running: "scriptsys_unittest"...
scriptsys_unittest: 1 file pushed. 8.7 MB/s (2689528 bytes in 0.294s)
Illegal instruction
ERROR: Unit tests in bundle "scriptsys_unittest" failed!
INFO: Running: "physics_unittest"...
physics_unittest: 1 file pushed. 8.4 MB/s (1822788 bytes in 0.206s)
Illegal instruction
ERROR: Unit tests in bundle "physics_unittest" failed!
INFO: Running: "renderer_unittest"...
renderer_unittest: 1 file pushed. 7.9 MB/s (1175064 bytes in 0.142s)
Illegal instruction
ERROR: Unit tests in bundle "renderer_unittest" failed!
All done - 9 test bundle(s) executed.
ERROR: 9 TEST BUNDLE(S) FAILED:
[android\jni] base_unittest
[android\jni] platform_unittest
[android\jni] vstdlib_unittest
[android\jni] filesystem_unittest
[android\jni] vtxlib_unittest
[android\jni] vmdlib_unittest
[android\jni] scriptsys_unittest
[android\jni] physics_unittest
[android\jni] renderer_unittest
Компилирую в 32-bit, armv7-a, softfp, api level 16, clang.
Эмулятор создавался так:
Что любопытно - некоторые программы (не юнит-тесты) на эмуляторе стартуют, например, компилятор текстур makevtx и компилятор моделей makevmd. Но в 90% случаев они тоже выдают эту ошибку "Illegal instruction". А в 10% случаев - запускаются.
Illegal instruction это как раз тот случай, когда в либе/бинаре исполнение натыкается на инструкцию, которая не поддерживается процессором, например, компиляция каких-то определённых модулей идёт с mfpu=neon или определённым march/mcpu/mtune.
Какой Android NDK? Новый или старый? Если новый, то там могли уже вообще дропнуть древние устройства без FPU и компилятор навставлял подобных инструкций. Google подобное может выкинуть, учитывая что все 32-битные приложения они официально дропают в августе 2019-го.
В общем, тебе нужно смотреть лог сборки на предмет проскакивания всяких там подозрительных опций компилятора. Заюзай такое, если у тебя Gradle:
И смотри в лог. Я так кстати обнаружил, что мне сборочные системы (ndk-build и CMake) пихают по умолчанию такое:
Но у меня была обратная ситуация -- мне нужно было нативный код собрать конкретно под мой девайс, а не под Generic ARM, то есть с моими:
code:-mcpu=cortex-a15 -mfpu=neon-vfpv4
И вот в добавление к захардкоженным Generic vfpv3-d16 добавлялась ещё и специфичная neon-vfpv4, но компилятор брал именно её, поскольку флаги "новых" CPU/FPU, заглушают уже заданные старые. Посмотреть информацию что там за CPU и FPU инструкции оно тебе вкомпилило можно через readelf:
Я склоняюсь ко мнению, что у тебя ситуация, когда эмулируемый процессор твоём Android Emulator не знает что такое vfpv3-d16, а компилятор навставлял этих инструкций потому что они теперь идут по умолчанию.
Точно, это оно. Видимо, по умолчанию в апи левел 16 стал неон. Раньше-то я с 14-м собирал.
Проблема решена добавлением "-mfpu=vfpv3-d16". EXL большое спасибо!
Добавлено 21-04-2019 в 16:02:
Разгадал загадку одного падающего юнит-теста, и просто оставлю это здесь:
Цитата:
Correct soname/path handling (Available in API level >= 23)
The dynamic linker now understands the difference between a library’s soname and its path (public bug https://code.google.com/p/android/issues/detail?id=6670). API level 23 is the first release where search by soname is implemented. Earlier releases would assume that the basename of the library was the soname, and used that to search for already-loaded libraries. For example, dlopen("/this/directory/does/not/exist/libc.so", RTLD_NOW) would find /system/lib/libc.so because it’s already loaded. This also meant that it was impossible to have two libraries "dir1/libx.so" and "dir2/libx.so" --- the dynamic linker couldn’t tell the difference and would always use whichever was loaded first, even if you explicitly tried to load both. This also applied to DT_NEEDED entries.
Т.е. до апи левела 23, если сошка была загружена, то попытка загрузить сошку с тем же именем, но по другому пути, всегда удавалась (и давала хэндл первой библиотеки), даже если этот путь не существовал. Потрясающая дыра в безопасности, надо сказать...
XaeroX аплодисменты стоя. Осталось Гуглу, Циске и Майку объединиться в какой-нибудь консорциум по безопасности и проводить высокоинтеллектуальные семинары!
Товарищи эндэкашники, а на Андроид какой версии вы обычно таргетируете свой код?
Я ориентировался на 4.0 как на минимальный (апи левел 16), но сейчас подумываю переориентироваться на 5.0 (апи левел 21), т.к. хочу собирать 64-битные бинарники, а это кажется только на 21 апи возможно (в 16-м тулчейне я не вижу кланга для arm64).
Это оправдано сейчас?
У меня самого две андроид-железки, одна 5.1 и другая 8.0.
Дядя Миша
Да. А с августа 2019 Гугл требует, чтобы все засылаемые в маркет программы и игры были 64-битными. При этом в APK можно класть и 32-битные, и 64-битные бинарники (андроид сам подцепит нужные в зависимости от своей битности). Но теперь 64-битные становятся строго обязательными для гугл-плея.
XaeroX
А ты уверен, что устройства, на которых Android 4, вообще потянут игру?
Если да, то на осень 2018 года доля устройств на 4.0-4.4 около десяти процентов.
Готов ли ты ими пожертвовать?
Я думаю, что стоит отказаться от их поддержки.