使用gradle

时间:2015-06-02 14:19:04

标签: gradle cross-platform

请您分享您对libxml2libpnglibfreetype等库的交叉编译的智慧,这些库有一个配置脚本和一个Makefile for android和其他主机,如linux, Windows和Mac Os X使用 gradle

目前我没有一个完整的工作示例,但是希望找到类似以下的解决方案:

https://github.com/couchbase/couchbase-lite-java-native/blob/master/crosscompile-build.gradle

//
// To cross compile to ARM replace the default build.gradle with this file.
// Before running the build install these additional linux packages
//
// gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
//
apply plugin: 'c'
apply plugin: 'java'
apply plugin: 'maven'

version = System.getenv("MAVEN_UPLOAD_VERSION")

model {
    platforms {
        osx_x86 {
            architecture "x86"
            operatingSystem "osx"
        }
        osx_x86_64 {
            architecture "x86_64"
            operatingSystem "osx"
        }
        linux_x86 {
            architecture "x86"
            operatingSystem "linux"
        }
        linux_x86_64 {
            architecture "x86_64"
            operatingSystem "linux"
        }
        linux_amd64 {
            architecture "amd64"
            operatingSystem "linux"
        }
        linux_arm {
            architecture "arm"
            operatingSystem "linux"
        }
        windows_x86 {
            architecture "x86"
            operatingSystem "windows"
        }
        windows_x86_64 {
            architecture "x86_64"
            operatingSystem "windows"
        }
        windows_amd64 {
            architecture "amd64"
            operatingSystem "windows"
        }
    }

    toolChains {
        visualCpp(VisualCpp)
        gcc(Gcc)
        gccArm(Gcc) {
            getCppCompiler().setExecutable 'arm-linux-gnueabihf-g++'
            getCCompiler().setExecutable 'arm-linux-gnueabihf-gcc'
            getAssembler().setExecutable 'arm-linux-gnueabihf-as'
            getLinker().setExecutable 'arm-linux-gnueabihf-gcc'
            getStaticLibArchiver().setExecutable 'arm-linux-gnueabihf-ar'
            addPlatformConfiguration(new ArmSupport())
        }
        clang(Clang)
    }
}

    class ArmSupport implements TargetPlatformConfiguration {
        boolean supportsPlatform(Platform element) {
            return element.getArchitecture().name == "arm"
        }

        List<String> getCppCompilerArgs() {
            []
        }

        List<String> getObjectiveCppCompilerArgs() {
            []
        }

        List<String> getObjectiveCCompilerArgs() {
            []
        }

        List<String> getCCompilerArgs() {
            []
        }

        List<String> getAssemblerArgs() {
            []
        }

        List<String> getLinkerArgs() {
            []
        }

        List<String> getStaticLibraryArchiverArgs() {
            []
        }
    }

sources {
    native_library {
        c {
            source {
                srcDir "src/main/c"
            }
            exportedHeaders {
                srcDir "src/main/include"
            }
        }
    }
}

libraries {
    native_library {
        baseName "CouchbaseLiteJavaNative"
    }

    all {
        binaries.withType(SharedLibraryBinary) { binary ->
            if (targetPlatform.operatingSystem.macOsX) {
                cCompiler.args '-I', "/System/Library/Frameworks/JavaVM.framework/Headers"
                linker.args '-framework', "JavaVM"
            } else if (targetPlatform.operatingSystem.linux) {
                cCompiler.args '-I', "${org.gradle.internal.jvm.Jvm.current().javaHome}/include"
                cCompiler.args '-I', "${org.gradle.internal.jvm.Jvm.current().javaHome}/include/linux"
            } else if (targetPlatform.operatingSystem.windows) {
                cCompiler.args "-I${org.gradle.internal.jvm.Jvm.current().javaHome}/include"
                cCompiler.args "-I${org.gradle.internal.jvm.Jvm.current().javaHome}/include/win32"
                linker.args "--add-stdcall-alias"
            }
        }
    }
}

binaries.withType(SharedLibraryBinary) { binary ->
    if (!buildable) {
        return
    }

    def builderTask = binary.tasks.builder

    jar.into("native/${targetPlatform.operatingSystem.name}/${targetPlatform.architecture.name}") {
            from builderTask.outputFile
    }

    jar.dependsOn builderTask
}

