I want to compile this program for Android and see it run on my phone:
#include "Hello World.h"
using namespace codewerks;
//=============================================
// Main Loop
//=============================================
int main(int argc, char* argv[])
{
Print(std::string("Hello World!"));
}
Where do I start? Can I compile this with GCC? The NDK seems focused on Java. Thank you.
This is now possible with the latest NDK. You will need an emulator or phone running Android 2.3 to try it, but the NativeActivity documentation has a complete example.
Unfortunately it is somewhat more complicated than a simple "hello world" example, and "main" is spelled "android_main". You still need to worry about your application life cycle as you do in Java, and the only real way to draw to the screen is to use OpenGL ES. It seems to be designed for writing games for Android.
Build as executable. (BUILD_EXECUTABLE)
Copy the executable to sdcard. (adb push)
Go to android shell. (adb shell)
Change the permission of the executable. (chmod 777)
Run the executable. (./out)
You will see the printed result on the console. (happy?)
Related
I cross-compiled my C application for Android ARM with arm-linux-gnueabi tool under Ubuntu 16.04 LTS. I compiled it with static linking flag. This C application is big and it has complicated makefile. It compiled successfully without any errors. But it behaves differently on Android phone and Ubuntu PC. More precisely i have two problems:
popen() and system() functions don't work on Android. They are carried out but do nothing and don't give any errors. This problem i solved with dirty hack.
fgets() functions works strange on Android.
1. About first problem.
I did small research and found that Android doesn't use ordinary libc library (glibc or another library which implements POSIX standard properly). It uses Bionic library instead of it (sorry, Android is new OS for me). I looked into popen() and system() functions code and noticed that these functions use _PATH_BSHELL macros. _PATH_BSHELL is path to the actual system shell. This path is "/system/bin/sh" on Android and "/bin/sh" on Ubuntu.
When i understood it i tried to hook popen() and system() functions. I copied code of these functions from the Bionic source, than i defined macros #define _MY_PATH_BSHELL "/system/bin/sh" and replaced calls like execve(_MY_PATH_BSHELL, argp, environ); by execve(_MY_PATH_BSHELL, argp, environ); calls. So it started work properly.
2. About second problem.
On Ubuntu this code works properly:
is_received = false;
while(!is_received) {
FILE *cmd = popen(command, "r");
is_received = fgets(buf, sizeof(buf), cmd) == NULL ? false : true;
}
But on Android fgets() always returns NULL and this loop works infinitely long. I tried to use read() function instead of fgets() and it worked.
On Android this code with read() works properly:
is_received = false;
while(!is_received) {
FILE *cmd = hooked_popen(command, "r");
int fd = fileno(cmd);
is_received = read(fd, buf, sizeof(buf)) == 0 ? false : true;
}
My questions.
How to solve my problems with popen() and system() neatly and correctly? I think i have to link statically with Bionic library. Is it right? How can i do it in console without Android Studio? I read that it is necessary to use NDK but it is not clear to me how.
Why fgets() behavior isn't similar on Android and Ubuntu?
I am working on a library that is supported on many platforms including Android. This library is unit tested with the Google Test infrastructure. I am currently using Visual Studio 2015's cross platform features to build, deploy and debug. The test suite is getting considerably large and it takes a while to run the whole thing. With the Google Test infrastructure, it is possible to pass a command line argument to filter out the tests to be ran (--gtest_filter...). For platforms such as Windows, PS4 and XboxOne, this is easy to achieve inside Visual Studio by setting it in Project Properties -->Configuration Properties --> Debugging --> Command Arguments. However for the cross-platform developpment projects and package (AndroidProj), this Debugger property doesn't seem to exist. Here'a snapshot of Android Native-Activity Project Properties.
I am aware that the Visual GDB extension offers a similar feature to the one I am looking for as shown here, but this is not a viable option as I would like to avoid paying for the extension license.
How can I provide command line arguments to the Android Debugger the same way I can do it for the Local Windows Debugger for example?
A colleague of mine found the answer not too long after I posted this question. Here's how we solved our issue.
In VS2015, in the property pages of the Android cross-platform Package/App project (Androidproj), more precisely in the Debugging tab, there is the Launch Activity field. This field can be used to pass command line intent arguments. When you launch the debugger after installing the package, it will execute the following command:
adb.exe am start -D -n com.YourPackageName/TheContentOfLaunchActivityField.
In the Launch Activity field by default the launcher activity is specified (android.app.NativeActivity), but you can provide further intent arguments. A list of them can be found in this documentation: https://developer.android.com/studio/command-line/adb.html#IntentSpec.
In our situation, we needed to provide string data to our app (e.g.: --gtest_filter=...), so we used the intent argument -e extra_key extra_value.
Inside our main function we can retrieve the values of the extras using the following piece of code and some parsing (not shown). It uses the JNI (Java Native Interface).
JNIEnv* env = NULL;
state->activity->vm->AttachCurrentThread(&env, 0);
Private::JNIObjRef nativeActivityObject(env, state->activity->clazz);
jclass nativeActivityClass = env->GetObjectClass(nativeActivityObject.Get());
jmethodID getIntentID = env->GetMethodID(nativeActivityClass, "getIntent", "()Landroid/content/Intent;");
Private::JNIObjRef intentObject(env, env->CallObjectMethod(nativeActivityObject.Get(), getIntentID));
jclass intentClass = env->FindClass("android/content/Intent");
jmethodID getExtrasID = env->GetMethodID(intentClass, "getExtras", "()Landroid/os/Bundle;");
Private::JNIObjRef extrasObject(env, env->CallObjectMethod(intentObject.Get(), getExtrasID));
I am using getline function and compiling using ndk but i am getting error :
'getline' was not declared in this scope
is this error due to limitations of armeabi-v7a or due to glib?How can it be resolved for the same function.
I have already #define _GNU_SOURCE before <stdio.h>
In general, when you encounter such an error, you go to your NDK directory and user either Midnight Commander (Linux) or Far Manager (Windows, Linux+Wine) to search the files (file mask: *.h) for your function, getline in this case. You will get a screenful of search results, and it's up to you to #include the right file.
Once in a while your function will not be found; in this case you search the 'net for a place where you can borrow the source.
Sometimes the function in the code being ported has just no meaning, e.g. if the function reads a line from stdin but the program going to invoke it is not a command-line utility, there is a problem.
Most likely, the source that you port #define-s switches for Linux, Mac (Darwin) and Windows, you have to choose the right configuration to derive the Android configuration from (and probably the Mac one will be the best).
I am looking at the source for the android shell reboot command.
int reboot_main(int argc, char *argv[])
What I am not clear about is if this is a standalone binary, who calls reboot_main() ?
In a standard glibc linked binary, I was expecting to find a "main()" as the entry point for the program.
What am I missing here, could someone help me understand what is going on ?
Thanks,
vj
They are all compiled into one overall executable, with main in https://android.googlesource.com/platform/system/core.git/+/android-4.2.2_r1/toolbox/toolbox.c
Then, based on the actual program name invoked (usually argv[0]) it calls the appropriate method.
The commands are part of the build via the
#define TOOL(name) int name##_main(int, char**);
macro in toolbox.c which is used in the Android.mk file to generate tools.h.
I am attempting to build an Android app that makes use of boost serialization. I have built the library against NDK r8d using arm 4.7's g++. When I go to compile my native code into a library using ndk-build, however, I get "undefined reference to 'mbtowc'" and "undefined reference to 'wctomb'" when the compiler attempts to link some code from Archive headers in boost.
I cannot seem to get a clear answer as to whether the NDK supports these functions.
Although it implements the functions, the CrystaX NDK is not an option as it has known crashes when using it with Boost, according to the Boost mailing list.
So, if the NDK does implement these functions somehow, why is NDK-build unable to link against them? I can find reference to them in cstdlib within the NDK, and I believe there may be a flag I need to set, but I'm not sure how or where to do so.
If there is no implementation of them, does anyone have any advice on how I can write them myself? I know roughly what mbtowc and its complement are supposed to do, but without much experience writing low-level C, and without much knowledge of Android / ARM architecture, I could really use some advice on doing so.
#ifdef ANDROID
int wctomb(char *s, wchar_t wc) { return wcrtomb(s,wc,NULL); }
int mbtowc(wchar_t *pwc, const char *s, size_t n) { return mbrtowc(pwc, s, n, NULL); }
#endif
Findings! Yes, boost has options to build it without requiring wchar support by adding preprocessor definitions to the boost build scripts. Boost still crashes when built using them at the line of code where I attempt to serialize an object to file. (the crash is a generic segfault at 0x00000000, and I was unable to gain any useful information).
So, I haven't bothered writing wctomb or its inverse. I shouldn't need to, is the answer to my question, although in the end the answer to the question doesn't matter.
To further clarify: don't bother doing what I've been trying to do. If you have been using Boost's serialization library and want your code to run on android ndk r8d or earlier, just give up. Write a serializer yourself, because there is no useful information to be found on how to make Serialization work. Hopefully a future release of the ndk fixes this problem, but for now I have no choice but to just rewrite everything.
I had the same problem. I was creating an android port for code that uses boost::serialization.
My code failed to compile because of missing implementation of mbtowc / wctomb (mb: multi-byte (char), wc: (wide-char)'
Implementation of these functions will probably be tricky cause as far as I know the wide-char for android is a single byte char instead of a true wide character..
However when I compiled boost with -DBOOST_NO_STD_WSTRING the link errors disappeared and I could use boost::archive::text_iarchive & boost::archive::text_oarchive on android.
I am now serializing STL containers of numerics and std::strings without a problem.
I compiled boost for android following the advice on this link: http://www.codexperiments.com/android/2011/05/tips-tricks-building-boost-with-ndk-r5/
I am using boost-1.55_0 and NDK r9c.
I added the following <compileflags>-DBOOST_NO_STD_WSTRING to the build command so it would build serialization library without wide character support.