import com.google.androidgamesdk.BuildFolders import com.google.androidgamesdk.BuildOptions import com.google.androidgamesdk.ExternalAndroidProject import com.google.androidgamesdk.ExternalAndroidProjectBuilder import com.google.androidgamesdk.SpecificToolchain import com.google.androidgamesdk.LocalToolchain import com.google.androidgamesdk.BuildInfoFile import com.google.androidgamesdk.Toolchain import com.google.androidgamesdk.ToolchainSet import com.google.androidgamesdk.AndroidArchiveLibrary import com.google.androidgamesdk.NativeLibrary import com.google.androidgamesdk.NativeLibrary.SampleFolder import com.google.androidgamesdk.ToolchainEnumerator import com.google.androidgamesdk.AarPrefabPatcher import com.google.androidgamesdk.LibraryVersions import org.gradle.internal.logging.text.StyledTextOutputFactory; import static org.gradle.internal.logging.text.StyledTextOutput.Style; import org.gradle.internal.os.OperatingSystem; import static groovy.lang.Closure.IDENTITY; import org.apache.tools.ant.filters.ReplaceTokens; import com.google.androidgamesdk.ExternalToolName; import static com.google.androidgamesdk.OsSpecificTools.osFolderName; import static com.google.androidgamesdk.OsSpecificTools.joinPath; import static com.google.androidgamesdk.CMakeWrapper.runAndroidCMake; import static com.google.androidgamesdk.CMakeWrapper.runHostCMake; import static com.google.androidgamesdk.CMakeWrapper.runNinja; import static com.google.androidgamesdk.ToolchainEnumerator.filterBuiltLibraries; import groovy.io.FileType import groovy.transform.Field buildscript { repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:7.2.0' } } // The following is needed for sub-projects that have their own gradle script and that are // not using the general swappy/tuningfork multi-ndk build logic below and in buildSrc. @Field isRunningOnBuildBot = System.getenv("BUILDBOT_SCRIPT") if (isRunningOnBuildBot) { Properties properties = new Properties() if (project.rootProject.file('local.properties').exists()) { properties.load(project.rootProject.file('local.properties').newDataInputStream()) } properties.setProperty('sdk.dir', System.getenv("ANDROID_HOME")) properties.setProperty('ndk.dir', System.getenv("ANDROID_NDK_HOME")) properties.setProperty('cmake.dir', System.getenv("BUILDBOT_CMAKE")) properties.store(project.rootProject.file('local.properties').newDataOutputStream(), '') } def versions = new LibraryVersions(project.rootProject.file('VERSIONS').getPath()) ext.getAGDKZipName = { -> return "agdk-libraries-"+ versions["AGDK"].version + (isExpressPackage() ? "_express" : "") + ".zip" } def getGitCommit() { def sout = new StringBuilder(), serr = new StringBuilder() def proc = ['sh', '-c', 'cd ' + project.projectDir.toString() + ' && git rev-parse --short HEAD'].execute() proc.consumeProcessOutput(sout, serr) proc.waitForOrKill(1000) println(serr) return sout.toString().trim() } def swappyNativeLibrary = new AndroidArchiveLibrary(versions['swappy']) def tuningForkNativeLibrary = new AndroidArchiveLibrary(versions['tuningfork']) def memoryAdviceNativeLibrary = new AndroidArchiveLibrary(versions['memory_advice']) def gameActivityLibrary = new AndroidArchiveLibrary(versions['game_activity']) // This can be removed after migrating to prefabPublishing: .setPrefabFolderName("prefab-src") def gameTextInputLibrary = new AndroidArchiveLibrary(versions['game_text_input']) // This can be removed after migrating to prefabPublishing: .setPrefabFolderName("prefab-src") def gameControllerLibrary = new AndroidArchiveLibrary(versions['paddleboat']) allprojects { buildDir = getOutPath() repositories { google() jcenter() } } // All the libraries that are part of the Game SDK. These can be native libraries (which we can // package in a zip, or in an AAR) or "Android libraries" (which are built by default in an AAR). def allLibraries = [ swappyNativeLibrary, tuningForkNativeLibrary, memoryAdviceNativeLibrary, gameActivityLibrary, gameTextInputLibrary, gameControllerLibrary, ] def getBuildPath() { return new File("$projectDir/build").getPath() } def getOutPath() { return new File("$projectDir/../out").getPath() } def getLibraryOutPath(library) { return new File("$projectDir/../out_"+library.libraryInfo.nickname).getPath() } def getPackagePath() { return new File("$projectDir/../package").getPath(); } def getDistPath() { if (project.hasProperty("distPath")) { return new File(project.distPath.trim()).getPath() } return new File("$projectDir/../dist").getPath() } def getBuildInfoPath() { return getDistPath()+"/build-info" } def getTempPath() { return new File("$projectDir/../.temp").getPath() } def buildHostModule(subdir, buildType) { def toolchain = getLocalToolchain() def buildKey = "host" def workingFolder = joinPath(getTempPath(), buildKey, '.cmake') def outputFolder = joinPath(getOutPath(), buildKey) def cmakeProjectFolder = joinPath("$projectDir", subdir) def buildFolders = new BuildFolders(cmakeProjectFolder, workingFolder, outputFolder) runHostCMake(project, buildFolders, toolchain, buildType) runNinja(project, toolchain, workingFolder) return [buildKey: buildKey, outputFolder: outputFolder] } def buildNativeModules(BuildOptions buildOptions, Toolchain toolchain, Collection libraries, subdir) { def buildKey = toolchain.getBuildKey(buildOptions) if (!libraries.isEmpty()) { def workingFolder = joinPath(getTempPath(), buildKey, '.cmake') def outputFolder = joinPath(getOutPath(), buildKey) def cmakeProjectFolder = joinPath("$projectDir", subdir) def buildFolders = new BuildFolders(cmakeProjectFolder, workingFolder, outputFolder) def builtLibraries = filterBuiltLibraries(libraries, buildOptions, toolchain) runAndroidCMake(project, buildFolders, toolchain, buildOptions, builtLibraries, getGitCommit()) if (!builtLibraries.isEmpty()) { runNinja(project, toolchain, workingFolder) def jsonDescription = new File(joinPath(outputFolder, "abi.json")) jsonDescription.text = '{"abi":"' + buildOptions.arch + '","api":' + toolchain.getAndroidVersion() + ',"ndk":' + toolchain.getNdkVersionNumber() + ',"stl":"' + buildOptions.stl + '"}' } } return [arch: buildOptions.arch, buildKey: buildKey] } task cleanPath(type: Delete) { delete getOutPath() delete getPackagePath() delete getTempPath() delete getBuildPath() } def prefabBuildFolder(outFolder) { return joinPath(getPackagePath(), outFolder) } def prefabDir(outFolder, libraryName) { return joinPath(prefabBuildFolder(outFolder), 'prefab', 'modules', libraryName) } /** * Generate the structure of files needed to make an AAR from a native library. */ def copyNativeLibraryToPrefabDir(buildInfo, outFolder, library) { def libraryName = library.nativeLibraryName def prefabName = library.aarLibraryName def prefabVersion = "1.0.0" def versionIndex = library.aarVersion.indexOf('-') if (versionIndex == -1) { prefabVersion = library.aarVersion } else { prefabVersion = library.aarVersion.substring(0, versionIndex) } def arch = buildInfo.arch def buildKey = buildInfo.buildKey def cmakeFolder = joinPath(getTempPath(), buildKey, '.cmake', libraryName) def buildFolder = prefabBuildFolder(outFolder) def assetsFolder = joinPath(buildFolder, 'assets') def prefabRoot = prefabDir(outFolder, libraryName) def sharedLibBuildFolder = joinPath(prefabRoot, 'libs', 'android.' + buildKey.replace("_static_","_shared_")) def staticLibBuildFolder = joinPath(prefabRoot + '_static', 'libs', 'android.' + buildKey.replace("_shared_","_static_")) def staticsFolder = joinPath(getOutPath(), buildKey) def sharedIncludeBuildFolder = joinPath(prefabRoot, 'include', libraryName) def staticIncludeBuildFolder = joinPath(prefabRoot + '_static', 'include', libraryName) def sharedCommonIncludeBuildFolder = joinPath(prefabRoot, 'include', 'common') def staticCommonIncludeBuildFolder = joinPath(prefabRoot + '_static', 'include', 'common') def headerFolder = './include/' + libraryName def commonHeaderFolder = './include/common' def buildSharedLibrary = true def buildStaticLibrary = true // 1. Copy dynamic library if (buildSharedLibrary) { copy { from file(cmakeFolder) include "lib" + libraryName + ".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("lib" + libraryName + "_static.a", "*.json") rename("lib" + libraryName + "_static.a", "lib" + libraryName + ".a") into file(staticLibBuildFolder) } } // 3.1 Copy headers (shared library) if (buildSharedLibrary) { copy { from file(headerFolder) include "*.h" into file(sharedIncludeBuildFolder) includeEmptyDirs = false } copy { from file(commonHeaderFolder) include "*.h" into file(sharedCommonIncludeBuildFolder) includeEmptyDirs = false } } // 3.2 Copy headers (static library) if (buildStaticLibrary) { copy { from file(headerFolder) include "*.h" into file(staticIncludeBuildFolder) includeEmptyDirs = false } copy { from file(commonHeaderFolder) include "*.h" into file(staticCommonIncludeBuildFolder) 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":"' + prefabName + '","schema_version":1,"dependencies":[],"version":"' + prefabVersion + '"}' if (buildSharedLibrary) { def jsonModuleDescription = new File(joinPath(buildFolder, 'prefab', 'modules', libraryName, 'module.json')) jsonModuleDescription.text = '{"library_name": "lib' + libraryName + '", "export_libraries": []}' } if (buildStaticLibrary) { def jsonStaticModuleDescription = new File(joinPath(buildFolder, 'prefab', 'modules', libraryName + '_static', 'module.json')) jsonStaticModuleDescription.text = '{"library_name": "lib' + libraryName + '", "export_libraries": []}' } // 6. Create assets folder if (library.getAssetsDirectory() != null) { copy { from file(library.getAssetsDirectory()) include "*.*" into file(assetsFolder) includeEmptyDirs = false } } } def deleteDir(File dir) { def contents = dir.listFiles() if (contents != null) { contents.each { file -> deleteDir(file) } } dir.delete() } def getExtension(String filename) { def ix = filename.lastIndexOf('.') if (ix == -1) return "" return filename.substring(ix+1) } // Remove any folders that don't have shared or static libraries in them. // These can be created if, e.g. swappy and GameController are built into 'out' and then // only one or the other is copied into the prefab structure. // It might be easier in future to separate the out directories for each library. def removeUnneededPrefabDirs(String outFolder, library) { def libraryName = library.nativeLibraryName def prefabRoot = prefabDir(outFolder, libraryName) println("Deleting unneeded directories from " + outFolder) def sharedLibBuildFolder = joinPath(prefabRoot, 'libs') def staticLibBuildFolder = joinPath(prefabRoot + "_static", 'libs') for (folder in [sharedLibBuildFolder,staticLibBuildFolder]) { File topfolder = new File(folder) if (topfolder.exists()) { def to_delete = [] topfolder.eachDir { dir -> def foundLib = false dir.eachFile FileType.FILES, { file -> def extension = getExtension(file.name) if (extension=="a" || extension=="so") foundLib = true } if (!foundLib) to_delete << dir } to_delete.each { dir -> deleteDir(dir) } } } println("Done") } /** * Copy the generated .so/.a files for native libraries to the package folder. */ def copyNativeLibs(buildInfo, outFolder, Collection libraries, 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) { libraries.forEach({ nativeLibrary -> copy { from file(cmakeFolder) include nativeLibrary.nativeLibraryName + "*/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) libraries.forEach({ nativeLibrary -> copy { from file(staticsFolder) include "lib" + nativeLibrary.nativeLibraryName + "_static.a" into file(staticLibsBuildFolder) } }) } } /** * Copy the header files of native libraries to the package folder. */ def copyNativeLibrariesIncludes(outFolder, Collection libraries) { def buildFolder = getPackagePath() + '/' + outFolder def headerFolder = './include' def includeBuildFolder = joinPath(buildFolder, 'include') libraries.forEach({ nativeLibrary -> copy { from file(headerFolder) include nativeLibrary.nativeLibraryName + "*/*.h" into file(includeBuildFolder) includeEmptyDirs = false } }) // Copy common headers copy { from file(headerFolder) include "common/*.h" into file(includeBuildFolder) includeEmptyDirs = false } } /** * Copy the common documentation files to the package folder. */ 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 copySampleSources(outFolder, Collection libraries) { def buildFolder = getPackagePath() + '/' + outFolder // CMake utility for the Game SDK copy { from file(joinPath('samples', "gamesdk.cmake")) into file(joinPath(buildFolder, 'samples')) } // Needed for samples that depend on proto preparation (agdktunnel). copy { from file('prepproto.gradle') into file(buildFolder) } // All sample common files copy { from file(joinPath('samples', "common")) into file(joinPath(buildFolder, 'samples', 'common')) } // Library specific files libraries.forEach({ nativeLibrary -> nativeLibrary.sampleAndroidProjects.forEach({ externalAndroidProject -> if (externalAndroidProject.projectDestinationPath) { copy { from file(externalAndroidProject.projectRootPath) into file(joinPath(buildFolder, externalAndroidProject.projectDestinationPath)) exclude '**/build', '**/out', "local.properties", "**/.externalNativeBuild", "**/.gradle", "**/OWNERS", "**/.idea", "**/.cxx", '**/CMakeLists.txt' rename 'CMakeLists.for-samples-in-archive.txt', 'CMakeLists.txt' includeEmptyDirs = false } } }) nativeLibrary.sampleExtraFolderPaths.forEach({ sampleFolder -> copy { from file(sampleFolder.sourcePath) into file(joinPath(buildFolder, sampleFolder.destinationPath)) if (sampleFolder.includePattern != null) { include sampleFolder.includePattern } includeEmptyDirs = false } }) }) } /** * Copy the generated AAR to the package folder. * Also patch the AAR with a prefab folder if necessary. */ def copyAndroidArchiveLibrary(AndroidArchiveLibrary library, String outFolder) { def aarPath = joinPath(getLibraryOutPath(library), "outputs", "aar", "${library.projectName}-release.aar"); def packageFolder = joinPath(getPackagePath(), outFolder) assert file(aarPath).exists() copy { from aarPath into packageFolder } } def buildNativeLibrariesForUnity(libraries, buildType = "Release") { def threadChecks = false def allAbis = new ToolchainEnumerator().allAbis return allAbis.collect { buildNativeModules( new BuildOptions(buildType, threadChecks, "c++_static", it), new SpecificToolchain(project, "21", "r19"), libraries, "src") } } def buildNativeLibraries(libraries, buildType = "Release", toolchainSet = ToolchainSet.ALL) { def threadChecks = false def toolchainEnumerator = new ToolchainEnumerator() def toolchains = toolchainEnumerator.enumerate(toolchainSet, project) def nLibraries = libraries.size() def nToolchains = toolchains.size() println("buildNativeLibraries: ${nLibraries} libraries x ${nToolchains} toolchains = ${nLibraries*nToolchains} variants") return libraries.collect { library -> def psize = parallelChunkSize(library); def libraryName = library.libraryInfo.nickname println("buildNativeLibraries: using ${psize} parallel tasks for ${libraryName}") toolchainEnumerator.parallelMap(toolchains, { enumeratedToolchain -> buildNativeModules( new BuildOptions( buildType, threadChecks, enumeratedToolchain.stl, enumeratedToolchain.abi), enumeratedToolchain.toolchain, [library], "src") }, psize, libraryName) }.flatten() } def buildSpecificNativeLibraries(specificToolchainConfiguration, libraries, buildType = "Release") { def threadChecks = false def allAbis = new ToolchainEnumerator().allAbis def toolchain = new SpecificToolchain(project, specificToolchainConfiguration.sdk, specificToolchainConfiguration.ndk) return allAbis.collect { buildNativeModules( new BuildOptions(buildType, threadChecks, specificToolchainConfiguration.stl, it), toolchain, libraries, "src") } } def getLocalToolchain() { def kApiLevel = project.hasProperty("androidApiLevel") ? project.androidApiLevel : "24" def ndkVersion = project.hasProperty("ndk") ? project.ndk : null; return new LocalToolchain(project, kApiLevel, ndkVersion) } def localNativeBuild(libraries, subdir = "src", buildType = "Release") { def allAbis = new ToolchainEnumerator().allAbis def toolchain = getLocalToolchain(); def threadChecks = true return allAbis.collect { def buildOptions = new BuildOptions(buildType, threadChecks, "c++_static", it) buildNativeModules(buildOptions, toolchain, libraries, subdir) } } def getBuildType() { return project.hasProperty("buildType") ? project.buildType : "Release" } def getPackageName() { return project.hasProperty("packageName") ? project.packageName : "gamesdk" } def getFullPackagePath() { return joinPath(getPackagePath(), getPackageName()) } def shouldIncludeSampleSources() { return project.hasProperty("includeSampleSources") } def shouldIncludeSampleArtifacts() { return project.hasProperty("includeSampleArtifacts") } def shouldSkipSamplesBuild() { return project.hasProperty("skipSamplesBuild") } def getSpecificToolchainConfiguration() { if (!project.hasProperty("sdk") || !project.hasProperty("ndk") || !project.hasProperty("stl")) { throw new GradleException(""" Must set SDK, NDK and STL for a specific build, e.g. ./gradlew packageSpecificZip -Plibraries=swappy -Psdk=14 -Pndk=r16 -Pstl='c++_static'""" ) } return [sdk: project.sdk, ndk: project.ndk, stl: project.stl] } /** Returns the library that should be built. */ def filterLibraries(allLibraries) { if (!project.hasProperty("libraries")) { return [] } // Both a comma or semicolon can be used to separate libraries in the project parameters, // to be compatible with CMake "lists" that are strings separated by semicolons. def requestedLibraryNames = project.libraries.split(',|;'); return requestedLibraryNames.collect { requestedLibraryName -> def library = allLibraries.find { library -> library.nativeLibraryName == requestedLibraryName } if (library == null) { throw new GradleException("Library ${requestedLibraryName} does not exist.") } return library } } Collection filterNativeLibraries(allLibraries) { return filterLibraries(allLibraries).findAll { library -> library instanceof NativeLibrary } } Collection filterAndroidArchiveLibraries(allLibraries) { return filterLibraries(allLibraries).findAll { library -> library instanceof AndroidArchiveLibrary } } class BuildTask extends DefaultTask { } def isExpressPackage() { return project.hasProperty("express") } def getToolchainSet() { if (isExpressPackage()) { return ToolchainSet.EXPRESS } else { return ToolchainSet.ALL } } def getAarToolchainSet() { if (isExpressPackage()) { return ToolchainSet.EXPRESS_AAR } else { return ToolchainSet.AAR } } // How to chunk the toolchain list for parallel execution. def parallelChunkSize(library) { if (project.hasProperty("parallelChunkSize")) { return project.getProperty("parallelChunkSize").toInteger() } else { // By default, use less parallelism for memory_advice and oboe since they // have parallelised sub-builds def isCompoundBuild = library.libraryInfo.nickname=="memory_advice" || library.libraryInfo.nickname=="oboe" if (isCompoundBuild) { if (isRunningOnBuildBot) return 16 else return 4 } else { if (isRunningOnBuildBot) return 64 else return 16 } } } task buildAll(type: BuildTask) { ext.flattenLibs = false ext.withSharedLibs = !isExpressPackage() ext.withStaticLibs = true ext.withFullBuildKey = true ext.nativeBuild = { -> buildNativeLibraries(filterNativeLibraries(allLibraries), getBuildType(), getToolchainSet()) } } task buildUnity(type: BuildTask) { ext.flattenLibs = true ext.withSharedLibs = true ext.withStaticLibs = true ext.withFullBuildKey = true ext.nativeBuild = { -> buildNativeLibrariesForUnity(filterNativeLibraries(allLibraries), getBuildType()) } } task buildLocal(type: BuildTask) { ext.flattenLibs = false ext.withSharedLibs = true ext.withStaticLibs = true ext.withFullBuildKey = true ext.nativeBuild = { -> localNativeBuild(filterNativeLibraries(allLibraries), "src", getBuildType()) } } task buildSpecific(type: BuildTask) { ext.flattenLibs = false ext.withSharedLibs = true ext.withStaticLibs = true ext.withFullBuildKey = false ext.nativeBuild = { -> buildSpecificNativeLibraries(getSpecificToolchainConfiguration(), filterNativeLibraries(allLibraries), getBuildType()) } } // The buildXxx tasks are the central tasks: they take care of building the native libraries // (i.e: C and C++ only libraries), the Android libraries (i.e: AAR projects, with C/C++ headers // provided by Prefab) and copy the generated files to the package folder. tasks.withType(BuildTask) { def nativeLibraries = filterNativeLibraries(allLibraries) def androidArchiveLibraries = filterAndroidArchiveLibraries(allLibraries) androidArchiveLibraries.each { androidLibrary -> dependsOn ":${androidLibrary.projectName}:assembleRelease" } def packageName = getPackageName() // Clear the package path to ensure the task zip is not polluted // by previous build tasks. delete getFullPackagePath() doFirst { // Ensure some libraries to build were set if (nativeLibraries.isEmpty() && androidArchiveLibraries.isEmpty()) { throw new GradleException(""" Must specify which libraries to build, e.g. ./gradlew build -Plibraries=swappy,tuningfork,game_activity""") } } doLast { // Android libraries are already built, just add the AARs to the package. androidArchiveLibraries.each { copyAndroidArchiveLibrary(it, packageName) } // Build native libraries, and add their libs/includes/docs/samples to the package. nativeBuild().each { copyNativeLibs(it, packageName, nativeLibraries, withStaticLibs, withFullBuildKey, flattenLibs, withSharedLibs) } copyNativeLibrariesIncludes(packageName, nativeLibraries) copyDocs(packageName) if (shouldIncludeSampleSources()) { copySampleSources(packageName, nativeLibraries) } } } task localUnitTests { // These unit tests require a single connected device with target architecture set by the // project property 'arch'. // Set the property 'component' to 'tuningfork' or 'swappy' to run the required test suite. // e.g. ./gradlew localUnitTests -Parch=x86 -Pcomponent=tuningfork // arch defaults to 'arm64-v8a' and component to 'tuningfork' if they are not set. doLast { def pcomponent = 'tuningfork' if (project.hasProperty('component')) pcomponent = component def parch = 'arm64-v8a' if (project.hasProperty('arch')) parch = arch def buildInfo = localNativeBuild([swappyNativeLibrary, tuningForkNativeLibrary, memoryAdviceNativeLibrary], "test/$pcomponent") def buildKey = buildInfo.buildKey.findAll { it.contains(parch) }[0] def cmakeFolder = getTempPath() + "/$buildKey/.cmake" def toolchain = getLocalToolchain(); def adb = toolchain.getAdbPath(); exec { workingDir cmakeFolder commandLine adb, "push", "${pcomponent}_test", "/data/local/tmp" } exec { workingDir cmakeFolder commandLine adb, "shell", "/data/local/tmp/${pcomponent}_test" } } } task localDeviceInfoUnitTests { doLast { def buildInfo = buildHostModule("test/device_info", "Release") exec { workingDir buildInfo.outputFolder commandLine "./device_info_test" } } } task format { doLast { def formattedFiles = fileTree(dir: 'src', include: ['**/*.cpp', '**/*.c', '**/*.h'], excludes: ["protobuf"]) + fileTree(dir: 'include', include: ['**/*.h'], excludes: ["third_party"]) + fileTree(dir: 'test/swappy', include: ['**/*.cpp', '**/*.c', '**/*.h']) + fileTree(dir: 'test/tuningfork', include: ['**/*.cpp', '**/*.c', '**/*.h']) + fileTree(dir: 'games-text-input/prefab-src', include: ['**/*.cpp', '**/*.c', '**/*.h']) + fileTree(dir: 'game-activity/prefab-src', include: ['**/*.cpp', '**/*.c', '**/*.h']) + fileTree(dir: 'games-controller/src', include: ['**/*.cpp', '**/*.c', '**/*.h', '**/*.hpp']) formattedFiles.files.each { file -> exec { commandLine "/bin/bash" args "-c", "clang-format -i " + file workingDir projectDir } } } } task buildSampleArtifacts { doFirst { def buildFolder = getFullPackagePath() def builder = new ExternalAndroidProjectBuilder(project, buildFolder) builder.setSkipSamplesBuild(shouldSkipSamplesBuild()) filterNativeLibraries(allLibraries).forEach { nativeLibrary -> logger.info("Building samples of " + nativeLibrary.nativeLibraryName + "...") builder.buildSampleArtifacts(nativeLibrary) } } } /** Add a task called $zipTask that creates a ZIP or AAR file, $outputArchiveFileName, for the entire "package" generated by $buildTask. The task then copies the archive to the 'build' directory and to the 'package' directory. */ def addZipTask(zipTask, buildTask, outputArchiveFileName) { tasks.register(zipTask, Zip) { dependsOn buildTask if (shouldIncludeSampleArtifacts()) { buildTask.dependsOn buildSampleArtifacts } def packageFolder = getFullPackagePath() from fileTree(packageFolder) exclude outputArchiveFileName destinationDirectory = file(packageFolder) archiveFileName = outputArchiveFileName doLast { // Copy the output archive to 'build' def outFolder = getBuildPath(); mkdir outFolder; copy { from file(outputArchiveFileName) into outFolder } // This copies across everything, including the zip, to the $distribution/$package directory. // We then delete stuff we don't need in the build.sh script. if (getDistPath() != getPackagePath()) { copy { from getFullPackagePath() into joinPath(getDistPath(), getPackageName()) } } def out = services.get(StyledTextOutputFactory).create("output") out.style(Style.Identifier).text('\n' + outputArchiveFileName + ' is in ') .style(Style.ProgressStatus) .println(destinationDirectory.get()); } } } addZipTask("packageUnityZip", buildUnity, "builds.zip") addZipTask("packageZip", buildAll, getAGDKZipName()) addZipTask("packageLocalZip", buildLocal, "gamesdk.zip") addZipTask("packageSpecificZip", buildSpecific, "gamesdk.zip") // Build task for making the structure of an AAR that can be used with Prefab. // The actual zipping up into an AAR is done in packageAar. task buildAarStructure { def nativeLibraries = filterNativeLibraries(allLibraries) def androidArchiveLibraries = filterAndroidArchiveLibraries(allLibraries) androidArchiveLibraries.each { androidLibrary -> dependsOn ":${androidLibrary.projectName}:assembleRelease" } doFirst { // Clear the package and output path to ensure AAR generation is not polluted // by previous build tasks. delete getFullPackagePath() } doLast { def packageName = getPackageName() // Android libraries are already built, just add the AARs to the package. androidArchiveLibraries.each { copyAndroidArchiveLibrary(it, packageName) } // Build native libraries, and add them to the AAR nativeLibraries.each { library -> buildNativeLibraries([library], getBuildType(), getAarToolchainSet()).each { buildInfo -> copyNativeLibraryToPrefabDir(buildInfo, packageName, library) if (library.isHybridLibrary()) { copyHybridClassesFromAar(library, packageName) } } removeUnneededPrefabDirs(packageName, library) } } } // Task performed before a maven file is prepared with prepareMavenZipContent. addZipTask("packageAar", buildAarStructure, "gamesdk.aar") task prepareMavenZipContent { description "Build the AAR and prepare the versioned pom file for the specified libraries" dependsOn "packageAar" doLast { def packageFolder = getFullPackagePath() def mavenZipContentFolder = joinPath(packageFolder, "maven-zip"); delete mavenZipContentFolder mkdir mavenZipContentFolder filterNativeLibraries(allLibraries).forEach { nativeLibrary -> def libraryName = nativeLibrary.aarLibraryName def aarVersion = nativeLibrary.aarVersion def path = joinPath(packageFolder, "gamesdk.aar") assert file(path).exists() copy { from file(path) into file(joinPath(mavenZipContentFolder)) rename "gamesdk.aar", libraryName + "-" + aarVersion + ".aar" } copy { from file(joinPath("src", "maven", libraryName + ".pom")) into file(joinPath(mavenZipContentFolder)) rename libraryName + ".pom", libraryName + "-" + aarVersion + ".pom" filter(ReplaceTokens, tokens: [aarVersion: aarVersion]) } } filterAndroidArchiveLibraries(allLibraries).forEach { androidLibrary -> def libraryName = androidLibrary.aarLibraryName def aarVersion = androidLibrary.aarVersion def path = joinPath(packageFolder, androidLibrary.projectName + "-release.aar") assert file(path).exists() copy { from file(path) into file(joinPath(mavenZipContentFolder)) rename androidLibrary.projectName + "-release.aar", libraryName + "-" + aarVersion + ".aar" } copy { from file(path) into file(joinPath(mavenZipContentFolder)) rename androidLibrary.projectName + "-release.aar", libraryName + "-" + aarVersion + ".aar" } copy { from file(joinPath("src", "maven", libraryName + ".pom")) into file(joinPath(mavenZipContentFolder)) rename libraryName + ".pom", libraryName + "-" + aarVersion + ".pom" filter(ReplaceTokens, tokens: [aarVersion: aarVersion]) } } } } // Generate a zip file with the library AAR and its pom file, all versioned, // so that it's ready to be uploaded to Maven. task packageMavenZip(type: Zip) { dependsOn prepareMavenZipContent def packageFolder = getFullPackagePath() def mavenZipContentFolder = joinPath(packageFolder, "maven-zip") from fileTree(mavenZipContentFolder) destinationDirectory = file(packageFolder) def aarName = filterLibraries(allLibraries).collect { it.aarLibraryName }.join('-') archiveFileName = aarName + "-maven-zip.zip" // Don't lose time compressing already compressed files entryCompression = ZipEntryCompression.STORED doLast { if (getDistPath() != getPackagePath()) { copy { from getPackagePath() into getDistPath() } } } } task jetpadJson { doFirst { // Clear the package and output path to ensure build info is not polluted // by previous build tasks. delete getBuildInfoPath() } doLast { mkdir getBuildInfoPath() def buildInfoFile = new BuildInfoFile() buildInfoFile.writeLibrariesAggregateBuildInfoFile( filterNativeLibraries(allLibraries), filterAndroidArchiveLibraries(allLibraries), getDistPath(), getPackageName()) buildInfoFile.writeLibrariesIndividualBuildInfoFiles( filterAndroidArchiveLibraries(allLibraries), getBuildInfoPath(), getPackageName()) } }