Copy native binary files

I have a problem since the latest (2.9) update of gradle. I want to copy over native binary files after they have been assembled.

Until 2.9, I achieved this via the following build script in the root project for all subprojects.

// copy all generated libraries
subprojects {
  task copyLibraries {
    group = "Install"
    description "Copies all relevant library artifacts to 'dependencies' directory"
    doLast {
      binaries.withType(StaticLibraryBinary) {
        if(buildType.name == rootProject.currentBuildType && buildable) {
          def platformFolder = targetPlatform == platforms.Win64 ? "x64" : targetPlatform.name;
          copy {
            from staticLibraryFile
            into file("${rootDir}/${rootProject.binDir}/${platformFolder}/libs")
          }
        }
      }
      binaries.withType(SharedLibraryBinary) {
        if(buildType.name == rootProject.currentBuildType && buildable) {
          def platformFolder = targetPlatform == platforms.Win64 ? "x64" : targetPlatform.name;
          copy {
            def sharedLibraryPdbFile = file(sharedLibraryFile.path.replaceFirst(~/\.[^\.]+$/, '') + ".pdb")
            from sharedLibraryFile
            from sharedLibraryLinkFile
            from sharedLibraryPdbFile
            into file("${rootDir}/${rootProject.binDir}/${platformFolder}/modules")
          }
        }
      }
    }
  }
}

This is obviously not correct in 2.9, since the breaking changes, so i reafctored to this:

// copy all generated libraries
subprojects {
  model {
    binaries {
      withType(StaticLibraryBinarySpec) {
        if(buildType.name == rootProject.currentBuildType && buildable) {
          def platformFolder = targetPlatform == platforms.Win64 ? "x64" : targetPlatform.name;
          def staticLibraryPdbFile = file(staticLibraryFile.path.replaceFirst(~/\.[^\.]+$/, '') + ".pdb")
          copyLibraries.doLast {
            copy {
              from staticLibraryFile
              from staticLibraryPdbFile
              into file("${rootDir}/${rootProject.binDir}/${platformFolder}/libs")
            }
          }
        }
      }
      withType(SharedLibraryBinarySpec) {
        if(buildType.name == rootProject.currentBuildType && buildable) {
          def platformFolder = targetPlatform == platforms.Win64 ? "x64" : targetPlatform.name;
          copyLibraries.doLast {
            def sharedLibraryPdbFile = file(sharedLibraryFile.path.replaceFirst(~/\.[^\.]+$/, '') + ".pdb")
            copy {
              from sharedLibraryFile
              from sharedLibraryLinkFile
              from sharedLibraryPdbFile
              into file("${rootDir}/${rootProject.binDir}/${platformFolder}/modules")
            }
          }
        }
      }
    }
  }
  task copyLibraries {
    group = "Install"
    description "Copies all relevant library artifacts to 'dependencies' directory"
  }
}

But this results in an exception:
> Attempt to mutate closed view of model of type 'java.lang.Object' given to rule 'model.binaries'
in line containing the copy.

Any idea, how to solve my issues? Maybe, I could refactor into own plugin (don’t know how though)?

Thanks and best regards,
Max

1 Like

Hi Max,

Not sure if you have solved this, but I recently needed to do something similar. You’ll need to define a task inside your model.

This is how I am doing it: I collect the NativeExecutableBinarySpecs (or in your case the Shared/StaticLibraryBinarySpecs) that I want to copy during the configuration phase in a list. Then during the execution phase I do the copy.

(I am using the Nightly snapshot but based the code off of the 2.9 API documentation.)

model {
    task distLinux64 {
        group 'Distribute'
        def bins = []
        binaries {
            withType(NativeExecutableBinarySpec) {
                if (buildable && buildType == buildTypes.release
                    && targetPlatform.architecture.amd64
                    && targetPlatform.operatingSystem.linux) {
                    bins << it
                }
            }
        }
        doLast {
            bins.each { bin ->
                def arch = bin.targetPlatform.architecture.name
                def os = bin.targetPlatform.operatingSystem.name
                def flavor = bin.flavor.name
                def app = bin.application.baseName
                copy {
                    from bin.executable.file
                    into file("$rootDir/$arch/$os/$flavor/$app/")
                }
            }
        }
    }
}

I hope this helps.

1 Like

That’s exactly what I was looking for.

Thank you very much!