How to generate a release build of a static library for Android?

I’m trying to generate a static JUCE library for Android, but I can’t find any .a file anywhere.

Here is what I did:

  • I open my project with Projucer
  • I select Android in ‘Selected exporter’
  • it opens Android Studio
  • in Android Studio, I click on Build > Make Project
  • it generates .aar files, but no .a file

Did I miss something?

Thanks.

You may end up with multiple .a files, one for each target architecture.

On my system, after running the build, I can find the staticlib file in:

Builds/Android/lib/build/intermediates/cmake/debug_Debug/obj/<arch>

Where <arch> is the architecture for which the library was compiled.

1 Like

Thanks, I found them.

Now, if I want to import those libraries in an Android project, I should need some .h header files at some point, right?

Where can I find them? Are they generated like the .a files?

You’d just use the JUCE headers directly. The Projucer will have generated a JuceHeader.h into JuceLibraryCode that you can use.

I’d also recommend enabling the “Use Global AppConfig” setting in the Projucer, as this will make it easier to ensure that the same preprocessor definitions are used inside the library, and by code including the library.

OK so here is what I did in my Android project:

  • in src/main/cpp/jucedemo/lib, I added the 4 directories (arm64-v8a, armeabi-v7a, x86, x86_64), with the different version of my libJuceDemo.a in each directory
  • I also added a include directory with JuceHeader.h and AppConfig.h in it
  • in the CMakeLists.txt file of my Android project (located in the app/ folder), here is what I added:
set(JuceDemo_DIR  ${CMAKE_SOURCE_DIR}/src/main/cpp/jucedemo)
add_library(JuceDemo STATIC IMPORTED)
include_directories(${JuceDemo_DIR}/lib/include)

target_link_libraries(
        native-lib
        JuceDemo
        ${JuceDemo_DIR}/lib/${ANDROID_ABI}/libJuceDemo.a)

I’m not a cmake expert (far from it!), so maybe I did some silly mistakes.

But the thing is: my Android project doesn’t compile anymore: error: 'JuceDemo-NOTFOUND'.

I feel like I’m close, but I’m really struggling!

What did I miss?

Thanks.

It’s difficult to say given that information. Does the IDE tell you which line of the CMakeLists produced the JuceDemo-NOTFOUND error? That would be the place to start looking.

Other than that, there are a few things I’d change in the CMake snippet.

Normally, importing a staticlib looks like this:

add_library(foo STATIC IMPORTED)
set_property(TARGET foo PROPERTY
             IMPORTED_LOCATION "/path/to/libfoo.a")

I think you should probably use this approach, and avoid linking libJuceDemo.a directly in the target_link_libraries(native-lib ... call.

In addition, include_directories is generally discouraged. You can use target_include_directories(JuceDemo PUBLIC to set include directories that will only apply to JuceDemo and its dependent targets.

Thanks!

OK so to give you more details, here is how I added my libJuceDemo.a library in my Android project:

image

And here is what I did now in my CMakeLists.txt file:

add_library(JuceDemo STATIC IMPORTED)
set_property(TARGET JuceDemo PROPERTY
             IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/cpp/jucedemo/${ANDROID_ABI}/libJuceDemo.a)
target_include_directories(JuceDemo
                           PUBLIC ${CMAKE_SOURCE_DIR}/src/main/cpp/jucedemo/lib/include)

For the last line (target_include_directories(...)), I get the following error: Cannot specify include directories for imported target "JuceDemo".
If I remove that last line, it compiles.

So I have two questions:

  • why do I have that error?
  • in my JuceDemo library, I created a simple JuceTest class. How to include it in an existing C++ file in the “parent” project so I can use it?

Thanks.

My bad, it looks like target_include_directories doesn’t work on imported targets. I think that set_target_properties(JuceDemo PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ...) would work, though.

Your parent project will need to be set up to see the header file in which JuceTest is declared. This probably means adding the path to JuceTest's header to the INTERFACE_INCLUDE_DIRECTORIES of the JuceDemo imported target.

My bad, it looks like target_include_directories doesn’t work on imported targets. I think that set_target_properties(JuceDemo PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ...) would work, though.

Thanks, it compiles now!

Your parent project will need to be set up to see the header file in which JuceTest is declared. This probably means adding the path to JuceTest 's header to the INTERFACE_INCLUDE_DIRECTORIES of the JuceDemo imported target.

That’s really what I don’t manage to understand: does it mean that I have to add something like this?

set_target_properties(JuceDemo PROPERTIES INTERFACE_INCLUDE_DIRECTORIES /path/to/JuceDemo/Source)

It looks really odd… And even by doing that, I still can’t include anything, so I guess I get something wrong again :confused:

That’s what I was thinking, yes.

How are you trying to use the class? If you’re trying to use it directly from java/kotlin etc. that won’t work, and you’ll need to read up on the JNI.

How are you trying to use the class? If you’re trying to use it directly from java/kotlin etc. that won’t work, and you’ll need to read up on the JNI.

No, I’m trying to use it in the JNI (so in my C++ code).

But then, if I have to point to the original JUCE project, what’s the point of adding the libJuceDemo.a files? Isn’t my JuceTest class supposed to be in that library?

I mean, a few years ago, I managed to compile the libogg/libvorbis libraries and added them in my app (as explained here), and I just had to add the .a library files, a few headers, add some stuff in CMakeFiles.txt and that it!

Isn’t that possible to do something similar with a JUCE static (or maybe dynamic) library?

The build process for JUCE is a little bit special (generates some files, sets some preprocessor flags etc.). Using the .a generated by a Projucer build might be easier than including the JUCE sources directly in some cases. At the same time, there’s nothing stopping you from including the JUCE module sources directly in the Android project.

The JuceTest class will be in the library, but dependent code won’t know anything about the symbols in the library unless it includes the headers from the library. That includes headers that you write yourself.

1 Like

Ooh ok, I have to write my own header files, makes more sense now. That being said, it’s a shame Projucer doesn’t do it automatically (unless it’s too complicated).

Anyway, I’ll try that.
Thanks for your answers and your time!