Eclipse run deletes shared object in libs folder


#1

I am trying to run Juce together with a library of my own. I use Eclipse Luna in Ubuntu 14.04. The problem is that when I start a new run or debug, Eclipse (or Juce?) deletes most of the contents in the libs folder. Thus, my library which was stored there is removed and I get errors that the library is not found. I logged onto the phone using the adb shell and only the juce library (libjuce_jni.so) is copied to the phone. My questions are as follows?

1. Is this supposed to happen? I mean, are the files in the libs folder supposed to get deleted an copied back every time I run or debug the application? Note that the files are deleted at the start of runtime, not during compile time.

2. Is it Eclipse or Juce that deletes the contents of the libs folder? Can I change this setting somehow?

3. Where should I put my own library so that it is copied to the libs folder and thus to the phone? I have tried putting it virtually everywhere inside the Builds/Android folder, but it does not help. I have also made sure to add those folders as extra library search paths in the Introjucer project.

Any help is appreciated.


#2

I had some similar issues to you trying to get a library working with an Android JUCE project.

Everything in the libs folder gets deleted/overwritten each time you run a build. This is the way ant works.

Have you looked at the Android.mk file? This is where ant (or eclipse I assume) pulls everything together.

Jules recently added an option to Introjucer to add external libraries, but it is not currently complete. I've sent a patch for this which should work on the latest tip. (See below, could not upload the file..)

If you apply the patch to JUCE, then when you open the project in Introjucer you should be able to declare the location of static (.a) or shared (.so) libraries there, and it will add the necessary lines to JUCE's Android.mk. You will also need to create a separate build for your library with its own Android.mk file, and set its location in NDK_MODULE_PATH.

I've given a working example for the Aubio library here: https://github.com/adamski/aubio-android

To understand the mechanics of all of this have a read around here: http://www.kandroid.org/ndk/docs/IMPORT-MODULE.html

You can of course declare everything in JUCE's Android.mk file but then you will need to manage it in your VCS, as it will get overwritten each time Introjucer saves the project. I made an earlier modification to Introjucer where it added everything into the one file but it got complicated to generalise it for different use cases. Separating the library build from JUCE simplifies things.

Good luck and feel free to post more details here.

 

Patch:

diff --git a/extras/Introjucer/Source/Project Saving/jucer_ProjectExport_Android.h b/extras/Introjucer/Source/Project Saving/jucer_ProjectExport_Android.h
index 3c99132..1f30928 100644
--- a/extras/Introjucer/Source/Project Saving/jucer_ProjectExport_Android.h    
+++ b/extras/Introjucer/Source/Project Saving/jucer_ProjectExport_Android.h    
@@ -100,8 +100,11 @@ public:
         props.add (new TextPropertyComponent (getOtherPermissionsValue(), "Custom permissions", 2048, false),
                    "A space-separated list of other permission flags that should be added to the manifest.");
 
-         props.add (new TextPropertyComponent (getImportModulesValue(), "Import modules", 8192, true),
-                   "Comma or whitespace delimited list of import-module calls.");
+        props.add (new TextPropertyComponent (getStaticLibrariesValue(), "Import static library modules", 8192, true),
+                   "Comma or whitespace delimited list of static libraries (.a) defined in NDK_MODULE_PATH.");
+
+        props.add (new TextPropertyComponent (getSharedLibrariesValue(), "Import shared library modules", 8192, true),
+                   "Comma or whitespace delimited list of static libraries (.so) defined in NDK_MODULE_PATH.");
 
         props.add (new TextPropertyComponent (getThemeValue(), "Android Theme", 256, false),
                    "E.g. @android:style/Theme.NoTitleBar or leave blank for default");
@@ -146,9 +149,12 @@ public:
     Value  getThemeValue()                          { return getSetting (Ids::androidTheme); }
     String getThemeString() const                   { return settings [Ids::androidTheme]; }
 
-    Value  getImportModulesValue()                  { return getSetting (Ids::androidImportModules); }
-    String getImportModulesString() const           { return settings [Ids::androidImportModules]; }
+    Value  getStaticLibrariesValue()                  { return getSetting (Ids::androidStaticLibraries); }
+    String getStaticLibrariesString() const           { return settings [Ids::androidStaticLibraries]; }
 
+    Value  getSharedLibrariesValue()                  { return getSetting (Ids::androidSharedLibraries); }
+    String getSharedLibrariesString() const           { return settings [Ids::androidSharedLibraries]; }
+    
     Value getCPP11EnabledValue()                    { return getSetting (Ids::androidCpp11); }
     bool isCPP11Enabled() const                     { return settings [Ids::androidCpp11]; }
 
@@ -478,6 +484,19 @@ private:
             out << "  " << (files.getReference(i).isAbsolute() ? "" : "../")
                 << escapeSpaces (files.getReference(i).toUnixStyle()) << "\\" << newLine;
 
