We've got a Visual Studio Android solution with (among others) a static library project that contains functionality implemented in assembly. Like:
my.S -> libMine.a -> libMyApp.so
Some hoops (below) have already been jumped through, to get it to compile. Then, the linking of the main app shared library project fails (on both architectures that we care about - x64 and arm64), with undefined references to the functions that are implemented in [the] assembly [file].
It appears that Visual Studio (or its Cross Platform Mobile Dev / Android plug-in) doesn't handle assembly file project items quite correctly - treated as C/C++ Compiler files, it'll error out on the first dot character (i.e. in .text); and the Microsoft Macro Assembler is "not supported on this platform". So I looked into setting up a custom build step, with the following command:
$(ClangToolExe) %(FullPath) --target=$(ClangTarget) -g -o $(IntDir)%(FileName).o
This will preprocess, compile and link - but with the wrong linker: instead of the one for the particular Android toolchain, it'll go for the one in my MinGW install, which doesn't recognise the emulation mode - anyway, that's not the location of my NDK toolchain.
We can skip the linking of the object for now (add -c to the above command). Much to our dismay, the resulting object file still doesn't get added to the static library, as confirmed by {Rest of the toolchain path}ar t libMine.a. And indeed, the library will have undefined symbols for our functions, as shown by {Rest of the toolchain path}objdump -t libMine.a.
Let's add the object file to the resulting library quite manually, as a post build step. Command:
$(ToolChainPrebuiltPath){Rest of the toolchain path}ar.exe ru $(TargetPath) $(IntDir)my.o
objdump -t libMine.a will now show that we've got the symbols. There is however also the *UND*efined pair.
Fast forward:
Adding my.o with ar rub otherObjectThatReferencesMyFunctions.o libMine.a, to have the good symbols show up before the undefined ones doesn't make a difference.
Linking my compiled assembly file with a second custom build step, $(ToolChainPrebuiltPath){Rest of the toolchain path}ld.exe $(IntDir)%(FileName).o -o $(IntDir)%(FileName).o doesn't make a meaningful difference.
Running the linker again on the static library, as a second post-build step $(ToolChainPrebuiltPath){Rest of the toolchain path}ld.exe $(TargetPath) doesn't make a meaningful difference.
The last two steps result in a warning about a missing symbol _start (entry point?). I'm guessing this is in reference to linking an executable, which we don't want.
What am I doing wrong? How can I resolve those undefined references?
What seems to have worked was to:
1, Make sure that the extension of the assembly file is .S, i.e. capital S. This is one of the few instances I've found, where the case of a filename matters on Windows.
2, Configure the project so that the assembly file is built with clang.exe {full/path/to/assembly.S, i.e. %(FullPath)} -c --target=$(ClangTarget) -g -o $(IntDir)%(FileName).o. In the case of VS Android, we need to specify the build output separately, which is the $(IntDir)%(FileName).o part all over again.
3, Run ar as a post build command: {correct toolchain}/ar.exe rus $(TargetPath) {output from assembly compilation}, for each assembly file.
One thing this solution is lacking is detecting [a lack of] changes, meaning that the assembly file will be rebuilt on each compilation, and everything that depends on it.
Related
I've spent many hours today trying to accomplish this seemingly very simple task so my frustration may seem strange to you.
I want to "run"/execute a program that contains OpenCL functions on my Samsung Galaxy S7 (Exynos SoC). Support for OpenCL shouldn't be an issue because:
1) It's a well supported flagship phone from a well-known manufacturer
2) libOpenCL.so is present in /system/vendor/lib/libOpenCL.so
3) OpenCL-Z reports a valid platform and device (GPU only for some reason)
Things that I tried:
Rooted the phone.
Installed cppdroid.
Tried to compile a simple program that contains references to standard OpenCL functions like clGetPlatformIDs().
Header files should be included somewhere, but I could not for the life of me find where to put them (using the same path where cppdroid stores standard header files did not work), so I manually included the headers in the .c file itself, making it barely editable on the phone itself.
My understanding is that I should link the library (libOpenCL.so) to the output of gcc during the linking phase. There seems to be an option to do that in cppdroid, under "Settings" "Project settings" "Link options" so I add:
-L/system/vendor/lib/libOpenCL.so
to that field. However compilation still fails and I'm getting "undefined references to clGetPlatformIDs()" as if I hadn't included the library at all.
After searching online for a solution, a possible remedy (see below) proved useless:
-Wl,--whole-archive -L/system/vendor/lib/libOpenCL.so
I thought I'd get gcc on its own since this is the compiler used by cppdroid and try to compile that way. Found out that it's supposed to be deprecated, and replaced by "clang". But cppdroid does include gcc, so I navigated to the folder containing the executable (I believe it's an executable, there seem to be no extensions here, and I'm a Windows person) which appears to be:
/data/data/name.antonsmirnov.android.cppdroid/sdk/gcc#4.8#2/bin
and tried to "execute" gcc-4.8 (which appears to be the executable compiler) from termux (a terminal emulator for Android). Much to my surprise I got the error message:
sush: gcc-4.8: not found
Even though ls -1 lists the file normally!
I tried various other stuff that did not work, but here's my question:
How do I go about compiling a simple OpenCL program that I've written in C, so as to execute it on my Android mobile device?
Why do I get the
sush: gcc-4.8: not found
error message?
My understanding is that I should link the library (libOpenCL.so) to the output of gcc during the linking phase. There seems to be an option to do that in cppdroid, under "Settings" "Project settings" "Link options" so I add:
-L/system/vendor/lib/libOpenCL.so
to that field. However compilation still fails and I'm getting "undefined references to clGetPlatformIDs()" as if I hadn't included the library at all.
You need to add -lOpenCL and -L/system/vendor/lib to the linker flags. The second option may not be required, as this directory should be in a default search path already.
First -L provides a search directory for libraries to link, you should be using -L/system/vendor/lib you can use -l to link to a library in your case -lOpenCL without the lib prefix.
I got it working on my Samsung S9+ Exynos phone. Here is what I did to use OpenCL in the Termux app:
apt update
apt upgrade
apt autoremove
apt install vim openssh clang git
vim ~/.bashrc
# press the i key, then paste the line below, then save and exit with :wq
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/system/vendor/lib64:/system/vendor/lib64/egl
# restart Termux
exit
And finally, to compile a C++ OpenCL program with headers as described here:
cd Test/src
g++ *.cpp -o Test.exe -std=c++11 -pthread -w -I./OpenCL/include -L/system/vendor/lib64 -lOpenCL
./Test.exe
To install clinfo do the following:
apt install cmake make
cd ~
mkdir opencl
cd ~/opencl
git clone https://github.com/KhronosGroup/OpenCL-Headers
cd ~/opencl/OpenCL-Headers
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=$PREFIX
cmake --build build --target install
cd ~/opencl
git clone https://github.com/Oblomov/clinfo
cd ~/opencl/clinfo
make OS=Android
./clinfo
I've completed the first part of my project, and I want to know how well / bad it performs by profiling it with gprof. I am working on Android using a Linux emulator named Termux, and I am using g++ as the compiler.
Everything compiles without errors and even warnings, and the binary runs perfectly.
So I decided to put the -pg flag among the other flags in my makefile, (meaning that both compilation and linking is performed with -pg) and tried recompiling everything. But something seems to not work properly: during compilation, everything is normal. But when linking I get a argument unused during compilation: '-pg' warning and then a lot of undefined reference to 'mcount' (it doesn't even display all of them, after a bit it says more undefined references to 'mcount' follows) errors, and at the end a linker command failed with exit code 1 error.
What is causing this behaviour? Is something broken / missing on the platform I am using? Can I fix that? How?
Sorry for the short answer, but I'm on mobile. Making a community wiki.
In Termux, g++ is a symlink to clang. -pg is a gnu feature, so does not function when linking using clang.
You could use clang-appropriate techniques for profiling, or install a real g++. One reference is https://android.stackexchange.com/questions/182130/use-gcc-compiler-in-termux but there is also "google performance tools" for profiling out there somewhere.
I've got a hold of a proprietary JNI application which I need to build for a MIPS device. I've read "Initializing a Build Environment", parts of the NDK docs, some Google Groups threads and numerous StackOverflow questions, but I'm still short of my answer.
So far, I've checked out the Android source using Google's repo script and have it under ~/AndroidSource. I've also separately downloaded the SDK under ~/AndroidSDK and the NDK under ~/AndroidNDK. The code I'm trying to build is in a separate location. The SDK and NDK binaries are in my path. For building, I tried to use two different versions of the NDK as well as the one under the Android source tree, and experienced different sets of problems. My current setup uses NDK r8b, downloaded separately from the Android source.
The application has its Android.mk and jni/Android.mk. However, several directives in the latter point to paths such as
frameworks/base/include
system/core/include
with no prefixes. I thought these were meant to point to the respective directories in the Android source, so I symlinked them to the current directory. After some more symlinking and makefile and source hacking, I got the application to compile, but am currently stuck on the linking phase with lots of references to missing method bodies. During the whole time I knew I was doing something wrong.
I'm on a Linux x86_64 host, if it is of any concern.
So my question is:
What is the proper method to set up a build environment for JNI applications? What environment variables, symlinks and/or path expansions should I set up? Do I need to call any scripts once or before each ndk-build invocation?
Also, I'd be happy if you corrected me on any concepts or terminology I've gotten wrong.
Your approach wiyh symlinking the AOSP tree for system headers is correct. What you need now are the system libraries compiled for MIPS. The easiest way to get them is to adb pull them from a target device (or emulator image). But you can also build these libraries yourself, as part of the AOSP build (see build instructions for the source tree you downloaded).
If you still have any problems remaining, run your ndk-build with parameter V=1 and publish the link command and its results.
I use the following in my build (YMMV).
Explicitly invoke arm-linux-androideabi-gcc as your compiler or linker (should be in PATH).
NDK_PLATFORM=/path/to/android-ndk-r*/platforms/android-14
Pass -I"$(NDK_PLATFORM)/arch-arm/usr/include" to the compiler
Pass -nostdlib -L"$(NDK_PLATFORM)/arch-arm/usr/lib/" -lgcc -lc -lm to the linker
I am trying to understand what a standalone toolchain means.
Following are my findings.
A toolchain which is ready to use with all the configuration that is the system headers and libraries in the correct path . For Android it will also have the API headers in the path where the toolchain can look it up. Why the term "standalone"? This probably will be different that the regular toolchain in the sense that the R T will need to be configured and made ready for android use withe sysroot and libc header paths given etc.
Please comment .
Hmm, I was compiling for android and one process was running a script called make-standalone-toolchain.sh a standalone toolchain is created .I was going through this script to understand what this is doing. Not really good at shell scripting. But made out certain things. ""Generate a customized Android toolchain installation that includes a working sysroot. The result is something that can more easily be used as a standalone cross-compiler, e.g. to run configure and make scripts." --toolchain arch ndk-dir package-dir system platform variables are set Compute source sysroot
SRC_SYSROOT="$NDK_DIR/platforms/$PLATFORM arch-$ARCH" Copying sysroot headers and libraries... libstdc++ headers and libraries... prebuilt binaries.all into a temporary folder then a copying from Tmp dir to install
dir creating a tar ie a package file to add the tmpdir wanted to know what exactly is happening here or a link or suggestion where to look.but ofcourse dont want to read very elaborate manuals.
~
This blog posting may answer your question:
http://clseto.mysinablog.com/index.php?op=ViewArticle&articleId=3480794
There is a recommended way to build native C/C++ program on Android: List your source files in a script (Android.mk) and run 'ndk-build'. It may not be a problem if you are writing new programs but if you already have a working build script (like those open source softwares) which can build you program nicely on Linux, it would be a headache to migrate your script to Android.mk. All you need in this situation is a C/C++ cross compiler and then replace the variables in your script (such as CC, CXX, AR, AS, RANLIB, ...) to something like 'arm-linux-androideabi-gcc', 'arm-linux-androideabi-g++', ...
Fortunatley, inside the 'Android NDK Dev Guide', there is a section 'Standalone Toolchain' which just describes what we need....
First of all, the best guide for stand alone toolchains in Android is here: https://developer.android.com/ndk/guides/standalone_toolchain.
I have used it several times for different devices and platform.
You need to download NDK and then run the script 'make-standalone-toolchain.sh' with a few parameters (as said in the link above) that will determine the API levels of your apps, the architecture of the device etc.
The output of the script will be a directory that you can use as a toolchain in order to cross compile native C/C++ code to run on Android devices. You need to put in your Makefile the path to the toolchain directory and add the architecture suffix for the binaries inside (for example 'arm-eabi-'). Something like:
CROSS_COMPILE = /path-to-toolchain-dir/bin/arm-eabi-
There should be files like '/path-to-toolchain-dir/bin/arm-eabi-gcc' in your toolchain directory.
Anyway, this will tell the Makefile to use your toolchain's binaries in order to compile the C/C++ native code and create the compatible executables for your target machine.
For example, this is the commands I used to create a stand alone tool chain for a certaion Android device:
./make-standalone-toolchain.shj --arch=arm --platform=android-21 --install-dir=<dest-dir> --toolchain=arm-linux-androideabi-4.9
I've been trying to cross compile wireless tools for linux.
I've got the cross compiler for android. So I've changed the Makefile and replaced the follwoing:
CC =arm-eabi-gcc
AR = arm-eabi-ar
RANLIB = arm-eabi-ranlib
I've exported the path to these files:
export PATH=/home/flitjes/android/system/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/:$PATH
The problem is, it compiles perfectly with standard gcc,ar and ranlib but when I replace them with the cross compile version It's erroring on every line it comes across. I'm thinking it has to do something wih the cross compiler so I'm not totally sure this is the right way of doing it.
I've tried to run the make file which resulted in this:
http://pastebin.com/jNw4j5WX
Answering an old post since someone might get this page from a search engine:
I've cross compiled linux-wireless for the PowerPC platform for several projects.
Modifying the Makefile is the wrong way to do it.
linux-wireless (latest is 3.5 at the time of this writing) can be cross compiled by just using extra parameters. This website shows the gist of the process.
You want the CROSS_COMPILE macro defined for your platform.
You want linux-wireless to see where your platforms (in this case ARM) kernel sources and .config is. You do that with the KLIB and KLIB_BUILD macros. If you don't define this linux-wireless will use the information from the current running kernel. You really don't want that.