Gradle 1.12用户指南翻译——第五十四章. 构建原生二进制文件

其他章节的翻译请参见:
http://blog.csdn.net/column/details/gradle-translation.html
翻译项目请关注Github上的地址:
https://github.com/msdx/gradledoc
本文翻译所在分支:
https://github.com/msdx/gradledoc/tree/1.12。
直接浏览双语版的文档请访问:
http://gradledoc.qiniudn.com/1.12/userguide/userguide.html。
另外,Android 手机用户可通过我写的一个程序浏览文档,带缓存功能的,目前0.5版本兼容 Android 2.3以上系统,项目地址如下:
https://github.com/msdx/gradle-doc-apk
翻译不易,转载请注明本文在CSDN博客上的出处:
http://blog.csdn.net/maosidiaoxian/article/details/55683474

关于我对Gradle的翻译,以Github上的项目及http://gradledoc.qiniudn.com 上的文档为准。如发现翻译有误的地方,将首先在以上两个地方更新。因时间精力问题,博客中发表的译文基本不会同步修改。

另外,目前Gradle1.12版本的文档进入校稿阶段,校稿的方式可以为到该项目https://github.com/msdx/gradledoc 提交issue或是pull request。校稿的结果不只是在此版本更新,也会用于改善Gradle下一版本(2.0)文档的翻译。


第五十四章. 构建原生二进制文件

Gradle 对构建原生二进制文件的支持目前还是孵化阶段。请务必注意,在以后的 Gradle 版本中,相关的 DSL 和其他配置可能会有所改变。

不同的原生二进制插件添加了对从C++,C,Objective-C,Objective-C++以及汇编源文件构建原生软件组件的支持。虽然对于这种软件开发的空间,已经有许多优秀的构建工具存在,但是Gradle 向开发人员提供的是它的强大特征和灵活性,以及在依赖管理实践上,在JVM开发空间上更为传统的发现。

54.1. 工具链支持

Gradle 提供了使用不同的工具链执行相同的构建的能力。你可以通过更改操作系统的PATH让其包含所需的工具链编译器,来控制使用哪个工具链。或者,你可以直接配置工具链,就如下面的“原生二进制变种”中描述的。

支持以下的工具链:

操作系统工具链备注
LinuxGCC 
LinuxClang 
Mac OS XGCC使用 XCode 中的 GCC。
Mac OS XClang使用 XCode 中的 Clang。
WindowsVisual C++Windows XP及以上,Visual C++ 2010 及以上版本。
WindowsGCCWindows XP及以上,使用Cygwin的GCC。
WindowsMinGWWindows XP 及以上。

54.2. 组件模型

一个原生二进制project定义了一组ExecutableLibrary组件,每一个的 Gradle 都映射大量的NativeBinary输出。对于每个定义的executablelibrary,Gradle 添加了具有相同名称的FunctionalSourceSet 。这些功能源码集将为project所支持的每一种语言包含指定语言的源码集。

为构建一个静态或共享的原生库二进制文件,一个Library组件将添加到libraries容器中。每个library组件可以产生至少一个SharedLibraryBinary和至少一个StaticLibraryBinary

示例 54.1. 定义一个库组件

build.gradle

libraries {hello {}
}

为构建一个可执行的二进制,Executable组件添加到executables容器中,并与源码集相关联。

示例 54.2. 定义可执行组件

build.gradle

executables {main {}
}

在许多情况下,一个组件可以产生超过一个的原生二进制文件。基于构建所使用的工具链,提供的编译器/链接器标志,提供的依赖或其他源文件,这些二进制文件可能会发生变化。组件所产生的每个原生二进制称为variant。下面将详细讨论二进制 variant。

54.3. 任务

针对由构建所产生的每一个 NativeBinary,我们构造了一个生命周期任务用于创建二进制,以及一系统的其他做实际工作,如编译,链接或者是装配二进制文件的任务。

