How can I get the Frege compiler to see Android API classes when using Gradle? - android-gradle-plugin

I am attempting to write an Android app using the Frege language. Unfortunately, I'm not aware of any examples of how to do this.
So, I'm using Gradle as my build system, with the Android Gradle plugin. Then to get the Frege code to be compiled, I'm using a javaexec to call the frege compiler before the Java files get compiled, as suggested in this post.
I was successful in building an Android application with Frege code that gets called by Java code, as shown here.
However, the Frege code can only call standard Java APIs. It can't call any of the Android APIs.
I'd like to be able to call Android APIs from Frege. There is a nice repo here that has Frege wrappers for the Android APIs. Unfortunately, it has no build system or instructions.
I believe I've successfully set up my build.gradle to build the FregeAndroid wrappers along with my project's code. The Frege compiler is indeed attempting to build them.
However, the FregeAndroid code fails to compile, because it can't see the Android API classes. I assume I need to somehow find where the Android API classes are, and then add that to the Frege compiler's classpath, so it can see those classes. Unfortunately, this is where I'm stuck. I'm a newbie at Gradle, and can't figure out how to do this.
Here is my project which I have so far, which fails to build, in the following way:
:compileDebugJavaWithJavac
Frege compiler args: "-inline -d src/frege -make -fp /Users/ppelleti/Library/Android/sdk/platforms/android-21/android.jar -sp /Users/ppelleti/programming/android/frege-on-android/FregeAndroid/src /Users/ppelleti/programming/android/frege-on-android/FregeAndroid/src/frege/android/animation/TimeInterpolator.fr"
calling: javac -cp /Users/ppelleti/.gradle/caches/modules-2/files-2.1/org.frege-lang/frege/3.23.401-g7c45277/716990197271fdc15917b4f8d023d63009ba6e39/frege-3.23.401-g7c45277.jar:/Users/ppelleti/Library/Android/sdk/extras/android/m2repository/com/android/support/multidex/1.0.0/multidex-1.0.0.aar:src/frege:/Users/ppelleti/Library/Android/sdk/platforms/android-21/android.jar -d src/frege -sourcepath /Users/ppelleti/programming/android/frege-on-android/FregeAndroid/src -encoding UTF-8 src/frege/frege/android/animation/TimeInterpolator.java
runtime 4.282 wallclock seconds.
Frege compiler args: "-inline -d src/frege -make -fp /Users/ppelleti/Library/Android/sdk/platforms/android-21/android.jar -sp /Users/ppelleti/programming/android/frege-on-android/FregeAndroid/src /Users/ppelleti/programming/android/frege-on-android/FregeAndroid/src/frege/android/app/Activity.fr"
Android.app.TaskStackBuilder: build failed because module is not on class path
Android.app.Fragment: build failed because module is not on class path
Android.app.LoaderManager: build failed because module is not on class path
[... omitted a bunch of similar lines ...]
Any ideas would be much appreciated!

It turns out that there were several problems, including problems with both the source path and the classpath. I've updated my repository to fix these problems.
However, ultimately the build fails because there are files missing from the FregeAndroid repo. So to get my example to build, it would be necessary to fix the FregeAndroid wrappers or write new wrappers.

Related

Dependencies between Android native modules (prefab) fail to build

Our Android application consists of 40-some Android Library Modules (ALMs), each of which also builds a C++ shared library with externalNativeBuild and CMake. So far we had the dependencies between these libs set up like this:
The dependent ALM references the dependency ALM with api project(':lib')
The dependent CMake script references the dependency .so with add_library(SHARED IMPORTED lib) and set_target_properties(lib PROPERTIES IMPORTED_LOCATION ...) and a relative path.
Recently we had to upgrade to the latest Android API version. This started off a cascade because now we were getting deprecated warnings in code generated by the navigation-ktx library, but upgrading that requires upgrading Gradle and the Android Gradle plugin. After that I started getting errors like liblib.so, needed by 'project', missing and no known rule to make it.
It looks like the latest Gradle parallelizes build tasks more heavily, and this means the dependent CMake/Ninja builds are being started concurrently with their dependencies, resulting in this error because the dependency is not yet built. I figured out that what we were doing was not entirely supported, but there is a "supported" way to do that now, so I refactored our entire build to use Prefab.
Now I started getting other errors, alternating between:
1.
C++ build system [prefab] failed while executing ...
Usage: prefab [OPTIONS] PACKAGE_PATH...
Error: Invalid value for "PACKAGE_PATH": Directory ... is not readable.
ld: error: undefined symbol ...
I looked into build/intermediates and found that in the 2nd case, the cmake config script was generated incorrectly: instead of add_library(lib::lib SHARED IMPORTED ) it had add_library(lib::lib INTERFACE IMPORTED) like it it was a header only library, and there was no IMPORTED_LOCATION set in the file.
What am I doing wrong and what should I do to unbreak our build?
It looks like the toolchain support for prefab interdependencies within a project is not quite finished. Others are reporting the same kind of errors at https://issuetracker.google.com/issues/265544858:
This appears to be a race condition with generating prefab cmake files.
It says in https://issuetracker.google.com/issues/221231432 that the header-only cmake config is generated to satisfy Android Studio's IDE features (completion, etc.) before the library is actually built.
Treat as-yet-unconfigured modules as if they are Header-only libraries for Android Studio purposes. This works because Android Studio doesn't care about linker flags for the purposes of providing language services.

