diff --git a/build.gradle b/build.gradle index 0fe367244..47e7170ad 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ apply plugin: 'idea' idea { project { - languageLevel = 'JDK_1_7' + languageLevel = 'JDK_1_8' } } diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index f842a1d21..de5b3cdbd 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -3,16 +3,6 @@ apply plugin: 'groovy' repositories { //mavenLocal() mavenCentral() - maven { - url 'http://nexus.rehlds.org/nexus/content/repositories/regamedll-releases/' - } - maven { - url 'http://nexus.rehlds.org/nexus/content/repositories/regamedll-snapshots/' - } - maven { - url 'http://nexus.rehlds.org/nexus/content/repositories/regamedll-dev/' - } - } dependencies { @@ -22,12 +12,6 @@ dependencies { compile 'commons-lang:commons-lang:2.6' compile 'joda-time:joda-time:2.7' - compile 'org.doomedsociety.gradlecpp:gradle-cpp-plugin:1.2' compile 'org.eclipse.jgit:org.eclipse.jgit:3.7.0.201502260915-r' - - compile 'org.apache.commons:commons-compress:1.9' - compile 'org.apache.ant:ant-compress:1.2' - compile 'org.apache.ant:ant:1.9.6' - compile 'org.apache.velocity:velocity:1.7' } diff --git a/buildSrc/src/main/groovy/dirsync/builder/FileSystemTreeBuilder.groovy b/buildSrc/src/main/groovy/dirsync/builder/FileSystemTreeBuilder.groovy deleted file mode 100644 index af2180c24..000000000 --- a/buildSrc/src/main/groovy/dirsync/builder/FileSystemTreeBuilder.groovy +++ /dev/null @@ -1,58 +0,0 @@ -package dirsync.builder - -import dirsync.model.tree.DirectoryNode -import dirsync.model.tree.FileNode -import groovy.transform.CompileStatic - -class FileSystemTreeBuilder { - - @CompileStatic - private static FileNode buildNodeForFile(File file, DirectoryNode parent) { - if (parent.getChildren(file.name)) { - throw new RuntimeException("Parent dir ${parent.name} already contains child node ${file.name}"); - } - - return new FileNode( - name: file.name, - lastModifiedDate: file.lastModified(), - data: file, - parent: parent, - size: file.size() - ); - } - - @CompileStatic - private static DirectoryNode buildNodeForDirectoryRecursive(File dir, DirectoryNode parent) { - if (!dir.isDirectory()) { - throw new RuntimeException("File ${dir.absolutePath} is not a directory") - } - - if (parent != null && parent.getChildren(dir.name)) { - throw new RuntimeException("Parent dir ${parent.name} already contains child node ${dir.name}"); - } - - DirectoryNode thisNode = new DirectoryNode( - name: dir.name, - lastModifiedDate: dir.lastModified(), - data: dir, - parent: parent - ); - - dir.eachFile { File f -> - if (f.isDirectory()) { - thisNode.childNodes[f.name] = buildNodeForDirectoryRecursive(f, thisNode) - } else { - thisNode.childNodes[f.name] = buildNodeForFile(f, thisNode) - } - } - - return thisNode; - } - - static DirectoryNode buildFileSystemTree(File rootDir) { - def root = buildNodeForDirectoryRecursive(rootDir, null); - PostBuildPass.doPostBuild(root) - - return root - } -} diff --git a/buildSrc/src/main/groovy/dirsync/builder/FileTreeMerger.groovy b/buildSrc/src/main/groovy/dirsync/builder/FileTreeMerger.groovy deleted file mode 100644 index df92119a3..000000000 --- a/buildSrc/src/main/groovy/dirsync/builder/FileTreeMerger.groovy +++ /dev/null @@ -1,60 +0,0 @@ -package dirsync.builder - -import dirsync.model.tree.DirectoryNode -import dirsync.model.tree.FileNode - -class FileTreeMerger { - - private static void mergeContentsRecursive(DirectoryNode newParent, DirectoryNode toMerge) { - toMerge.childNodes.each { cn -> - def node = cn.value - def existingNode = newParent.childNodes[node.name] - if (existingNode) { - if (!(existingNode instanceof DirectoryNode) || !(node instanceof DirectoryNode)) - throw new RuntimeException("Failed to merge non-directory nodes ${node.fullPath}") - - def existingDirNode = existingNode as DirectoryNode - def dirNode = node as DirectoryNode - - existingDirNode.lastModifiedDate = Math.max(existingDirNode.lastModifiedDate, dirNode.lastModifiedDate) - mergeContentsRecursive(existingDirNode, dirNode) - } else { - if (node instanceof DirectoryNode) { - def dirNode = node as DirectoryNode - def newNode = new DirectoryNode( - name: dirNode.name, - data: dirNode.data, - parent: newParent, - lastModifiedDate: dirNode.lastModifiedDate - ) - newParent.childNodes[node.name] = newNode - - mergeContentsRecursive(newNode, dirNode) - } else { - FileNode fileNode = node as FileNode - FileNode newNode = new FileNode( - name: fileNode.name, - data: fileNode.data, - parent: newParent, - lastModifiedDate: fileNode.lastModifiedDate, - size: fileNode.size - ) - - newParent.childNodes[node.name] = newNode - } - } - } - } - - public static DirectoryNode mergeTrees(DirectoryNode tree1, DirectoryNode tree2) { - DirectoryNode newRoot = new DirectoryNode( - name: tree1.name ?: tree2.name - ) - - mergeContentsRecursive(newRoot, tree1) - mergeContentsRecursive(newRoot, tree2) - PostBuildPass.doPostBuild(newRoot) - - return newRoot - } -} diff --git a/buildSrc/src/main/groovy/dirsync/builder/PostBuildPass.groovy b/buildSrc/src/main/groovy/dirsync/builder/PostBuildPass.groovy deleted file mode 100644 index 87782dd7d..000000000 --- a/buildSrc/src/main/groovy/dirsync/builder/PostBuildPass.groovy +++ /dev/null @@ -1,22 +0,0 @@ -package dirsync.builder - -import dirsync.model.tree.DirectoryNode - -class PostBuildPass { - - private static void postProcessRecursive(DirectoryNode dir) { - dir.childNodes.each { cne -> - def childNode = cne.value - childNode.fullPath = dir.fullPath ? dir.fullPath + '/' + childNode.name : childNode.name - if (childNode instanceof DirectoryNode) { - def childDirNode = childNode as DirectoryNode - postProcessRecursive(childDirNode) - } - } - } - - static void doPostBuild(DirectoryNode root) { - root.fullPath = '' - postProcessRecursive(root) - } -} diff --git a/buildSrc/src/main/groovy/dirsync/builder/ZipTreeBuilder.groovy b/buildSrc/src/main/groovy/dirsync/builder/ZipTreeBuilder.groovy deleted file mode 100644 index c14092d58..000000000 --- a/buildSrc/src/main/groovy/dirsync/builder/ZipTreeBuilder.groovy +++ /dev/null @@ -1,53 +0,0 @@ -package dirsync.builder - -import dirsync.model.tree.DirectoryNode -import dirsync.model.tree.FileNode -import dirsync.model.tree.ZipData - -import java.util.zip.ZipFile - -class ZipTreeBuilder { - static DirectoryNode buildForZipArchive(String zipArchive, ZipFile zf) { - DirectoryNode root = new DirectoryNode<>() - - zf.entries().each { ze -> - def path = ze.name.replace('\\', '/') - if (path.endsWith('/')) - path = path.substring(0, path.length() - 1) - - def parentPath = path.contains('/') ? path.substring(0, path.lastIndexOf('/')) : '' - def childPath = path.contains('/') ? path.substring(path.lastIndexOf('/') + 1) : path - - def parentNode = (DirectoryNode) root.getByPath(parentPath) - if (parentNode == null) - throw new RuntimeException("Error reading ${zipArchive}: could not find parent path ${parentPath} for path ${path}") - - def childNode = parentNode.getChildren(childPath) - if (childNode) - throw new RuntimeException("Error reading ${zipArchive}: duplicate path ${path}") - - if (ze.directory) { - childNode = new DirectoryNode( - name: childPath, - lastModifiedDate: ze.time, - data: new ZipData(zipEntryName: ze.name, zipArchiveName: zipArchive), - parent: parentNode - ); - } else { - childNode = new FileNode( - name: childPath, - lastModifiedDate: ze.time, - data: new ZipData(zipEntryName: ze.name, zipArchiveName: zipArchive), - parent: parentNode, - size: ze.size - ); - } - parentNode.childNodes[childPath] = childNode - - //println '' + ze.directory + ' ' + ze.name + ' ' + parentPath + ' ' + childPath - } - - PostBuildPass.doPostBuild(root) - return root - } -} diff --git a/buildSrc/src/main/groovy/dirsync/merger/FileTreeComparator.groovy b/buildSrc/src/main/groovy/dirsync/merger/FileTreeComparator.groovy deleted file mode 100644 index e018a2c7b..000000000 --- a/buildSrc/src/main/groovy/dirsync/merger/FileTreeComparator.groovy +++ /dev/null @@ -1,97 +0,0 @@ -package dirsync.merger - -import dirsync.model.synccmd.AbstractSyncCmd -import dirsync.model.synccmd.CopyDirCmd -import dirsync.model.synccmd.CopyFileCmd -import dirsync.model.synccmd.DeleteDirCmd -import dirsync.model.synccmd.DeleteFileCmd -import dirsync.model.synccmd.ReplaceFileCmd -import dirsync.model.tree.DirectoryNode -import dirsync.model.tree.FileNode -import groovy.transform.TypeChecked - -@TypeChecked -class FileTreeComparator { - - private static void mergeDirsRecursive(DirectoryNode left, DirectoryNode right, List> diffs) { - - // left => right - left.childNodes.each { le -> - def leftNode = le.value - def rightNode = right.childNodes[leftNode.name] - - if (rightNode == null) { - switch (leftNode) { - case DirectoryNode: - def leftDirNode = leftNode as DirectoryNode - diffs << new CopyDirCmd<>(src: leftDirNode, dstParentDir: right) - break - - case FileNode: - def leftFileNode = leftNode as FileNode - diffs << new CopyFileCmd<>(src: leftFileNode, dstDir: right) - break - - default: - throw new RuntimeException("Invalid node class ${leftNode.class.name}") - } - - return - } - - if (rightNode.class != leftNode.class) { - throw new RuntimeException("node classes mismatch: ${leftNode.class.name} != ${rightNode.class.name}") - } - - switch (rightNode) { - case DirectoryNode: - def leftDirNode = leftNode as DirectoryNode - def rightDirNode = rightNode as DirectoryNode - mergeDirsRecursive(leftDirNode, rightDirNode, diffs) - break - - case FileNode: - def leftFileNode = leftNode as FileNode - def rightFileNode = rightNode as FileNode - if (leftFileNode.size != rightFileNode.size || leftFileNode.lastModifiedDate != rightFileNode.lastModifiedDate) { - diffs << new ReplaceFileCmd<>(src: leftFileNode, dst: rightFileNode) - } - break - - default: - throw new RuntimeException("Invalid node class ${rightNode.class.name}") - } - } // ~left => right - - //right => left - right.childNodes.each { re -> - def rightNode = re.value - def leftNode = left.childNodes[rightNode.name] - - if (leftNode != null) { - return //already processed in left => right - } - - switch (rightNode) { - case DirectoryNode: - def rightDirNode = rightNode as DirectoryNode - diffs << new DeleteDirCmd<>(dirNode: rightDirNode) - break - - case FileNode: - def rightFileNode = rightNode as FileNode - diffs << new DeleteFileCmd<>(node: rightFileNode) - break - - default: - throw new RuntimeException("Invalid node class ${rightNode.class.name}") - } - } // ~right => left - } - - static List> mergeTrees(DirectoryNode leftRoot, DirectoryNode rightRoot) { - List> res = [] - mergeDirsRecursive(leftRoot, rightRoot, res) - return res - } -} diff --git a/buildSrc/src/main/groovy/dirsync/merger/FileTreeDiffApplier.groovy b/buildSrc/src/main/groovy/dirsync/merger/FileTreeDiffApplier.groovy deleted file mode 100644 index 1c1404e48..000000000 --- a/buildSrc/src/main/groovy/dirsync/merger/FileTreeDiffApplier.groovy +++ /dev/null @@ -1,103 +0,0 @@ -package dirsync.merger - -import dirsync.model.synccmd.AbstractSyncCmd -import dirsync.model.synccmd.CopyDirCmd -import dirsync.model.synccmd.CopyFileCmd -import dirsync.model.synccmd.DeleteDirCmd -import dirsync.model.synccmd.DeleteFileCmd -import dirsync.model.synccmd.ReplaceFileCmd -import dirsync.model.tree.DirectoryNode -import dirsync.model.tree.FileNode -import dirsync.model.tree.TreePhysMapper -import groovy.transform.TypeChecked -import org.apache.commons.io.IOUtils - -@TypeChecked -public class FileTreeDiffApplier { - - static void copyDirRecursive(DirectoryNode src, TreePhysMapper srcMapper, TreePhysMapper dstMapper) { - dstMapper.createDirectory(src.fullPath) - src.childNodes.each { ce -> - def childNode = ce.value - def childPath = childNode.fullPath - switch (childNode) { - case FileNode: - srcMapper.fileContent(childNode.data).withStream { InputStream inStream -> - dstMapper.createFile(childPath).withStream { OutputStream outStream -> - IOUtils.copy(inStream, outStream) - } - - dstMapper.setFileLastUpdatedDate(childPath, childNode.lastModifiedDate) - } - break; - - case DirectoryNode: - copyDirRecursive(childNode as DirectoryNode, srcMapper, dstMapper) - break; - - default: - throw new RuntimeException("Invalid node class: ${childNode.class.name}") - } - } - } - - static void handleCopyFile(CopyFileCmd fileCopy, TreePhysMapper srcMapper, TreePhysMapper dstMapper) { - def dstPath = fileCopy.dstDir.fullPath ? fileCopy.dstDir.fullPath + '/' + fileCopy.src.name : fileCopy.src.name - srcMapper.fileContent(fileCopy.src.data).withStream { InputStream inStream -> - dstMapper.createFile(dstPath).withStream { OutputStream outStream -> - IOUtils.copy(inStream, outStream) - } - - dstMapper.setFileLastUpdatedDate(dstPath, fileCopy.src.lastModifiedDate) - } - } - - static void handleDeleteDir(DeleteDirCmd delDir, TreePhysMapper srcMapper, TreePhysMapper dstMapper) { - dstMapper.removeDirectory(delDir.dirNode.fullPath) - } - - static void handleDeleteFile(DeleteFileCmd delFile, TreePhysMapper srcMapper, TreePhysMapper dstMapper) { - dstMapper.removeFile(delFile.node.fullPath) - } - - static void handleReplaceFile(ReplaceFileCmd replaceFile, TreePhysMapper srcMapper, TreePhysMapper dstMapper) { - dstMapper.removeFile(replaceFile.dst.fullPath) - srcMapper.fileContent(replaceFile.src.data).withStream { InputStream inStream -> - dstMapper.createFile(replaceFile.dst.fullPath).withStream { OutputStream outStream -> - IOUtils.copy(inStream, outStream) - } - - dstMapper.setFileLastUpdatedDate(replaceFile.dst.fullPath, replaceFile.src.lastModifiedDate) - } - } - - static void applyDiffs(List> diffs, TreePhysMapper srcMapper, TreePhysMapper dstMapper) { - diffs.each { diff -> - switch (diff) { - case CopyDirCmd: - def copyDir = diff as CopyDirCmd - copyDirRecursive(copyDir.src, srcMapper, dstMapper) - break - - case CopyFileCmd: - handleCopyFile(diff as CopyFileCmd, srcMapper, dstMapper) - break - - case DeleteDirCmd: - handleDeleteDir(diff as DeleteDirCmd, srcMapper, dstMapper) - break - - case DeleteFileCmd: - handleDeleteFile(diff as DeleteFileCmd, srcMapper, dstMapper) - break - - case ReplaceFileCmd: - handleReplaceFile(diff as ReplaceFileCmd, srcMapper, dstMapper) - break - - default: - throw new RuntimeException("Invalid diff command ${diff.class.name}") - } - } - } -} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/dirsync/model/synccmd/AbstractSyncCmd.groovy b/buildSrc/src/main/groovy/dirsync/model/synccmd/AbstractSyncCmd.groovy deleted file mode 100644 index 20e0a1b61..000000000 --- a/buildSrc/src/main/groovy/dirsync/model/synccmd/AbstractSyncCmd.groovy +++ /dev/null @@ -1,4 +0,0 @@ -package dirsync.model.synccmd - -class AbstractSyncCmd { -} diff --git a/buildSrc/src/main/groovy/dirsync/model/synccmd/CopyDirCmd.groovy b/buildSrc/src/main/groovy/dirsync/model/synccmd/CopyDirCmd.groovy deleted file mode 100644 index 8a03abed2..000000000 --- a/buildSrc/src/main/groovy/dirsync/model/synccmd/CopyDirCmd.groovy +++ /dev/null @@ -1,8 +0,0 @@ -package dirsync.model.synccmd - -import dirsync.model.tree.DirectoryNode - -class CopyDirCmd extends AbstractSyncCmd { - DirectoryNode src - DirectoryNode dstParentDir -} diff --git a/buildSrc/src/main/groovy/dirsync/model/synccmd/CopyFileCmd.groovy b/buildSrc/src/main/groovy/dirsync/model/synccmd/CopyFileCmd.groovy deleted file mode 100644 index 8511dc376..000000000 --- a/buildSrc/src/main/groovy/dirsync/model/synccmd/CopyFileCmd.groovy +++ /dev/null @@ -1,9 +0,0 @@ -package dirsync.model.synccmd - -import dirsync.model.tree.DirectoryNode -import dirsync.model.tree.FileNode - -class CopyFileCmd extends AbstractSyncCmd { - FileNode src - DirectoryNode dstDir -} diff --git a/buildSrc/src/main/groovy/dirsync/model/synccmd/DeleteDirCmd.groovy b/buildSrc/src/main/groovy/dirsync/model/synccmd/DeleteDirCmd.groovy deleted file mode 100644 index f5a8d2abd..000000000 --- a/buildSrc/src/main/groovy/dirsync/model/synccmd/DeleteDirCmd.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package dirsync.model.synccmd - -import dirsync.model.tree.DirectoryNode - -class DeleteDirCmd extends AbstractSyncCmd { - DirectoryNode dirNode -} diff --git a/buildSrc/src/main/groovy/dirsync/model/synccmd/DeleteFileCmd.groovy b/buildSrc/src/main/groovy/dirsync/model/synccmd/DeleteFileCmd.groovy deleted file mode 100644 index 0cd429d3a..000000000 --- a/buildSrc/src/main/groovy/dirsync/model/synccmd/DeleteFileCmd.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package dirsync.model.synccmd - -import dirsync.model.tree.FileNode - -class DeleteFileCmd extends AbstractSyncCmd { - FileNode node -} diff --git a/buildSrc/src/main/groovy/dirsync/model/synccmd/ReplaceFileCmd.groovy b/buildSrc/src/main/groovy/dirsync/model/synccmd/ReplaceFileCmd.groovy deleted file mode 100644 index 3153b1e4b..000000000 --- a/buildSrc/src/main/groovy/dirsync/model/synccmd/ReplaceFileCmd.groovy +++ /dev/null @@ -1,8 +0,0 @@ -package dirsync.model.synccmd - -import dirsync.model.tree.FileNode - -class ReplaceFileCmd extends AbstractSyncCmd { - FileNode src - FileNode dst -} diff --git a/buildSrc/src/main/groovy/dirsync/model/tree/AbstractFileTreeNode.groovy b/buildSrc/src/main/groovy/dirsync/model/tree/AbstractFileTreeNode.groovy deleted file mode 100644 index 12d0a141d..000000000 --- a/buildSrc/src/main/groovy/dirsync/model/tree/AbstractFileTreeNode.groovy +++ /dev/null @@ -1,27 +0,0 @@ -package dirsync.model.tree - -import groovy.transform.CompileStatic - -@CompileStatic -abstract class AbstractFileTreeNode { - DirectoryNode parent - String name - String fullPath - long lastModifiedDate - T data - - boolean equals(o) { - if (this.is(o)) return true - if (getClass() != o.class) return false - - AbstractFileTreeNode that = (AbstractFileTreeNode) o - - if (name != that.name) return false - - return true - } - - int hashCode() { - return (name != null ? name.hashCode() : 0) - } -} diff --git a/buildSrc/src/main/groovy/dirsync/model/tree/DirectoryNode.groovy b/buildSrc/src/main/groovy/dirsync/model/tree/DirectoryNode.groovy deleted file mode 100644 index 3e4687752..000000000 --- a/buildSrc/src/main/groovy/dirsync/model/tree/DirectoryNode.groovy +++ /dev/null @@ -1,42 +0,0 @@ -package dirsync.model.tree - -import groovy.transform.CompileStatic - -@CompileStatic -class DirectoryNode extends AbstractFileTreeNode { - Map> childNodes = new HashMap<>() - - AbstractFileTreeNode getChildren(String name) { - return childNodes[name]; - } - - AbstractFileTreeNode getChildren(String[] names, int idx) { - if (idx == names.length) - return this - - AbstractFileTreeNode c = childNodes[names[idx]] - if (c == null) - return null - - if (c instanceof DirectoryNode) { - def d = (DirectoryNode) c; - return d.getChildren(names, idx + 1) - } - - return null; - } - - AbstractFileTreeNode getByPath(String path) { - path = path.replace('\\', '/') - if (path.endsWith('/')) - path = path.substring(0, path.length() - 1) - - if (path.empty) { - return this - } - - String[] components = path.split('/') - return getChildren(components, 0) - } - -} diff --git a/buildSrc/src/main/groovy/dirsync/model/tree/FSMapper.groovy b/buildSrc/src/main/groovy/dirsync/model/tree/FSMapper.groovy deleted file mode 100644 index 9c187c4f7..000000000 --- a/buildSrc/src/main/groovy/dirsync/model/tree/FSMapper.groovy +++ /dev/null @@ -1,50 +0,0 @@ -package dirsync.model.tree - -class FSMapper extends TreePhysMapper { - final File root - - FSMapper(File root) { - this.root = root - } - - @Override - InputStream fileContent(File file) { - return file.newDataInputStream() - } - - @Override - void createDirectory(String dir) { - def target = new File(root, dir) - if (!target.mkdirs()) { - throw new RuntimeException("Failed to create directory ${target.absolutePath}") - } - } - - @Override - void removeDirectory(String dir) { - def target = new File(root, dir) - if (!target.deleteDir()) { - throw new RuntimeException("Failed to delete directory ${target.absolutePath}") - } - } - - @Override - void removeFile(String path) { - def target = new File(root, path) - if (!target.delete()) { - throw new RuntimeException("Failed to delete file ${target.absolutePath}") - } - } - - @Override - OutputStream createFile(String path) { - def target = new File(root, path) - return target.newOutputStream() - } - - @Override - void setFileLastUpdatedDate(String path, long date) { - def target = new File(root, path) - target.setLastModified(date) - } -} diff --git a/buildSrc/src/main/groovy/dirsync/model/tree/FileNode.groovy b/buildSrc/src/main/groovy/dirsync/model/tree/FileNode.groovy deleted file mode 100644 index e17c28491..000000000 --- a/buildSrc/src/main/groovy/dirsync/model/tree/FileNode.groovy +++ /dev/null @@ -1,8 +0,0 @@ -package dirsync.model.tree - -import groovy.transform.CompileStatic - -@CompileStatic -class FileNode extends AbstractFileTreeNode { - long size -} diff --git a/buildSrc/src/main/groovy/dirsync/model/tree/TreePhysMapper.groovy b/buildSrc/src/main/groovy/dirsync/model/tree/TreePhysMapper.groovy deleted file mode 100644 index 34ebce048..000000000 --- a/buildSrc/src/main/groovy/dirsync/model/tree/TreePhysMapper.groovy +++ /dev/null @@ -1,11 +0,0 @@ -package dirsync.model.tree - -abstract class TreePhysMapper { - abstract InputStream fileContent(T file) - abstract void createDirectory(String dir) - abstract void removeDirectory(String dir) - abstract void removeFile(String path) - abstract OutputStream createFile(String path) - - abstract void setFileLastUpdatedDate(String path, long date) -} diff --git a/buildSrc/src/main/groovy/dirsync/model/tree/ZipData.groovy b/buildSrc/src/main/groovy/dirsync/model/tree/ZipData.groovy deleted file mode 100644 index 12114e570..000000000 --- a/buildSrc/src/main/groovy/dirsync/model/tree/ZipData.groovy +++ /dev/null @@ -1,9 +0,0 @@ -package dirsync.model.tree - -import groovy.transform.CompileStatic - -@CompileStatic -class ZipData { - String zipEntryName - String zipArchiveName -} diff --git a/buildSrc/src/main/groovy/dirsync/model/tree/ZipTreeMapper.groovy b/buildSrc/src/main/groovy/dirsync/model/tree/ZipTreeMapper.groovy deleted file mode 100644 index 3adb50f28..000000000 --- a/buildSrc/src/main/groovy/dirsync/model/tree/ZipTreeMapper.groovy +++ /dev/null @@ -1,72 +0,0 @@ -package dirsync.model.tree - -import dirsync.builder.FileTreeMerger -import dirsync.builder.ZipTreeBuilder -import sun.reflect.generics.reflectiveObjects.NotImplementedException - -import java.util.zip.ZipFile - -public class ZipTreeMapper extends TreePhysMapper implements Closeable { - Map zipArchives = [:] - - void addZipArchive(String zipArchive) { - zipArchives[zipArchive] = new ZipFile(zipArchive) - } - - DirectoryNode buildFileTree() { - def root = new DirectoryNode() - zipArchives.each { ze -> - def zipTree = ZipTreeBuilder.buildForZipArchive(ze.key, ze.value) - root = FileTreeMerger.mergeTrees(root, zipTree) - } - - return root - } - - @Override - void close() throws IOException { - zipArchives.each { ze -> - try { ze.value.close() } catch (Exception ignored) { } - } - } - - @Override - InputStream fileContent(ZipData file) { - def archive = zipArchives[file.zipArchiveName] - if (!archive) { - throw new RuntimeException("Archive ${file.zipArchiveName} is not loaded"); - } - - def zipEntry = archive.getEntry(file.zipEntryName) - if (!zipEntry) { - throw new RuntimeException("File ${file.zipEntryName} not found in archive ${file.zipArchiveName}"); - } - - return archive.getInputStream(zipEntry) - } - - @Override - void createDirectory(String dir) { - throw new NotImplementedException() - } - - @Override - void removeDirectory(String dir) { - throw new NotImplementedException() - } - - @Override - void removeFile(String path) { - throw new NotImplementedException() - } - - @Override - OutputStream createFile(String path) { - throw new NotImplementedException() - } - - @Override - void setFileLastUpdatedDate(String path, long date) { - throw new NotImplementedException() - } -} diff --git a/buildSrc/src/main/groovy/gradlecpp/CppUnitTestPlugin.groovy b/buildSrc/src/main/groovy/gradlecpp/CppUnitTestPlugin.groovy index 986eb472d..3910b7556 100644 --- a/buildSrc/src/main/groovy/gradlecpp/CppUnitTestPlugin.groovy +++ b/buildSrc/src/main/groovy/gradlecpp/CppUnitTestPlugin.groovy @@ -1,6 +1,5 @@ package gradlecpp -import gradlecpp.teamcity.TeamCityIntegration import org.gradle.api.Action import org.gradle.api.GradleException import org.gradle.api.Plugin @@ -199,39 +198,25 @@ class CppUnitTestPlugin implements Plugin { // run all tests println "Running ${root.test.size()} tests..." - TeamCityIntegration.suiteStarted("unitTests.${libBin.name}") + int failCount = 0; root.test.list().each { testInfo -> def testName = '' + testInfo.@name.text() def testGroup = '' + testInfo.@group.text() def testTimeout = ('' + testInfo.@timeout.text()) as int - if (!TeamCityIntegration.writeOutput) { - print " ${testGroup}-${testName}..." - System.out.flush() - } + print " ${testGroup}-${testName}..." + System.out.flush() - TeamCityIntegration.testStarted("${testGroup}-${testName}") def testExecStatus = runTestExecutable(libBin, testExecBin.executableFile.absolutePath, ['-runTest', testGroup, testName], "${testGroup}-${testName}", testTimeout) if (!testExecStatus.successful) { - if (!TeamCityIntegration.writeOutput) { - println " Failed" - } - - TeamCityIntegration.testFailed("${testGroup}-${testName}", "test executable return code is ${testExecStatus.exitCode}", "test executable return code is ${testExecStatus.exitCode}") + println "Failed (return code is ${testExecStatus.exitCode})" dumpTestExecStatus(testExecStatus) failCount++ } else { - if (!TeamCityIntegration.writeOutput) { - println " OK" - } + println " OK" } - - TeamCityIntegration.testStdOut("${testGroup}-${testName}", testExecStatus.output) - TeamCityIntegration.testFinished("${testGroup}-${testName}", testExecStatus.durationMsec) - } - TeamCityIntegration.suiteFinished("unitTests.${libBin.name}") if (failCount) { throw new GradleException("CPP unit tests: ${failCount} tests failed"); diff --git a/buildSrc/src/main/groovy/gradlecpp/RegameDLLPlayTestPlugin.groovy b/buildSrc/src/main/groovy/gradlecpp/RegameDLLPlayTestPlugin.groovy deleted file mode 100644 index 639cb22e8..000000000 --- a/buildSrc/src/main/groovy/gradlecpp/RegameDLLPlayTestPlugin.groovy +++ /dev/null @@ -1,17 +0,0 @@ -package gradlecpp - -import org.gradle.api.Plugin -import org.gradle.api.Project - -class RegamedllPlayTestPlugin implements Plugin { - @Override - void apply(Project project) { - project.configurations { - regamedll_playtest_image - } - - project.dependencies { - regamedll_playtest_image 'regamedll.testimg:testimg:2.0' - } - } -} diff --git a/buildSrc/src/main/groovy/gradlecpp/RegameDLLPlayTestTask.groovy b/buildSrc/src/main/groovy/gradlecpp/RegameDLLPlayTestTask.groovy index 0fe4947d6..cee6cc8fe 100644 --- a/buildSrc/src/main/groovy/gradlecpp/RegameDLLPlayTestTask.groovy +++ b/buildSrc/src/main/groovy/gradlecpp/RegameDLLPlayTestTask.groovy @@ -1,6 +1,5 @@ package gradlecpp -import gradlecpp.teamcity.TeamCityIntegration import org.apache.commons.lang.SystemUtils import org.gradle.api.DefaultTask import org.gradle.api.file.FileCollection @@ -11,11 +10,10 @@ import regamedll.testdemo.RegamedllTestParser class RegamedllPlayTestTask extends DefaultTask { - def FileCollection testDemos + def Set testDemos def Closure postExtractAction def File regamedllImageRoot def File regamedllTestLogs - def NativeBinarySpec testFor @TaskAction def doPlay() { @@ -30,54 +28,32 @@ class RegamedllPlayTestTask extends DefaultTask { regamedllImageRoot.mkdirs() regamedllTestLogs.mkdirs() - def demoRunner = new RegamedllDemoRunner(this.project.configurations.regamedll_playtest_image.getFiles(), regamedllImageRoot, postExtractAction) + def demoRunner = new RegamedllDemoRunner(regamedllImageRoot, postExtractAction) println "Preparing engine..." demoRunner.prepareEngine() - println "Running ${testDemos.getFiles().size()} ReGameDLL_CS test demos..." + println "Running ${testDemos.size()} ReGameDLL_CS test demos..." - TeamCityIntegration.suiteStarted("regamedllDemo.${testFor.name}") int failCount = 0; - testDemos.getFiles().each { f -> + testDemos.each { s -> - demoRunner.prepareEngine(); - def testInfo = RegamedllTestParser.parseTestInfo(f) + def testInfo = RegamedllTestParser.parseTestInfo(regamedllImageRoot.absolutePath + '/testdemos/', s) - TeamCityIntegration.testStarted(testInfo.testName) - - if (!TeamCityIntegration.writeOutput) { - println "Running ReGameDLL_CS test demo ${testInfo.testName} " - System.out.flush() - } - - println "Preparing files for test demo ${testInfo.testName} " - - demoRunner.prepareDemo(f) + println "Running ReGameDLL_CS test demo ${testInfo.testName} " def testRes = demoRunner.runTest(testInfo, regamedllTestLogs) - if (testRes.success) { - if (!TeamCityIntegration.writeOutput) { - println ' OK' - } + println ' OK' } else { - - TeamCityIntegration.testFailed(testInfo.testName, "Exit code: ${testRes.returnCode}", "Exit code: ${testRes.returnCode}") - if (!TeamCityIntegration.writeOutput) { - println ' Failed' - println "ReGameDLL_CS testdemo ${testInfo.testName} playback failed. Exit status is ${testRes.returnCode}." - println "Dumping console output:" - println testRes.hldsConsoleOutput - } + println ' Failed' + println "ReGameDLL_CS testdemo ${testInfo.testName} playback failed. Exit status is ${testRes.returnCode}." + println "Dumping console output:" + println testRes.hldsConsoleOutput failCount++ } - - TeamCityIntegration.testStdOut(testInfo.testName, testRes.hldsConsoleOutput) - TeamCityIntegration.testFinished(testInfo.testName, testRes.duration) } - TeamCityIntegration.suiteFinished("regamedllDemo.${testFor.name}") if (failCount) { throw new RuntimeException("ReGameDLL_CS testdemos: failed ${failCount} tests") diff --git a/buildSrc/src/main/groovy/gradlecpp/teamcity/TeamCityIntegration.groovy b/buildSrc/src/main/groovy/gradlecpp/teamcity/TeamCityIntegration.groovy deleted file mode 100644 index 9832a8518..000000000 --- a/buildSrc/src/main/groovy/gradlecpp/teamcity/TeamCityIntegration.groovy +++ /dev/null @@ -1,84 +0,0 @@ -package gradlecpp.teamcity - -import groovy.transform.CompileStatic - - -class TeamCityIntegration { - - static final String flowId = System.getenv('TEAMCITY_PROCESS_FLOW_ID') - static final boolean underTeamcity = System.getenv('TEAMCITY_PROJECT_NAME') - static boolean writeOutput = underTeamcity - - @CompileStatic - private static String escape(String s) { - StringBuilder sb = new StringBuilder((int)(s.length() * 1.2)); - for (char c in s.chars) { - switch (c) { - case '\n': sb.append('|n'); break; - case '\r': sb.append('|r'); break; - case '\'': sb.append('|\''); break; - case '|': sb.append('||'); break; - case ']': sb.append('|]'); break; - default: sb.append(c); - } - } - - return sb.toString() - } - - @CompileStatic - static void writeMessage(String name, Map params) { - if (!writeOutput) return - StringBuilder sb = new StringBuilder() - sb.append('##teamcity[').append(name) - params.each { e -> - if (e.value != null) { - sb.append(' ').append('' + e.key).append('=\'').append(escape('' + e.value)).append('\'') - } - } - sb.append(']') - - println sb.toString() - } - - static void suiteStarted(String suiteName) { - writeMessage('testSuiteStarted', [name: suiteName, flowId: flowId ?: null]) - } - - static void suiteFinished(String suiteName) { - writeMessage('testSuiteFinished', [name: suiteName, flowId: flowId ?: null]) - } - - static void testStarted(String testName) { - writeMessage('testStarted', [name: testName, flowId: flowId ?: null]) - } - - static void testStdOut(String testName, String output) { - writeMessage('testStdOut', [name: testName, out: output, flowId: flowId ?: null]) - } - - static void testFinished(String testName, long durationMs) { - writeMessage('testFinished', [ - name: testName, - flowId: flowId ?: null, - duration: (durationMs >= 0) ? durationMs : null - ]) - } - - static void testFailed(String testName, String message, String details) { - writeMessage('testFailed', [ - name: testName, - flowId: flowId ?: null, - message: message, - details: details - ]) - } - - static void testIgnored(String testName, String message) { - writeMessage('testIgnored', [ - name: testName, - flowId: flowId ?: null, - message: message, - ]) - } -} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/GradleCppPlugin.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/GradleCppPlugin.groovy new file mode 100644 index 000000000..d33fe96c2 --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/GradleCppPlugin.groovy @@ -0,0 +1,11 @@ +package org.doomedsociety.gradlecpp + +import org.gradle.api.Plugin +import org.gradle.api.Project + +class GradleCppPlugin implements Plugin { + @Override + void apply(Project target) { + + } +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/GradleCppUtils.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/GradleCppUtils.groovy new file mode 100644 index 000000000..670a723b8 --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/GradleCppUtils.groovy @@ -0,0 +1,105 @@ +package org.doomedsociety.gradlecpp + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.apache.commons.io.FilenameUtils +import org.apache.commons.lang.SystemUtils +import org.gradle.api.Action +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.internal.project.AbstractProject +import org.gradle.language.c.tasks.CCompile +import org.gradle.language.cpp.tasks.CppCompile +import org.gradle.language.nativeplatform.tasks.AbstractNativeCompileTask +import org.gradle.model.internal.core.DirectNodeModelAction +import org.gradle.model.internal.core.ModelActionRole +import org.gradle.model.internal.core.ModelPath +import org.gradle.model.internal.core.ModelReference +import org.gradle.model.internal.core.MutableModelNode +import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor +import org.gradle.model.internal.core.rule.describe.SimpleModelRuleDescriptor +import org.gradle.model.internal.registry.ModelRegistry +import org.gradle.nativeplatform.NativeBinarySpec +import org.gradle.nativeplatform.NativeExecutableBinarySpec +import org.gradle.nativeplatform.SharedLibraryBinarySpec +import org.gradle.nativeplatform.StaticLibraryBinarySpec +import org.gradle.nativeplatform.internal.AbstractNativeBinarySpec + +import java.nio.file.Files + +class GradleCppUtils { + static boolean isWindows() { + return SystemUtils.IS_OS_WINDOWS + } + + static File changeFileExt(File f, String newExt) { + def fPath = f.absolutePath + return new File(FilenameUtils.getFullPath(fPath) + FilenameUtils.getBaseName(fPath) + newExt) + } + + static Task getLinkTask(NativeBinarySpec binary) { + if (binary.buildTask == null) { + throw new RuntimeException("BuldTask for ${binary.name} is not created yet; move your action to project.afterEvaluate") + } + + def binImpl = binary as AbstractNativeBinarySpec + def taskName = binImpl.namingScheme.getTaskName((binary instanceof StaticLibraryBinarySpec) ? 'create' : 'link') + def linkTask = binary.tasks.find { t -> t.name == taskName} + + if (linkTask == null) { + throw new RuntimeException("Unable to find link task for ${binary.name}") + } + + return linkTask + } + + static List getCompileTasks(NativeBinarySpec binary) { + def linkTask = getLinkTask(binary) + + List res = [] + linkTask.taskDependencies.getDependencies(linkTask).each { Task t -> + switch (t) { + case CppCompile: + case CCompile: + res << t; + break; + } + } + + return res + } + + static void copyFile(String srcPath, String dstPath, boolean overwrite) { + copyFile(new File(srcPath), new File(dstPath), overwrite) + } + + static void copyFile(File src, File dst, boolean overwrite) { + if (overwrite) { + dst.delete() + } + Files.copy(src.toPath(), dst.toPath()) + } + + static File getBinaryOutputFile(NativeBinarySpec binary) { + if (binary instanceof SharedLibraryBinarySpec) { + return (binary as SharedLibraryBinarySpec).sharedLibraryFile + } else if (binary instanceof NativeExecutableBinarySpec) { + return (binary as NativeExecutableBinarySpec).executableFile + } + + return null + } + + static void onTasksCreated(Project p, String desc, Closure action) { + ModelRegistry mr = (p as AbstractProject).getModelRegistry() + def modelPath = ModelPath.path("tasks") + ModelRuleDescriptor ruleDescriptor = new SimpleModelRuleDescriptor(desc); + + mr.configure(ModelActionRole.Finalize, DirectNodeModelAction.of(ModelReference.of(modelPath), ruleDescriptor, new Action() { + @Override + void execute(MutableModelNode node) { + action() + } + })) + } +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/LazyNativeDepSet.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/LazyNativeDepSet.groovy new file mode 100644 index 000000000..571f1f601 --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/LazyNativeDepSet.groovy @@ -0,0 +1,72 @@ +package org.doomedsociety.gradlecpp + +import org.gradle.api.Project +import org.gradle.api.file.FileCollection +import org.gradle.nativeplatform.NativeBinarySpec +import org.gradle.nativeplatform.NativeDependencySet +import org.gradle.nativeplatform.NativeLibraryBinary +import org.gradle.nativeplatform.SharedLibraryBinarySpec +import org.gradle.nativeplatform.StaticLibraryBinarySpec + +class LazyNativeDepSet implements NativeDependencySet { + NativeLibraryBinary binary; + Closure resolveFunc + + LazyNativeDepSet(Closure resolveFunc) { + this.resolveFunc = resolveFunc + } + + public FileCollection getIncludeRoots() { + return getBinary().getHeaderDirs(); + } + + public FileCollection getLinkFiles() { + return getBinary().getLinkFiles(); + } + + public FileCollection getRuntimeFiles() { + return getBinary().getRuntimeFiles(); + } + + public NativeLibraryBinary getBinary() { + if (binary == null) { + binary = resolveBinary(); + } + + return binary; + } + + public NativeLibraryBinary resolveBinary() { + return (NativeLibraryBinary) resolveFunc() + } + + public static LazyNativeDepSet create(Closure resolveFunc) { + return new LazyNativeDepSet(resolveFunc); + } + + public static LazyNativeDepSet create(Project p, String libName, String buildType, boolean staticLib) { + return new LazyNativeDepSet({ + List candidates = p.binaries.findAll { NativeBinarySpec b -> + if (staticLib) { + if (!(b instanceof StaticLibraryBinarySpec)) return false + } else { + if (!(b instanceof SharedLibraryBinarySpec)) return false + } + + if (libName != null && b.component.name != libName) return false + if (buildType != null && b.buildType.name != buildType) return false + return true + } as List + + if (candidates.empty) { + throw new RuntimeException("Could not find library name=${libName}, buildType=${buildType}, static=${staticLib} in project ${p.name}") + } + + if (candidates.size() > 1) { + throw new RuntimeException("> 1 candidates found for find library name=${libName}, buildType=${buildType}, static=${staticLib} in project ${p.name}: ${candidates}") + } + + return candidates[0] + }) + } +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/OptionsFileArgsWriter.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/OptionsFileArgsWriter.groovy new file mode 100644 index 000000000..96f0872db --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/OptionsFileArgsWriter.groovy @@ -0,0 +1,66 @@ +/* + * Copyright 2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.nativeplatform.toolchain.internal; + +import com.google.common.collect.Lists; +import org.apache.commons.io.IOUtils; +import org.gradle.api.Action; +import org.gradle.api.Transformer; +import org.gradle.api.UncheckedIOException; +import org.gradle.platform.base.internal.toolchain.ArgWriter; +import org.gradle.util.GFileUtils; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Arrays; +import java.util.List; + +public class OptionsFileArgsWriter implements Action> { + private final Transformer argWriterFactory; + private final File tempDir; + + public OptionsFileArgsWriter(Transformer argWriterFactory, File tempDir) { + this.argWriterFactory = argWriterFactory; + this.tempDir = tempDir; + } + + @Override + public void execute(List args) { + List originalArgs = Lists.newArrayList(args); + args.clear(); + args.addAll(transformArgs(originalArgs, tempDir)); + } + + protected List transformArgs(List originalArgs, File tempDir) { + GFileUtils.mkdirs(tempDir); + File optionsFile = new File(tempDir, "options.txt"); + try { + PrintWriter writer = new PrintWriter(optionsFile); + try { + ArgWriter argWriter = argWriterFactory.transform(writer); + argWriter.args(originalArgs); + } finally { + IOUtils.closeQuietly(writer); + } + } catch (IOException e) { + throw new UncheckedIOException(String.format("Could not write compiler options file '%s'.", optionsFile.getAbsolutePath()), e); + } + + return Arrays.asList(String.format("@%s", optionsFile.getAbsolutePath())); + } +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/BaseConfigurator.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/BaseConfigurator.groovy new file mode 100644 index 000000000..53bdaacc3 --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/BaseConfigurator.groovy @@ -0,0 +1,64 @@ +package org.doomedsociety.gradlecpp.cfg + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.gradle.api.Project +import org.gradle.nativeplatform.NativeBinarySpec +import org.gradle.nativeplatform.Tool + +import java.lang.reflect.Field + +@CompileStatic @TypeChecked +abstract class BaseConfigurator { + + abstract void applyToolchainConfig(Project p, ToolchainConfig cfg, NativeBinarySpec bin); + + static void applyToolConfig(Tool tool, ToolConfig cfgModel, Set ignoreList) { + cfgModel.class.declaredFields.each { Field f -> + String param = null + + if (f.name in ignoreList) { + return + } + + if (ParameterOption.isAssignableFrom(f.type)) { + f.setAccessible(true) + ParameterOption po = (ParameterOption) f.get(cfgModel) + param = po?.parameter + } else { + BoolParam boolParam = null + StringParam stringParam = null + + f.declaredAnnotations.each { a -> + switch (a.class) { + case BoolParam: boolParam = (BoolParam) a; break; + case StringParam: stringParam = (StringParam) a; break; + } + } + + if (boolParam) { + f.setAccessible(true) + Boolean val = (Boolean) f.get(cfgModel) + if (val != null) { + param = val ? boolParam.on() : boolParam.off() + } + } else if (stringParam) { + f.setAccessible(true) + String prefix = stringParam.prefix() + Object val = f.get(cfgModel) + if (val != null) { + param = (prefix ?: '') + val + } + } + } + + if (param) { + tool.args(param) + } + } + + cfgModel.extraArgs?.each { a -> + tool.args(a) + } + } +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/BinaryKind.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/BinaryKind.groovy new file mode 100644 index 000000000..537eb8f6a --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/BinaryKind.groovy @@ -0,0 +1,11 @@ +package org.doomedsociety.gradlecpp.cfg + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked + +@CompileStatic @TypeChecked +public enum BinaryKind { + EXECUTABLE, + SHARED_LIBRARY, + STATIC_LIBRARY +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/BoolParam.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/BoolParam.groovy new file mode 100644 index 000000000..6d43fcb2e --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/BoolParam.groovy @@ -0,0 +1,13 @@ +package org.doomedsociety.gradlecpp.cfg + +import java.lang.annotation.ElementType +import java.lang.annotation.Retention +import java.lang.annotation.RetentionPolicy +import java.lang.annotation.Target + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface BoolParam { + String on() + String off() +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/CompilerConfig.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/CompilerConfig.groovy new file mode 100644 index 000000000..360198663 --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/CompilerConfig.groovy @@ -0,0 +1,33 @@ +package org.doomedsociety.gradlecpp.cfg + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.gradle.api.Project + +@CompileStatic @TypeChecked +abstract class CompilerConfig extends ToolConfig { + Map extraDefines = [:] + List includeDirs = [] + + void projectInclude(Project p, String... dirs) { + dirs.each { String d -> + includeDirs.add(p.projectDir.absolutePath + d) + } + } + + void include(String... dirs) { + includeDirs.addAll dirs + } + + void singleDefines(String... defs) { + defs.each { String d -> + extraDefines.put(d, null) + } + } + + void defines(Map defs) { + defs.each { kv -> + extraDefines[kv.key.toString()] = kv.value.toString() + } + } +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/LinkerConfig.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/LinkerConfig.groovy new file mode 100644 index 000000000..4cca89652 --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/LinkerConfig.groovy @@ -0,0 +1,25 @@ +package org.doomedsociety.gradlecpp.cfg + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.gradle.api.Project + +@CompileStatic @TypeChecked +abstract class LinkerConfig extends ToolConfig { + List libDirectories = [] + List extraLibs = [] + + void projectLibpath(Project p, String... dirs) { + dirs.each { String d -> + libDirectories.add(p.projectDir.absolutePath + d) + } + } + + void libpath(String... dirs) { + libDirectories.addAll dirs + } + + void extraLibs(String... libs) { + extraLibs.addAll libs + } +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/ParameterOption.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/ParameterOption.groovy new file mode 100644 index 000000000..a49b3e596 --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/ParameterOption.groovy @@ -0,0 +1,9 @@ +package org.doomedsociety.gradlecpp.cfg + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked + +@CompileStatic @TypeChecked +public interface ParameterOption { + String getParameter() +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/StringParam.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/StringParam.groovy new file mode 100644 index 000000000..303ae7bfd --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/StringParam.groovy @@ -0,0 +1,12 @@ +package org.doomedsociety.gradlecpp.cfg + +import java.lang.annotation.ElementType +import java.lang.annotation.Retention +import java.lang.annotation.RetentionPolicy +import java.lang.annotation.Target + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface StringParam { + public String prefix() +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/ToolConfig.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/ToolConfig.groovy new file mode 100644 index 000000000..4de422155 --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/ToolConfig.groovy @@ -0,0 +1,13 @@ +package org.doomedsociety.gradlecpp.cfg + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked + +@CompileStatic @TypeChecked +abstract class ToolConfig { + List extraArgs = [] + + void args(String... args) { + extraArgs.addAll args + } +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/ToolchainConfig.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/ToolchainConfig.groovy new file mode 100644 index 000000000..653f464dc --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/ToolchainConfig.groovy @@ -0,0 +1,39 @@ +package org.doomedsociety.gradlecpp.cfg + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.gradle.api.Project + +@CompileStatic @TypeChecked +public abstract class ToolchainConfig { + abstract CompilerConfig getCompilerConfig() + abstract LinkerConfig getLinkerConfig() + + void projectInclude(Project p, String... dirs) { + compilerConfig.projectInclude(p, dirs) + } + + void includeDirs(String... dirs) { + compilerConfig.include(dirs) + } + + void singleDefines(String... defs) { + compilerConfig.singleDefines(defs) + } + + void defines(Map defs) { + compilerConfig.defines(defs) + } + + void projectLibpath(Project p, String... dirs) { + linkerConfig.projectLibpath(p, dirs) + } + + void libpath(String... dirs) { + linkerConfig.libpath(dirs) + } + + void extraLibs(String... libs) { + linkerConfig.extraLibs(libs) + } +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/ToolchainConfigUtils.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/ToolchainConfigUtils.groovy new file mode 100644 index 000000000..9e9a8f11d --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/ToolchainConfigUtils.groovy @@ -0,0 +1,14 @@ +package org.doomedsociety.gradlecpp.cfg + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.gradle.api.Project +import org.gradle.nativeplatform.NativeBinarySpec + +@CompileStatic @TypeChecked +class ToolchainConfigUtils { + static void apply(Project p, ToolchainConfig cfg, NativeBinarySpec bin) { + def configurator = ToolchainConfiguratorFactory.createConfigurator(cfg) + configurator.applyToolchainConfig(p, cfg, bin) + } +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/ToolchainConfiguratorFactory.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/ToolchainConfiguratorFactory.groovy new file mode 100644 index 000000000..e4e9ca9b2 --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/cfg/ToolchainConfiguratorFactory.groovy @@ -0,0 +1,19 @@ +package org.doomedsociety.gradlecpp.cfg + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.doomedsociety.gradlecpp.gcc.GccToolchainConfig +import org.doomedsociety.gradlecpp.gcc.GccToolchainConfigurator +import org.doomedsociety.gradlecpp.msvc.MsvcToolchainConfig +import org.doomedsociety.gradlecpp.msvc.MsvcToolchainConfigurator + +@CompileStatic @TypeChecked +class ToolchainConfiguratorFactory { + static BaseConfigurator createConfigurator(ToolchainConfig cfg) { + switch (cfg.class) { + case MsvcToolchainConfig: return new MsvcToolchainConfigurator() + case GccToolchainConfig: return new GccToolchainConfigurator() + default: throw new RuntimeException("Unknown ToolchainConfig ${cfg.class.name}") + } + } +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/gcc/GccCompatibleNativeCompiler.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/gcc/GccCompatibleNativeCompiler.groovy new file mode 100644 index 000000000..640f1b690 --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/gcc/GccCompatibleNativeCompiler.groovy @@ -0,0 +1,39 @@ +package org.doomedsociety.gradlecpp.gcc + +import org.gradle.api.Transformer; +import org.gradle.internal.operations.BuildOperationProcessor; +import org.gradle.nativeplatform.toolchain.internal.*; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +class GccCompatibleNativeCompiler extends NativeCompiler { + + GccCompatibleNativeCompiler(BuildOperationProcessor buildOperationProcessor, CommandLineToolInvocationWorker commandLineTool, CommandLineToolContext invocationContext, final ArgsTransformer argsTransformer, Transformer specTransformer, String objectFileExtension, boolean useCommandFile) { + super(buildOperationProcessor, commandLineTool, invocationContext, argsTransformer, specTransformer, objectFileExtension, useCommandFile); + } + + @Override + protected List getOutputArgs(T spec, File outputFile) { + return Arrays.asList("-o", outputFile.getAbsolutePath()); + } + + @Override + protected void addOptionsFileArgs(List args, File tempDir) { + OptionsFileArgsWriter writer = new GccOptionsFileArgsWriter(tempDir); + // modifies args in place + writer.execute(args); + } + + @Override + protected List getPCHArgs(T spec) { + List pchArgs = new ArrayList(); + if (spec.getPrefixHeaderFile() != null) { + pchArgs.add("-include"); + pchArgs.add(spec.getPrefixHeaderFile().getAbsolutePath()); + } + return pchArgs; + } +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/gcc/GccOptionsFileArgsWriter.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/gcc/GccOptionsFileArgsWriter.groovy new file mode 100644 index 000000000..fc5796e32 --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/gcc/GccOptionsFileArgsWriter.groovy @@ -0,0 +1,37 @@ +package org.doomedsociety.gradlecpp.gcc + +import com.google.common.collect.Lists; +import org.gradle.platform.base.internal.toolchain.ArgWriter; +import org.gradle.nativeplatform.toolchain.internal.OptionsFileArgsWriter; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Uses an option file for arguments passed to GCC if possible. + * Certain GCC options do not function correctly when included in an option file, so include these directly on the command line as well. + */ +class GccOptionsFileArgsWriter extends OptionsFileArgsWriter { + private static final List CLI_ONLY_ARGS = Arrays.asList("-m32", "-m64"); + + public GccOptionsFileArgsWriter(File tempDir) { + super(ArgWriter.unixStyleFactory(), tempDir); + } + + @Override + public List transformArgs(List originalArgs, File tempDir) { + List commandLineOnlyArgs = getCommandLineOnlyArgs(originalArgs); + List finalArgs = Lists.newArrayList(); + finalArgs.addAll(super.transformArgs(originalArgs, tempDir)); + finalArgs.addAll(commandLineOnlyArgs); + return finalArgs; + } + + private List getCommandLineOnlyArgs(List allArgs) { + List commandLineOnlyArgs = new ArrayList(allArgs); + commandLineOnlyArgs.retainAll(CLI_ONLY_ARGS); + return commandLineOnlyArgs; + } +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/gcc/GccToolchainConfig.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/gcc/GccToolchainConfig.groovy new file mode 100644 index 000000000..85f319c01 --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/gcc/GccToolchainConfig.groovy @@ -0,0 +1,61 @@ +package org.doomedsociety.gradlecpp.gcc + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.doomedsociety.gradlecpp.cfg.BoolParam +import org.doomedsociety.gradlecpp.cfg.CompilerConfig +import org.doomedsociety.gradlecpp.cfg.LinkerConfig +import org.doomedsociety.gradlecpp.cfg.StringParam +import org.doomedsociety.gradlecpp.cfg.ToolConfig +import org.doomedsociety.gradlecpp.cfg.ToolchainConfig + +@CompileStatic @TypeChecked +class GccToolchainConfig extends ToolchainConfig { + + static class PrecompilerHeaderOptions { + boolean enabled + String pchSourceSet + } + + static class CompilerOptions extends CompilerConfig { + @BoolParam(on = '-fno-builtin', off = '') Boolean noBuiltIn + @BoolParam(on = '-intel-extensions', off = '-no-intel-extensions') Boolean intelExtensions + @BoolParam(on = '-fasm-blocks', off = '-fno-asm-blocks') Boolean asmBlocks + + @BoolParam(on = '-ipo', off = '') Boolean interProceduralOptimizations + @BoolParam(on = '-fstack-protector', off = '-fno-stack-protector') Boolean stackProtector + + OptimizationLevel optimizationLevel + + @StringParam(prefix = '-std=') String languageStandard + + PrecompilerHeaderOptions pchConfig + Boolean positionIndependentCode + } + + static class LinkerOptions extends LinkerConfig { + @BoolParam(on = '-ipo', off = '') Boolean interProceduralOptimizations + @BoolParam(on = '-s', off = '') Boolean stripSymbolTable + @BoolParam(on = '-static-libgcc', off = '') Boolean staticLibGcc + @BoolParam(on = '-static-intel', off = '') Boolean staticIntel + @BoolParam(on = '-static-libstdc++', off = '') Boolean staticLibStdCpp + } + + static class LibrarianOptions extends ToolConfig { + + } + + CompilerOptions compilerOptions + LinkerOptions linkerOptions + LibrarianOptions librarianOptions + + @Override + CompilerConfig getCompilerConfig() { + return compilerOptions + } + + @Override + LinkerConfig getLinkerConfig() { + return linkerOptions + } +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/gcc/GccToolchainConfigurator.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/gcc/GccToolchainConfigurator.groovy new file mode 100644 index 000000000..8a9475abf --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/gcc/GccToolchainConfigurator.groovy @@ -0,0 +1,99 @@ +package org.doomedsociety.gradlecpp.gcc + +import org.doomedsociety.gradlecpp.GradleCppUtils +import org.doomedsociety.gradlecpp.cfg.BaseConfigurator +import org.doomedsociety.gradlecpp.cfg.ToolchainConfig +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.language.PreprocessingTool +import org.gradle.language.nativeplatform.tasks.AbstractNativeCompileTask +import org.gradle.nativeplatform.NativeBinarySpec +import org.gradle.nativeplatform.Tool + +class GccToolchainConfigurator extends BaseConfigurator { + + static void setupPrecompiledHeaders(Project p, NativeBinarySpec bin, GccToolchainConfig.PrecompilerHeaderOptions pchConfig) { + def pchDir = new File(p.buildDir, "pch") + pchDir = new File(pchDir, "${bin.name}_${bin.targetPlatform.name}_${bin.buildType.name}_${bin.flavor.name}") + + GradleCppUtils.onTasksCreated(p, GccToolchainConfigurator.name + '.setupPrecompiledHeaders()', { + GradleCppUtils.getCompileTasks(bin).each { Task compileTask -> + compileTask.doFirst { + pchDir.mkdirs() + } + + compileTask.compilerArgs = new ArrayList(compileTask.compilerArgs) + + compileTask.compilerArgs << '-pch-dir' + compileTask.compilerArgs << pchDir.absolutePath + compileTask.compilerArgs << '-pch' + } + }) + } + + static void applyCompilerConfig(Project p, NativeBinarySpec bin, Tool compiler, GccToolchainConfig.CompilerOptions cfg, Set ignoreList) { + cfg.includeDirs.each { incDir -> + compiler.args('-I' + incDir) + } + + cfg.extraDefines.each { kv -> + if (kv.value == null) { + compiler.args("-D${kv.key}") + } else { + compiler.args("-D${kv.key}=${kv.value}") + } + } + + applyToolConfig(compiler, cfg, ignoreList) + + if (cfg.pchConfig?.enabled) { + setupPrecompiledHeaders(p, bin, cfg.pchConfig) + } + + if (cfg.positionIndependentCode != null) { + GradleCppUtils.onTasksCreated(p, GccToolchainConfigurator.name + '.setupPrecompiledHeaders()', { + GradleCppUtils.getCompileTasks(bin).each { Task t -> + if (t instanceof AbstractNativeCompileTask) { + t.setPositionIndependentCode(cfg.positionIndependentCode) + } + + } + }) + } + } + + static void applyLinkerConfig(Project p, NativeBinarySpec bin, Tool linker, GccToolchainConfig.LinkerOptions cfg) { + applyToolConfig(linker, cfg, null) + cfg.libDirectories.each { incDir -> + linker.args('-L' + incDir) + } + + cfg.extraLibs.each { lib -> + linker.args('-l' + lib) + } + } + + @Override + void applyToolchainConfig(Project p, ToolchainConfig cfg, NativeBinarySpec bin) { + GccToolchainConfig config = (GccToolchainConfig) cfg + + boolean isCpp + PreprocessingTool compiler + + if (null != bin.convention.findByName('cCompiler')) { + compiler = (PreprocessingTool) bin.cCompiler + isCpp = false + } else if (null != bin.convention.findByName('cppCompiler')) { + compiler = (PreprocessingTool) bin.cppCompiler + isCpp = true + } else { + throw new RuntimeException("Binary ${bin} has no attached C/C++ compiler") + } + + applyCompilerConfig(p, bin, compiler, config.compilerOptions, null) + applyLinkerConfig(p, bin, bin.linker, config.linkerOptions) + applyToolConfig(bin.staticLibArchiver, config.librarianOptions, null) + } + + +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/gcc/OptimizationLevel.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/gcc/OptimizationLevel.groovy new file mode 100644 index 000000000..2fd6319bf --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/gcc/OptimizationLevel.groovy @@ -0,0 +1,28 @@ +package org.doomedsociety.gradlecpp.gcc + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.doomedsociety.gradlecpp.cfg.ParameterOption + +@CompileStatic @TypeChecked +enum OptimizationLevel implements ParameterOption { + + DISABLE('-O0'), + LEVEL_1('-O1'), + LEVEL_2('-O2'), + LEVEL_3('-O3'), + OPTIMIZE_SIZE('-Os'), + OPTIMIZE_SPEED('-Ofast'), + OPTIMIZE_DEBUG('-Og') + + String param; + + OptimizationLevel(String param) { + this.param = param + } + + @Override + String getParameter() { + return param + } +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/CallingConvention.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/CallingConvention.groovy new file mode 100644 index 000000000..fed7ab172 --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/CallingConvention.groovy @@ -0,0 +1,25 @@ +package org.doomedsociety.gradlecpp.msvc + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.doomedsociety.gradlecpp.cfg.ParameterOption + +@CompileStatic @TypeChecked +public enum CallingConvention implements ParameterOption { + + CDECL('/Gd'), + FASTCALL('/Gr'), + STDCALL('/Gz'), + VECTORCALL('/Gv') + + String param; + + CallingConvention(String param) { + this.param = param + } + + @Override + String getParameter() { + return param + } +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/CodeGenerationKind.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/CodeGenerationKind.groovy new file mode 100644 index 000000000..07f5fc3c1 --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/CodeGenerationKind.groovy @@ -0,0 +1,24 @@ +package org.doomedsociety.gradlecpp.msvc + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.doomedsociety.gradlecpp.cfg.ParameterOption + +@CompileStatic @TypeChecked +public enum CodeGenerationKind implements ParameterOption { + MULTITHREADED('/MT'), + MULTITHREADED_DLL('/MD'), + MULTITHREADED_DEBUG('/MTd'), + MULTITHREADED_DEBUG_DLL('/MDd') + + String param; + + CodeGenerationKind(String param) { + this.param = param + } + + @Override + String getParameter() { + return param + } +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/CppExceptions.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/CppExceptions.groovy new file mode 100644 index 000000000..99432c7c1 --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/CppExceptions.groovy @@ -0,0 +1,21 @@ +package org.doomedsociety.gradlecpp.msvc + +import org.doomedsociety.gradlecpp.cfg.ParameterOption + +public enum CppExceptions implements ParameterOption { + DISABLED(null), + ENABLED('/EHsc'), + ENABLED_WITH_SEH('/EHa'), + ENABLED_WITH_EXTERN_C_FUNCS('/EHs') + + String param; + + CppExceptions(String param) { + this.param = param + } + + @Override + String getParameter() { + return param + } +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/EnhancedInstructionsSet.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/EnhancedInstructionsSet.groovy new file mode 100644 index 000000000..b69614a3e --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/EnhancedInstructionsSet.groovy @@ -0,0 +1,22 @@ +package org.doomedsociety.gradlecpp.msvc + +import org.doomedsociety.gradlecpp.cfg.ParameterOption + +public enum EnhancedInstructionsSet implements ParameterOption { + DISABLED('/arch:IA32'), + SSE('/arch:SSE'), + SSE2('/arch:SSE2'), + AVX('/arch:AVX'), + AVX2('/arch:AVX2') + + String param; + + EnhancedInstructionsSet(String param) { + this.param = param + } + + @Override + String getParameter() { + return param + } +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/ErrorReporting.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/ErrorReporting.groovy new file mode 100644 index 000000000..93fdf27c6 --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/ErrorReporting.groovy @@ -0,0 +1,24 @@ +package org.doomedsociety.gradlecpp.msvc + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.doomedsociety.gradlecpp.cfg.ParameterOption + +@CompileStatic @TypeChecked +public enum ErrorReporting implements ParameterOption { + PROMPT_IMMEDIATELY('/ERRORREPORT:PROMPT'), + QUEUE_FOR_NEXT_LOGIN('/ERRORREPORT:QUEUE'), + SEND_ERROR_REPORT('/ERRORREPORT:SEND'), + NO_ERROR_REPORT('/ERRORREPORT:NONE') + + String param; + + ErrorReporting(String param) { + this.param = param + } + + @Override + String getParameter() { + return param + } +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/FloatingPointModel.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/FloatingPointModel.groovy new file mode 100644 index 000000000..4734b39de --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/FloatingPointModel.groovy @@ -0,0 +1,24 @@ +package org.doomedsociety.gradlecpp.msvc + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.doomedsociety.gradlecpp.cfg.ParameterOption + +@CompileStatic @TypeChecked +public enum FloatingPointModel implements ParameterOption { + PRECISE('/fp:precise'), + STRICT('/fp:strict'), + FAST('/fp:fast') + + String param; + + FloatingPointModel(String param) { + this.param = param + } + + @Override + String getParameter() { + return param + } +} + diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/GradleMsvcUtils.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/GradleMsvcUtils.groovy new file mode 100644 index 000000000..3a1f297ca --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/GradleMsvcUtils.groovy @@ -0,0 +1,32 @@ +package org.doomedsociety.gradlecpp.msvc + +import org.doomedsociety.gradlecpp.GradleCppUtils +import org.gradle.api.Task +import org.gradle.language.nativeplatform.tasks.AbstractNativeCompileTask +import org.gradle.nativeplatform.NativeBinarySpec + +class GradleMsvcUtils { + static class PCHInfo { + AbstractNativeCompileTask pchTask + List compileTasks = [] + } + + static PCHInfo getPchCompileTask(NativeBinarySpec binary, String sourceSetName) { + PCHInfo res = new PCHInfo() + def linkTask = GradleCppUtils.getLinkTask(binary) + linkTask.taskDependencies.getDependencies(linkTask).each { Task t -> + if (t instanceof AbstractNativeCompileTask) { + if (t.name.toUpperCase().endsWith(sourceSetName.toUpperCase())) { + if (res.pchTask) { + throw new RuntimeException("Binary ${binary.name} contains >1 PCH compile tasks") + } + res.pchTask = t + } else { + res.compileTasks << t + } + } + } + + return res.pchTask ? res : null + } +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/LinkTimeCodeGenKind.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/LinkTimeCodeGenKind.groovy new file mode 100644 index 000000000..f3ab2098f --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/LinkTimeCodeGenKind.groovy @@ -0,0 +1,25 @@ +package org.doomedsociety.gradlecpp.msvc + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.doomedsociety.gradlecpp.cfg.ParameterOption + +@CompileStatic @TypeChecked +public enum LinkTimeCodeGenKind implements ParameterOption { + DEFAULT(null), + USE_LTCG('/LTCG'), + LTCG_PROFILING_INSTRUMENT('/LTCG:PGInstrument'), + LTCG_PROFILING_OPTIMIZE('/LTCG:PGOoptimize'), + LTCG_PROFILING_UPDATE('/LTCG:PGUpdate') + + String param; + + LinkTimeCodeGenKind(String param) { + this.param = param + } + + @Override + String getParameter() { + return param + } +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/MsvcToolchainConfig.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/MsvcToolchainConfig.groovy new file mode 100644 index 000000000..5a56e909e --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/MsvcToolchainConfig.groovy @@ -0,0 +1,82 @@ +package org.doomedsociety.gradlecpp.msvc + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.doomedsociety.gradlecpp.cfg.BoolParam +import org.doomedsociety.gradlecpp.cfg.CompilerConfig +import org.doomedsociety.gradlecpp.cfg.LinkerConfig +import org.doomedsociety.gradlecpp.cfg.StringParam +import org.doomedsociety.gradlecpp.cfg.ToolConfig +import org.doomedsociety.gradlecpp.cfg.ToolchainConfig + +@CompileStatic @TypeChecked +class MsvcToolchainConfig extends ToolchainConfig { + + static class PrecompiledHeadersConfig { + boolean enabled + String pchHeader + String pchSourceSet + } + + static class CompilerOptions extends CompilerConfig { + CodeGenerationKind codeGeneration + OptimizationLevel optimizationLevel + DebugInfoFormat debugInfoFormat + RuntimeChecks runtimeChecks + CppExceptions cppExceptions + WarningLevel warningLevel + CallingConvention callingConvention + EnhancedInstructionsSet enhancedInstructionsSet + FloatingPointModel floatingPointModel + + + @BoolParam(on = '/Gm', off = '/Gm-') Boolean enableMinimalRebuild + @BoolParam(on = '/Oy', off = '/Oy-') Boolean omitFramePointers + @BoolParam(on = '/GL', off = '') Boolean wholeProgramOptimization + @BoolParam(on = '/Gy', off = '/Gy-') Boolean enabledFunctionLevelLinking + @BoolParam(on = '/GS', off = '/GS-') Boolean enableSecurityCheck + @BoolParam(on = '/analyze', off = '/analyze-') Boolean analyzeCode + @BoolParam(on = '/sdl', off = '/sdl-') Boolean sdlChecks + @BoolParam(on = '/WX', off = '/WX-') Boolean treatWarningsAsErrors + @BoolParam(on = '/Zc:wchar_t', off = '/Zc:wchar_t-') Boolean treatWchartAsBuiltin + @BoolParam(on = '/Zc:forScope', off = '/Zc:forScope-') Boolean forceConformanceInForLoopScope + + PrecompiledHeadersConfig pchConfig + } + + static class LinkerOptions extends LinkerConfig { + LinkTimeCodeGenKind linkTimeCodeGenKind + ErrorReporting errorReportingMode + + @BoolParam(on = '/INCREMENTAL', off = '/INCREMENTAL:NO') Boolean enableIncrementalLinking + @BoolParam(on = '/OPT:REF', off = '/OPT:NOREF') Boolean eliminateUnusedRefs + @BoolParam(on = '/OPT:ICF', off = '/OPT:NOICF') Boolean enableCOMDATFolding + @BoolParam(on = '/DEBUG', off = '') Boolean generateDebugInfo + @BoolParam(on = '/NXCOMPAT', off = '/NXCOMPAT:NO') Boolean dataExecutionPrevention + @BoolParam(on = '/DYNAMICBASE', off = '/DYNAMICBASE:NO') Boolean randomizedBaseAddress + @BoolParam(on = '/FIXED', off = '/FIXED:NO') Boolean fixedBaseAddress + @StringParam(prefix = '/BASE:') String baseAddress + + String definitionFile + } + + static class LibrarianOptions extends ToolConfig { + LinkTimeCodeGenKind linkTimeCodeGenKind + } + + Boolean generatePdb + + CompilerOptions compilerOptions + LinkerOptions linkerOptions + LibrarianOptions librarianOptions + + @Override + CompilerConfig getCompilerConfig() { + return compilerOptions + } + + @Override + LinkerConfig getLinkerConfig() { + return linkerOptions + } +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/MsvcToolchainConfigurator.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/MsvcToolchainConfigurator.groovy new file mode 100644 index 000000000..64ed5a325 --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/MsvcToolchainConfigurator.groovy @@ -0,0 +1,138 @@ +package org.doomedsociety.gradlecpp.msvc + +import org.doomedsociety.gradlecpp.GradleCppUtils +import org.doomedsociety.gradlecpp.cfg.BaseConfigurator +import org.doomedsociety.gradlecpp.cfg.ToolchainConfig +import org.gradle.api.Action +import org.gradle.api.Project +import org.gradle.language.PreprocessingTool +import org.gradle.model.internal.core.DirectNodeModelAction +import org.gradle.model.internal.core.ModelActionRole +import org.gradle.model.internal.core.ModelPath +import org.gradle.model.internal.core.ModelReference +import org.gradle.model.internal.core.MutableModelNode +import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor +import org.gradle.model.internal.core.rule.describe.SimpleModelRuleDescriptor +import org.gradle.model.internal.registry.ModelRegistry +import org.gradle.nativeplatform.NativeBinarySpec +import org.gradle.nativeplatform.StaticLibraryBinarySpec +import org.gradle.nativeplatform.Tool + +class MsvcToolchainConfigurator extends BaseConfigurator { + + static final Set cppOnlyCompilerOpts = new HashSet(['cppExceptions']) + + static void applyCompilerConfig(Project p, NativeBinarySpec bin, Tool compiler, MsvcToolchainConfig.CompilerOptions cfg, Set ignoreList) { + cfg.includeDirs.each { incDir -> + compiler.args('/I' + incDir) + } + + cfg.extraDefines.each { kv -> + if (kv.value == null) { + compiler.args("/D${kv.key}") + } else { + compiler.args("/D${kv.key}=${kv.value}") + } + } + + applyToolConfig(compiler, cfg, ignoreList) + + if (cfg.pchConfig?.enabled) { + setupPrecompiledHeaders(p, bin, cfg.pchConfig) + } + } + + static void applyLinkerConfig(Tool linker, MsvcToolchainConfig.LinkerOptions cfg) { + applyToolConfig(linker, cfg, null) + + if (cfg.definitionFile) { + linker.args('/DEF:' + cfg.definitionFile) + } + + cfg.libDirectories.each { incDir -> + linker.args('/LIBPATH:' + incDir) + } + + cfg.extraLibs.each { lib -> + linker.args(lib) + } + } + + static void setupPrecompiledHeaders(Project p, NativeBinarySpec bin, MsvcToolchainConfig.PrecompiledHeadersConfig pchConfig) { + def pchDir = new File(p.buildDir, "pch") + def pchFile = new File(pchDir, "${bin.name}_${bin.targetPlatform.name}_${bin.buildType.name}_${bin.flavor.name}.pch") + + GradleCppUtils.onTasksCreated(p, MsvcToolchainConfigurator.name + '.setupPrecompiledHeaders()', { + def pchInfo = GradleMsvcUtils.getPchCompileTask(bin, pchConfig.pchSourceSet) + if (!pchInfo) { + throw new RuntimeException("Can't find PCH task for project ${p.name} / binary ${bin.name}") + } + + pchInfo.pchTask.doFirst { + pchDir.mkdirs() + } + + pchInfo.pchTask.compilerArgs = new ArrayList(pchInfo.pchTask.compilerArgs) + pchInfo.pchTask.compilerArgs << '/Yc' + pchConfig.pchHeader + pchInfo.pchTask.compilerArgs << '/Fp' + pchFile.absolutePath + pchInfo.compileTasks.each { compileTask -> + compileTask.compilerArgs = new ArrayList(compileTask.compilerArgs) + compileTask.compilerArgs << '/Yu' + pchConfig.pchHeader + compileTask.compilerArgs << '/Fp' + pchFile.absolutePath + compileTask.dependsOn pchInfo.pchTask + } + }) + } + + static void setupPdbGeneration(Project p, MsvcToolchainConfig config, NativeBinarySpec bin, Tool compiler, Tool linker) { + if (!config.generatePdb) { + return + } + + if (!(bin instanceof StaticLibraryBinarySpec)) { + def outputFile = GradleCppUtils.getBinaryOutputFile(bin) + def linkerPdbFile = GradleCppUtils.changeFileExt(outputFile, '.pdb') + linker.args "/PDB:${linkerPdbFile.absolutePath}" + } + + def pdbDir = new File(p.buildDir, "pdb") + def pdbFile = new File(pdbDir, "${bin.name}_${bin.targetPlatform.name}_${bin.buildType.name}_${bin.flavor.name}.pdb") + compiler.args('/Fd' + pdbFile.absolutePath) + //compiler.args('/FS') + + GradleCppUtils.onTasksCreated(p, MsvcToolchainConfigurator.name + '.setupPdbGeneration()', { + def compileTasks = GradleCppUtils.getCompileTasks(bin) + compileTasks.each { compileTask -> + compileTask.doFirst { + pdbDir.mkdirs() + } + } + }) + } + + + @Override + void applyToolchainConfig(Project p, ToolchainConfig cfg, NativeBinarySpec bin) { + MsvcToolchainConfig config = (MsvcToolchainConfig) cfg + PreprocessingTool compiler + + boolean isCpp + + if (null != bin.convention.findByName('cCompiler')) { + compiler = (PreprocessingTool) bin.cCompiler + isCpp = false + } else if (null != bin.convention.findByName('cppCompiler')) { + compiler = (PreprocessingTool) bin.cppCompiler + isCpp = true + } else { + throw new RuntimeException("Binary ${bin} has no attached C/C++ compiler") + } + + applyCompilerConfig(p, bin, compiler, config.compilerOptions, isCpp ? null : cppOnlyCompilerOpts) + applyLinkerConfig(bin.linker, config.linkerOptions) + applyToolConfig(bin.staticLibArchiver, config.librarianOptions, null) + setupPdbGeneration(p, config, bin, compiler, bin.linker) + + + } +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/OptimizationLevel.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/OptimizationLevel.groovy new file mode 100644 index 000000000..b5b70862e --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/OptimizationLevel.groovy @@ -0,0 +1,24 @@ +package org.doomedsociety.gradlecpp.msvc + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.doomedsociety.gradlecpp.cfg.ParameterOption + +@CompileStatic @TypeChecked +public enum OptimizationLevel implements ParameterOption { + DISABLED('/Od'), + MINIMIZE_SIZE('/O1'), + MAXIMIZE_SPEED('/O2'), + FULL_OPTIMIZATION('/Ox') + + String param; + + OptimizationLevel(String param) { + this.param = param + } + + @Override + String getParameter() { + return param + } +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/RuntimeChecks.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/RuntimeChecks.groovy new file mode 100644 index 000000000..e8b9ea296 --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/RuntimeChecks.groovy @@ -0,0 +1,24 @@ +package org.doomedsociety.gradlecpp.msvc + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.doomedsociety.gradlecpp.cfg.ParameterOption + +@CompileStatic @TypeChecked +public enum RuntimeChecks implements ParameterOption { + DEFAULT(null), + STACK_FRAMES('/RTCs'), + UNINITIALIZED_VARS('/RTCu'), + STACK_FRAMES_AND_UNINITIALIZED_VARS('/RTC1') + + String param; + + RuntimeChecks(String param) { + this.param = param + } + + @Override + String getParameter() { + return param + } +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/WarningLevel.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/WarningLevel.groovy new file mode 100644 index 000000000..59410c270 --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/msvc/WarningLevel.groovy @@ -0,0 +1,26 @@ +package org.doomedsociety.gradlecpp.msvc + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.doomedsociety.gradlecpp.cfg.ParameterOption + +@CompileStatic @TypeChecked +enum WarningLevel implements ParameterOption { + DISABLE_ALL('/W0'), + LEVEL_1('/W1'), + LEVEL_2('/W2'), + LEVEL_3('/W3'), + LEVEL_4('/W4'), + ENABLE_ALL('/Wall') + + String param; + + WarningLevel(String param) { + this.param = param + } + + @Override + String getParameter() { + return param + } +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/toolchain/icc/Icc.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/toolchain/icc/Icc.groovy new file mode 100644 index 000000000..969a24418 --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/toolchain/icc/Icc.groovy @@ -0,0 +1,18 @@ +package org.doomedsociety.gradlecpp.toolchain.icc + +import org.gradle.nativeplatform.toolchain.GccCompatibleToolChain + +public interface Icc extends GccCompatibleToolChain { + /** + * The path required for executing the tool chain. + * These are used to locate tools for this tool chain, and are prepended to the system PATH when executing these tools. + */ + List getPath(); + + /** + * Append an entry or entries to the tool chain path. + * + * @param pathEntries The path values to append. These are evaluated as per {@link org.gradle.api.Project#files(Object...)} + */ + void path(Object... pathEntries); +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/toolchain/icc/IccCompilerPlugin.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/toolchain/icc/IccCompilerPlugin.groovy new file mode 100644 index 000000000..5fae496bc --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/toolchain/icc/IccCompilerPlugin.groovy @@ -0,0 +1,45 @@ +package org.doomedsociety.gradlecpp.toolchain.icc + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.gradle.api.NamedDomainObjectFactory +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.internal.file.FileResolver +import org.gradle.internal.operations.BuildOperationProcessor +import org.gradle.internal.os.OperatingSystem +import org.gradle.internal.reflect.Instantiator +import org.gradle.internal.service.ServiceRegistry +import org.gradle.model.Defaults +import org.gradle.model.RuleSource +import org.gradle.nativeplatform.plugins.NativeComponentPlugin +import org.gradle.nativeplatform.toolchain.internal.NativeToolChainRegistryInternal +import org.gradle.nativeplatform.toolchain.internal.gcc.version.CompilerMetaDataProviderFactory +import org.gradle.process.internal.ExecActionFactory + +@CompileStatic @TypeChecked +class IccCompilerPlugin implements Plugin { + + public void apply(Project project) { + project.getPluginManager().apply(NativeComponentPlugin.class); + } + + static class Rules extends RuleSource { + @Defaults + public static void addToolChain(NativeToolChainRegistryInternal toolChainRegistry, ServiceRegistry serviceRegistry) { + final FileResolver fileResolver = serviceRegistry.get(FileResolver.class); + final ExecActionFactory execActionFactory = serviceRegistry.get(ExecActionFactory.class); + final Instantiator instantiator = serviceRegistry.get(Instantiator.class); + final BuildOperationProcessor buildOperationProcessor = serviceRegistry.get(BuildOperationProcessor.class); + final CompilerMetaDataProviderFactory metaDataProviderFactory = serviceRegistry.get(CompilerMetaDataProviderFactory.class); + + toolChainRegistry.registerFactory(Icc.class, new NamedDomainObjectFactory() { + public Icc create(String name) { + return instantiator.newInstance(IccToolchain.class, name, buildOperationProcessor, OperatingSystem.current(), fileResolver, execActionFactory, metaDataProviderFactory, instantiator); + } + }); + toolChainRegistry.registerDefaultToolChain(IccToolchain.DEFAULT_NAME, Icc.class); + } + + } +} diff --git a/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/toolchain/icc/IccToolchain.groovy b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/toolchain/icc/IccToolchain.groovy new file mode 100644 index 000000000..607921291 --- /dev/null +++ b/buildSrc/src/main/groovy/org/doomedsociety/gradlecpp/toolchain/icc/IccToolchain.groovy @@ -0,0 +1,40 @@ +package org.doomedsociety.gradlecpp.toolchain.icc + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.gradle.api.internal.file.FileResolver +import org.gradle.internal.operations.BuildOperationProcessor +import org.gradle.internal.reflect.Instantiator +import org.gradle.internal.os.OperatingSystem +import org.gradle.nativeplatform.toolchain.internal.gcc.AbstractGccCompatibleToolChain +import org.gradle.nativeplatform.toolchain.internal.gcc.DefaultGccPlatformToolChain +import org.gradle.nativeplatform.toolchain.internal.gcc.version.CompilerMetaDataProviderFactory +import org.gradle.process.internal.ExecActionFactory + +@CompileStatic @TypeChecked +class IccToolchain extends AbstractGccCompatibleToolChain implements Icc { + public static final String DEFAULT_NAME = "icc"; + + public IccToolchain(String name, BuildOperationProcessor buildOperationProcessor, OperatingSystem operatingSystem, FileResolver fileResolver, ExecActionFactory execActionFactory, CompilerMetaDataProviderFactory metaDataProviderFactory, Instantiator instantiator) { + super(name, buildOperationProcessor, operatingSystem, fileResolver, execActionFactory, metaDataProviderFactory.gcc(), instantiator); + } + + @Override + protected void configureDefaultTools(DefaultGccPlatformToolChain toolChain) { + toolChain.getLinker().setExecutable("/opt/intel/bin/icpc"); + toolChain.getStaticLibArchiver().setExecutable("/opt/intel/bin/xiar") + toolChain.getcCompiler().setExecutable("/opt/intel/bin/icc"); + toolChain.getCppCompiler().setExecutable("/opt/intel/bin/icpc"); + toolChain.getObjcCompiler().setExecutable("/opt/intel/bin/icc"); + toolChain.getObjcppCompiler().setExecutable("/opt/intel/bin/icpc"); + toolChain.getAssembler().setExecutable("as"); + + } + + @Override + protected String getTypeName() { + return "Icc"; + + } + +} diff --git a/buildSrc/src/main/groovy/regamedll/testdemo/RegameDLLDemoRunner.groovy b/buildSrc/src/main/groovy/regamedll/testdemo/RegameDLLDemoRunner.groovy index 6f78a4c86..e0c86f41a 100644 --- a/buildSrc/src/main/groovy/regamedll/testdemo/RegameDLLDemoRunner.groovy +++ b/buildSrc/src/main/groovy/regamedll/testdemo/RegameDLLDemoRunner.groovy @@ -1,76 +1,40 @@ package regamedll.testdemo -import dirsync.builder.FileSystemTreeBuilder -import dirsync.merger.FileTreeComparator -import dirsync.merger.FileTreeDiffApplier -import dirsync.model.tree.DirectoryNode -import dirsync.model.tree.FSMapper -import dirsync.model.tree.ZipData -import dirsync.model.tree.ZipTreeMapper -import org.apache.ant.compress.taskdefs.Unzip -import org.apache.tools.ant.types.PatternSet; +import org.doomedsociety.gradlecpp.GradleCppUtils +import org.apache.commons.io.FilenameUtils +import org.apache.commons.io.FileUtils class RegamedllDemoRunner { - ZipTreeMapper regamedllImage = new ZipTreeMapper() File rootDir - DirectoryNode engineImageTree Closure postExtract - static class TestResult { + static class TestResult + { boolean success int returnCode String hldsConsoleOutput long duration } - RegamedllDemoRunner(Collection engineImageZips, File rootDir, Closure postExtract) { + RegamedllDemoRunner(File rootDir, Closure postExtract) + { this.rootDir = rootDir - engineImageZips.each { f -> - regamedllImage.addZipArchive(f.absolutePath) - } - engineImageTree = regamedllImage.buildFileTree() this.postExtract = postExtract } - void prepareDemo(File demoArchive) { - - if (demoArchive == null) { - throw new RuntimeException("ReGameDLL_CS testdemos: file is null") - } - - PatternSet patt = new PatternSet(); - - patt.setExcludes("**/*.bin"); - patt.setExcludes("**/*.xml"); - - //patt.setIncludes("**/cstrike/*"); - //patt.setIncludes("**/czero/*"); - //patt.setIncludes("**/valve/*"); - - Unzip unzipper = new Unzip(); - - unzipper.setDest( rootDir ); // directory unzipped - unzipper.setSrc( demoArchive ); // zip file - unzipper.addPatternset( patt ); - unzipper.execute(); - } - - void prepareEngine() { - def existingTree = FileSystemTreeBuilder.buildFileSystemTree(rootDir) - def cmds = FileTreeComparator.mergeTrees(engineImageTree, existingTree) + void prepareEngine() + { + FileUtils.copyDirectory(new File(rootDir.toString() + '/deps/regamedll'), rootDir); - FSMapper fsMapper = new FSMapper(rootDir) - FileTreeDiffApplier.applyDiffs(cmds, regamedllImage, fsMapper) if (postExtract != null) { postExtract.run() } } - TestResult runTest(RegamedllTestInfo info, File testLogDir) { + TestResult runTest(RegamedllTestInfo info, File testLogDir) + { long startTime = System.currentTimeMillis() - //prepareEngine() - def outPath = new File(testLogDir, "${info.testName}_run.log") def cmdParams = [] @@ -86,8 +50,8 @@ class RegamedllDemoRunner { def p = pb.start() p.consumeProcessOutput(sout, sout) - p.waitForOrKill(info.timeoutSeconds * 1000) + int exitVal = p.exitValue() outPath.withWriter('UTF-8') { writer -> diff --git a/buildSrc/src/main/groovy/regamedll/testdemo/RegameDLLTestParser.groovy b/buildSrc/src/main/groovy/regamedll/testdemo/RegameDLLTestParser.groovy index bf54f159f..161c6cc9c 100644 --- a/buildSrc/src/main/groovy/regamedll/testdemo/RegameDLLTestParser.groovy +++ b/buildSrc/src/main/groovy/regamedll/testdemo/RegameDLLTestParser.groovy @@ -3,61 +3,35 @@ package regamedll.testdemo import groovy.util.slurpersupport.GPathResult import org.apache.commons.io.IOUtils -import java.util.zip.ZipFile - class RegamedllTestParser { - static final String REGAMEDLL_TEST_METAINFO_FILE = 'regamedll_test_metainfo.xml' - - static RegamedllTestInfo parseTestInfo(File testArchive) { - def zf = new ZipFile(testArchive); - try { - def metaInfoEntry = zf.getEntry(REGAMEDLL_TEST_METAINFO_FILE) - if (metaInfoEntry == null) { - throw new RuntimeException("Unable to open ${REGAMEDLL_TEST_METAINFO_FILE} in ${testArchive.absolutePath}") - } - - GPathResult metaInfo = null - zf.getInputStream(metaInfoEntry).withStream { InputStream ins -> - metaInfo = new XmlSlurper().parse(ins) - } - - RegamedllTestInfo testInfo = new RegamedllTestInfo( - testName: metaInfo.name.text(), - hldsArgs: metaInfo.runArgs.arg.list().collect { it.text().trim() }, - timeoutSeconds: metaInfo.timeout.text() as int - ) - - //validate testInfo - if (!testInfo.testName) { - throw new RuntimeException("Error parsing ${testArchive.absolutePath}: test name is not specified") - } - - if (!testInfo.hldsArgs) { - throw new RuntimeException("Error parsing ${testArchive.absolutePath}: run arguments are not specified") - } - - if (testInfo.timeoutSeconds <= 0) { - throw new RuntimeException("Error parsing ${testArchive.absolutePath}: bad timeout") - } - - def testBinName = testInfo.testName + '.bin' - def testBinEntry = zf.getEntry(testBinName) - if (testBinEntry == null) { - throw new RuntimeException("Error parsing ${testArchive.absolutePath}: test binary ${testBinName} not found inside archive") - } - - testInfo.testBinFile = File.createTempFile(testBinName, 'regamedll') - testInfo.testBinFile.deleteOnExit() - zf.getInputStream(testBinEntry).withStream { InputStream ins -> - testInfo.testBinFile.withOutputStream { OutputStream os -> - IOUtils.copy(ins, os) - } - } - - return testInfo - } finally { - try { zf.close() } catch (Exception ignored) { } + static RegamedllTestInfo parseTestInfo(String testRootName, String testName) { + File manifestFile = new File(testRootName + testName + '.xml') + if (!manifestFile.exists()) { + throw new RuntimeException("Unable to open "+testName+".xml in "+testRootName) + } + + GPathResult metaInfo = new XmlSlurper().parse(manifestFile) + RegamedllTestInfo testInfo = new RegamedllTestInfo( + testName: metaInfo.name.text(), + hldsArgs: metaInfo.runArgs.arg.list().collect { it.text().trim() }, + timeoutSeconds: metaInfo.timeout.text() as int + ) + + testInfo.testBinFile = new File(testRootName + testName + '.bin') + + // validate testInfo + if (!testInfo.testName) { + throw new RuntimeException("Error parsing ${testInfo.testBinFile.absolutePath}: test name is not specified") + } + + if (!testInfo.hldsArgs) { + throw new RuntimeException("Error parsing ${testInfo.testBinFile.absolutePath}: run arguments are not specified") + } + + if (testInfo.timeoutSeconds <= 0) { + throw new RuntimeException("Error parsing ${testInfo.testBinFile.absolutePath}: bad timeout") } + return testInfo } } diff --git a/buildSrc/src/test/groovy/dirsync/builder/ZipTreeBuilderTest.groovy b/buildSrc/src/test/groovy/dirsync/builder/ZipTreeBuilderTest.groovy deleted file mode 100644 index 38a2eabb2..000000000 --- a/buildSrc/src/test/groovy/dirsync/builder/ZipTreeBuilderTest.groovy +++ /dev/null @@ -1,44 +0,0 @@ -package dirsync.builder - -import org.junit.Test - -import java.io.File - -import dirsync.builder.ZipTreeBuilder - -import java.util.zip.ZipEntry -import java.util.zip.ZipFile -import java.util.zip.ZipOutputStream; - -import static org.junit.Assert.*; - -class ZipTreeBuilderTest { - - @Test - void test1() { - File zipFile = File.createTempFile('ZipTreeBuilderTest', 'zip') - zipFile.deleteOnExit() - - new ZipOutputStream(zipFile.newDataOutputStream()).withStream { ZipOutputStream zos -> - zos.putNextEntry(new ZipEntry('aRootFile1.txt')) - zos.write(65) //'A' - - zos.putNextEntry(new ZipEntry('dir1/')) - zos.putNextEntry(new ZipEntry('dir1/dir2/')) - - zos.putNextEntry(new ZipEntry('dir1/dir2/d1d2f1.txt')) - zos.write(65); zos.write(66) //'AB' - - zos.putNextEntry(new ZipEntry('dir1/d1f1.txt')) - zos.write(65); zos.write(66); zos.write(67) //'ABC' - - zos.putNextEntry(new ZipEntry('zRootFile2.txt')) - zos.write(65); zos.write(66); zos.write(67); zos.write(68) //'ABCD' - } - - ZipFile zf = new ZipFile(zipFile.absolutePath) - def tree = ZipTreeBuilder.buildForZipArchive(zipFile.absolutePath, zf) - - assert tree.childNodes.size() == 3 - } -} \ No newline at end of file diff --git a/getucrtinfo.bat b/getucrtinfo.bat index 29f5bb163..4e5abeef9 100644 --- a/getucrtinfo.bat +++ b/getucrtinfo.bat @@ -1,17 +1,13 @@ @echo off -if defined VS150COMNTOOLS ( - if not exist "%VS150COMNTOOLS%vcvarsqueryregistry.bat" goto NoVS - call "%VS150COMNTOOLS%vcvarsqueryregistry.bat" - goto :run -) else if defined VS140COMNTOOLS ( +if defined VS140COMNTOOLS ( if not exist "%VS140COMNTOOLS%vcvarsqueryregistry.bat" goto NoVS call "%VS140COMNTOOLS%vcvarsqueryregistry.bat" goto :run ) :NoVS -echo Error: Visual Studio 2015 or 2017 required. +echo Error: Visual Studio 2015 required. exit /b 1 :run diff --git a/publish.gradle b/publish.gradle index a0c1fc03f..1bd370d3b 100644 --- a/publish.gradle +++ b/publish.gradle @@ -67,6 +67,15 @@ task publishPackage(type: Zip, dependsOn: 'publishPrepareFiles') { from 'publish/publishRoot' } +Properties repoCreds = new Properties() +project.ext.repoCreds = repoCreds +if (file('repo_creds.properties').exists()) { + println 'Loading maven repo credentials' + file('repo_creds.properties').withReader('UTF-8', { Reader r -> + repoCreds.load(r) + }) +} + publishing { publications { maven(MavenPublication) { @@ -107,18 +116,7 @@ publishing { } } } -} -Properties repoCreds = new Properties() -project.ext.repoCreds = repoCreds -if (file('repo_creds.properties').exists()) { - println 'Loading maven repo credentials' - file('repo_creds.properties').withReader('UTF-8', { Reader r -> - repoCreds.load(r) - }) -} - -publishing { repositories { maven { if (project.version.contains('dev')) { diff --git a/regamedll/build.gradle b/regamedll/build.gradle index 848bb01ed..173ab5a99 100644 --- a/regamedll/build.gradle +++ b/regamedll/build.gradle @@ -1,4 +1,3 @@ -import gradlecpp.RegamedllPlayTestPlugin import gradlecpp.RegamedllPlayTestTask import gradlecpp.VelocityUtils @@ -19,30 +18,14 @@ import org.gradle.nativeplatform.NativeLibrarySpec import org.gradle.nativeplatform.SharedLibraryBinarySpec import regamedll.testdemo.RegamedllDemoRunner import versioning.RegamedllVersionInfo -import org.apache.commons.io.FilenameUtils -import org.apache.commons.compress.archivers.ArchiveInputStream apply plugin: 'cpp' apply plugin: IccCompilerPlugin apply plugin: GccCompilerPlugin -apply plugin: RegamedllPlayTestPlugin apply plugin: gradlecpp.CppUnitTestPlugin -repositories { - maven { - url 'http://nexus.rehlds.org/nexus/content/repositories/regamedll-releases/' - } -} - -configurations { - regamedll_tests -} - -dependencies { - regamedll_tests 'regamedll.testdemos:cstrike-basic:1.0' -} - project.ext.dep_cppunitlite = project(':dep/cppunitlite') +project.ext.hldsroot = System.getenv('HLDS') void createIntergrationTestTask(NativeBinarySpec b) { boolean regamedllFixes = b.flavor.name.contains('regamedllFixes') @@ -55,13 +38,11 @@ void createIntergrationTestTask(NativeBinarySpec b) { def demoItgTestTask = project.tasks.create(b.namingScheme.getTaskName('demoItgTest'), RegamedllPlayTestTask) demoItgTestTask.with { - regamedllImageRoot = new File(project.projectDir, '_regamedllTestImg') - regamedllTestLogs = new File(this.project.buildDir, "_regamedllTestLogs/${b.name}") - testDemos = project.configurations.regamedll_tests - testFor = b + regamedllImageRoot = new File(project.ext.hldsroot) + regamedllTestLogs = new File(project.ext.hldsroot, "/_regamedllTestLogs") + testDemos = [ 'cstrike-basic-1' ] - // inputs/outputs for up-to-date check - inputs.files testDemos.files + // outputs for up-to-date check outputs.dir regamedllTestLogs // dependencies on test executable @@ -71,7 +52,7 @@ void createIntergrationTestTask(NativeBinarySpec b) { postExtractAction { def binaryOutFile = GradleCppUtils.getBinaryOutputFile(b) - def binaryOutDir = new File(project.projectDir, '/_regamedllTestImg/cstrike/dlls') + def binaryOutDir = new File(project.ext.hldsroot, '/cstrike/dlls') GradleCppUtils.copyFile(binaryOutFile, new File(binaryOutDir, binaryOutFile.name), true) } } @@ -378,35 +359,22 @@ gradle.taskGraph.whenReady { graph -> } task prepareDevEnvTests { - def regamedllTests = new File(project.projectDir, '_dev/testDemos') - - inputs.files configurations.regamedll_tests.files - outputs.dir regamedllTests + def demoItgTestTask = project.tasks.create('checkTestDemos', RegamedllPlayTestTask) + demoItgTestTask.with { + regamedllImageRoot = new File(project.ext.hldsroot) + regamedllTestLogs = new File(project.ext.hldsroot, "/_regamedllTestLogs") + testDemos = [ 'cstrike-basic-1' ] - doLast { - regamedllTests.mkdirs() - configurations.regamedll_tests.files.each { File f -> - def t = zipTree(f) - copy { - into new File(regamedllTests, FilenameUtils.getBaseName(f.absolutePath)) - from t - } - } + // outputs for up-to-date check + outputs.dir regamedllTestLogs } -} -task prepareDevEnvGamedll << { - ['_dev/regamedll', '_dev/regamedll_mp'].each { gamedllDir -> - def regamedllImage = new File(project.projectDir, gamedllDir) - regamedllImage.mkdirs() - def demoRunner = new RegamedllDemoRunner(project.configurations.regamedll_playtest_image.getFiles(), regamedllImage, null) - demoRunner.prepareEngine() - //demoRunner.prepareDemo() - } + demoItgTestTask.doPlay() } -task prepareDevEnv { - dependsOn prepareDevEnvGamedll, prepareDevEnvTests +task prepareDevEnvGamedll { + def demoRunner = new RegamedllDemoRunner(new File(project.ext.hldsroot), null) + demoRunner.prepareEngine() } tasks.clean.doLast { @@ -428,7 +396,7 @@ task generateAppVersion { inputs.property('version', rootProject.version) inputs.property('commitDate', verInfo.asCommitDate()) - println "##teamcity[buildNumber '" + verInfo.asMavenVersion(false) + "']"; + println "Build number: " + verInfo.asMavenVersion(false) doLast { def templateCtx = [ diff --git a/shared.gradle b/shared.gradle index 47ed31b10..2644b8070 100644 --- a/shared.gradle +++ b/shared.gradle @@ -12,6 +12,7 @@ apply from: 'shared_clang.gradle' apply from: 'shared_gcc.gradle' rootProject.ext.createToolchainConfig = { NativeBinarySpec bin -> + BinaryKind binaryKind if (bin instanceof NativeExecutableBinarySpec) { @@ -31,6 +32,7 @@ rootProject.ext.createToolchainConfig = { NativeBinarySpec bin -> } boolean releaseBuild = bin.buildType.name.toLowerCase() == 'release' + if (bin.toolChain instanceof VisualCpp) { return rootProject.createMsvcConfig(releaseBuild, binaryKind)