组件类型原生二进制文件类型生命周期任务创建二进制文件的位置
ExecutableExecutableBinary$component.nameExecutable$buildDir/binaries/$binary.name/$component.name
LibrarySharedLibraryBinary$component.nameSharedLibrary$buildDir/binaries/$binary.name/lib$component.name.so
LibraryStaticLibraryBinary$component.nameStaticLibrary$buildDir/binaries/$binary.name/$component.name.a

54.3.1. 使用共享库

对于每个产生的可执行二进制文件, cpp插件提供了install${binary.name}任务,这个任务可以创建该可执行文件及它需要的共享库的开发安装。它允许你运行可执行文件,而无需在其最终的位置安装共享库。

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

目前,Gradle 支持从C++,C,Assembler,Objective-C 和 Objective-C++源码的任意组合中构建原生二进制文件。一个原生二进制project 将包含一个或多个叫做FunctionalSourceSet的实例(如"main","test"等),其中每一个都可以包含含有C++,C,Assembler,Objective-C或Objective-C++源代码的LanguageSourceSets。

54.4.1. C++ 源代码

'cpp' 插件提供了C++ 语言的支持。

示例 54.3. cpp 插件

build.gradle

apply plugin: 'cpp'

把 C++ 源码包含到原生二进制文件中,是通过一个 CppSourceSet来实现的,它定义了一个C++源文件集以及(可选的)一个可导出的头文件(用于library)集默认情况下,对于任何命名的组件,CppSourceSet包含了在src/${name}/cpp中的.cpp源文件,和在src/${name}/headers中的头文件。

cpp插件为每个CppSourceSet定义了这些默认的位置,且可以扩展或重写这些默认值使能够成为不同的项目布局。

示例 54.4. C++ 源代码集

build.gradle

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

对于名字为“main”的library, src/main/headers中的文件都被视为"公共"或"导出"的头文件。不应该被导出(而是内部使用)的头文件,应该放在 src/main/cpp 目录(不过要注意,这样的文件应该总是以相对于包含它们的文件这样的一种方式被引用)。

54.4.2. C 源代码

'c' 插件提供了C 语言的支持。

示例 54.5. “C” 插件

build.gradle

apply plugin: 'c'

把 C 源码包含到原生二进制文件中,是通过一个 CSourceSet来实现的,它定义了一个C源文件集以及(可选的)一个可导出的头文件(用于library)集默认情况下,对于任何命名的组件,CSourceSet包含了在src/${name}/c中的.c源文件,和在src/${name}/headers中的头文件。

c插件为每个CSourceSet定义了这些默认的位置,且可以扩展或重写这些默认值使能够成为不同的项目布局。

示例 54.4. C 源代码集

build.gradle

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

对于名字为“main”的library, src/main/headers中的文件都被视为"公共"或"导出"的头文件。不应该被导出(而是内部使用)的头文件,应该放在 src/main/c 目录(不过要注意,这样的文件应该总是以相对于包含它们的文件这样一种方式被引用)。

54.4.3. 汇编代码

“assembler” 插件提供了汇编语言的支持。

示例 54.3. assembler 插件

build.gradle

apply plugin: 'assembler'

把汇编源码包含到原生二进制文件中,是通过一个 AssemblerSourceSet来实现的,它定义了一个汇编源文件集。默认情况下,对于任何命名的组件,AssemblerSourceSet包含了在src/${name}/asm中的.s源文件。

54.4.4. Objective-C 源码

'objective-c' 插件提供了Objective-C 语言的支持。

示例 54.8. “objective-c”插件

build.gradle

apply plugin: 'objective-c'

把Objective-C源码包含到原生二进制文件中,是通过一个 ObjectiveCSourceSet来实现的,它定义了一个Objective-C源文件集。默认情况下,对于任何命名的组件,ObjectiveCSourceSet包含了在src/${name}/objectiveC中的.m源文件。

54.4.5. Objective-C++ 源码

'objective-cpp' 插件提供了Objective-C++ 语言的支持。

示例 54.9. “objective-cpp” 插件