+        const StringArray staticLibraries (getCommaOrWhitespaceSeparatedItems (getStaticLibrariesString()));
+        const StringArray sharedLibraries (getCommaOrWhitespaceSeparatedItems (getSharedLibrariesString()));
+        
+        if (staticLibraries.size() > 0) out << newLine << "LOCAL_STATIC_LIBRARIES :=";
+        for (int i = 0; i < staticLibraries.size(); ++i)
+            out << " " << staticLibraries[i];
+        if (staticLibraries.size() > 0) out << newLine;
+
+        if (sharedLibraries.size() > 0) out << newLine << "LOCAL_SHARED_LIBRARIES :=";
+        for (int i = 0; i < sharedLibraries.size(); ++i)
+            out << " " << sharedLibraries[i];
+        if (sharedLibraries.size() > 0) out << newLine;
+
         out << newLine
             << "ifeq ($(NDK_DEBUG),1)" << newLine;
         writeConfigSettings (out, true);
@@ -487,11 +506,13 @@ private:
             << newLine
             << "include $(BUILD_SHARED_LIBRARY)" << newLine;
 
-        const StringArray importModules (getCommaOrWhitespaceSeparatedItems (getImportModulesString()));
 
-        for (int i = 0; i < importModules.size(); ++i)
-            out << "$(call import-module," << importModules[i] << ")" << newLine;
-    }
+        for (int i = 0; i < staticLibraries.size(); ++i)
+            out << "$(call import-module," << staticLibraries[i] << ")" << newLine;
+
+        for (int i = 0; i < sharedLibraries.size(); ++i)
+            out << "$(call import-module," << sharedLibraries[i] << ")" << newLine;
+   }
 
     void writeConfigSettings (OutputStream& out, bool forDebug) const
     {
diff --git a/extras/Introjucer/Source/Utility/jucer_PresetIDs.h b/extras/Introjucer/Source/Utility/jucer_PresetIDs.h
index 7e1b952..69f1527 100644
--- a/extras/Introjucer/Source/Utility/jucer_PresetIDs.h
+++ b/extras/Introjucer/Source/Utility/jucer_PresetIDs.h
@@ -142,7 +142,8 @@ namespace Ids
     DECLARE_ID (androidKeyAlias);
     DECLARE_ID (androidKeyAliasPass);
     DECLARE_ID (androidTheme);
-    DECLARE_ID (androidImportModules);
+    DECLARE_ID (androidStaticLibraries);
+    DECLARE_ID (androidSharedLibraries);
     DECLARE_ID (font);
     DECLARE_ID (colour);
     DECLARE_ID (userNotes);

 

 

 


#3

Thank you for your comments, adamski, I have lots of things to learn. I ended up adding the below code to my Android.mk as a temporary workaround as I will not do anything fancy yet. The code is inserted directly after LOCAL_PATH := $(call my-dir) so that the relative paths work. Not sure if everything here is needed though, but it works.

I will look at the patch you provided when I need it at a later time.

#####################################################################
# Extra includes. This is taken out of the Android.mk file since
# any save run from the Juicer will overwrite the Android.mk.
#
# Put the stuff in this file straight after the line
# LOCAL_PATH := $(call my-dir)
# in the real Android.mk file.
#####################################################################

include $(CLEAR_VARS)
MYLIB_INCL    := $(LOCAL_PATH)/../../../SDK/include
MYLIB_LIB    := $(LOCAL_PATH)/armeabi
LOCAL_MODULE    := mylib
LOCAL_SRC_FILES    := $(MMAP_LIB)/libmylib.so
LOCAL_EXPORT_CPPFLAGS     := -Wno-unused
LOCAL_EXPORT_C_INCLUDES    := $(MYLIB_INCL)
include $(PREBUILT_SHARED_LIBRARY)
LOCAL_SHARED_LIBRARIES := mylib

#4

 

From the build script you gave, you could put that in its own Android.mk file alongside the builds you have for your library. 

 

Your Android.mk file would look something like this:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
MYLIB_INCL    := $(LOCAL_PATH)/../../../SDK/include
MYLIB_LIB    := $(LOCAL_PATH)/$(TARGET_ARCH_ABI)
LOCAL_MODULE    := mylib
LOCAL_SRC_FILES    := $(MYLIB_LIB)/libmylib.so
LOCAL_EXPORT_CPPFLAGS     := -Wno-unused
LOCAL_EXPORT_C_INCLUDES    := $(MYLIB_INCL)
include $(PREBUILT_SHARED_LIBRARY)

And you would then need to have in the JUCE Android.mk only:

​LOCAL_SHARED_LIBRARIES := mylib  #after the source files

and right at the very end:

$(call import-module mylib)

If you apply the patch I posted above, (or wait until Jules has time to look at it) these will be added by Introjucer each time you save the project.  

Finally you would need to define the NDK_MODULE_PATH enviroment variable to tell ant where to find your library's Android.mk file:

export NDK_MODULE_PATH=<path-to-mylib>

Best thing is to add this to your .bashrc or .zshrc so its loaded automatically.