Encapsulating a JNI library inside a jar file

I am trying to develop a plugin for Fiji/ImageJ that relies on a native library (JNI).
The JNI library itself depends on libtiff and fftw. On OSX and Linux, I use the class NativeUtils and everything works fine.
On windows, I included binary versions of libtiff and fftw in the CMake package and managed to link the JNI library against those (either statically of dynamically). However, the resulting JNI module does not include libtiff or fftw and I obtain an error when I try to load the JNI library with NativeUtils.loadLibraryFromJar. This is also the case when I include the dependent .dll in the .jar since they are not extracted by NativeUtils.
Here are the relevant lines in CMakeLists.txt:
add_library(fftw STATIC IMPORTED GLOBAL)
set_target_properties(fftw PROPERTIES IMPORTED_LOCATION "${libdir}/libfftw3f-3.lib"
INTERFACE_INCLUDE_DIRECTORIES "${incdir}")
SWIG_ADD_LIBRARY(javainterf
TYPE MODULE
LANGUAGE java
SOURCES javainterf.i javainterf.c src1.c)
SWIG_LINK_LIBRARIES(javainterf libcode1 fftw)
add_jar(Foo
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/java/foo1.java
INCLUDE_JARS java/resources/ij-1.51p.jar
VERSION ${JAR_VERSION})
add_dependencies(Foo javainterf)
add_custom_command(TARGET Foo POST_BUILD
COMMAND "${Java_JAR_EXECUTABLE}" -uf Foo-${JAR_VERSION}.jar
-C ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} ${JNI_LIB_NAME})
How would you make sure that all the dependencies are properly included in the jar and loaded?
You can't load library from inside JAR without extracting it in a first place.
Take a look here at full sample where native code is embedded inside JAR and extracted when needed.
https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo031
Update
Well, in that case, when you need to pack more libs and you want to properly resolve locations, you need to play with runtime env a little bit.
Take a look here:
https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo035
git clone https://github.com/mkowsiak/jnicookbook
cd jnicookbook/recipes/recipeNo035
make
make test
Have fun with JNI!

compile mixed Kotlin and Java code from the command line

I'd like to start adding some Kotlin to my Java project. To do that I need to be able to compile both Java and Kotlin files from the command line, which is fine apart from when files of different types depend on each other e.g. A.java depends on B.kt which in turn depends on C.java.
Is there any way to do this without using Gradle, Maven etc?
Edited to clarify thanks #Nikita for pointing out it is not clear that I want both java and Kotlin files in the same source tree
To achieve this, you will need to run two steps.
Run kotlinc targeting *.kt files. Add all required java sources on classpath. Note the destination location.
Run javac targeting *.java files. Add *.class files created by step 1 to classpath.
Result is a combination of *.class files from both steps.
Here is a documetation on Kotlin compiler
Remember to compile Kotlin first, then compile Java with kotlin-build-classpath from first step.
simple like this:
1. kotlinc ./src/* -d ./buildTmp
2. javac ./src/**.java -d ./buildTmp -classpath ./buildTmp

mono mkbundle : what are mono_mkbundle_init() and JIT inizialization?

I tried to bundle my app with mkbundle command due to this help:
http://www.mono-project.com/Guide:Running_Mono_Applications#Bundles
but I don't understand this part of this doc:
With -c, the further option --nomain will generate the host.c file without a main method so that
you can embed it as a library in an existing native application in which you are embedding the Mono
runtime yourself. Just call mono_mkbundle_init() before initializing the JIT to make the bundled
assemblies available.
which is absolutely what I need to do!
I also looked up this doc:
http://man.he.net/man1/mkbundle2
again the same part:
You may also use mkbundle to generate a bundle you can use when embed-
ding the Mono runtime in a native application. In that case, use both
the -c and --nomain options. The resulting host.c file will not have a
main() function. Call mono_mkbundle_init() before initializing the JIT
in your code so that the bundled assemblies are available to the embed-
ded runtime.
I don't really know what are mono_mkbundle_init() and initializing the JIT...
Thanx
mono_mkbundle_init() is a function generated by mkbundle in host.c
"initializing the JIT" should be mono function mono_jit_init()
so the meaning is that, link the generated c file in your native application and invoke mono_mkbundle_init() before invoking mono_jit_init()

Call external programs with CMake

I tried to search the CMake documentation, but I couldn't figure out how to call external programs from CMake.
There are few things I want to do.
Compile other third-party dependencies that uses a makefile
Compile Thrift definition files to C++ / Python stubs.
Compile Cython definition files.
Another question is, what is a good way to handle those cases anyway? It feels like calling a shell script directly from CMake doesn't feel so clean, when "C" in CMake stands for Cross Platform.
EDIT: I have few extra questions. Before, in my build, I prebuilt my dependencies, and the project itself used FIND_PACKAGE(...) to find the header / libraries for the dependencies.
Now, I'm ExternalProject_Add() to compile the dependencies, but the problem is, all my FindXYZ() functions fails when I run cmake ., because the dependencies aren't present when CMake gets executed.
How should I include the third-party libraries in my project in this case?
http://www.kitware.com/media/html/BuildingExternalProjectsWithCMake2.8.html
2+3. can be hacked with CONFIGURE_COMMAND/BUILD_COMMAND/INSTALL_COMMAND