build.gradle

apply plugin: 'objective-cpp'

把Objective-C++源码包含到原生二进制文件中,是通过一个 ObjectiveCppSourceSet来实现的,它定义了一个Objective-C++源文件集。默认情况下,对于任何命名的组件,ObjectiveCppSourceSet包含了在src/${name}/objectiveCpp中的.mm源文件。

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

每一个产生的二进制文件都和一系列的编译器和链接器设置相关联,这些设置包含了命令行参数,以及宏定义。这些设置可以应用于所有的二进制文件,单个二进制文件,或选择性地应用于基于某些条件的一组二进制文件。

示例 54.10. 应用于所有二进制文件的设置

build.gradle

binaries.all {// Define a preprocessor macro for every binarycppCompiler.define "NDEBUG"// Define toolchain-specific compiler and linker optionsif (toolChain in Gcc) {cppCompiler.args "-O2", "-fno-access-control"linker.args "-Xlinker", "-S"}if (toolChain in VisualCpp) {cppCompiler.args "/Zi"linker.args "/DEBUG"}
}

每个二进制文件与特定的ToolChain关联,允许设置基于此值进行针对性的配置。

让设置应用于指定类型的所有二进制文件很简单:

示例 54.11. 应用于所有共享库的设置

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"}
}

此外,还可以指定设置应用于某个特定的executable 或 library 组件 产生的所有二进制文件:

示例 54.12. 应用于“main”可执行组件所产生的所有二进制文件的设置

build.gradle

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

上面的例子将会把提供的配置应用到所有构建的 executable二进制文件。

同样,也可以为某种特定类型的组件,把设置指向目标二进制文件:例如所有main library组件的shared libraries

示例 54.13. 仅应用于“main”library组件所产生的共享库的设置

build.gradle

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

54.6. Windows Resource

当使用VisualCpp工具链时,Gradle 时能够编译Window Resource (rc) 文件并将它们链接到本地的二进制文件。这个功能是由'windows-resources' 插件所提供的。

示例 54.14. 'windows-resources' 插件

build.gradle

apply plugin: 'windows-resources'

将 Windows 资源包含进本机二进制文件中,是通过一个WindowsResourceSet提供的,它定义了一组Windows Resource源文件。默认情况下,WindowsResourceSet为所有的命名组件包含了在src/${name}/rc下的.rc源文件。

与其他源文件类型一样,您可以配置把windows 资源的位置包含进二进制文件中。

示例 54.15. 配置 Windows 资源源文件的位置

build-resource-only-dll.gradle

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

你能够通过提供没有任何其他语言来源的 Windows Resource 源文件,来构造纯资源库,并适当地配置链接器︰

示例 54.16. 构建一个纯资源 dll

build-resource-only-dll.gradle

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

上面的示例还演示了将额外的命令行参数传递给资源编译器的机制。rcCompiler扩展是PreprocessingTool类型。

54.7. 库依赖

C++ 项目的依赖是导出头文件的二进制库。这些头文件在编译期间使用,而编译的二进制依赖则在链接过程中使用。

54.7.1. 同一项目的依赖

一组源文件可能依赖于在同一个项目中由另一个二进制组件提供的头文件。一个常见的例子是一个本地可执行组件,使用了由一个单独的本地库组件提供的功能。

这样的库依赖可以很方便地提供给source set关联上executable组件。

示例 54.17. 向source set提供库依赖

build.gradle

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

另外,一个库依赖项可以直接提供给ExecutableBinaryexecutable

示例 54.18. 向二进制文件提供库依赖

build.gradle

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

54.7.2. 项目依赖

对于在不同的 Gradle 项目产生的组件,notation是类似的。

示例 54.19. 定义项目依赖

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. 本地二进制变种

对于每个定义的可执行文件或库,Gradle 能够构建多个不同的本机二进制变种。这样的例子包括debug及release的二进制文件,32位及64位的二进制文件,以及使用不同的自定义预处理标志生成的二进制文件。