task createMavenDirectory(type: Exec) {
    ext {
        uploadUser = System.getenv("MAVEN_UPLOAD_USERNAME") + ":" + System.getenv("MAVEN_UPLOAD_PASSWORD")
        mkcolPath  = System.getenv("MAVEN_UPLOAD_REPO_URL") + "com/couchbase/lite/java-native/" + version + "/"
    }
    commandLine "curl", "--user", uploadUser, "-X", "MKCOL", mkcolPath
}

// this hack is only needed for apache mod_dav based Maven repo's like file.couchbase.com.  otherwise, skip it
createMavenDirectory.onlyIf { System.getenv("MAVEN_UPLOAD_REPO_URL").contains("files") }

// first create the directory, then do the upload
task uploadArchivesWrapper(dependsOn: createMavenDirectory) << {
    uploadArchives.execute()
}

// this will upload, but will not first create a directory (which is needed on some servers)
uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: System.getenv("MAVEN_UPLOAD_REPO_URL")) {
                authentication(userName: System.getenv("MAVEN_UPLOAD_USERNAME"), password: System.getenv("MAVEN_UPLOAD_PASSWORD"))
            }
            pom.version = version
            pom.groupId = 'com.couchbase.lite'
            pom.artifactId = 'java-native'
            pom.project {
                licenses {
                    license {
                        name 'Couchbase Community Edition License Agreement'
                        url 'http://www.couchbase.com/agreement/community'
                        distribution 'repo'
                    }
                }
            }
        }
    }
}

task sourcesJar(type: Jar, dependsOn: classes) {
    classifier = 'sources'
    from sourceSets.main.java.srcDirs
}

artifacts {
    archives sourcesJar
}

最好使用 Android NDK 提供的工具链,而不是指定 gnueabi 并静态链接所有内容。

修改

我已经扩展了构建文件,但是我得到了UP-TO DATE所有任务:

设置是: libxml2-2.9.2

build.gradle

apply plugin: 'c'

import com.ulabs.gradle.AutoConfigureTask
import com.ulabs.gradle.MakefileTask
import com.ulabs.gradle.ConfigureTask

gradle.allprojects {
    ext.getLibXmlLibsPath = {
        def distDir = new File(project(":libxml2").projectDir, "buildLibxml2")
        return distDir.toString()
    }
    ext.getLibXmlHeaderPath = {
        def hDir = new File(project(":libxml2").projectDir, "include")
        return hDir.toString()
    }
}

project(':libxml2') {
    model {
        toolChains {
            visualCpp(VisualCpp)
            gcc(Gcc)
            clang(Clang)
        }

        platforms {
            x86 {
                architecture "x86"
            }
            x64 {
                architecture "x86_64"
            }
            itanium {
                architecture "ia-64"
            }
        }

        components {
            xml2(NativeLibrarySpec) {
                sources {
                    c {
                        exportedHeaders {
                            srcDir "include"
                            include "libxml/*.h"
                        }
                        exportedHeaders {
                            srcDir "include"
                            include "win32config.h", "wsockcompat.h"
                        }
                        exportedHeaders {
                            srcDir "."
                            include "libxml.h"
                        }
                    }
                }
            }
        }

        repositories {
            libs(PrebuiltLibraries) {
                libxml2 {
                    headers.srcDir getLibXmlHeaderPath()
                    binaries.withType(StaticLibraryBinary) {
                        def baseDir = getLibXmlLibsPath()
                        staticLibraryFile = file("${baseDir}/libxml2.a")
                    }

                    binaries.withType(SharedLibraryBinary) {
                        def os = targetPlatform.operatingSystem
                        def baseDir = getLibXmlLibsPath()
                        if (os.windows) {
                            sharedLibraryFile = file("${baseDir}/libxml2.dll")
                            if (file("${baseDir}/util.lib").exists()) {
                                sharedLibraryLinkFile = file("${baseDir}/libxml2.lib")
                            }
                        } else if (os.macOsX) {
                            sharedLibraryFile = file("${baseDir}/libxml2.dylib")
                        } else {
                            sharedLibraryFile = file("${baseDir}/libxml2.so")
                        }
                    }
                }
            }
        }
    }

    task autoConfigTask(type: AutoConfigureTask) << {
        extraArgs ""
    }

    task configureTask(type: ConfigureTask, dependsOn: autoConfigTask) << {
        extraArgs "--without-python", "--without-zlib"
    }

    task makeFileTask(type: MakefileTask, dependsOn: configureTask) << {
        println "Running makefile Task ${project}"
    }

    task make(dependsOn : makeFileTask) << {
        def distDir = new File(getLibXmlLibsPath())
        delete distDir.toString()
        distDir.mkdirs()
        def binDir = projectDir.toString() + "/.libs"
        FileTree tree = fileTree(binDir.toString()) {
            include 'libxml2*'
            exclude '*.la*'
        }
        tree.each {File file ->
           copy {
               from file.toString()
               into distDir.toString()
           }
        }
    }
}

