第54章. 构建原生二进制文件

Chapter 54. Building native binaries

Gradle 对构建原生二进制文件的支持目前还是孵化阶段。请务必注意,在以后的 Gradle 版本中,相关的 DSL 和其他配置可能会有所改变。
The Gradle support for building native binaries is currently incubating. Please be aware that the DSL and other configuration may change in later Gradle versions.

不同的原生二进制插件添加了对从C++,C,Objective-C,Objective-C++以及汇编源文件构建原生软件组件的支持。虽然对于这种软件开发的空间,已经有许多优秀的构建工具存在,但是Gradle 向开发人员提供的是它的强大特征和灵活性,以及在依赖管理实践上,在JVM开发空间上更为传统的发现。
The various native binary plugins add support for building native software components from C++, C, Objective-C, Objective-C++ and Assembler sources. While many excellent build tools exist for this space of software development, Gradle offers developers it's trademark power and flexibility together with the dependency management practices more traditionally found in the JVM development space.

54.1. 工具链支持

54.1. Tool chain support

Gradle 提供了使用不同的工具链执行相同的构建的能力。你可以通过更改操作系统的PATH让其包含所需的工具链编译器,来控制使用哪个工具链。或者,你可以直接配置工具链,就如下面的“原生二进制变种”中描述的。
Gradle offers the ability to execute the same build using different tool chains. You can control which tool chain will be used to build by changing the operating system PATH to include the desired tool chain compiler. Alternatively, you can configure the tool chains directly, as described in the `Native Binary Variants` section, below.

支持以下的工具链:
The following tool chains are supported:

操作系统
Operating System
工具链
Tool Chain
备注
Notes
Linux GCC
Linux Clang
Mac OS X GCC 使用 XCode 中的 GCC。
Using GCC distributed with XCode.
Mac OS X Clang 使用 XCode 中的 Clang。
Using Clang distributed with XCode.
Windows Visual C++ Windows XP及以上,Visual C++ 2010 及以上版本。
Windows XP and later, Visual C++ 2010 and later.
Windows GCC Windows XP及以上,使用Cygwin的GCC。
Windows XP and later, using GCC distributed with Cygwin.
Windows MinGW Windows XP 及以上。
Windows XP and later.

54.2. 组件模型

54.2. Component model

一个原生二进制project定义了一组ExecutableLibrary组件,每一个的 Gradle 都映射大量的NativeBinary输出。对于每个定义的executablelibrary,Gradle 添加了具有相同名称的FunctionalSourceSet 。这些功能源码集将为project所支持的每一种语言包含指定语言的源码集。
A native binary project defines a set of Executable and Library components, each of which Gradle maps to a number of NativeBinary outputs. For each executable or library defined, Gradle adds a FunctionalSourceSet with the same name. Each of these functional source sets will contain a language-specific source set for each of the languages supported by the project.

为构建一个静态或共享的原生库二进制文件,一个Library组件将添加到libraries容器中。每个library组件可以产生至少一个SharedLibraryBinary和至少一个StaticLibraryBinary
To build either a static or shared native library binary, a Library component is added to the libraries container. Each library component can produce at least one SharedLibraryBinary and at least one StaticLibraryBinary.

示例 54.1. 定义一个库组件 - Example 54.1. Defining a library component

build.gradle

libraries {
    hello {}
}

为构建一个可执行的二进制,Executable组件添加到executables容器中,并与源码集相关联。
To build an executable binary, an Executable component is added to the executables container and associated with a set of sources.

示例 54.2. 定义可执行组件 - Example 54.2. Defining executable components

build.gradle

executables {
    main {}
}

在许多情况下,一个组件可以产生超过一个的原生二进制文件。基于构建所使用的工具链,提供的编译器/链接器标志,提供的依赖或其他源文件,这些二进制文件可能会发生变化。组件所产生的每个原生二进制称为variant。下面将详细讨论二进制 variant。
In many cases, more than one native binary can be produced for a component. These binaries may vary based on the tool chain used to build, the compiler/linker flags supplied, the dependencies provided, or additional source files provided. Each native binary produced for a component is referred to as variant. Binary variants are discussed in detail below.

54.3. 任务

54.3. Tasks

针对由构建所产生的每一个 NativeBinary,我们构造了一个生命周期任务用于创建二进制,以及一系统的其他做实际工作,如编译,链接或者是装配二进制文件的任务。
For each NativeBinary that can be produced by a build, a single lifecycle task is constructed that can be used to create that binary, together with a set of other tasks that do the actual work of compiling, linking or assembling the binary.

组件类型
Component Type
原生二进制文件类型
Native Binary Type
生命周期任务
Lifecycle task
创建二进制文件的位置
Location of created binary
Executable ExecutableBinary $component.nameExecutable $buildDir/binaries/$binary.name/$component.name
Library SharedLibraryBinary $component.nameSharedLibrary $buildDir/binaries/$binary.name/lib$component.name.so
Library StaticLibraryBinary $component.nameStaticLibrary $buildDir/binaries/$binary.name/$component.name.a

