C++, find subprojects based on NativeLibrarySpec/SharedLibraryBinary etc

Hi,

One of my C/C++ project is build using gradle. We are generating libs and executables. We want to find and zip all subprojects built using NativeLibrarySpec or NativeExecutablesSpec.
Also i need to collect build output of task. earlier i was getting output like…

.collect (it.libraries.main.spec.getOutputFile())
.collect (it.executable.main.spec.getOutputFile())

is there any other was to get it?

Can some one please help on this?

Can someone please come back on this?

What version of Gradle are you using? From the look of it, it seems you are using somewhere near 2.0ish. If I understand correct, you want to find all C/C++ project and for each component (either NativeLibrarySpec or NativeExecutableSpec) you want to zip all the binaries into a single zip?

What is the end goal? Is it for distribution of the artifact to be consume by order project or simply releasing and who ever get them deal with the integration?

I’m asking lots of question because depending on what you want to do, various answers can be applied. If you just want to zip all native binaries per project there is 2 path that can be explored:
1- Loop through NativeComponentSpec on the components model node and for each one you create a Zip task that gets populated with the getBinaries() (each binary for that component, make sure you filter for getting only the NativeBinarySpec)
2- Loop trough the global project binaries container and create Zip task as you find new component and populate the zip task with each binaries.

Disclaimer, I have to say it’s a bit annoying that each binary type have various ways of getting the output files:

  • SharedLibraryBinarySpec: getSharedLibraryFile and getShareLibraryLinkFile
  • StaticLibraryBinarySpec: getStaticLibraryFile
  • ExecutableBinarySpec: getExecutableFile

In the end, can you tell us a bit more about what you are trying to achieve? At the very least the version of Gradle you are using (Gradle evolved quite a bit in the last couple release and solution varies depending on which version you may be using).

Thanks Daniel for replying.

I was using earlier GRADLE 1.3 and now 2.4 version.
End goal is to zip all libs in one libs.zip and executables in bin.zip file. I tried using below task. But this is getting evaluated before any of the subprojects task is evaluated.

task assetLibs(type: Zip, dependsOn: subprojects.build) {
destinationDir = file("$buildDir/distributions/")
archiveName = 'lib.zip’
from binaries.withType(SharedLibraryBinarySpec).collect { it.sharedLibraryFile }
}

I have added one more check for proper evaluation
subprojects.each { subproject -> evaluationDependsOn(subproject.path) }

But still zip task is not having any zip file. as it is throwing that no source file.

Also folder structure we have like bin/ and lib/

WOW! Gradle 1.3… It was a smart move to use a newer version. However this didn`t fix your problem because starting Gradle 2.x a new model concept has been introduce (https://docs.gradle.org/current/userguide/new_model.html). The entire native support is built on top of this. The legacy tasks (how the current Java plugin work) has some difficulty to interact with the model. Even newer version are a bit better at this but eventually, everything will switch to the model. Here is a piece of code that will make everything work through the model:

project(":a") {
  apply plugin: "cpp"
  model {
    components {
      main (NativeLibrarySpec)
    }
  }
}
project(":b") {
  apply plugin: "cpp"
  model {
    components {
      main (NativeLibrarySpec)
    }
  }
}
subprojets.each { evaluationDependsOn(it.path) }  // This may not be needed
model {
  tasks {
    assetLibs(Zip) {
      dependsOn subprojects.build
      destinationDir = file("$buildDir/distributions/")
      archiveName = 'lib.zip'
      from subprojects.binaries*.withType(SharedLibraryBinarySpec)*.collect { it.sharedLibraryFile }
    }
  }
}

The tasks node under the model is basically the TaskContainer under Project. The from statement is a bit modified from the one you had. Let’s decompose it:

  • subprojects.binaries returns a list of Binary set (here it’s a Gradle smart set). Note that it’s a list of set so we need to use the Groovy spread operator.
  • subprojects.binaries.withType(SharedLibraryBinarySpec)* returns a list of SharedLibraryBinarySpec set. Note that is we collect here we will be collecting sets of binaries instead of the actual binaries.
  • subprojects.binaries.withType(SharedLibraryBinarySpec)*.collect* return a list of File. Now we have our files for the zip task.

One last note, this code assume all subproject are applying one of the native plugin (C/C++/assembler) and that you have one layer of subprojects.

Don’t hesitate to ask more questions!

Thanks Daniel for replay.
Still my problem is not solved.
Root level build script

  1. having zip tasks, common compiler setting and plugin applied to all subprojects

individual build scripts for sub projects
2) using all compiler options, linking options dependent library etc

pply plugin: 'cpp’
apply plugin: ‘c’

subprojects.each { subproj -> evaluationDependsOn(subproj.path) } // ensure all subprojects are evaluated

subprojects {
apply plugin: 'cpp’
apply plugin: ‘c’

model {
toolChains {
gcc(Gcc) {
path
}
}
binaries.all {

}

}

assetLibs(Zip) {
dependsOn subprojects.build
destinationDir = file("$buildDir/distributions/")
archiveName = 'lib.zip’
from subprojects.binaries*.withType(SharedLibraryBinarySpec)*.collect { it.sharedLibraryFile }
}

generateXml {
dependsOn [ ‘assetLibs’]
inputs.files taskDependencies.getDependencies().outputs.getFiles()
outputs.file ‘abc.xml’

}

packageBuild {
dependsOn project.tasks.findByName(‘generateXml’)
abcXmlTemplate = tasks.findByName(‘generateXml’).outputs.getFiles().getSingleFile()
}

Above is my root level build script. I am able to build but packaging is not happening.

i got some solution. It seems hack but working for me.

task assetLibs(type: Zip, dependsOn: subprojects.build) {
allprojects {
afterEvaluate {
binaries.withType(SharedLibraryBinarySpec) {
from it.sharedLibraryFile
}
destinationDir = file("${rootDir}/distribution/")
archiveName = ‘lib.zip’
}
}
}

From my experimentation, your assetLibs task needs to be declared in the model. If you don’t, you need to do exactly what you did in yout last post. I would prefer the model declaration as it’s the direction where Gradle is going. This is what I did in my example.

Don’t hesitate to ask more questions!