build.dependsOn(make)
assemble.dependsOn(make)

buildSrc/src/main/groovy/com/ulabs/gradle/*.groovy包含:

package com.ulabs.gradle

import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Optional
import org.gradle.api.Project
import org.gradle.api.tasks.incremental.IncrementalTaskInputs

class AutoConfigureTask extends DefaultTask {
    @Input
    @Optional
    def extraArgs

    @TaskAction
    def execConfigure(IncrementalTaskInputs inputs) {
        println "Launching AutoConfigureTask from: " + project.projectDir

        if(!new File(project.projectDir, 'configure.ac').exists() &&
           !new File(project.projectDir, 'configure.in').exists()) {
            throw new FileNotFoundException(
                'autoconfigure task should have either configure.in or configure.ac ')
        }

        boolean outDated = false
        inputs.outOfDate { change ->
            outDated = true
        }

        if(outDated) {
            project.exec {
                executable "autoreconf"
                args "-ivf", hasProperty("extraArgs") ? extraArgs : ""
            }
        }
    }
}

package com.ulabs.gradle

import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Optional
import org.gradle.api.Project
import org.gradle.api.tasks.incremental.IncrementalTaskInputs

class ConfigureTask extends DefaultTask {
    @Input
    @Optional
    def extraArgs

    @TaskAction
    def execConfigure(IncrementalTaskInputs inputs) {
        if(!new File(project.projectDir, 'configure').exists()) {
            throw new FileNotFoundException(
                'configure task should have a configure script')
        }

        boolean outDated = false
        inputs.outOfDate { change ->
            outDated = true
        }

        if(outDated) {
            project.exec {
                executable "./configure"
                args hasProperty("extraArgs") ? extraArgs : ""
            }
        }
    }
}


package com.ulabs.gradle

import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Optional
import org.gradle.api.Project
import org.gradle.api.tasks.incremental.IncrementalTaskInputs

class MakefileTask extends DefaultTask {
    @Input
    @Optional
    def extraArgs

    @Input
    @Optional
    def env

    @TaskAction
    def execConfigure(IncrementalTaskInputs inputs) {
        if(!new File(project.projectDir, 'configure').exists()) {
            throw new FileNotFoundException(
                'makefile task should have a Makefile script')
        }

        boolean outDated = false
        inputs.outOfDate { change ->
            outDated = true
        }

        if(outDated) {
            project.exec {
                executable "make"
                args hasProperty("extraArgs") ? extraArgs : "-f Makefile"
            }
        }
    }
}

这很可能与任务的输入或任务的混乱配置/运行时阶段有关,但我尝试了很多选项,但似乎都没有。

所以最后我想:

  • ./configureautotoolsmake除非参数更改(extraArgsenv
  • ,否则不会运行
  • 当参数发生变化时,我希望它们都能在依赖项指定的链中运行
  • 我希望libxml2能像一个项目,可以与其他人联系,并能够匹配依赖的平台/架构,与链接api,共享或静态

1 个答案:

答案 0 :(得分:1)

因此,调用库本身附带的构建系统似乎更好。

以下是执行此操作的脚本:

task autoReconfigure(type : Exec) {
    executable "autoreconf"
    args "-vif"
    workingDir "."
}

task configureTask(type : Exec, dependsOn : autoReconfigure) {
    executable "./configure"
    args "--without-zlib"
    workingDir "."
}

task makeFileTask(type : Exec, dependsOn : configureTask) {
    executable "make"
    args "-f", "Makefile"
    workingDir "."
}

build.dependsOn(makeFileTask)
assemble.dependsOn(makeFileTask)

我将尝试添加对不同工具链/平台的支持