54.3.1. 使用共享库

54.3.1. Working with shared libraries

对于每个产生的可执行二进制文件, cpp插件提供了install${binary.name}任务,这个任务可以创建该可执行文件及它需要的共享库的开发安装。它允许你运行可执行文件,而无需在其最终的位置安装共享库。
For each executable binary produced, the cpp plugin provides an install${binary.name} task, which creates a development install of the executable, along with the shared libraries it requires. This allows you to run the executable without needing to install the shared libraries in their final locations.

544.核心语言支持: C、C++、汇编,Objective-C和Objective-C++

54.4. Core language support: C, C++, Assembler, Objective-C and Objective-C++

目前,Gradle 支持从C++,C,Assembler,Objective-C 和 Objective-C++源码的任意组合中构建原生二进制文件。一个原生二进制project 将包含一个或多个叫做FunctionalSourceSet的实例(如"main","test"等),其中每一个都可以包含含有C++,C,Assembler,Objective-C或Objective-C++源代码的LanguageSourceSets。
Presently, Gradle supports building native binaries from any combination of C++, C, Assembler, Objective-C and Objective-C++ sources. A native binary project will contain one or more named FunctionalSourceSet instances (eg 'main', 'test', etc), each of which can contain LanguageSourceSets containing C++, C, Assembler, Objective-C or Objective-C++ source files.

54.4.1. C++ 源代码

54.4.1. C++ sources

'cpp' 插件提供了C++ 语言的支持。
C++ language support is provided by means of the 'cpp' plugin.

示例 54.3. cpp 插件 - Example 54.3. The 'cpp' plugin

build.gradle

apply plugin: 'cpp'

把 C++ 源码包含到原生二进制文件中,是通过一个 CppSourceSet来实现的,它定义了一个C++源文件集以及(可选的)一个可导出的头文件(用于library)集默认情况下,对于任何命名的组件,CppSourceSet包含了在src/${name}/cpp中的.cpp源文件,和在src/${name}/headers中的头文件。
C++ sources to be included in a native binary are provided via a CppSourceSet, which defines a set of C++ source files and optionally a set of exported header files (for a library). By default, for any named component the CppSourceSet contains .cpp source files in src/${name}/cpp, and header files in src/${name}/headers.

cpp插件为每个CppSourceSet定义了这些默认的位置,且可以扩展或重写这些默认值使能够成为不同的项目布局。
While the cpp plugin defines these default locations for each CppSourceSet, it is possible to extend or override these defaults to allow for a different project layout.

示例 54.4. C++ 源代码集 - Example 54.4. C++ source set

build.gradle

sources {
    main {
        cpp {
            source {
                srcDir "src/source"
                include "**/*.cpp"
            }
        }
    }
}

对于名字为“main”的library, src/main/headers中的文件都被视为"公共"或"导出"的头文件。不应该被导出(而是内部使用)的头文件,应该放在 src/main/cpp 目录(不过要注意,这样的文件应该总是以相对于包含它们的文件这样的一种方式被引用)。
For a library named 'main', files in src/main/headers are considered the “public” or “exported” headers. Header files that should not be exported (but are used internally) should be placed inside the src/main/cpp directory (though be aware that such header files should always be referenced in a manner relative to the file including them).

54.4.2. C 源代码

54.4.2. C sources

'c' 插件提供了C 语言的支持。
C language support is provided by means of the 'c' plugin.

示例 54.5. “C” 插件 - Example 54.5. The 'c' plugin

build.gradle

apply plugin: 'c'

把 C 源码包含到原生二进制文件中,是通过一个 CSourceSet来实现的,它定义了一个C源文件集以及(可选的)一个可导出的头文件(用于library)集默认情况下,对于任何命名的组件,CSourceSet包含了在src/${name}/c中的.c源文件,和在src/${name}/headers中的头文件。
C sources to be included in a native binary are provided via a CSourceSet, which defines a set of C source files and optionally a set of exported header files (for a library). By default, for any named component the CSourceSet contains .c source files in src/${name}/c, and header files in src/${name}/headers.

c插件为每个CSourceSet定义了这些默认的位置,且可以扩展或重写这些默认值使能够成为不同的项目布局。
While the c plugin defines these default locations for each CSourceSet, it is possible to extend or override these defaults to allow for a different project layout.

示例 54.4. C 源代码集 - Example 54.6. C source set

build.gradle

sources {
    hello {
        c {
            source {
                srcDir "src/source"
                include "**/*.c"
            }
            exportedHeaders {
                srcDir "src/include"
            }
        }
    }
}

对于名字为“main”的library, src/main/headers中的文件都被视为"公共"或"导出"的头文件。不应该被导出(而是内部使用)的头文件,应该放在 src/main/c 目录(不过要注意,这样的文件应该总是以相对于包含它们的文件这样一种方式被引用)。
For a library named 'main', files in src/main/headers are considered the “public” or “exported” headers. Header files that should not be exported (but are used internally) should be placed inside the src/main/c directory (though be aware that such header files should always be referenced in a manner relative to the file including them).

