Create static library task is always UP-TO-DATE?

I have a pretty simple build (I’m just getting the concept working) where I compile for my host machine and for another target. I have defined two platforms and two toolchains (one’s just the default clang and one is a clang for the other platform). I have two projects: ‘:app’ and ‘:module’. The app project has two components main and helper with a dependency between: main->helper. The module project has two components ‘main’ and ‘other’ with main->other. And, :app:main->:module:main.


apply plugin: 'cpp'

model {
    components {
        main(NativeExecutableSpec) {
            targetPlatform 'android-arm64'
            targetPlatform 'osx-x86_64'

            sources {
                cpp {
                    lib project: ':module', library: 'main'
                    lib library: 'helper'
        helper(NativeLibrarySpec) {
            targetPlatform 'android-arm64'
            targetPlatform 'osx-x86_64'


apply plugin: 'cpp'

model {
    components {
        main(NativeLibrarySpec) {
            targetPlatform 'android-arm64'
            targetPlatform 'osx-x86_64'

            sources {
                cpp {
                    lib library: 'other', linkage: 'static'
        other(NativeLibrarySpec) {
            targetPlatform 'android-arm64'
            targetPlatform 'osx-x86_64'

(The toolchains and platforms are defined in the top level build.gradle for all subprojects.)

One of my goals is to hide the other component by statically linking it to the module’s main component (nothing from other leaks through the headers, either). When I build for osx and install the main component, everything works fine. When I build the android binaries, linking fails because the file libother.a does not exist:

$ gradle clean build --continue
:app:createHelperAndroid-arm64StaticLibrary UP-TO-DATE
:app:helperAndroid-arm64StaticLibrary UP-TO-DATE
:module:createOtherAndroid-arm64StaticLibrary UP-TO-DATE
:module:otherAndroid-arm64StaticLibrary UP-TO-DATE
clang: error: no such file or directory: '.../module/build/libs/other/static/android-arm64/libother.a'
:module:linkMainAndroid-arm64SharedLibrary FAILED
:app:check UP-TO-DATE
:module:check UP-TO-DATE
FAILURE: Build failed with an exception.


:module:createOtherAndroid-arm64StaticLibrary UP-TO-DATE

A clean build doesn’t even reset this task because it has no inputs. When I run explicitly with --rerun-tasks I see the llvm-ar help message since the task is passing no inputs to the archiver. When I remove the linkage: 'static' property, you get the same result (all the static library tasks for the android platform receive no input) but the build doesn’t fail as there’s no static link step to fail on (well other than building the executable which I expect to fail).

This is what I see in the create[OtherAndroid...]StaticLibrary task output when I use --rerun-tasks:

archiving libother.a successful.
OVERVIEW: LLVM Archiver (llvm-ar)
  This program archives bitcode files into single libraries
USAGE: llvm-ar [options] [relpos] [count] <archive-file> [members]...
  -M                               - 
  -aarch64-neon-syntax             - Choose style of NEON code to emit from AArch64 backend:
    =generic                       -   Emit generic NEON assembly
    =apple                         -   Emit Apple-style NEON assembly
  -enable-tbaa                     - 
  -help                            - Display available options (-help-hidden for more)
  -join-liveintervals              - Coalesce copies (default=true)
  -mc-x86-disable-arith-relaxation - Disable relaxation of arithmetic instruction for X86
  -print-after-all                 - Print IR after each pass
  -print-before-all                - Print IR before each pass
  -rng-seed=<seed>                 - Seed for the random number generator
  -stackmap-version=<int>          - Specify the stackmap encoding version (default = 1)
  -stats                           - Enable statistics output from program (available with Asserts)
  -time-passes                     - Time each pass, printing elapsed time for each on exit
  -verify-dom-info                 - Verify dominator info (time consuming)
  -verify-loop-info                - Verify loop info (time consuming)
  -verify-scev                     - Verify ScalarEvolution's backedge taken counts (slow)
  -version                         - Display the version of this program
  -x86-asm-syntax                  - Choose style of code to emit from X86 backend:
    =att                           -   Emit AT&T-style assembly
    =intel                         -   Emit Intel-style assembly

Is there something I’m missing here?

User error 0.o

I was configuring my archiver as such:

staticLibArchiver.executable = 'llvm-ar'
staticLibArchiver.withArguments {
    remove '-rcs'
    add 'rcs' // llvm-ar don't like hyphens... 

But the order of the arguments for the archiver actually matters:

staticLibArchiver.executable = 'llvm-ar'
staticLibArchiver.withArguments {
    remove '-rcs'
    add 0, 'rcs' // llvm-ar don't like hyphens... 

Things work as expected now.

Hi David, could you post your complete clang toolchain configuration? I’m trying to configure clang 3.8.0 on OS X and I think seeing how you did it would help me a lot. Thanks!

This might be more fool proof

staticLibArchiver.withArguments { List<String> args ->
    int index = args.indexOf('-rcs')
    if (index < 0) throw new RuntimeException("Invalid staticLibArchiver args $args")
    args[index] = 'rcs' // llvm-ar don't like hyphens... 

Hi Ralf, I would suggest posting another question. I’m happy to post any related config there.