Building separate Android modules with dexpreopt disabled - android

For my thesis, I'm modifying the android framework and building the source (4.1.1 Jelly Bean).
I can do a full build, but because this is very time consuming (I'm developing on a ubuntu 12.04 64bit virtual machine) I'd like to build separate modules.
For example:
When doing changes to the location modules, it should be possible to just build the changed module, and make a new system image:
mmm frameworks/base
make snod
But this doesn't work. Every time I try to boot, the new system image won't boot because of:
I/dalvikvm( 1696): DexOpt: mismatch dep signature for '/system/framework/framework.odex'
After some research, I tried to disable dexpreopt with the enviroment variables
export $WITH_DEXPREOPT=false
and
export $DISABLE_DEXPREOPT=true
and doing a full rebuild with 'make installclean'. The full rebuild works, and the changes to the framework are present in the build. But after doing a new change, still 'mmm frameworks/base' and 'make snod' result in dexpreopt mismatch.
The build/core/makefile from 'make snod' also gives the warning: 'Warning: with dexpreopt enabled, you may need a full rebuild.', which comes from this line in the makefile:
ifeq (true,$(WITH_DEXPREOPT))
$(warning Warning: with dexpreopt enabled, you may need a full rebuild.)
endif
This leads me to believe the $WITH_DEXPREOPT variable isn't correctly set or read?
So far I haven't been able to get a bootable system image without doing a clean full rebuild. Is the procedure I follow the correct to disable dexpreopt, or are there any other ways to build separate modules after doing changes to the framework and getting a new system image?
Build target is 'full-eng'.

Apparently the WITH_DEXPREOPT environment variable is overwritten by an internal WITH_DEXPREOPT variable in
build/target/board/generic/BoardConfig.mk
Changing this to false, or according to the people at google groups, starting a make with:
make showcommands WITH_DEXPREOPT=false
does the trick. Building a specific module and making a new system image now results in a bootable build.
(source: https://groups.google.com/d/topic/android-building/vJCkg8Yq9Ic/discussion )

Related

How to add rpath $ORIGIN to native executable for android cross build

I am trying to build an executable for Android with cross compiling, everything works but the executable complains that it could not find the .so file it needs, which is in the same directory as the executable.
So what I did is to add the following lines
set(TARGET myapp)
# following 4 lines added to add RPATH of ./ to the binary
# so it searches the .so in the same directory
SET(CMAKE_SKIP_BUILD_RPATH FALSE)
SET(CMAKE_SKIP_RPATH FALSE)
set(CMAKE_INSTALL_RPATH $ORIGIN)
SET(CMAKE_BUILD_WITH_INSTALL_RPATH ON)
# add source code to target
add_executable(${TARGET} src.cpp)
...
However, it builds the executable, but RPATH seems not working no matter how I play with the four lines above, I just could not find any RPATH info in the binary using readelf or objdump.
I also tried set_target_properties(${TARGET} PROPERTIES INSTALL_RPATH $ORIGIN) but still not working.
Did I miss use anything here for RPATH configuration?
update
just to note that if I build the app for host(Linux) (using the same cmake file except using the android ndk tool chain) then everything is fine, I see $ORIGIN in the binary RPATH using readelf.
although i dont know what is been done in android ndk tool chain
This is probably not what you want:
(I am mentioning it just to be complete with my answer)
I assume that $ORIGIN is an environment variable. If that is the case you need to explain to CMake that it is such an variable. You can use $ENV{VAR} to do this, e.g.:
set(CMAKE_INSTALL_RPATH $ENV{ORIGIN})
This is probably what you want:
Ofcourse if the variable is not accessible during CMake generation step. You can try to use bracket arguments, however I do not think that alone would work (see last note at the bottom). Bracket arguments [=[...]=] tell CMake to skip the evaluation, because $ is a special character. e.g.:
set(CMAKE_INSTALL_RPATH [=[$ORIGIN]=])
To understand what [=[]=] do here is a simple example:
set(FOO "bar")
message(STATUS ${FOO})
message(STATUS [=[${FOO}]=])
Should output
bar
${FOO} #<-- evaluation of ${FOO} was skipped
Also if I'm not mistaken you also need to pass $ORIGIN to linker with single quotes so that it doesn't get evaluated during linking, i.e.
'$ORIGIN'
#and not $ORIGIN

How to get an ENV var available in project which uses Android.mk

I have an Android project which uses Android.mk files for the setup. I would like to introduce Build Variants to the project and based on a build var such as BUILD_BRAND to perform some UI changes.
My case is:
I have BUILD_BRAND exported on my Ubuntu in the .bashrc.
If I echo $BUILD_BRAND I would get the value printed in the terminal.
I also do $(warning $(BUILD_BRAND)) and I can see during the build the value is printed so it is available.
But when I try to do System.getEnv("BUILD_BRAND"); in an activity, a null is returned.
The question is how to make this value under BUILD_BRAND to become globally available to the project.
Thanks!
In my case the solution was to use SystemProperties.get("the.property.name").
The "the.property.name" was set in the Makefile.mk located in the core.
I also find out that I can export ENV vars to the project during build time using the same Makefile.mk.
N.B - You can't access an env var during runtime directly using System.getEnv() !

Delphi 11: Find correct toolsversion for MSBuild programmatically

We're upgrading to Delphi 11.1 from 10.4.
We have a few scripts which build and deploy Android projects. They assemble an msbuild command that looked like this:
msbuild someproject.dproj /v:q /p:Platform=Android /t:Build;Deploy /p:Config=Release /p:BT_BuildType=AppStore
With 11.1, this throws an error message:
C:\Program Files (x86)\Embarcadero\Studio\22.0\bin\CodeGear.Common.Targets(940,7): error MSB4036: The "XmlPeek" task was not found. Check the following: 1.) The name of the task in the project file is the same as the name of the task class. 2.) The task class is "public" and implements the Microsoft.Build.Framework.ITask interface. 3.) The task is correctly declared with <UsingTask> in the project file, or in the *.tasks files located in the "C:\Windows\Microsoft.NET\Framework\v2.0.50727" directory. [someproject.dproj]
Now, C:\Program Files (x86)\Embarcadero\Studio\22.0\bin\rsvars.bat, which is used by all of our build scripts, explicitly sets the .NET framework as below:
#SET FrameworkDir=C:\Windows\Microsoft.NET\Framework\v4.0.30319
#SET FrameworkVersion=v4.5
After some research, I hit on the idea of adding a toolsversion parameter to the msbuild command as below, and this worked:
msbuild someproject.dproj /v:q /p:Platform=Android /t:Build;Deploy /p:Config=Release /p:BT_BuildType=AppStore /toolsversion:4.0
This is all well and good, but I would prefer not to hard-code the toolsversion number in the script(s).
Is there a way I can programmatically obtain the correct value of the toolsversion that Delphi itself is using when it generates builds, etc.?
I assume that just finding the highest .NET version installed will not suffice (and even then, one has to "translate" that to a toolsversion). It has to marry up with whatever Delphi is doing (e.g., in the CodeGear.Common.Targets file referenced in the original error message).
This is a bug in Delphi 11.1 that has at least 3 bug reports: RSP-37855, RSP-38466, and RSP-38467.
You can add /tv:4.0 to your MSBuild command line, or modify the first line in the .dproj file to:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0" DefaultTargets="Build">
Assuming that rsvars.bat has been run,
FOR %%v IN ("%frameworkdir%") DO SET "toolsversion=%%~nv"
ECHO msbuild ...blah... /toolsversion:%toolsversion:~1%
The variable frameworkdir will be set by rsvars.bat. The for command parses its value (eg. C:\Windows\Microsoft.NET\Framework\v4.0.30319 as though it is a filename, and picks v4.0 as the "filename" (~n modifier [filename] of the metavariable %%v)
Then use the value assigned to toolsversion, starting at character 1 (where the first character is "character 0")
--- Given more info in comment
FOR %%v IN ("%frameworkdir%") DO ECHO %%~nxv|FINDSTR /R ".*\..*\.">nul&IF ERRORLEVEL 1 (SET "toolsversion=%%~nxv") ELSE SET "toolsversion=%%~nv"
Oh ye of little faith :)