54.4.3. 汇编代码

54.4.3. Assembler sources

“assembler” 插件提供了汇编语言的支持。
Assembly language support is provided by means of the 'assembler' plugin.

示例 54.3. assembler 插件 - Example 54.7. The 'assembler' plugin

build.gradle

apply plugin: 'assembler'

把汇编源码包含到原生二进制文件中,是通过一个 AssemblerSourceSet来实现的,它定义了一个汇编源文件集。默认情况下,对于任何命名的组件,AssemblerSourceSet包含了在src/${name}/asm中的.s源文件。
Assembler sources to be included in a native binary are provided via a AssemblerSourceSet, which defines a set of Assembler source files. By default, for any named component the AssemblerSourceSet contains .s source files under src/${name}/asm.

54.4.4. Objective-C 源码

54.4.4. Objective-C sources

'objective-c' 插件提供了Objective-C 语言的支持。
Objective-C language support is provided by means of the 'objective-c' plugin.

示例 54.8. “objective-c”插件 - Example 54.8. The 'objective-c' plugin

build.gradle

apply plugin: 'objective-c'

把Objective-C源码包含到原生二进制文件中,是通过一个 ObjectiveCSourceSet来实现的,它定义了一个Objective-C源文件集。默认情况下,对于任何命名的组件,ObjectiveCSourceSet包含了在src/${name}/objectiveC中的.m源文件。
Objective-C sources to be included in a native binary are provided via a ObjectiveCSourceSet, which defines a set of Objective-C source files. By default, for any named component the ObjectiveCSourceSet contains .m source files under src/${name}/objectiveC.

54.4.5. Objective-C++ 源码

54.4.5. Objective-C++ sources

'objective-cpp' 插件提供了Objective-C++ 语言的支持。
Objective-C++ language support is provided by means of the 'objective-cpp' plugin.

示例 54.9. “objective-cpp” 插件 - Example 54.9. The 'objective-cpp' plugin

build.gradle

apply plugin: 'objective-cpp'

把Objective-C++源码包含到原生二进制文件中,是通过一个 ObjectiveCppSourceSet来实现的,它定义了一个Objective-C++源文件集。默认情况下,对于任何命名的组件,ObjectiveCppSourceSet包含了在src/${name}/objectiveCpp中的.mm源文件。
Objective-C++ sources to be included in a native binary are provided via a ObjectiveCppSourceSet, which defines a set of Objective-C++ source files. By default, for any named component the ObjectiveCppSourceSet contains .mm source files under src/${name}/objectiveCpp.

54.5. 配置编译器,汇编器和连接器

54.5. Configuring the compiler, assembler and linker

每一个产生的二进制文件都和一系列的编译器和链接器设置相关联,这些设置包含了命令行参数,以及宏定义。这些设置可以应用于所有的二进制文件,单个二进制文件,或选择性地应用于基于某些条件的一组二进制文件。
Each binary to be produced is associated with a set of compiler and linker settings, which include command-line arguments as well as macro definitions. These settings can be applied to all binaries, an individual binary, or selectively to a group of binaries based on some criteria.

示例 54.10. 应用于所有二进制文件的设置 - Example 54.10. Settings that apply to all binaries

build.gradle

binaries.all {
    // Define a preprocessor macro for every binary
    cppCompiler.define "NDEBUG"

    // Define toolchain-specific compiler and linker options
    if (toolChain in Gcc) {
        cppCompiler.args "-O2", "-fno-access-control"
        linker.args "-Xlinker", "-S"
    }
    if (toolChain in VisualCpp) {
        cppCompiler.args "/Zi"
        linker.args "/DEBUG"
    }
}

每个二进制文件与特定的ToolChain关联,允许设置基于此值进行针对性的配置。
Each binary is associated with a particular ToolChain, allowing settings to be targeted based on this value.

让设置应用于指定类型的所有二进制文件很简单:
It is easy to apply settings to all binaries of a particular type:

示例 54.11. 应用于所有共享库的设置 - Example 54.11. Settings that apply to all shared libraries

build.gradle

// For any shared library binaries built with Visual C++, define the DLL_EXPORT macro
binaries.withType(SharedLibraryBinary) {
    if (toolChain in VisualCpp) {
        cCompiler.args "/Zi"
        cCompiler.define "DLL_EXPORT"
    }
}

此外,还可以指定设置应用于某个特定的executablelibrary 组件 产生的所有二进制文件:
Furthermore, it is possible to specify settings that apply to all binaries produces for a particular executable or library component:

示例 54.12. 应用于“main”可执行组件所产生的所有二进制文件的设置 - Example 54.12. Settings that apply to all binaries produced for the 'main' executable component

build.gradle

executables {
    main {
        binaries.all {
            if (toolChain in VisualCpp) {
                assembler.args "/Zi"
            } else {
                assembler.args "-g"
            }
        }
    }
}

