- Как собрать нативную библиотеку для Android
- Собираем Opus из исходников
- Добавляем собранные библиотеки в проект
- [question] arm-linux-androideabi-gcc: not found | Error 127, Error 2, #1321
- Comments
- LovableFatty commented Jul 21, 2020
- LovableFatty commented Jul 21, 2020
- stephenhines commented Jul 21, 2020
- stephenhines commented Jul 21, 2020
- LovableFatty commented Jul 21, 2020 •
- DanAlbert commented Jul 21, 2020
- LovableFatty commented Jul 21, 2020
- LovableFatty commented Jul 21, 2020 •
- DanAlbert commented Jul 21, 2020
- stephenhines commented Jul 21, 2020
- Tydus / howto-standalone-toolchain.md
- This comment has been minimized.
- nikhilkilivayil commented Feb 5, 2016
- This comment has been minimized.
- MichaelSX commented Apr 13, 2016
- This comment has been minimized.
- usman313 commented May 1, 2016 •
- This comment has been minimized.
- ranshalit commented Feb 14, 2017
- This comment has been minimized.
- hannesa2 commented Dec 28, 2017 •
- This comment has been minimized.
- AxelNennker commented Apr 20, 2018
- This comment has been minimized.
- KrishnaCAmjuri commented Jun 2, 2018 •
- This comment has been minimized.
- unalkalkan commented Jun 3, 2018
- This comment has been minimized.
- KrishnaCAmjuri commented Jun 4, 2018
- This comment has been minimized.
- bybilly commented Aug 14, 2018
- This comment has been minimized.
- tonyw5 commented Aug 14, 2018
- This comment has been minimized.
- jainabhinav249 commented Mar 5, 2019
- This comment has been minimized.
- jainabhinav249 commented Mar 5, 2019
- This comment has been minimized.
- w1252675615 commented Sep 29, 2019
Как собрать нативную библиотеку для Android
Собрать и заставить работать приложение с небольшим количеством нативного кода несложно. Если же вы хотите использовать нативную библиотеку, в которой много файлов, становится труднее. Сложность в том, что нативные библиотеки распространяются в виде исходного кода, который нужно компилировать под нужную архитектуру процессора. На примере аудиокодека Opus я покажу, как это сделать.
В своей предыдущей статье я на примере аудиокодека Opus показал, как решить задачу сборки нативной библиотеки для Android, но в проект был добавлен весь исходный код Opus, а так делать не хочется. По-хорошему нужно иметь в проекте уже собранные .so или .a, и используя их, писать свои врапперы на C/C++ и собирать приложение. Об этом и пойдёт речь в статье. На примере того же аудиокодека Opus я покажу, как с помощью NDK получить скомпилированные .so и .a, чтобы далее использовать их в Android-проекте.
Чтобы использовать любую нативную библиотеку, нам нужно написать враппер на C/C++, в котором мы будем вызывать методы самой библиотеки. Мы скомпилируем и соберём библиотеку Opus как статическую (.a).
Мы вызываем функцию в нашем C файле, которая описана в другой библиотеке. Для этого в начале файла пишем #include . Далее на этапе компиляции C файла, если библиотека статическая(.a), то вместо #include компилятор подставит весь код этой функции. Если динамическая(.so), то подставит только ссылку на функцию. Таким образом, при использовании статической библиотеки у нас есть весь код, который нам необходим из другой библиотеки, а при использовании динамической код будет подгружаться динамически.
Использование .so в зависимостях может уменьшить размер нашей итоговой библиотеки. Это было бы так, если бы Opus был стандартной библиотекой, но так как её нет в Android, мы должны её предоставить. Поэтому итоговый размер нашего libjniopus.so будет одинаковым, что при использовании libopus.a, что при использовании libopus.so.
Для компиляции нативных библиотек из исходников в NDK c версии 19 есть готовые удобные инструменты «из коробки». В документации описано, как их использовать. Описание довольно короткое, поэтому человек, не имеющий опыта в сборке нативных библиотек, неизбежно столкнётся со сложностями. Как их решить, я разберу ниже.
Собираем Opus из исходников
Сначала скачиваем исходники: либо из репозитория (git clone), либо архивом. У Opus есть Autoconf — утилита, которая автоматически создаёт конфигурационные скрипты. В проекте с Autoconf можно задать toolchain для компиляции, используя ENV-переменные. Autoconf, как правило, работает только на Unix подобных системах. Поэтому если у вас Windows, то вам, скорее всего, придётся использовать средства эмуляции.
В итоге мы хотим получить 4 файла библиотеки с расширением .a по одной на каждую архитектуру процессора: armeabi-v7a, arm64-v8a, x86, x86-64.
Для каждой архитектуры нужно задать свои ENV-переменные. Общими будут только NDK, HOST_TAG и TOOLCHAIN. В Linux, ENV-переменную для текущей сессии терминала можно задать, используя команду export:
Однако заданные ENV-переменные будут существовать, пока активна текущая сессия терминала, и только в ней. Если вы откроете другую сессию, то там этих переменных не будет. Чтобы каждый раз не прописывать ENV-переменные заново, можно добавить их в конец файла .bashrc, который находится в домашнем каталоге (
). Перед запуском каждой сессии терминала запускается .bashrc. Поэтому переменные, объявленные в нём, будут существовать во всех сессиях терминала. Вот ENV-переменные, которые отличаются в зависимости от архитектуры:
Сначала скомпилируем под arm64-v8a, поэтому закомментируем в .bashrc объявление ENV-переменных для остальных архитектур. Стоит отметить, что в переменных CC и CXX есть цифра 21, которая очень похожа на Android API level. Так и есть, а если быть точнее, то это ваша minSdkVersion. В нашем примере это 21, но если у вас другие потребности, можете смело поменять. В NDK доступны версии с 16 по 29 для 32-разрядных ABI (armeabi-v7a и x86) и с 21 по 29 для 64-разрядных ABI (arm64-v8a и x86-64).
Итак, мы объявили ENV-переменные, которые определяют toolchain для компиляции под выбранную архитектуру, и выкачали репозиторий с исходниками Opus. Теперь открываем Readme в папке с исходниками Opus и видим, что для компиляции библиотеки надо всего-навсего запустить:
Но не всё так просто. Таким образом мы скомпилируем библиотеку под архитектуру нашей рабочей машины, а нам надо под 4 архитектуры мобильных девайсов.
В NDK с версии r19 «из коробки» идут toolchains. Как и показано в примере на странице, нужно выставить ENV-переменные (выставили их выше в .bashrc), соответствующие архитектуре, под которую компилируется библиотека. Затем нужно запустить команду configure с соответствующим аргументом host. Для arm64-v8a получается такое:
/.bashrc необходимо запускать, чтобы изменения переменных среды для сборки «подхватывались» текущей сессией терминала без перезапуска.
После выполнения всех вышеописанных команд, в папке с исходниками Opus появится папка .libs. В ней будут находиться все артефакты компиляции, в том числе и нужный нам libopus.a.
Далее в .bashrc комментим/раскомменчиваем, чтобы активными были ENV-переменные для armeabi-v7a, и прописываем команды уже с другим аргументом host:
./autogen.sh не выполняем, так как он нужен был только для первоначальной генерации конфигурационных файлов и того самого configure, который мы запускаем.
В этот раз команда make завершится ошибкой. Я долго не понимал, из-за чего так происходит. Поискав в интернете похожие проблемы, понял, что файлы и тесты, которые создаются для определённой архитектуры, во время компиляции не удаляются автоматически после переконфигурации на другую архитектуру (запуск configure с другим host). А так как в папке с исходниками, в которой появляются все артефакты сборки, и так много файлов, понять, какие из них надо удалять потом, очень сложно.
Решение оказалось довольно простым. Можно запускать все команды для конфигурации и компиляции, не находясь в папке с исходниками Opus. Тогда можно создать свою отдельную папку для каждой архитектуры, где будут все артефакты сборки и временные файлы для этой архитектуры.
Теперь всего-то нужно создать 4 папки и последовательно сделать одни и те же действия по выставлению ENV-переменных и прописыванию команд с нужным аргументом. Это слишком долго и скучно, поэтому есть отличная возможность написать bash-скрипт, который всё это сделает за нас. Вот такой небольшой скрипт получился:
Если использовать скрипт, то объявлять ENV-переменные в .bashrc нет необходимости, так как они объявлены в скрипте.
Чтобы использовать скрипт, нужно сделать его исполняемым:
Далее необходимо прописать путь к NDK на вашей машине и поменять HOST_TAG, если вы не на Linux (в скрипте значение linux-x86_64):
- 32-bit Windows: windows
- 64-bit Windows: windows-x86_64
- macOS: darwin-x86_64
Затем запускаем скрипт таким образом:
Ему нужно передать minSdkVersion и путь к папке с исходниками Opus. Опционально можно передать путь к папке, куда поместим артефакты сборки. По умолчанию создаётся папка opus_android_build в папке, где расположен скрипт buildOpus.sh.
Выполнение скрипта займёт некоторое время. Потом в папке opus_android_build или в той, которую вы передали, будут располагаться папки с названиями ABI, под которые была скомпилирована библиотека. Соответственно, внутри каждой папки будет уже знакомая нам папка .libs, в которой лежат все артефакты сборки.
Добавляем собранные библиотеки в проект
Отлично, у нас есть 4 файла libopus.a под разные архитектуры, самое сложное позади. Осталось добавить их в наш Android-проект и поправить CmakeLists.txt, чтобы к итоговой .so линковалась скомпилированная нами статическая библиотека Opus.
У нас есть папка app/src/main/cpp, в которой лежит наш C-враппер (jniopus.c), к которому идут external вызовы из Kotlin. В ней создаём папку includes. Затем в неё копируем содержимое папки include из исходников Opus. Там находятся файлы хедеров (.h). Они нам нужны для использования функции и структуры Opus в нашем C-враппере. Файлы хедеров содержат прототипы функций и являются своего рода контрактом, который определяет, какие аргументы может принимать и возвращать та или иная функция.
После этого в той же в папке app/src/main/cpp создадим папку libopus, а внутри неё 4 папки с названиями, идентичными названиям ABI, под которые мы скомпилировали библиотеку Opus: armeabi-v7a, arm64-v8a, x86, x86-64. В каждую из них помещаем файл libopus.a, скомпилированный под соответствующую архитектуру.
Далее модифицируем CmakeLists.txt, который был в предыдущей статье, где мы собирали Opus из исходников прямо в проекте. Сначала удаляем «простыню» со всеми путями к исходникам. Затем задаём переменные для путей:
Теперь добавляем Opus в сборку:
add_library используется для добавления библиотеки в сборку. Сначала идёт имя, которое у неё будет, далее тип библиотеки STATIC(.a) или SHARED(.so) и путь к исходникам, либо слово IMPORTED, если у нас уже собранная библиотека и мы хотим её использовать. В этом случае путь к готовым (импортируемым) библиотекам указывается ниже с помощью конструкции:
ANDROID_ABI это NDK toolchain аргумент, который сам туда подставит ABI.
Для компиляции нашего С-враппера, куда идут external вызовы из Kotlin, мы оставляем:
Также оставляем библиотеку, которая идёт «из коробки» в NDK для логирования таким образом:
И в конце мы объединяем всё это вместе:
Первым параметром идёт имя итоговой библиотеки, далее идут имена библиотек, которые нужно прилинковать к нашей. Вот и всё, теперь синхронизируем проект с помощью Gradle, нажимаем Run, и готово. Приложение открывается, жмём на кнопку Start call и говорим. Если тут же слышим то, что сказали, значит всё работает как надо.
Источник
[question] arm-linux-androideabi-gcc: not found | Error 127, Error 2, #1321
Comments
LovableFatty commented Jul 21, 2020
Steps I followed:
make ARCH=arm goldfish_armv7_defconfig
make ARCH=arm menuconfig
check «enable loadable module support»
check «module unloading»
make ARCH=arm SUB_ARCH=arm CROSS_COMPILE=$/home/noah/Downloads/prebuilt-darwin/darwin-x86/toolchain/arm-linux-androideabi-4.4.x/bin/arm-linux-androideabi-
The text was updated successfully, but these errors were encountered:
LovableFatty commented Jul 21, 2020
It states arm-linux-androideabi-gcc: not found but going into the file shows arm-linux-androideabi-gcc
stephenhines commented Jul 21, 2020
It looks like you’re trying to build the Linux kernel with some NDK prebuilts that you have, but you really need to supply us with more information before we can help here. I’m also going to point out that you need to be building the Linux kernel with Clang instead of gcc, as we no longer provide support for gcc in the Android toolchain. @nickdesaulniers, can you post a sample command line for your suggested kernel build?
stephenhines commented Jul 21, 2020
Actually, I just spotted your bug. $/home/noah/Downloads/prebuilt-darwin/darwin-x86/toolchain/arm-linux-androideabi-4.4.x/bin/arm-linux-androideabi- in your command line should probably be $HOME/Downloads/. or just drop the $ from that part of your command line.
LovableFatty commented Jul 21, 2020 •
Actually, I just spotted your bug. $/home/noah/Downloads/prebuilt-darwin/darwin-x86/toolchain/arm-linux-androideabi-4.4.x/bin/arm-linux-androideabi- in your command line should probably be $HOME/Downloads/. or just drop the $ from that part of your command line.
Tried both solutions and didn’t work
DanAlbert commented Jul 21, 2020
The NDK doesn’t have GCC 4.4. The path you’re using isn’t pointing at a real directory.
LovableFatty commented Jul 21, 2020
The NDK doesn’t have GCC 4.4. The path you’re using isn’t pointing at a real directory.
Doesn’t this image showcase gcc 4.4.3? Also what do you mean by ‘The path you’re using isn’t pointing at a real directory.’ ?
LovableFatty commented Jul 21, 2020 •
building the Linux kernel with Clang
@stephenhines
After I build a linux kernel with clang how do I build an android LKM? that’s my end goal
DanAlbert commented Jul 21, 2020
That’s an extremely old NDK then.
stephenhines commented Jul 21, 2020
building the Linux kernel with Clang
@stephenhines
After I build a linux kernel with clang how do I build an android LKM? that’s my end goal
Источник
Tydus / howto-standalone-toolchain.md
HOWTO Cross compiling on Android
NDK (Native Develop Toolkit) is a toolchain from Android official, originally for users who writes native C/C++ code as JNI library. It’s not designed for compiling standalone programs (./a.out) and not compatible with automake/cmake etc.
What is Standalone Toolchain
«Standalone» refers to two meanings:
- The program is standalone (has nothing connect to NDK, and don’t need helper scripts to run it)
- The toolchain is made for building standalone programs and libs, and which can used by automake etc.
(Optional) Why NDK is hard to use
By default, NDK uses android flavor directory structure when it’s finding headers and libs, which is different from GNU flavor, so the compiler cannot find them. For Example:
Although we can manuall specify the path (someone wrote a program called «agcc» to handle this automatically, but still not good), it’s really annoying.
- Download Android NDK
from https://developer.android.com/tools/sdk/ndk/index.html - Extract the NDK
tar xf android-ndk-r9d-*.tar.bz2 && cd android-ndk-r9d - Make GNU Android Toolchain from NDK
build/tools/make-standalone-toolchain.sh —toolchain=arm-linux-androideabi-4.8 —platform=android-19 —install-dir=../toolchain - Delete the NDK (Yes, we don’t need it any more)
cd .. && rm -rf android-ndk-r9d - Test the native toolchain
cd toolchain/bin
echo «main()<>» | ./arm-linux-androideabi-gcc -x c —
file a.out # a.out: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped - (Optional) Now you can use it as a standard GNU toolchain
For example: ./configure —prefix=/opt/android —host=arm-linux-androideabi && make && make install
This comment has been minimized.
Copy link Quote reply
nikhilkilivayil commented Feb 5, 2016
I am getting this issue :
/home/umn/android/android-ndk-r7c/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/../lib/gcc/arm-linux-androideabi/4.4.3/../../../../arm-linux-androideabi/bin/ld: cannot find -lssl
collect2: ld returned 1 exit status
This comment has been minimized.
Copy link Quote reply
MichaelSX commented Apr 13, 2016
Check if you have libssl-dev installed when using ubuntu reffering to this thread (even though it isn’t about android, but still about your issue).
This comment has been minimized.
Copy link Quote reply
usman313 commented May 1, 2016 •
I am getting this error each time I try to do any work on Android Studio 2.1 and everything in each activity become red. How can I resolve this issue??
This comment has been minimized.
Copy link Quote reply
ranshalit commented Feb 14, 2017
That’s amazing. Thank you very much. I don’t have to build now with «-static». Right ?
This comment has been minimized.
Copy link Quote reply
hannesa2 commented Dec 28, 2017 •
I downloaded android-ndk-r16b and after make-standalone-toolchain.sh the command
in step .5 echo «main()<>» | ./arm-linux-androideabi-gcc -x c — shows nothing.
Is this right, or did I something wrong ?
This comment has been minimized.
Copy link Quote reply
AxelNennker commented Apr 20, 2018
@hannesa2
echo «main()<>» | ./arm-linux-androideabi-gcc -x c — && file a.out
This comment has been minimized.
Copy link Quote reply
KrishnaCAmjuri commented Jun 2, 2018 •
Is this procedure valid for mac(unix) also?
This comment has been minimized.
Copy link Quote reply
unalkalkan commented Jun 3, 2018
Tried in Debian 9, works like a charm!
This comment has been minimized.
Copy link Quote reply
KrishnaCAmjuri commented Jun 4, 2018
This will only build the toolchain for one architecture that is «armv7-a». What about the other architectures? Can you please clarify?
This comment has been minimized.
Copy link Quote reply
bybilly commented Aug 14, 2018
I am having this issue:
»
expr: syntax error
expr: syntax error
./make-standalone-toolchain.sh: can’t open name: No such file or directory
./make-standalone-toolchain.sh: OPTIONS_abstract_Specify: not found
expr: syntax error
expr: syntax error
./make-standalone-toolchain.sh: can’t open name: No such file or directory
./make-standalone-toolchain.sh: OPTIONS_abstract_Specify: not found
expr: syntax error
expr: syntax error
./make-standalone-toolchain.sh: can’t open path: No such file or directory
./make-standalone-toolchain.sh: can’t open path: No such file or directory
./make-standalone-toolchain.sh: OPTIONS_default_.=: not found
expr: syntax error
expr: syntax error
./make-standalone-toolchain.sh: can’t open name: No such file or directory
./make-standalone-toolchain.sh: OPTIONS_abstract_Specify: not found
./make-standalone-toolchain.sh: OPTIONS_default_linux-armv7l=: not found
[and there’s more]
«
At the top it says «WARNING: The shell running this script isn’t bash. Although we try to avoid bashism in scripts, things can happen.»
At the bottom it says that «—toolchain» is an unknown option. Even if —help is the first parameter it says it is an unknown option.
I’d appreciate any help. What can I do?
This comment has been minimized.
Copy link Quote reply
tonyw5 commented Aug 14, 2018
tonywilliams$ /Users/tonywilliams/android-ndk-r17b/build/tools/make-standalone-toolchain.sh —toolchain=arm-linux-androideabi-4.8 —platform=android-19 —install-dir=../toolchain
HOST_OS=darwin
HOST_EXE=
HOST_ARCH=x86_64
HOST_TAG=darwin-x86_64
HOST_NUM_CPUS=4
BUILD_NUM_CPUS=8
Auto-config: —arch=arm
ERROR: Failed to create toolchain.
When trying to build the toolchain arm I am getting this error. Why is that?
This comment has been minimized.
Copy link Quote reply
jainabhinav249 commented Mar 5, 2019
i am using android-ndk 14 and i am getting the clang:error: unknown argument: ‘-mandroid’ can any one help me
This comment has been minimized.
Copy link Quote reply
jainabhinav249 commented Mar 5, 2019
i an trying to build android-27 version
This comment has been minimized.
Copy link Quote reply
w1252675615 commented Sep 29, 2019
hello, i got «ignoring DT_PREINIT_ARRAY in shared library» when run my app on my phone, can you offer me some help or suggestion? thanks
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Источник