Gradle 产生的二进制文件可以区分 构建类型, 平台以及 flavor。对于这里的每一个“变种维度”,它可以指定一组可用的值,并且针对每个组件使用这里的一个或多个或全部的值。例如,一个插件可以定义一系列的支持平台,但你可以选择某个特定组件只构建Windows-x86平台。

54.8.1. 构建类型

一个 build type 确定了一个二进制文件的各种非功能性方面,比如是否包含调试信息,或者使用什么样的优化级别来编译二进制文件。典型的构建类型是“debug”和“release”,但一个project可以自由定义任意的构建类型。

示例 54.20. 定义构建类型

build.gradle

model {buildTypes {debugrelease}
}

如果在project中没有定义任何构建类型,那么会有一个默认的“debug”构建类型被加进去。

对于一个构建类型,Gradle project 通常会定义一组每个工具链的编译器/链接器标志。

示例 54.21. 配置debug二进制文件

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. 平台

通过为每个平台生成一个变种,能够使一个可执行文件或库构建为可以运行在不同的操作系统及CPU架构上。Gradle 把每一个系统架构组合定义为一个 Platform,一个project可以定义多个platforms。如果在project里没有定义任何平台,那么会添加一个默认的“current”平台。

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

示例 54.22. 定义platform

build.gradle

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

对于给定的变种,Gradle 将尝试查找能够构建目标平台的ToolChain。可用的工具链将按照定义的顺序进行查找。更多的细节请参阅下面的工具链部分。

54.8.3. Flavor

每个组件都可以有一组flavors,并且能为每一个flavor生成一个单独的二进制变种。在Gradle中 build type 和 target platform 变种维度是有一个确定的定义的,而每一个project都可以自由地定义数量的flavor并且用任何方式去应用它们的意义。

一个关于组件flavor的例子是可以区分组件的“demo”,“paid”和“enterprise”版本,它们都用同样的源码来生成不同功能的二进制文件。

示例 54.23. 定义flavors

build.gradle

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

在上面的示例中,library 定义了“english”和“french”两个flavor。当编译“french”变种时,会定义一个单独的宏,以产生不同的二进制文件。

如果一个组件没有定义任何的flavor,那么会使用一个默认的“default”的flavor。

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

对于一个默认的组件, Gradle会尝试为这个project所定义的每一个buildType, platform 和 flavor,以及它们的每一种组合,创建一个本地二进制变种。通过指定的 targetBuildTypes, targetPlatforms 或 targetFlavors,是可以在每一个组件的基础上进行重写的。

示例 54.24. 针对一个组件的特定平台

build.gradle

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

在这里你可以看到 TargetedNativeComponent.targetPlatforms() 方法被用于为 executables.main选择一组平台。

在选择 TargetedNativeComponent.targetBuildTypes() and和TargetedNativeComponent.targetFlavors()上也有类似的机制。

54.8.5. 构建所有可能的变种

当为一个组件定义了一组构建类型,目标平台,以及flavor时,将会为它们的每一种可能的组合创建一个NativeBinary 模型元素。然而,在许多情况下是不可能构建一个特定的变种的,可能的原因是某个特定的平台没有可用的工具链。

如果一个二进制变种因为某些原因不能构建,那么与之关联的NativeBinary将不会是buildable。可以用这个属性来创建一个任务,生成在某一特定计算机上所有可能的变种。

示例 54.25. 构建所有可能的变种

build.gradle

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

54.9. 工具链

一个构建可以使用不同的工具链来构建不同平台的变种。为此,核心的“native-binary”将尝试查找并使支持的工具链可用。不过,一个项目里的一组工具链也可以被显示地定义,允许配置额外的交叉编译器以及指定安装目录。

54.9.1. 定义工具链

支持的工具链类型有︰

  • Gcc

  • Clang

  • VisualCpp

示例 54.26. 定义工具链

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文档)

54.9.2. 使用工具链