上面的例子将会把提供的配置应用到所有构建的 executable二进制文件。
The example above will apply the supplied configuration to all executable binaries built.

同样,也可以为某种特定类型的组件,把设置指向目标二进制文件:例如所有main library组件的shared libraries
Similarly, settings can be specified to target binaries for a component that are of a particular type: eg all shared libraries for the main library component.

示例 54.13. 仅应用于“main”library组件所产生的共享库的设置 - Example 54.13. Settings that apply only to shared libraries produced for the 'main' library component

build.gradle

libraries {
    main {
        binaries.withType(SharedLibraryBinary) {
            // Define a preprocessor macro that only applies to shared libraries
            cppCompiler.define "DLL_EXPORT"
        }
    }
}

54.6. Windows Resource

54.6. Windows Resources

当使用VisualCpp工具链时,Gradle 时能够编译Window Resource (rc) 文件并将它们链接到本地的二进制文件。这个功能是由'windows-resources' 插件所提供的。
When using the VisualCpp tool chain, Gradle is able to compile Window Resource (rc) files and link them into a native binary. This functionality is provided by the 'windows-resources' plugin.

示例 54.14. 'windows-resources' 插件 - Example 54.14. The 'windows-resources' plugin

build.gradle

apply plugin: 'windows-resources'

将 Windows 资源包含进本机二进制文件中,是通过一个WindowsResourceSet提供的,它定义了一组Windows Resource源文件。默认情况下,WindowsResourceSet为所有的命名组件包含了在src/${name}/rc下的.rc源文件。
Windows resources to be included in a native binary are provided via a WindowsResourceSet, which defines a set of Windows Resource source files. By default, for any named component the WindowsResourceSet contains .rc source files under src/${name}/rc.

与其他源文件类型一样,您可以配置把windows 资源的位置包含进二进制文件中。
As with other source types, you can configure the location of the windows resources that should in included in the binary.

示例 54.15. 配置 Windows 资源源文件的位置 - Example 54.15. Configuring the location of Windows resource sources

build-resource-only-dll.gradle

sources {
    helloRes {
        rc {
            source {
                srcDirs "src/hello/rc"
            }
            exportedHeaders {
                srcDirs "src/hello/headers"
            }
        }
    }
}

你能够通过提供没有任何其他语言来源的 Windows Resource 源文件,来构造纯资源库,并适当地配置链接器︰
You are able to construct a resource-only library by providing Windows Resource sources with no other language sources, and configure the linker as appropriate:

示例 54.16. 构建一个纯资源 dll - Example 54.16. Building a resource-only dll

build-resource-only-dll.gradle

libraries {
    helloRes {
        binaries.all {
            rcCompiler.args "/v"
            linker.args "/noentry", "/machine:x86"
        }
    }
}

上面的示例还演示了将额外的命令行参数传递给资源编译器的机制。rcCompiler扩展是PreprocessingTool类型。
The example above also demonstrates the mechanism of passing extra command-line arguments to the resource compiler. The rcCompiler extension is of type PreprocessingTool.

54.7. 库依赖

54.7. Library Dependencies

C++ 项目的依赖是导出头文件的二进制库。这些头文件在编译期间使用,而编译的二进制依赖则在链接过程中使用。
Dependencies for C++ projects are binary libraries that export header files. The header files are used during compilation, with the compiled binary dependency being used during the linking.

54.7.1. 同一项目的依赖

54.7.1. Dependencies within the same project

一组源文件可能依赖于在同一个项目中由另一个二进制组件提供的头文件。一个常见的例子是一个本地可执行组件,使用了由一个单独的本地库组件提供的功能。
A set of sources may depend on header files provided by another binary component within the same project. A common example is a native executable component that uses functions provided by a separate native library component.

这样的库依赖可以很方便地提供给source set关联上executable组件。
Such a library dependency can be easily provided to source set associated with the executable component:

示例 54.17. 向source set提供库依赖 - Example 54.17. Providing a library dependency to the source set

build.gradle

sources {
    main {
        cpp {
            lib libraries.hello
        }
    }
}

另外,一个库依赖项可以直接提供给ExecutableBinaryexecutable
Alternatively, a library dependency can be provided directly to the ExecutableBinary for the executable.

示例 54.18. 向二进制文件提供库依赖 - Example 54.18. Providing a library dependency to the binary

build.gradle

executables {
    main {
        binaries.all {
            // Each executable binary produced uses the 'hello' static library binary
            lib libraries.hello.static
        }
    }
}

54.7.2. 项目依赖

54.7.2. Project Dependencies

对于在不同的 Gradle 项目产生的组件,notation是类似的。
For a component produced in a different Gradle project, the notation is similar.

示例 54.19. 定义项目依赖 - Example 54.19. Declaring project dependencies

build.gradle

project(":lib") {
    apply plugin: "cpp"
    libraries {
        main {}
    }
}

project(":exe") {
    apply plugin: "cpp"

    executables {
        main {}
    }

    sources {
        main {
            cpp {
                lib project: ':lib', library: 'main'
            }
        }
    }
}

