Nim programming language finally hit 1.0

H. S. Teoh hsteoh at quickfur.ath.cx
Fri Oct 4 16:50:07 UTC 2019


On Fri, Oct 04, 2019 at 03:19:48PM +0000, Adam D. Ruppe via Digitalmars-d wrote:
[...]
> (the android thing is painful enough, I don't even know how to do it
> and most the work is already done for me by others!)

Just in case this is helpful, here's an overview of I get from sources
to .apk in my mixed Java/D project:

1) Generate R.java from Java sources by running `aapt` (from the
   SDK/NDK; some Linux distros ship it separately as well -- be aware
   that the version must match the rest of your environment or you might
   get strange errors / compatibility issues).

2) Build Java sources by invoking `javac`.

3) Run the `dx` tool to transform the resulting .class files to
   the classes.dex format required by Android.

4) Cross-compile D sources to the target architecture using LDC (in my
   case, I target cortex-a8 / armv7 androideabi). In my case, I found
   that I need to compile to object files first, and link separately
   (see following step).

5) Link .o files to .so file using the clang compiler from the Android
   NDK. This is to ensure that you get the right native libs linked to
   your D code, otherwise you'll end up with link errors and/or runtime
   problems. Be sure to specify -shared and the right -soname.

   EXTRA NOTE: In order to optimize the resulting binary size, I also
   specify -Wl,--gc-sections and -Wl,--version-script=libmyapp.version,
   where libmyapp.version contains the following:

	LIBGAME_1.0 {
		global:
			Java_*;
		local:
			*;
	};

   This is to ensure that --gc-sections deletes all sections not
   reachable from a symbol that matches the name Java_* (i.e., a JNI
   entry point). Without this, tons of unused symbols from druntime and
   Phobos get included in the .so, significantly bloating the APK size.

   If you're generating a Java-free native app, you'll have to customize
   the global: line to point to your app's entry point so that it
   doesn't get GC'd. :-D

6) Create the initial (unaligned) APK file using the following commands:

	aapt package -f -m -M$manifest_file -S$resource_dir -I$sdkjar -F $target-unaligned.apk
	aapt add $target-unaligned.apk classes.dex
	aapt add $target-unaligned.apk path/to/libmyapp.so

	where:
		$manifest_file
			is the Android manifest file for your project;
		$sdkjar
			points to platforms/android-$version/android.jar
			where $version is the Android API version number
			you're targeting;
		$resource_dir
			Points to the subdir (generally called `res`)
			containing various XML resources and other
			media.

7) Sign the APK:

	apksigner sign --ks-pass file:path/to/passwordfile -ks path/to/keystore $target-unaligned.apk

   (Note: apksigner expects a keystore in the proprietary Java format;
   if you want to use a different keystore format you'll have to
   manually do the signing -- google for instructions on how to do
   this. Be warned that it will not be pretty.)

8) Align the APK:

	zipalign -f 4 $target-unaligned.apk $target.apk

Now $target.apk should be ready for installation.

Most of the above steps are customarily hidden from view when you use an
IDE like Android Studio, and it's mostly automated by Gradle.  Ideally,
to make the above more accessible to D users, you'd probably want to
create a Gradle plugin that integrates the LDC cross-compilation and
linking step into Gradle, or whatever IDE / build system you want to
target, so that users can just add the plugin to their build config and
build away.

I did all of the above manually primarily because I have auxiliary code
generators in my project (small D programs running on the host PC that
read in a bunch of data files and process them into a form suitable for
inclusion into the APK, along the way also generating D wrapper code for
working with said data). Doing it manually is also more direct, and has
less external dependencies, which makes it faster (using SCons, I can
already finish building the darned thing from start to finish in the
time it takes just for Gradle to *start up* -- and this, in a fraction
of the RAM required to even run Gradle in the first place).

Generally, I don't recommend doing all of this manually. :-D  So for
your general D user who's uncomfortable with writing build scripts
manually you probably want to look into Gradle integration of some sort,
or whatever IDE or build system you want to target.  Note that the
current version of dub is unable to handle some of the above steps
without heavy hackery / hard-coding of stuff / external scripting.  (The
cross-compilation step and the need to compile Java are big
show-stoppers when it comes to dub.) It would be *very* nice if you
could somehow coax dub to do the Right Thing(tm), but I honestly have my
doubts about it.  You *should* be able to do the cross-compilation and
linking step as a Gradle plugin, though, and Gradle will take care of
the rest of the APK heavy-lifting for you, so perhaps this could be a
first target: get D cross-compilation working in Android Studio.

(Unfortunately, I have not bothered to use Gradle to any meaningful
degree, so I'm unable to help you on that front.)


T

-- 
The best way to destroy a cause is to defend it poorly.


More information about the Digitalmars-d mailing list