指定构建所使用的工具链是不必要和可能的。对于给定的变种,Gradle 将尝试查找能够构建目标平台的ToolChain。可用的工具链将按照定义的顺序进行查找。

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

核心 Gradle 工具链针对以下的架构能够开箱即用。在每种情况中,工具链将针对当前的操作系统。关于其他操作系统的交叉编译的信息,可以参考下一节。

工具链架构
GCCx86, x86_64
Clangx86, 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的一部分,但以后将会实现。)

如果在project里没有定义任何平台,那么所有的二进制文件会针对一个默认平台“current”进行构建。该默认平台不指定任何architectureoperatingSystem的值,因此会使用第一个可用的工具链的默认值。

54.9.3. 使用GCC进行交叉编译

使用 Gcc 和 Clang 工具链,通过 以编程方式添加附加的目标平台的支持,是可以做到交叉编译的。它通过 PlatformConfigurableToolChain API来完成。每个添加的 TargetPlatformConfiguration 定义了对一个特定的目标平台的支持,并且提供了针对该平台所需要的额外的工具参数。

54.10. Visual Studio IDE 集成

Gradle 可以为在你的构建中定义的本地组件生成生成 Visual Studio 项目及解决方案文件。这个功能是通过 visual-studio 插件添加的。对于多项目构建,所有带有本地组件的project都应该应用这个插件。

当应用 visual-studio 插件后,会为每一个定义的组件创建一个名为 ${component.name}VisualStudio 的任务。这个任务会为所命名的组件生成一个 Visual Studio Solution 文件。这个方案包含了一个该组件的 Visual Studio Project ,并且为每一个依赖的二进制文件链接到项目文件中。

通过由visualStudio 提供的编程hook,可以修改所生成的visual studio文件的内容, 更详细的信息,可以参考“visual-studio”例子,或者参阅 VisualStudioExtension.getProjects() 及 VisualStudioExtension.getSolutions() 。

54.11. CUnit 支持

Gradle cunit 插件向你的native-binary项目提供了编译及执行CUnit 测试的支持。对于在你的项目中定义的每一个 Executable 和 Library,Gradle将创建一个匹配的 CUnitTestSuite 组件,名字为${component.name}Test

54.11.1. CUnit 源码

Gradle将为项目中的每一个 CUnitTestSuite 组件创建一个名字为“cunit”的CSourceSet。这个源码集应包含组件源码的 cunit 测试文件。源文件可以位于约定的位置(src/${component.name}Test/cunit),或者是像其他源集一样配置到别的地方。

初始化 CUnit 测试注册以及执行这些测试的工作,都由 Gradle 通过一些生成的 CUnit 启动器源码来执行。Gradle 将认定和调用一个void gradle_cunit_register() 函数,这个函数你可以用于配置实际的CUnit套件以及要执行的测试。

示例 54.27. 注册 CUnit 测试

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 可执行文件

一个 CUnitTestSuite 组件会有一个相关联的 Executable 或 Library 组件。对于为main 组件配置的每一个ProjectNativeBinary,在测试套件组件上都会配置一个匹配的 TestSuiteExecutableBinary 。这些测试套件二进制文件可以以一种类似的方式配置到任何其他二进制的实例︰

示例 54.28. 注册 CUnit 测试

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 测试

对于每个TestSuiteExecutableBinary,Gradle 将创建一个任务来执行此二进制文件,这项任务将运行所有注册的 CUnit 测试。生成的测试结果将位于${build.dir}/test-results目录。

示例 54.29. 运行 CUnit 测试

build.gradle