54.8. 本地二进制变种

54.8. Native Binary Variants

对于每个定义的可执行文件或库,Gradle 能够构建多个不同的本机二进制变种。这样的例子包括debug及release的二进制文件,32位及64位的二进制文件,以及使用不同的自定义预处理标志生成的二进制文件。
For each executable or library defined, Gradle is able to build a number of different native binary variants. Examples of different variants include debug vs release binaries, 32-bit vs 64-bit binaries, and binaries produced with different custom preprocessor flags.

Gradle 产生的二进制文件可以区分 构建类型平台以及 flavor。对于这里的每一个“变种维度”,它可以指定一组可用的值,并且针对每个组件使用这里的一个或多个或全部的值。例如,一个插件可以定义一系列的支持平台,但你可以选择某个特定组件只构建Windows-x86平台。
Binaries produced by Gradle can be differentiated on build type, platform and flavor. For each of these 'variant dimensions', it is possible to specify a set of available values as well as target each component at one, some or all of these. For example, a plugin may define a range of support platforms, but you may choose to only target Windows-x86 for a particular component.

54.8.1. 构建类型

54.8.1. Build types

一个 build type 确定了一个二进制文件的各种非功能性方面,比如是否包含调试信息,或者使用什么样的优化级别来编译二进制文件。典型的构建类型是“debug”和“release”,但一个project可以自由定义任意的构建类型。
A build type determines various non-functional aspects of a binary, such as whether debug information is included, or what optimisation level the binary is compiled with. Typical build types are 'debug' and 'release', but a project is free to define any set of build types.

示例 54.20. 定义构建类型 - Example 54.20. Defining build types

build.gradle

model {
    buildTypes {
        debug
        release
    }
}

如果在project中没有定义任何构建类型,那么会有一个默认的“debug”构建类型被加进去。
If no build types are defined in a project, then a single, default build type called 'debug' is added.

对于一个构建类型,Gradle project 通常会定义一组每个工具链的编译器/链接器标志。
For a build type, a Gradle project will typically define a set of compiler/linker flags per tool chain.

示例 54.21. 配置debug二进制文件 - Example 54.21. Configuring debug binaries

build.gradle

binaries.all {
    if (toolChain in Gcc && buildType == buildTypes.debug) {
        cppCompiler.args "-g"
    }
    if (toolChain in VisualCpp && buildType == buildTypes.debug) {
        cppCompiler.args '/Zi'
        cppCompiler.define 'DEBUG'
        linker.args '/DEBUG'
    }
}

在这个阶段,它就完全符合构建脚本来为每个构建类型配置相关的编译器/链接器标志。未来版本的 Gradle 将自动包括任何“debug”构建类型的适当调试标志,并且还可能知道各个优化级别。

54.8.2. 平台

54.8.2. Platform

通过为每个平台生成一个变种,能够使一个可执行文件或库构建为可以运行在不同的操作系统及CPU架构上。Gradle 把每一个系统架构组合定义为一个 Platform,一个project可以定义多个platforms。如果在project里没有定义任何平台,那么会添加一个默认的“current”平台。
An executable or library can be built to run on different operating systems and cpu architectures, with a variant being produced for each platform. Gradle defines each OS/architecture combination as a Platform, and a project may define any number of platforms. If no platforms are defined in a project, then a single, default platform 'current' is added.

目前,一个 Platform由一个定义的操作系统和架构构成。随着我们继续开发 Gradle 的本地二进制支持,将扩展Platform的概念,包括 C-runtime版本,Windows SDK,ABI,等等。复杂的构建,可能使用 Gradle 的扩展性来把附加属性应用到每个platform中,然后可以查询为一个本地二进制包含了哪些特别指定的预处理器或者是编译器参数。

示例 54.22. 定义platform - Example 54.22. Defining platforms

build.gradle

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

对于给定的变种,Gradle 将尝试查找能够构建目标平台的ToolChain。可用的工具链将按照定义的顺序进行查找。更多的细节请参阅下面的工具链部分。
For a given variant, Gradle will attempt to find a ToolChain that is able to build for the target platform. Available tool chains are searched in the order defined. See the tool chain section below for more details.

54.8.3. Flavor

54.8.3. Flavor

每个组件都可以有一组flavors,并且能为每一个flavor生成一个单独的二进制变种。在Gradle中 build typetarget platform 变种维度是有一个确定的定义的,而每一个project都可以自由地定义数量的flavor并且用任何方式去应用它们的意义。
Each component can have a set of named flavors, and a separate binary variant can be produced for each flavor. While the build type and target platform variant dimensions have a defined meaning in Gradle, each project is free to define any number of flavors and apply meaning to them in any way.

一个关于组件flavor的例子是可以区分组件的“demo”,“paid”和“enterprise”版本,它们都用同样的源码来生成不同功能的二进制文件。
An example of component flavors might differentiate between 'demo', 'paid' and 'enterprise' editions of the component, where the same set of sources is used to produce binaries with different functions.