How to compile boost 1.68.0 for Android using NDK r18b using Windows

I had to build a version of boost for Android using NDK r18b, I had a hardtime achieving this so I post Question+Answer here as it may help other persons.
Firstly, I tried https://github.com/moritz-wundke/Boost-for-Android, but this was unsuccessful, see How to build boost 1.69.0 for Android with NDK r18b using moritz-wundke/Boost-for-Android?.
Secondly, I tried https://github.com/dec1/Boost-for-Android, but this was unsuccessful too, see How to build boost 1.69.0 for Android with NDK r18b using dec1/Boost-for-Android?.
What are the steps to follow to achieve compilation of boost?
Actually, those scripts were designed for Linux, and they hardly work under Windows. Then, I started from scratch and could finally find the good config under Windows to achieve this. I basically checked how other libraries are compiled (I use QtCreator to deploy on Android, so the compilation window reported me how clang++ has to be invoked, so I write a user-config.jam based on that.
Here are the steps to follow to compile boost 1.68.0 for Android armeabiv7 and x86 using NDK r18b:
Download boost 1.68.0 from boost.org: https://www.boost.org/users/history/version_1_68_0.html
Apply moritz-wundke's patch, else it won't compile (thanks by the way). Take it from here: https://github.com/moritz-wundke/Boost-for-Android/tree/master/patches
Run bootstrap.bat (you'll need it to find a compiler, I have VS 2015 installed so it works just fine)
Then set some environment variables:
set ANDROIDNDKROOT=C:\Android\android-ndk-r18b (change this accordingly)
set NDKVER=r18b
set CLANGPATH=%ANDROIDNDKROOT%\toolchains\llvm\prebuilt\windows-x86_64\bin
Copy user-config.jam to boost folder tools/build/src:
import os ;
local AndroidNDKRoot = [ os.environ ANDROIDNDKROOT ] ;
local AndroidBinariesPath = [ os.environ CLANGPATH ] ;
using clang : armeabiv7a
:
$(AndroidBinariesPath)/clang++
:
<compileflags>-fexceptions
<compileflags>-frtti
<compileflags>-mthumb
<compileflags>-ffunction-sections
<compileflags>-funwind-tables
<compileflags>-fstack-protector-strong
<compileflags>-Wno-invalid-command-line-argument
<compileflags>-Wno-unused-command-line-argument
<compileflags>-no-canonical-prefixes
<compileflags>-I$(AndroidNDKRoot)/sources/cxx-stl/llvm-libc++/include
<compileflags>-I$(AndroidNDKRoot)/sources/cxx-stl/llvm-libc++abi/include
<compileflags>-I$(AndroidNDKRoot)/sources/android/support/include
<compileflags>-DANDROID
<compileflags>-Wa,--noexecstack
<compileflags>-Wformat
<compileflags>-Werror=format-security
<compileflags>-DNDEBUG
<compileflags>-D_REENTRANT
<compileflags>-O2
<compileflags>-gcc-toolchain
<compileflags>$(AndroidNDKRoot)/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64
<compileflags>-target
<compileflags>armv7-linux-androideabi
<compileflags>-march=armv7-a
<compileflags>-mfloat-abi=softfp
<compileflags>-mfpu=vfp
<compileflags>-fno-builtin-memmove
<compileflags>-fpic
<compileflags>-DHAVE_CONFIG_H
<compileflags>-fno-integrated-as
<compileflags>--sysroot
<compileflags>$(AndroidNDKRoot)/sysroot
<compileflags>-isystem
<compileflags>$(AndroidNDKRoot)/sysroot/usr/include/arm-linux-androideabi
<compileflags>-D__ANDROID_API__=18
<archiver>$(AndroidNDKRoot)/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64/arm-linux-androideabi/bin/ar
<ranlib>$(AndroidNDKRoot)/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64/arm-linux-androideabi/bin/ranlib
;
# --------------------------------------------------------------------
using clang : x86
:
$(AndroidBinariesPath)/clang++
:
<compileflags>-fexceptions
<compileflags>-frtti
<compileflags>-mthumb
<compileflags>-ffunction-sections
<compileflags>-funwind-tables
<compileflags>-fstack-protector-strong
<compileflags>-Wno-invalid-command-line-argument
<compileflags>-Wno-unused-command-line-argument
<compileflags>-no-canonical-prefixes
<compileflags>-I$(AndroidNDKRoot)/sources/cxx-stl/llvm-libc++/include
<compileflags>-I$(AndroidNDKRoot)/sources/cxx-stl/llvm-libc++abi/include
<compileflags>-I$(AndroidNDKRoot)/sources/android/support/include
<compileflags>-DANDROID
<compileflags>-Wa,--noexecstack
<compileflags>-Wformat
<compileflags>-Werror=format-security
<compileflags>-DNDEBUG
<compileflags>-D_REENTRANT
<compileflags>-O2
<compileflags>-gcc-toolchain
<compileflags>$(AndroidNDKRoot)/toolchains/x86-4.9/prebuilt/windows-x86_64
<compileflags>-target
<compileflags>i686-linux-android
<compileflags>-march=i686
<compileflags>-mfloat-abi=softfp
<compileflags>-mfpu=vfp
<compileflags>-fno-builtin-memmove
<compileflags>-fPIC
<compileflags>-mstackrealign
<compileflags>--sysroot
<compileflags>$(AndroidNDKRoot)/sysroot
<compileflags>-isystem
<compileflags>$(AndroidNDKRoot)/sysroot/usr/include/i686-linux-android
<compileflags>-D__ANDROID_API__=18
<archiver>$(AndroidNDKRoot)/toolchains/x86-4.9/prebuilt/windows-x86_64/i686-linux-android/bin/ar
<ranlib>$(AndroidNDKRoot)/toolchains/x86-4.9/prebuilt/windows-x86_64/i686-linux-android/bin/ranlib
;
Then, for armeabiv7-a:
Run bjam -q --without-math --without-context --without-coroutine --without-fiber --without-python architecture=arm --ignore-site-config -j4 target-os=android toolset=clang-armeabiv7a link=static threading=multi --layout=tagged --build-dir=build/arm/%NDKVER% --stagedir=stage_arm_%NDKVER% stage
Then, for x86:
Run bjam -q --without-math --without-context --without-coroutine --without-fiber --without-python architecture=arm --ignore-site-config -j4 target-os=android toolset=clang-armeabiv7a link=static threading=multi --layout=tagged --build-dir=build/arm/%NDKVER% --stagedir=stage_arm_%NDKVER% stage
Hopefully, the same steps can be followed to compile 1.69.0 (not tested)
Thanks for the helpful instructions.
moritz-wundke/Boost-for-Android is a great project and the original Boost-for-Android. However, the way it works, it requires constant maintenance in order to support each new combination of the ndk and boost as new versions come out (you can only build for the explicit versions the project has been configured to support). After a long time (boost version 1.53 -> 1.63, and ndk 10->16) where its seemed like the project was no longer being maintained, and my efforts to contact the maintainer were in vain, I decided to fork it, which is why dec1/Boost-for-Android came into existence.
It has the advantage that it does not, in general, need to be updated to support new versions of google's ndk, or boost. They generally build out of the box, or need rare adjustments (but I still test regularly to make sure).
Using dec1/Boost-for-Android is arguably also simpler (certainly than following your instructions above). You can build for any/all architectures (arm64-v8a, armeabi-v7a, x86, x86_64), in one go in a single line of code. And if you dont need a custom build you can simply download prebuilt binaries (boost 1.69.0, with ndk 19 and 18b, both dynamic and static are now also available) from here. There's also an example app to help you test your build.
Im pretty sure that it could be made to work on windows or mac too (possibly with less effort than you spent above), but its a lot easier to just use a virtual machine (eg the free virtualbox) to do the build, and copy the resulting binaries to windows if you really want to develop there.
Nonetheles, moritz-wundke/Boost-for-Android seems to have gotten a new influx of contributions of late, which is good news for everybody. And if you find it more suitable for building boost on windows (or any other platform) then thats great.
Good luck with your projects and thanks again for the insights.

Android NDK path variable for "strip" command in CMake build tool chain

I am trying to add a strip debug symbols step for my Android library which includes native shared libraries for different ABIs, e.g. x86/native-lib.so, x86_64/native-lib.so, arm64-v8a/native-lib.so, etc.
I understand that the strip command must be respective to each ABI. So, I need to invoke the correct strip command, for which I need to know its correct path during build time.
For example, for ABI x86_64, I need to have below path setting:
set(STRIP ~/Library/Android/android-ndk-r16b/toolchains/x86_64-4.9/prebuilt/darwin-x86_64/bin/x86_64-linux-android-strip)
add_custom_command(TARGET ${SHARED_LIBRARY_NAME} POST_BUILD
COMMAND ${STRIP}
"${DIST_LIBS_DIR}/${LIB_BUILD_TYPE}/${ANDROID_ABI}/lib${SHARED_LIBRARY_NAME}.so"
COMMENT "Strip debug symbols done on final binary.")
The path I need is illustrated like below:
So, my questions are:
Is there an existing CMake variable to point at this path, i.e. /android-ndk-r16b/toolchains/???/prebuilt/???/bin/???-???-???-strip?
If not, is there a way to form this path utilising other known Android CMake variable, e.g. ANDROID_NDK, ANDROID_ABI, etc?
Thanks #Alex Cohn a lot for pointing out the file android.toolchain.cmake which usually exists at directory ~/Library/Android/sdk/cmake/cmake_version_xxx/android.toolchain.cmake on macOS.
There are many useful Android CMake variables already configured inside, e.g.
ANDROID_NDK
ANDROID_TOOLCHAIN
ANDROID_ABI
ANDROID_PLATFORM
ANDROID_STL
ANDROID_PIE
ANDROID_CPP_FEATURES
ANDROID_ALLOW_UNDEFINED_SYMBOLS
ANDROID_ARM_MODE
ANDROID_ARM_NEON
ANDROID_DISABLE_NO_EXECUTE
ANDROID_DISABLE_RELRO
ANDROID_DISABLE_FORMAT_STRING_CHECKS
ANDROID_CCACHE
And the one ANDROID_TOOLCHAIN_PREFIX is exactly what I looked for, so my final CMake script comes into below:
add_custom_command(TARGET ${SHARED_LIBRARY_NAME} POST_BUILD
COMMAND "${ANDROID_TOOLCHAIN_PREFIX}strip" -g -S -d --strip-debug --verbose
"${DIST_LIBS_DIR}/${LIB_BUILD_TYPE}/${ANDROID_ABI}/lib${SHARED_LIBRARY_NAME}.so"
COMMENT "Strip debug symbols done on final binary.")
And I don't need to explicitly pass any additional arguments, i.e. DCMAKE_TOOLCHAIN_FILE=android.toolchain.cmake, from command line to the build process. Because, this file, i.e. android.toolchain.cmake, was already taken into account automatically by Android native build system.
You can use ${CMAKE_STRIP}. It is set appropriately when you use -DCMAKE_TOOLCHAIN_FILE=android.toolchain.cmake. I hope it is OK also if you work with 'built-in' Android support with supported NDK version.

Categories

Resources