apply plugin: "c"
apply plugin: "cunit"model {flavors {passingfailing}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中找到。。

> gradle -q runFailingOperatorsTestCUnitExeThere were test failures:1. /home/user/gradle/samples/native-binaries/cunit/src/operatorsTest/cunit/test_plus.c:6  - plus(0, -2) == -22. /home/user/gradle/samples/native-binaries/cunit/src/operatorsTest/cunit/test_plus.c:7  - plus(2, 2) == 4:runFailingOperatorsTestCUnitExe FAILEDBUILD FAILEDTotal time: 1 secs

当前对 CUnit 的支持还是相当简陋。未来的集成计划包括:

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

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

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

  • 支持另外的测试框架。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/282816.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android 调用c wcf服务,如何使用命名管道从c调用WCF方法?

更新&#xff1a;通过协议here,我无法弄清楚未知的信封记录.我在网上找不到任何例子.原版的&#xff1a;我有以下WCF服务static void Main(string[] args){var inst new PlusFiver();using (ServiceHost host new ServiceHost(inst,new Uri[] { new Uri("net.pipe://loc…

VK Cup 2015 - Qualification Round 1 A. Reposts(树)

传送门 Description One day Polycarp published a funny picture in a social network making a poll about the color of his handle. Many of his friends started reposting Polycarps joke to their news feed. Some of them reposted the reposts and so on. These event…

Lombok@Builder和@NoArgsConstructor冲突

问题 今天在使用lombok简化model类时。使用Builder建造者模式。报以下异常 解决办法。 去掉NoArgsConstructor添加AllArgsConstructor源码分析 下图是编译后的源码 只使用Builder会自动创建全参构造器。而添加上NoArgsConstructor后就不会自动产生全参构造器

现在商业有种竞争叫“跨界打击”

随着互联网的发展&#xff0c;“跨界打击”的事情可谓是无处不在。行业跨界打击会抢占某个行业的市场份额&#xff0c;甚至可能淘汰一个行业。跨界打击者可能是某个行业的新进入者&#xff0c;也可能是现有竞争者&#xff0c;更可能是彻底的替代者或颠覆者。跨界打击&#xff0…

架构之美阅读笔记之一

寒假生活开始了&#xff0c;关于软件架构这部分的学习&#xff0c;我选择的是《架构之美》这本书。这本出版于2009年的书&#xff0c;由浅入深地讲述了从架构的概述&#xff0c;到企业级应用架构&#xff0c;系统架构&#xff0c;最终用户应用架构&#xff0c;再到语言与架构模…

ntop linux,Linux下开源监控软件Ntop的性能提升方案

摘要&#xff1a;Ntop是一款Linux下常见的开源监控软件&#xff0c;它可以监测的数据包括&#xff1a;网络流量、使用协议、系统负载、端口情况、数据包发送时间等。正常情况下它工作的时候就像一部被动声纳&#xff0c;默默的接收看来自网络的各种信息&#xff0c;通过对这些数…

Java异常处理教程

异常是在没有定义正常执行路径时在Java程序的执行期间可能出现的条件。Java通过将执行操作的代码与处理错误的代码分离来处理错误。 当发生异常时&#xff0c;Java会创建一个包含有关异常的所有信息的对象&#xff0c;并将其传递给相应的异常处理代码。有关异常的信息包括异常的…

性能优化8--内存泄露

一.根源&#xff1a; 内存泄露简单说就是已经没有用的资源&#xff0c;但是由于被其他资源引用着无法被GC销毁。 二.内存泄露常见场景 1.单例导致内存泄露 单例的静态特性使得它的生命周期同应用的生命周期一样长&#xff0c;如果一个对象已经没有用处了&#xff0c;但是单例还…

那些年,登山徒步记录,立贴

2018年1月-9月份暂无数据。&#xff08;惨无人道&#xff0c;已经丧失了自我。&#xff09; 10月份2017年2月份02月12日 25.00KM 牛木外线3月份暂无数据。 4月份1.04月09日 16.00KM 火凤线 5月份1.05月06日 20.00KM 渔帽线&#xff08;第一机耕路&#xff09; 6月份1.06月11日 …

记一次 .NET 某打印服务 非托管内存泄漏

一&#xff1a;背景 1. 讲故事前段时间有位朋友在微信上找到我&#xff0c;说他的程序出现了内存泄漏&#xff0c;能不能帮他看一下&#xff0c;这个问题还是比较经典的&#xff0c;加上好久没上非托管方面的东西了&#xff0c;这篇就和大家分享一下&#xff0c;话不多说&#…

android静态方法如何测试,android – 如何使用mock()和spy()测试静态方法

通常情况下,如果你最终使用PowerMock,这是一个很好的迹象,表明你最有可能是错误的方式.如果不是直接引用毕加索,而是创建一个组件,它的职责是加载图像,让我们说类ImageLoader.这会给你什么&#xff1f;>关注点分离&#xff1a;如果明天你决定转移到Glide,你不应该改变你使用…

mysql经典的8小时问题-wait_timeout

2019独角兽企业重金招聘Python工程师标准>>> 前段时间 现网突然频繁报出 连接不上数据库&#xff0c;偶滴的妖孽&#xff0c;其他地方都是用mysql&#xff0c;也没遇到这个问题呀。 java.io.EOFExceptionat at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:1913…

Chrome DevTools — Network

记录网络请求 默认情况下&#xff0c;只要DevTools在开启状态&#xff0c;DevTools会记录所有的网络请求&#xff0c;当然&#xff0c;记录都是在Network面板展示的。 停止记录网络请求 点击Stop recording network log红色图标&#xff0c;当它变为灰色时&#xff0c;表示DevT…

Blazor University 中文版网站已上线

在学习 Blazor 的过程中&#xff0c;找到了一个网站 Blazor University&#xff08;https://blazor-university.com&#xff09;。发现网站内容非常详实&#xff0c;正像首页所说的&#xff1a;通过浏览本网站中的信息&#xff0c;我打算带您从完全的新手到Blazor的所有方面的专…

android:paddingtop 百分比,相对层中的百分比宽度

相对层中的百分比宽度我正在为登录进行表单布局。Activity在我的Android应用程序中。下面的图片是我希望它看起来的样子&#xff1a;我能够通过以下方式实现这个布局XML..问题是&#xff0c;这有点麻烦。我不得不对主机EditText的宽度进行硬编码。具体而言&#xff0c;我必须具…

MySQL 查看表结构简单命令

一、简单描述表结构&#xff0c;字段类型 desc tabl_name; 显示表结构&#xff0c;字段类型&#xff0c;主键&#xff0c;是否为空等属性&#xff0c;但不显示外键。 例如&#xff1a;desc table_name 二、查询表中列的注释信息 select * from information_schema.columns wher…

简单获取任意app的URL Schemes

简单说明 最近业务需要&#xff0c;一直在查询App的scheme相关信息&#xff0c;找到一种比较可靠的方法&#xff0c;分享给大家 步骤如下&#xff1a; 在电脑上使用iTunes下载那个app下载完后&#xff0c;在itunes里点击这个app&#xff0c;选择->Show in Finder&#xff0c…

Java中short、int、long、float、double的取值范围

一、基本数据类型的特点&#xff0c;位数&#xff0c;最大值和最小值。1、基本类型&#xff1a;short 二进制位数&#xff1a;16 包装类&#xff1a;java.lang.Short 最小值&#xff1a;Short.MIN_VALUE-32768 &#xff08;-2的15此方&#xff09;最大值&#xff1a;Short.MAX_…

.Net之接口文档精度丢失处理

目的最近两天在给朋友讲解如何使用ajax调用接口时候&#xff0c;我发现我用swagger调用接口返回的long类型的数据最后几位都变成了0(例如&#xff1a;6974150586715898000)&#xff0c;本来是以为sqlite数据库不支持long类型导致我存进去的数据出了问题&#xff0c;然后我使用接…

android 访问sqlite,android中访问已有的sqlite数据库

推荐文章每天进步记录一点点话说经常性的操作svn出现各种问题,而度娘一直帮倒忙,是不是很手足无措.有时问题还是要记录下来的.说不定还会有惊喜. 昨天遇到个问题,搜索了一下,发现第一条就是自己写的.惊呆我了,更惊呆我的是,我是在csdn写的,为什么在别的网站看到,完全一模一样..…