示例 54.23. 定义flavors - Example 54.23. Defining flavors

build.gradle

model {
    flavors {
        english
        french
    }
}

libraries {
    hello {
        binaries.all {
            if (flavor == flavors.french) {
                cppCompiler.define "FRENCH"
            }
        }
        source sources.lib
    }
}

在上面的示例中,library 定义了“english”和“french”两个flavor。当编译“french”变种时,会定义一个单独的宏,以产生不同的二进制文件。
In the example above, a library is defined with a 'english' and 'french' flavor. When compiling the 'french' variant, a separate macro is defined which leads to a different binary being produced.

如果一个组件没有定义任何的flavor,那么会使用一个默认的“default”的flavor。
If no flavor is defined for a component, then a single default flavor named 'default' is used.

54.8.4. 为一个组件选择构建类型,平台和flavor

54.8.4. Selecting the build types, platforms and flavors for a component

对于一个默认的组件, Gradle会尝试为这个project所定义的每一个buildTypeplatformflavor,以及它们的每一种组合,创建一个本地二进制变种。通过指定的 targetBuildTypestargetPlatformstargetFlavors,是可以在每一个组件的基础上进行重写的。
For a default component, Gradle will attempt to create a native binary variant for each and every combination of buildType, platform and flavor defined for the project. It is possible to override this on a per-component basis, by specifying the set of targetBuildTypes, targetPlatforms and/or targetFlavors.

示例 54.24. 针对一个组件的特定平台 - Example 54.24. Targeting a component at particular platforms

build.gradle

executables {
    main {
        targetPlatforms "x86", "x64"
    }
}

在这里你可以看到 TargetedNativeComponent.targetPlatforms() 方法被用于为 executables.main选择一组平台。
Here you can see that the TargetedNativeComponent.targetPlatforms() method is used to select the set of platforms to target for executables.main.

在选择 TargetedNativeComponent.targetBuildTypes() and和TargetedNativeComponent.targetFlavors()上也有类似的机制。
A similar mechanism exists for selecting TargetedNativeComponent.targetBuildTypes() and TargetedNativeComponent.targetFlavors().

54.8.5. 构建所有可能的变种

54.8.5. Building all possible variants

当为一个组件定义了一组构建类型,目标平台,以及flavor时,将会为它们的每一种可能的组合创建一个NativeBinary 模型元素。然而,在许多情况下是不可能构建一个特定的变种的,可能的原因是某个特定的平台没有可用的工具链。
When a set of build types, target platforms, and flavors is defined for a component, a NativeBinary model element is created for every possible combination of these. However, in many cases it is not possible to build a particular variant, perhaps because no tool chain is available to build for a particular platform.

如果一个二进制变种因为某些原因不能构建,那么与之关联的NativeBinary将不会是buildable。可以用这个属性来创建一个任务,生成在某一特定计算机上所有可能的变种。
If a binary variant cannot be built for any reason, then the NativeBinary associated with that variant will not be buildable. It is possible to use this property to create a task to generate all possible variants on a particular machine.

示例 54.25. 构建所有可能的变种 - Example 54.25. Building all possible variants

build.gradle

task buildAllExecutables {
    dependsOn binaries.withType(ExecutableBinary).matching {
        it.buildable
    }
}

54.9. 工具链

54.9. Tool chains

一个构建可以使用不同的工具链来构建不同平台的变种。为此,核心的“native-binary”将尝试查找并使支持的工具链可用。不过,一个项目里的一组工具链也可以被显示地定义,允许配置额外的交叉编译器以及指定安装目录。
A single build may utilize different tool chains to build variants for different platforms. To this end, the core 'native-binary' plugins will attempt to locate and make available supported tool chains. However, the set of tool chains for a project may also be explicitly defined, allowing additional cross-compilers to be configured as well as allowing the install directories to be specified.

54.9.1. 定义工具链

54.9.1. Defining tool chains

支持的工具链类型有︰
The supported tool chain types are:

示例 54.26. 定义工具链 - Example 54.26. Defining tool chains

build.gradle

model {
    toolChains {
        visualCpp(VisualCpp) {
            // Specify the installDir if Visual Studio cannot be located by default
            // installDir "C:/Apps/Microsoft Visual Studio 10.0"
        }
        gcc(Gcc) {
            // Uncomment to use a GCC install that is not in the PATH
            // path "/usr/bin/gcc"
        }
        clang(Clang)
    }
}

每个工具链的实现都允许一定程度的配置(更多细节请参阅API文档)
Each tool chain implementation allows for a certain degree of configuration (see the API documentation for more details).

54.9.2. 使用工具链

54.9.2. Using tool chains

指定构建所使用的工具链是不必要和可能的。对于给定的变种,Gradle 将尝试查找能够构建目标平台的ToolChain。可用的工具链将按照定义的顺序进行查找。
It is not necessary or possible to specify the tool chain that should be used to build. For a given variant, Gradle will attempt to locate a ToolChain that is able to build for the target platform. Available tool chains are searched in the order defined.

