blob: 6deba1a7efc3e031310b3a8bd1796c47b10cd041 [file] [log] [blame]
import java.nio.file.Paths
import org.gradle.internal.logging.text.StyledTextOutput;
import org.gradle.internal.logging.text.StyledTextOutputFactory;
import static org.gradle.internal.logging.text.StyledTextOutput.Style;
import org.gradle.internal.os.OperatingSystem;
import org.gradle.api.Project;
import static groovy.lang.Closure.IDENTITY;
import groovy.util.GroovyCollections;
import groovyx.gpars.GParsPool;
apply plugin: 'java'
defaultTasks 'cleanPath', 'archiveZip'
enum ExternalToolName { PROTOBUF, CMAKE }
def osFolderName(externalToolName) {
if (OperatingSystem.current().isMacOsX()) {
if (externalToolName == ExternalToolName.PROTOBUF) {
return "mac";
} else if (externalToolName == ExternalToolName.CMAKE) {
return "darwin-x86"
}
} else if (OperatingSystem.current().isLinux())
return "linux-x86";
else if (OperatingSystem.current().isWindows()) {
if (externalToolName == ExternalToolName.PROTOBUF) {
return "win";
} else if (externalToolName == ExternalToolName.CMAKE) {
return "windows-x86";
}
}
throw new GradleException("Unsupported OS");
}
def osExecutableSuffix() {
if (OperatingSystem.current().isWindows())
return ".exe"
else
return ""
}
def protobufInstallDir() {
return new File("$projectDir/third_party/protobuf-3.0.0/install/"
+ osFolderName(ExternalToolName.PROTOBUF)).getPath()
}
def joinPath(String first, String... more) {
return Paths.get(first, more).toString()
}
def getEnvironment() {
def env = [:]
def trans = IDENTITY
if (OperatingSystem.current().isWindows()) {
trans = { it.toUpperCase() }
}
System.getenv().each{entry -> env[trans(entry.key)] = entry.value}
return env
}
task prepare_proto_before {
def protocBinDir = protobufInstallDir() + "/bin"
def env = getEnvironment()
env['PATH'] = protocBinDir + System.getProperty("path.separator") + env['PATH']
doLast {
// Install python-protobuf
exec {
workingDir "./third_party/protobuf-3.0.0/python"
setEnvironment env
commandLine "python", "setup.py", "install", "--user"
}
// Generate nano-pb requirements
exec {
workingDir '../external/nanopb-c/generator/proto'
setEnvironment env
commandLine 'make'
}
}
}
task prepare_proto(dependsOn: prepare_proto_before) {
doLast {
exec {
commandLine "python"
args = ["ab_info.py"]
}
}
}
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.2'
classpath "org.codehaus.gpars:gpars:1.2.0"
}
}
allprojects {
buildDir = getOutPath()
repositories {
google()
jcenter()
}
}
abstract class Toolchain {
protected Project project_;
protected String androidVersion_;
protected String ndkVersion_;
abstract String getAndroidNDKPath();
public String getAndroidVersion() { return androidVersion_; }
public String getNdkVersion() { return ndkVersion_; }
public String getNdkVersionNumber() {
def (n) = ndkVersion_ =~ /[0-9]+/;
return n;
}
public String getBuildKey(String arch, String stl, String buildType) {
return arch + "_API" + androidVersion_ + "_NDK" + getNdkVersionNumber() + '_' +
sanitize(stl)+ '_'+buildType
}
protected String getNdkVersionFromPropertiesFile() {
def f = new File(getAndroidNDKPath(), 'source.properties')
if (!f.exists()) {
println "Warning: can't get NDK version"
return "UNKNOWN"
}
else {
Properties props = new Properties()
f.withInputStream {
props.load(it)
}
def ver = props."Pkg.Revision"
def parts = ver.findAll("[^.]+")
// Ignore the minor version
return parts[0]
}
}
private String sanitize(String s) {
return s.replaceAll(/[+]/, "p")
}
String findNDKTool(String name) {
def tools = project_.fileTree(project_.joinPath(getAndroidNDKPath(), 'toolchains')).matching {
include '**/bin/' + name + project_.osExecutableSuffix()
// Be sure not to use tools that would not support architectures for which we're buidling:
exclude "**/aarch64-*", "**/arm-*"
}
if (tools==null || tools.size() == 0) {
throw new GradleException('No ' + name + ' found in ' + ndkPath_ + '/toolchains')
}
return tools.getFiles().last().toString()
}
String getArPath() {
return findNDKTool("ar")
}
public String getCMakePath() {
return new File("${project_.projectDir}/../prebuilts/cmake/"
+ project_.osFolderName(ExternalToolName.CMAKE)
+ "/bin/cmake" + project_.osExecutableSuffix()).getPath()
}
public String getNinjaPath() {
return new File("${project_.projectDir}/../prebuilts/cmake/"
+ project_.osFolderName(ExternalToolName.CMAKE)
+ "/bin/ninja" + project_.osExecutableSuffix()).getPath()
}
}
class SpecificToolchain extends Toolchain {
SpecificToolchain(Project project, String androidVersion, String ndkVersion) {
project_ = project
androidVersion_ = androidVersion
ndkVersion_ = ndkVersion
}
public String getAndroidNDKPath() {
return new File("${project_.projectDir}/../prebuilts/ndk/" + ndkVersion_).getPath()
}
}
class LocalToolchain extends Toolchain {
String sdkPath_;
String ndkPath_;
String adbPath_;
LocalToolchain(Project project, String androidVersion) {
project_ = project
androidVersion_ = androidVersion
sdkPath_ = System.getenv("ANDROID_HOME")
if(sdkPath_ == null && project.rootProject.file('local.properties').isFile()) {
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
sdkPath_ = properties.getProperty('sdk.dir')
}
if(sdkPath_ == null)
throw new GradleException('Must set ANDROID_HOME or sdk.dir in local.properties')
// Try to find a side-by-side NDK if a specific version is specified
def requestedNdkRevision = System.getenv("ANDROID_NDK_REVISION")
if (requestedNdkRevision != null) {
def ndkSideBySidePath = project_.joinPath(sdkPath_, 'ndk', requestedNdkRevision);
if (project_.file(ndkSideBySidePath).exists())
ndkPath_ = ndkSideBySidePath;
// Don't throw an error if not found, as the version might be the default one
// installed (see next lines).
}
// Try to find the NDK specified in ANDROID_NDK or the default one.
if(ndkPath_ == null) {
ndkPath_ = System.getenv("ANDROID_NDK")
}
if(ndkPath_ == null) {
ndkPath_ = System.getenv("ANDROID_NDK_HOME")
}
if(ndkPath_ == null && project.rootProject.file('local.properties').isFile()) {
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
ndkPath_ = properties.getProperty('ndk.dir')
}
if(ndkPath_ == null) {
ndkPath_ = project_.joinPath(sdkPath_, 'ndk-bundle')
if (!project_.file(ndkPath_).exists())
throw new GradleException('No NDK found in SDK: must set ANDROID_NDK or ANDROID_NDK_REVISION with the version of a NDK installed in the SDK "ndk" folder (NDK side-by-side).')
}
// Get the version of the NDK that was found and sanity check that it's the proper one.
ndkVersion_ = getNdkVersionFromPropertiesFile()
adbPath_ = project_.joinPath(sdkPath_, 'platform-tools', 'adb')
if (requestedNdkRevision != null) {
def requestNDKMajorVersion = requestedNdkRevision.findAll("[^.]+")
if (ndkVersion_ != requestNDKMajorVersion[0]) {
throw new GradleException("You specified NDK $requestedNdkRevision but only NDK $ndkVersion_ was found in $ndkPath_. Verify that you have the requested NDK installed with the SDK manager.")
}
}
}
String getAndroidNDKPath() {
return ndkPath_;
}
String getAdbPath() {
return adbPath_;
}
}
def getBuildPath() {
return new File("$projectDir/build").getPath()
}
def getOutPath() {
return new File("$projectDir/../out").getPath()
}
def getPackagePath() {
return new File("$projectDir/../package").getPath();
}
def getDistPath() {
def distDir = System.getenv('DIST_DIR');
if (distDir != null) {
return new File(distDir).getPath();
}
else {
return getPackagePath();
}
}
def getTempPath() {
return new File("$projectDir/../.temp").getPath()//.getAbsolutePath()
}
def useNinja() {
return true;
}
def cmake(projectFolder, workingFolder, outputFolder, arch, toolchain, stl,
threadChecks, buildTuningFork, buildType = "Release") {
def ndkPath = toolchain.getAndroidNDKPath()
def toolchainFilePath = ndkPath + "/build/cmake/android.toolchain.cmake"
def androidVersion = toolchain.getAndroidVersion()
def ninjaPath = toolchain.getNinjaPath()
def buildtfval = buildTuningFork ? "ON" : "OFF"
def protocBinDir = protobufInstallDir() + "/bin"
mkdir workingFolder
mkdir outputFolder
def threadFlags = ""
if (threadChecks) {
threadFlags = "-DGAMESDK_THREAD_CHECKS=1"
} else {
threadFlags = "-DGAMESDK_THREAD_CHECKS=0"
}
def cxx_flags = "-DANDROID_NDK_VERSION=${toolchain.getNdkVersionNumber()}"
if (stl=="gnustl_static" || stl=="gnustl_shared")
cxx_flags += " -DANDROID_GNUSTL"
def cmdLine = [toolchain.getCMakePath(),
"$projectFolder",
"-DCMAKE_BUILD_TYPE=$buildType",
"-DANDROID_PLATFORM=android-$androidVersion",
"-DANDROID_NDK=$ndkPath",
"-DANDROID_STL=$stl",
"-DANDROID_ABI=$arch",
"-DANDROID_UNIFIED_HEADERS=1",
"-DCMAKE_CXX_FLAGS=$cxx_flags",
"-DCMAKE_TOOLCHAIN_FILE=$toolchainFilePath",
"-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY=$outputFolder",
"-DGAMESDK_BUILD_TUNINGFORK=$buildtfval",
threadFlags]
if (useNinja()) {
cmdLine += ["-DCMAKE_MAKE_PROGRAM=" + "$ninjaPath",
"-GNinja"]
}
exec {
environment "PATH", "$protocBinDir:${environment.PATH}"
workingDir workingFolder
commandLine cmdLine
}
}
def hostCmake(projectFolder, workingFolder, outputFolder, toolchain, buildType) {
mkdir workingFolder
mkdir outputFolder
def cmdLine = [toolchain.getCMakePath(),
"$projectFolder",
"-DCMAKE_BUILD_TYPE=$buildType",
"-DCMAKE_CXX_FLAGS=",
"-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=$outputFolder"
]
exec {
workingDir workingFolder
commandLine cmdLine
}
}
def buildHostModule(subdir, buildType) {
def toolchain = getLocalToolchain();
def buildKey = "host"
def workingFolder = joinPath(getTempPath(), buildKey, '.cmake')
def outputFolder = joinPath(getOutPath(), buildKey)
def cmakeProjectLocation = joinPath("$projectDir", subdir)
hostCmake(cmakeProjectLocation, workingFolder, outputFolder, toolchain, buildType)
def cmdLine = ["make", "-j"]
exec {
workingDir workingFolder
commandLine cmdLine
}
return [buildKey: buildKey, outputFolder: outputFolder]
}
def buildNativeModules(arch, Toolchain toolchain, stl, threadChecks, buildtf, subdir = "src",
buildType = "Release") {
def buildKey = toolchain.getBuildKey(arch, stl, buildType)
def workingFolder = joinPath(getTempPath(), buildKey, '.cmake')
def outputFolder = joinPath(getOutPath(), buildKey)
def cmakeProjectLocation = joinPath("$projectDir", subdir)
cmake(cmakeProjectLocation, workingFolder, outputFolder, arch, toolchain,
stl, threadChecks, buildtf, buildType)
def cmdLine = useNinja() ? [toolchain.getNinjaPath()] : ["make", "-j"]
exec {
workingDir workingFolder
commandLine cmdLine
}
def jsonDescription = new File(joinPath(outputFolder, "abi.json"))
jsonDescription.text = '{"abi":"'+arch+'","api":'+toolchain.getAndroidVersion()+
',"ndk":'+toolchain.getNdkVersionNumber()+',"stl":"'+stl+'"}'
return [arch: arch, buildKey: buildKey]
}
def buildNativeModules(arch, androidVersion, ndkVersion, stl, threadChecks,
buildtf, buildType) {
return buildNativeModules(arch,
new SpecificToolchain(project, androidVersion, ndkVersion),
stl, threadChecks, buildtf, "src", buildType)
}
task cleanPath(type: Delete) {
delete getOutPath()
delete getPackagePath()
delete getTempPath()
delete getBuildPath()
}
clean.dependsOn cleanPath
def executeCmd(cmd, dir) {
def out = new StringBuilder()
def err = new StringBuilder()
def process = cmd.execute(null, new File(dir))
process.consumeProcessOutput(out, err)
process.waitFor()
logger.info("Runnig $cmd")
if(out.length()>0)
logger.info(out.toString())
if(err.length()>0)
logger.error(err.toString())
}
// Create outAr from the contents of inArs
// All files taken/created in dir
def repackArchives(dir, inArs, outAr) {
def arPath = getLocalToolchain().getArPath()
if (OperatingSystem.current().isWindows()) {
inArs.each {
executeCmd("cmd /c ${arPath} -x ${it}", dir)
}
executeCmd("cmd /c for %i in (*.o) do ${arPath} -rcs ${outAr} %i", dir)
executeCmd("cmd /c del *.o", dir)
} else {
def cmd = /pushd $dir &&/
inArs.each {
cmd <<= /$arPath -x $it &&/
}
cmd <<= /$arPath -rcs $outAr *.o && rm *.o && popd/
['/bin/bash', '-c', cmd.toString()].execute().waitFor()
}
}
def aarSdkCopy(buildInfo, outFolder) {
def arch = buildInfo.arch
def buildKey = buildInfo.buildKey
def cmakeFolder = joinPath(getTempPath(), buildKey, '.cmake', 'swappy')
def buildFolder = joinPath(getPackagePath(), outFolder)
def sharedLibBuildFolder = joinPath(buildFolder, 'prefab','modules', 'swappy', 'libs',
'android.'+buildKey)
def staticLibBuildFolder = joinPath(buildFolder, 'prefab','modules', 'swappy_static', 'libs',
'android.'+buildKey)
def staticsFolder = joinPath(getOutPath(), buildKey)
def sharedIncludeBuildFolder = joinPath(buildFolder, 'prefab','modules', 'swappy', 'include', 'swappy')
def staticIncludeBuildFolder = joinPath(buildFolder, 'prefab','modules', 'swappy_static', 'include', 'swappy')
def headerFolder = './include/swappy'
// TODO: including the dynamic library (uncommenting these next lines)
// errors because no proper library can be found for module swappy (the shared version),
// probably because we're using c++_static in samples?
def buildSharedLibrary = false
def buildStaticLibrary = true
// 1. Copy dynamic library
if (buildSharedLibrary) {
copy {
from file(cmakeFolder)
include "*.so"
into file(sharedLibBuildFolder)
includeEmptyDirs = false
}
copy {
from file(staticsFolder)
include "*.json"
into file(sharedLibBuildFolder)
}
}
// 2. Copy the static libary
if (buildStaticLibrary) {
copy {
from file(staticsFolder)
include "*.a","*.json"
rename("libswappy_static.a", "libswappy.a")
into file(staticLibBuildFolder)
}
}
// 3.1 Copy headers (shared library)
if (buildSharedLibrary) {
copy {
from file(headerFolder)
include "*.h"
into file(sharedIncludeBuildFolder)
includeEmptyDirs = false
}
}
// 3.2 Copy headers (static library)
if (buildStaticLibrary) {
copy {
from file(headerFolder)
include "*.h"
into file(staticIncludeBuildFolder)
includeEmptyDirs = false
}
}
// 4. Copy the manifest
copy {
from file("./src")
include "AndroidManifest.xml"
into file(buildFolder)
includeEmptyDirs = false
}
// 5. Create the json files
def jsonPrefabDescription = new File(joinPath(buildFolder, 'prefab', 'prefab.json'))
jsonPrefabDescription.text = '{"name":"gamesdk","schema_version":1,"dependencies":[],"version":"1.3.0"}'
if (buildSharedLibrary) {
def jsonModuleDescription = new File(joinPath(buildFolder, 'prefab', 'modules', 'swappy', 'module.json'))
jsonModuleDescription.text = '{"library_name": "libswappy", "export_libraries": []}'
}
if (buildStaticLibrary) {
def jsonStaticModuleDescription = new File(joinPath(buildFolder, 'prefab', 'modules', 'swappy_static', 'module.json'))
jsonStaticModuleDescription.text = '{"library_name": "libswappy", "export_libraries": []}'
}
}
def sdkCopy(buildInfo, outFolder, all = true, staticToo = false,
useFullBuildKey = false, flattenLibDirs = false, shared = true) {
def arch = buildInfo.arch
def buildKey = buildInfo.buildKey
def cmakeFolder = joinPath(getTempPath(), buildKey, '.cmake')
def buildFolder = joinPath(getPackagePath(), outFolder)
def libBuildFolder = joinPath(buildFolder, 'libs',
useFullBuildKey ? buildKey : arch, 'lib')
if (shared) {
copy {
from file(cmakeFolder)
include all ? "*/lib*.so" : "swappy*/lib*.so"
into file(libBuildFolder)
includeEmptyDirs = false
if (flattenLibDirs) {
eachFile {
path = name
}
}
}
}
if (staticToo) {
def staticsFolder = joinPath(getOutPath(), buildKey)
def staticLibsBuildFolder = joinPath(buildFolder, 'libs', buildKey)
def staticLibs = ['libswappy_static.a']
if (all)
staticLibs += 'libtuningfork_static.a'
repackArchives(staticsFolder, staticLibs, 'libgamesdk.a')
copy {
from file(staticsFolder)
include "libgamesdk.a"
into file(staticLibsBuildFolder)
}
}
}
def copyExtras(outFolder, all = true) {
def buildFolder = getPackagePath() + '/' + outFolder
def headerFolder = './include'
def aarFolder = joinPath(getOutPath(), 'outputs', 'aar')
def includeBuildFolder = joinPath(buildFolder, 'include')
def aarBuildFolder = joinPath(buildFolder, 'aar')
copy {
from file(headerFolder)
include all ? "*/*.h" : "swappy*/*.h"
into file(includeBuildFolder)
includeEmptyDirs = false
}
copy {
from file(aarFolder)
into file(aarBuildFolder)
includeEmptyDirs = false
}
}
def copyDocs(outFolder) {
copy {
from "LICENSE", "THIRD_PARTY_NOTICES", "RELEASE_NOTES"
into getPackagePath() + '/' + outFolder
}
}
// Copy samples for packaging. Also rename CMakeLists.txt files so that the
// one distributed are using the packaged game sdk.
def copySamples(outFolder, includeTuningForkSamples = true) {
def buildFolder = getPackagePath() + '/' + outFolder
// CMake utility for the Game SDK
copy {
from file(joinPath('samples', "gamesdk.cmake"))
into file(joinPath(buildFolder, 'samples'))
}
// All sample common files
copy {
from file(joinPath('samples', "common"))
into file(joinPath(buildFolder, 'samples', 'common'))
}
// Bouncyball
copy {
from file(joinPath('samples', "bouncyball"))
into file(joinPath(buildFolder, 'samples', "bouncyball"))
exclude '**/build', '**/out', "local.properties", "**/.externalNativeBuild", "**/.gradle",
"**/OWNERS", "**/.idea", '**/CMakeLists.txt'
rename 'CMakeLists.for-samples-in-archive.txt', 'CMakeLists.txt'
includeEmptyDirs = false
}
// Cube
copy {
from file(joinPath('samples', "cube"))
into file(joinPath(buildFolder, 'samples', "cube"))
exclude '**/build', '**/out', "local.properties", "**/.externalNativeBuild",
"**/.gradle", "**/OWNERS", "**/.idea"
includeEmptyDirs = false
}
copy {
from file(joinPath('third_party', "cube"))
into file(joinPath(buildFolder, 'third_party', "cube"))
rename 'CMakeLists.for-samples-in-archive.txt', 'CMakeLists.txt'
exclude '**/build', '**/out', "local.properties", "**/.externalNativeBuild", "**/.gradle",
"**/OWNERS", "**/.idea"
includeEmptyDirs = false
}
if (includeTuningForkSamples) {
// All Tuning Fork sample common files
copy {
from file(joinPath('samples', 'tuningfork', "common"))
into file(joinPath(buildFolder, 'samples', 'tuningfork', 'common'))
}
copy {
from file(joinPath('samples', "tuningfork", "expertballs"))
into file(joinPath(buildFolder, 'samples', "tuningfork", "expertballs"))
exclude '**/build', '**/out', "local.properties", "**/.externalNativeBuild", "**/.gradle",
"**/OWNERS", "**/.idea", '**/CMakeLists.txt'
rename 'CMakeLists.for-samples-in-archive.txt', 'CMakeLists.txt'
includeEmptyDirs = false
}
copy {
from file(joinPath('samples', "tuningfork", "scaledballs"))
into file(joinPath(buildFolder, 'samples', "tuningfork", "scaledballs"))
exclude '**/build', '**/out', "local.properties", "**/.externalNativeBuild", "**/.gradle",
"**/OWNERS", "**/.idea", '**/CMakeLists.txt'
rename 'CMakeLists.for-samples-in-archive.txt', 'CMakeLists.txt'
includeEmptyDirs = false
}
copy {
from file(joinPath('src', 'protobuf'))
into file(joinPath(buildFolder, 'src', 'protobuf'))
includeEmptyDirs = false
}
copy {
from file(joinPath('third_party', 'protobuf-3.0.0'))
into file(joinPath(buildFolder, 'third_party', 'protobuf-3.0.0'))
includeEmptyDirs = false
}
copy {
from file(joinPath('..', 'external', 'nanopb-c'))
into file(joinPath(buildFolder, 'external', 'nanopb-c'))
includeEmptyDirs = false
}
copy {
from file(joinPath('src', 'tuningfork', 'tools', 'validation'))
into file(joinPath(buildFolder, 'src', 'tuningfork', 'tools', 'validation'))
exclude '**/build'
includeEmptyDirs = false
}
copy {
from file(joinPath('src', 'tuningfork', 'proto'))
into file(joinPath(buildFolder, 'src', 'tuningfork', 'proto'))
include 'tuningfork.proto'
includeEmptyDirs = false
}
}
}
def abis32Bits() { return ["armeabi-v7a", "x86"] }
def abis64Bits() { return ["arm64-v8a", "x86_64"] }
def defaultAbis() { return abis32Bits() + abis64Bits() }
def allSTLs() { return ["c++_static", "c++_shared", "gnustl_static", "gnustl_shared"] }
def post17STLs() { return ["c++_static", "c++_shared"] }
def versionMapping() { return [ [["r14"], [14,15,16,17,18,19,20,21,22,23,24]],
[["r15"], [14,15,16,17,18,19,21,22,23,24,26]],
[["r16"], [14,15,16,17,18,19,21,22,23,24,26,27]],
[["r17"], [14,15,16,17,18,19,21,22,23,24,26,27,28]]] }
def versionMappingPost17() { return [ [["r18"], [16,17,18,19,21,22,23,24,26,27,28]],
[["r19"], [16,17,18,19,21,22,23,24,26,27,28]],
[["r20"], [16,17,18,19,21,22,23,24,26,27,28]],
[["r21"], [16,17,18,19,21,22,23,24,26,27,28,29]]] }
def unityNativeBuild(withTuningFork=false, buildType="Release") {
def threadChecks = false
return defaultAbis().collect {
buildNativeModules(it, "21", "r19", "c++_static", threadChecks, withTuningFork, buildType)
}
}
def sdkNativeBuild(withTuningFork = true, buildType="Release") {
def threadChecks = false
def versions = versionMapping().collectMany { GroovyCollections.combinations(it) }
def versionsPost17 = versionMappingPost17().collectMany { GroovyCollections.combinations(it) }
def allCombos = GroovyCollections.combinations(defaultAbis(), versions, allSTLs()) +
GroovyCollections.combinations(defaultAbis(), versionsPost17, post17STLs());
GParsPool.withPool {
return allCombos.collectParallel { x ->
buildNativeModules(
/*arch=*/ x[0],
/*androidVersion=*/ x[1][1].toString(),
/*ndkVersion=*/ x[1][0],
/*stlVersion=*/ x[2],
threadChecks, withTuningFork, buildType)
}
}
}
// For the AAR, only build the dynamic libraries against shared STL.
def aarSTLs() { return ["c++_shared", "gnustl_shared"] }
def aarPost17STLs() { return ["c++_shared"] }
// In the AAR, library search is handled by Prefab, that looks for API 21 for 64 bits architectures
// even if a lower API level is requested. We need to build a different set of libraries for 32 and
// 64 bits as a consequence.
def aarVersionMapping32Bits() { return versionMapping() }
def aarVersionMapping32BitsPost17() { return versionMappingPost17() }
def aarVersionMapping64Bits() { return [ [["r14"], [21,22,23,24]],
[["r15"], [21,22,23,24,26]],
[["r16"], [21,22,23,24,26,27]],
[["r17"], [21,22,23,24,26,27,28]]] }
def aarVersionMapping64BitsPost17() { return [ [["r18"], [21,22,23,24,26,27,28]],
[["r19"], [21,22,23,24,26,27,28]],
[["r20"], [21,22,23,24,26,27,28]],
[["r21"], [21,22,23,24,26,27,28,29]]] }
def sdkAarNativeBuild(withTuningFork = true, buildType="Release") {
def threadChecks = false
def versions32Bits = aarVersionMapping32Bits().collectMany { GroovyCollections.combinations(it) }
def versions32BitsPost17 = aarVersionMapping32BitsPost17().collectMany { GroovyCollections.combinations(it) }
def versions64Bits = aarVersionMapping64Bits().collectMany { GroovyCollections.combinations(it) }
def versions64BitsPost17 = aarVersionMapping64BitsPost17().collectMany { GroovyCollections.combinations(it) }
def allCombos =
GroovyCollections.combinations(abis32Bits(), versions32Bits, aarSTLs()) +
GroovyCollections.combinations(abis32Bits(), versions32BitsPost17, aarPost17STLs()) +
GroovyCollections.combinations(abis64Bits(), versions64Bits, aarSTLs()) +
GroovyCollections.combinations(abis64Bits(), versions64BitsPost17, aarPost17STLs());
GParsPool.withPool {
return allCombos.collectParallel { x ->
buildNativeModules(
/*arch=*/ x[0],
/*androidVersion=*/ x[1][1].toString(),
/*ndkVersion=*/ x[1][0],
/*stlVersion=*/ x[2],
threadChecks, withTuningFork, buildType)
}
}
}
def specificNativeBuild(sdkVersion, ndkVersion, stlVersion, withTuningFork = false,
buildType="Release") {
def threadChecks = false
return defaultAbis().collect {
buildNativeModules(it, sdkVersion, ndkVersion, stlVersion, threadChecks, withTuningFork,
buildType)
}
}
def getLocalToolchain() {
def kApiLevel = project.hasProperty("GAMESDK_ANDROID_API_LEVEL") ?
project.GAMESDK_ANDROID_API_LEVEL : "24"
return new LocalToolchain(project, kApiLevel)
}
def localNativeBuild(withTuningFork = false, subdir = "src", buildType="Release") {
def toolchain = getLocalToolchain();
def stl = "c++_static"
def threadChecks = true
return defaultAbis().collect {
buildNativeModules(it, toolchain , stl, threadChecks, withTuningFork, subdir, buildType)
}
}
def defaultBuildType() {
return project.hasProperty("GAMESDK_BUILD_TYPE") ?
project.GAMESDK_BUILD_TYPE : "Release"
}
class BuildTask extends DefaultTask {
}
// Just build swappy shared libraries
task swappyUnityBuild(type: BuildTask) {
dependsOn ':extras:assembleRelease'
ext.packageName = 'swappyUnity'
ext.flattenLibs = true
ext.withTuningFork = false
ext.withSharedLibs = false
ext.withStaticLibs = true
ext.withFullBuildKey = true
ext.withSamples = false
ext.buildType = "Release";
ext.nativeBuild = { tf,bt -> unityNativeBuild(tf,bt) }
}
task swappyUnityDebugBuild(type: BuildTask) {
dependsOn ':extras:assembleRelease'
ext.packageName = 'swappyUnity'
ext.flattenLibs = true
ext.withTuningFork = false
ext.withSharedLibs = true
ext.withStaticLibs = true
ext.withFullBuildKey = true
ext.withSamples = false
ext.buildType = "Debug";
ext.nativeBuild = { tf,bt -> unityNativeBuild(tf,bt) }
}
// Full build including tuning fork for unity, shared libraries only
task unityBuild(type: BuildTask) {
dependsOn ':extras:assembleRelease', prepare_proto
ext.packageName = 'unity'
ext.flattenLibs = true
ext.withTuningFork = true
ext.withSharedLibs = false
ext.withStaticLibs = true
ext.withFullBuildKey = true
ext.withSamples = false
ext.buildType = "Release";
ext.nativeBuild = { tf,bt -> unityNativeBuild(tf,bt) }
}
// Build everything
task fullSdkBuild(type: BuildTask) {
dependsOn ':extras:assembleRelease', prepare_proto
ext.packageName = 'fullsdk'
ext.flattenLibs = false
ext.withTuningFork = true
ext.withSharedLibs = true
ext.withStaticLibs = true
ext.withFullBuildKey = true
ext.withSamples = true
ext.buildType = "Release"
ext.nativeBuild = { tf,bt -> sdkNativeBuild(tf,bt) }
}
// Build everything without TF
task releaseSdkBuild(type: BuildTask) {
dependsOn ':extras:assembleRelease', prepare_proto
ext.packageName = 'gamesdk'
ext.flattenLibs = false
ext.withTuningFork = false
ext.withSharedLibs = true
ext.withStaticLibs = true
ext.withFullBuildKey = true
ext.withSamples = true
ext.buildType = "Release";
ext.nativeBuild = { tf,bt -> sdkNativeBuild(tf,bt) }
}
// Build everything and package as an aar file
task releaseAarSdkBuild() {
dependsOn ':extras:assembleRelease', prepare_proto
ext.packageName = 'gamesdk'
ext.flattenLibs = false
ext.withTuningFork = false
ext.withSharedLibs = true
ext.withStaticLibs = true
ext.withFullBuildKey = true
ext.withSamples = true
ext.buildType = "Release";
ext.nativeBuild = { tf,bt -> sdkAarNativeBuild(tf,bt) }
doLast {
nativeBuild(withTuningFork, buildType).each {
aarSdkCopy(it, packageName)
}
}
}
// Build everything in debug without TF
task debugSdkBuild(type: BuildTask) {
dependsOn ':extras:assembleRelease', prepare_proto
ext.packageName = 'gamesdk_debug'
ext.flattenLibs = false
ext.withTuningFork = false
ext.withSharedLibs = true
ext.withStaticLibs = true
ext.withFullBuildKey = true
ext.withSamples = true
ext.buildType = "Debug";
ext.nativeBuild = { tf,bt -> sdkNativeBuild(tf,bt) }
}
// Build using local SDK, no tuning fork
task localBuild(type: BuildTask) {
dependsOn ':extras:assembleRelease'
ext.packageName = 'local'
ext.flattenLibs = false
ext.withTuningFork = false;
ext.withSharedLibs = true
ext.withStaticLibs = true;
ext.withFullBuildKey = false;
ext.withSamples = false;
ext.buildType = defaultBuildType();
ext.nativeBuild = { tf,bt -> localNativeBuild(tf, "src", bt) }
}
// Build using local SDK, with tuning fork
task localTfBuild(type: BuildTask) {
dependsOn ':extras:assembleRelease', prepare_proto
ext.packageName = 'localtf'
ext.flattenLibs = false
ext.withTuningFork = true;
ext.withSharedLibs = true
ext.withStaticLibs = true;
ext.withFullBuildKey = false;
ext.withSamples = false;
ext.buildType = defaultBuildType();
ext.nativeBuild = { tf,bt -> localNativeBuild(tf, "src", bt) }
}
task specificBuild(type: BuildTask) {
dependsOn ':extras:assembleRelease'
ext.packageName = "specific"
ext.flattenLibs = false
ext.withTuningFork = false;
ext.withSharedLibs = true
ext.withStaticLibs = true;
ext.withFullBuildKey = false;
ext.withSamples = true;
ext.buildType = defaultBuildType();
ext.nativeBuild = { tf,bt ->
def sdk = System.getenv("SDK")
def ndk = System.getenv("NDK")
def stl = System.getenv("STL")
if (sdk==null || ndk==null || stl==null) {
throw new GradleException("""
Must set SDK, NDK and STL for a specific build,
e.g. SDK=14 NDK=r16 STL='c++_static' ./gradlew specificZip"""
)
}
specificNativeBuild(sdk, ndk, stl, tf, bt)
}
}
tasks.withType(BuildTask) {
doLast {
nativeBuild(withTuningFork, buildType).each {
sdkCopy(it, packageName, withTuningFork, withStaticLibs,
withFullBuildKey, flattenLibs, withSharedLibs)
}
copyExtras(packageName, withTuningFork)
copyDocs(packageName)
if (withSamples) {
copySamples(packageName, withTuningFork)
}
}
}
task localUnitTests {
// These unit tests require a connected ARM64 device to run
doLast {
def buildInfo = localNativeBuild(true, "test/tuningfork")
def buildKey = buildInfo.buildKey.findAll{it.contains('arm64-v8a')}[0]
def cmakeFolder = getTempPath() + '/' + buildKey + '/.cmake'
def toolchain = getLocalToolchain();
def adb = toolchain.getAdbPath();
exec {
workingDir cmakeFolder
commandLine adb, "push", "tuningfork_test", "/data/local/tmp"
}
exec {
workingDir cmakeFolder
commandLine adb, "shell", "/data/local/tmp/tuningfork_test"
}
}
}
task localSwappyUnitTests {
// These unit tests require a connected ARM64 device to run
doLast {
def buildInfo = localNativeBuild(false, "test/swappy")
def buildKey = buildInfo.buildKey.findAll{it.contains('arm64-v8a')}[0]
def cmakeFolder = getTempPath() + '/' + buildKey + '/.cmake'
def toolchain = getLocalToolchain();
def adb = toolchain.getAdbPath();
exec {
workingDir cmakeFolder
commandLine adb, "push", "swappy_test", "/data/local/tmp"
}
exec {
workingDir cmakeFolder
commandLine adb, "shell", "/data/local/tmp/swappy_test"
}
}
}
task localDeviceInfoUnitTests {
doLast {
def buildInfo = buildHostModule("test/device_info", "Release")
exec {
workingDir buildInfo.outputFolder
commandLine "./device_info_test"
}
}
}
// Zipping things up
def addZipTask(name, buildTask, zipName) {
def packPath = buildTask.packageName
tasks.register(name, Zip) {
dependsOn buildTask
def buildFolder = joinPath(getPackagePath(), packPath)
def archName = zipName + (zipName.contains(".") ? "" : ".zip")
from fileTree(buildFolder)
exclude archName
destinationDirectory = file(buildFolder)
archiveFileName = archName
doLast {
def outFolder = getBuildPath();\
mkdir outFolder;
copy {
from file(archiveName)
into outFolder
}
if (getDistPath() != getPackagePath()) {
copy {
from getPackagePath()
into getDistPath()
}
}
def out = services.get(StyledTextOutputFactory).create("output")
out.style(Style.Identifier).text('\n' + archName +' is in ')
.style(Style.ProgressStatus)
.println(destinationDirectory.get());
}
}
}
addZipTask("swappyUnityZip", swappyUnityBuild, "builds")
addZipTask("swappyUnityDebugZip", swappyUnityDebugBuild, "builds")
addZipTask("unityZip", unityBuild, "builds")
addZipTask("archiveZip", localBuild, "gamesdk")
addZipTask("archiveTfZip", localTfBuild, "gamesdk")
addZipTask("fullSdkZip", fullSdkBuild, "gamesdk")
addZipTask("specificZip", specificBuild, "gamesdk")
addZipTask("gamesdkZip", releaseSdkBuild, "gamesdk")
addZipTask("gamesdkDebugZip", debugSdkBuild, "gamesdk_debug")
addZipTask("gameSdkAAR", releaseAarSdkBuild, "gaming-frame-pacing.aar")