当一个平台并没有定义一个架构或操作系统时,会被认为使用默认的工具链目标。所以如果一个平台没有为 operatingSystem定义一个值的话,Gradle 将会找到第一个可以用来构建这个指定 architecture的工具链。

核心 Gradle 工具链针对以下的架构能够开箱即用。在每种情况中,工具链将针对当前的操作系统。关于其他操作系统的交叉编译的信息,可以参考下一节。
The core Gradle tool chains are able to target the following architectures out of the box. In each case, the tool chain will target the current operating system. See the next section for information on cross-compiling for other operating systems.

工具链
Tool Chain
架构
Architectures
GCC x86, x86_64
Clang x86, x86_64
Visual C++ x86, x86_64, ia-64

所以对于linux上运行的GCC,支持的目标平台是“linux/x86”和“linux/x86_64”。对于通过Cygwin运行在Windows上的GCC,则支持“windows/x86”和“windows/x86_64”。(Cywgin运行时还不能模拟为Platform的一部分,但以后将会实现。)
So for GCC running on linux, the supported target platforms are 'linux/x86' and 'linux/x86_64'. For GCC running on Windows via Cygwin, platforms 'windows/x86' and 'windows/x86_64' are supported. (The Cygwin runtime is not yet modelled as part of the Platform, but will be in the future.)

如果在project里没有定义任何平台,那么所有的二进制文件会针对一个默认平台“current”进行构建。该默认平台不指定任何architectureoperatingSystem的值,因此会使用第一个可用的工具链的默认值。
If no target platforms are defined for a project, then all binaries are built to target a default platform named 'current'. This default platform does not specify any architecture or operatingSystem value, hence using the default values of the first available tool chain.

54.9.3. 使用GCC进行交叉编译

54.9.3. Cross-compiling with GCC

使用 GccClang 工具链,通过 以编程方式添加附加的目标平台的支持,是可以做到交叉编译的。它通过 PlatformConfigurableToolChain API来完成。每个添加的 TargetPlatformConfiguration 定义了对一个特定的目标平台的支持,并且提供了针对该平台所需要的额外的工具参数。
Cross-compiling is possible with the Gcc and Clang tool chains, by programmatically adding support for additional target platforms. This is done using the PlatformConfigurableToolChain API. Each added TargetPlatformConfiguration defines support for a particular target platform, and supplies additional tool arguments that are required to target this platform.

54.10. Visual Studio IDE 集成

54.10. Visual Studio IDE integration

Gradle 可以为在你的构建中定义的本地组件生成生成 Visual Studio 项目及解决方案文件。这个功能是通过 visual-studio 插件添加的。对于多项目构建,所有带有本地组件的project都应该应用这个插件。
Gradle has the ability to generate Visual Studio project and solution files for the native components defined in your build. This ability is added by the visual-studio plugin. For a multi-project build, all projects with native components should have this plugin applied.

当应用 visual-studio 插件后,会为每一个定义的组件创建一个名为 ${component.name}VisualStudio 的任务。这个任务会为所命名的组件生成一个 Visual Studio Solution 文件。这个方案包含了一个该组件的 Visual Studio Project ,并且为每一个依赖的二进制文件链接到项目文件中。
When the visual-studio plugin is applied, a task name ${component.name}VisualStudio is created for each defined component. This task will generate a Visual Studio Solution file for the named component. This solution will include a Visual Studio Project for that component, as well as linking to project files for each depended-on binary.

通过由visualStudio 提供的编程hook,可以修改所生成的visual studio文件的内容, 更详细的信息,可以参考“visual-studio”例子,或者参阅 VisualStudioExtension.getProjects()VisualStudioExtension.getSolutions()
The content of the generated visual studio files can be modified via programmatic hooks, provided by the visualStudio extension. Take a look at the 'visual-studio' sample, or see VisualStudioExtension.getProjects() and VisualStudioExtension.getSolutions() for more details.

54.11. CUnit 支持

54.11. CUnit support

Gradle cunit 插件向你的native-binary项目提供了编译及执行CUnit 测试的支持。对于在你的项目中定义的每一个 ExecutableLibrary,Gradle将创建一个匹配的 CUnitTestSuite 组件,名字为${component.name}Test
The Gradle cunit plugin provides support for compiling and executing CUnit tests in your native-binary project. For each Executable and Library defined in your project, Gradle will create a matching CUnitTestSuite component, named ${component.name}Test.

54.11.1. CUnit 源码

54.11.1. CUnit sources

Gradle将为项目中的每一个 CUnitTestSuite 组件创建一个名字为“cunit”的CSourceSet。这个源码集应包含组件源码的 cunit 测试文件。源文件可以位于约定的位置(src/${component.name}Test/cunit),或者是像其他源集一样配置到别的地方。
Gradle will create a CSourceSet named 'cunit' for each CUnitTestSuite component in the project. This source set should contain the cunit test files for the component sources. Source files can be located in the conventional location (src/${component.name}Test/cunit) or can be configured like any other source set.

初始化 CUnit 测试注册以及执行这些测试的工作,都由 Gradle 通过一些生成的 CUnit 启动器源码来执行。Gradle 将认定和调用一个void gradle_cunit_register() 函数,这个函数你可以用于配置实际的CUnit套件以及要执行的测试。
The job of initialising the CUnit test registry and executing the tests is performed by Gradle, via some generated CUnit launcher sources. Gradle will expect and call a function with the signature void gradle_cunit_register() that you can use to configure the actual CUnit suites and tests to execute.

示例 54.27. 注册 CUnit 测试 - Example 54.27. Registering CUnit tests

suite_operators.c

#include <CUnit/Basic.h>
#include "gradle_cunit_register.h"
#include "test_operators.h"

int suite_init(void) {
    return 0;
}

int suite_clean(void) {
    return 0;
}

void gradle_cunit_register() {
    CU_pSuite pSuiteMath = CU_add_suite("operator tests", suite_init, suite_clean);
    CU_add_test(pSuiteMath, "test_plus", test_plus);
    CU_add_test(pSuiteMath, "test_minus", test_minus);
}

由于这一机制,你的 CUnit 源碼可能不包含一个 main方法,因为这会与 Gradle 所提供的方法产生冲突。

54.11.2. 构建 CUnit 可执行文件

54.11.2. Building CUnit executables

一个 CUnitTestSuite 组件会有一个相关联的 ExecutableLibrary 组件。对于为main 组件配置的每一个ProjectNativeBinary,在测试套件组件上都会配置一个匹配的 TestSuiteExecutableBinary 。这些测试套件二进制文件可以以一种类似的方式配置到任何其他二进制的实例︰
A CUnitTestSuite component has an associated Executable or Library component. For each ProjectNativeBinary configured for the main component, a matching TestSuiteExecutableBinary will be configured on the test suite component. These test suite binaries can be configured in a similar way to any other binary instance:

示例 54.28. 注册 CUnit 测试 - Example 54.28. Registering CUnit tests

build.gradle

binaries.withType(TestSuiteExecutableBinary) {
    lib library: "cunit", linkage: "static"

    if (flavor == flavors.failing) {
        cCompiler.define "PLUS_BROKEN"
    }
}

由你的项目和生成的启动器提供的两种 CUnit 源码,都需要核心 CUnit 头文件和库。目前,这个库依赖项必须由你的项目为每个 TestSuiteExecutableBinary提供。

54.11.3. 运行 CUnit 测试

54.11.3. Running CUnit tests

对于每个TestSuiteExecutableBinary,Gradle 将创建一个任务来执行此二进制文件,这项任务将运行所有注册的 CUnit 测试。生成的测试结果将位于${build.dir}/test-results目录。
For each TestSuiteExecutableBinary, Gradle will create a task to execute this binary, which will run all of the registered CUnit tests. The generated test results will be located in the ${build.dir}/test-results directory.

示例 54.29. 运行 CUnit 测试 - Example 54.29. Running CUnit tests

build.gradle

apply plugin: "c"
apply plugin: "cunit"

model {
    flavors {
        passing
        failing
    }
    repositories {
        libs(PrebuiltLibraries) {
            cunit {
                headers.srcDir "lib/cunit/2.1-2/include"
                binaries.withType(StaticLibraryBinary) {
                    staticLibraryFile = file("lib/cunit/2.1-2/lib/" + findCUnitLibForPlatform(targetPlatform))
                }
            }
        }
    }
}

libraries {
    operators {}
}
binaries.withType(TestSuiteExecutableBinary) {
    lib library: "cunit", linkage: "static"

    if (flavor == flavors.failing) {
        cCompiler.define "PLUS_BROKEN"
    }
}

注意︰ 此示例的代码可以在Gradle 的 binary 或 source 分发包的samples/native-binaries/cunit中找到。。
Note: The code for this example can be found at samples/native-binaries/cunit which is in both the binary and source distributions of Gradle.


> gradle -q runFailingOperatorsTestCUnitExe

There were test failures:
  1. /home/user/gradle/samples/native-binaries/cunit/src/operatorsTest/cunit/test_plus.c:6  - plus(0, -2) == -2
  2. /home/user/gradle/samples/native-binaries/cunit/src/operatorsTest/cunit/test_plus.c:7  - plus(2, 2) == 4

:runFailingOperatorsTestCUnitExe FAILED

BUILD FAILED

Total time: 1 secs

当前对 CUnit 的支持还是相当简陋。未来的集成计划包括:
The current support for CUnit is quite rudimentary. Plans for future integration include:

  • 允许测试声明为 javadoc 风格的注解。

    Allow tests to be declared with javadoc-style annotations.

  • 改进 HTML 报告,类似于 JUnit 提供的那样。

    Improved HTML reporting, similar to that available for JUnit.

  • 测试执行的的实时反馈。

    Real-time feedback for test execution.

  • 支持另外的测试框架。

    Support for additional test frameworks.