org.gradle.nativeplatform.sourceset.GeneratedSourcesIntegrationTest.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-api Show documentation
Show all versions of gradle-api Show documentation
Gradle 6.9.1 API redistribution.
/*
* Copyright 2013 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.sourceset
import org.apache.commons.io.FileUtils
import org.gradle.ide.visualstudio.fixtures.ProjectFile
import org.gradle.ide.visualstudio.fixtures.SolutionFile
import org.gradle.nativeplatform.fixtures.AbstractInstalledToolChainIntegrationSpec
import org.gradle.nativeplatform.fixtures.RequiresInstalledToolChain
import org.gradle.nativeplatform.fixtures.app.CHelloWorldApp
import org.gradle.nativeplatform.fixtures.app.CppHelloWorldApp
import org.gradle.nativeplatform.fixtures.app.MixedLanguageHelloWorldApp
import org.gradle.nativeplatform.fixtures.app.WindowsResourceHelloWorldApp
import static org.gradle.nativeplatform.fixtures.ToolChainRequirement.VISUALCPP
// TODO: Test incremental
class GeneratedSourcesIntegrationTest extends AbstractInstalledToolChainIntegrationSpec {
def setup() {
settingsFile << "rootProject.name = 'test'"
buildFile << """
class GenerateSources extends DefaultTask {
@InputDirectory File inputDir
@OutputDirectory File sourceDir
@OutputDirectory @Optional File headerDir
@TaskAction
void processInputFiles() {
project.copy {
from inputDir
into sourceDir.parentFile
filter { String line ->
line.replaceAll('REMOVE_ME', '')
}
}
}
}
task generateCSources(type: GenerateSources) {
inputDir project.file("src/input")
headerDir project.file("build/src/generated/headers")
sourceDir project.file("build/src/generated/c")
}
"""
}
private void degenerateInputSources() {
FileUtils.listFiles(file("src/input"), null, true).each { File file ->
file.text = "REMOVE_ME\n" + file.text
}
}
def "generator task produces c sources and headers"() {
given:
def app = new CHelloWorldApp()
app.writeSources(file("src/input"))
degenerateInputSources()
when:
buildFile << """
apply plugin: 'c'
model {
components {
main(NativeExecutableSpec) {
sources {
c.generatedBy tasks.generateCSources
}
}
}
}
"""
then:
executableBuilt(app)
}
def "generator task produces sources for dependent source set with headers only"() {
given:
// Write sources to src/main, headers to src/input
def app = new CHelloWorldApp()
app.executable.writeSources(file("src/main"))
app.library.sourceFiles*.writeToDir(file("src/main"))
app.library.headerFiles*.writeToDir(file("src/input"))
degenerateInputSources()
when:
buildFile << """
apply plugin: 'c'
model {
components { comp ->
headersOnly(NativeLibrarySpec) {
sources {
c.generatedBy tasks.generateCSources
}
}
main(NativeExecutableSpec) {
sources {
c.lib \$.components.headersOnly.sources.c
}
}
}
}
"""
then:
executableBuilt(app)
}
def "generator task produces sources for dependent source set"() {
given:
def app = new CHelloWorldApp()
app.executable.writeSources(file("src/main"))
app.library.writeSources(file("src/input"))
degenerateInputSources()
when:
buildFile << """
apply plugin: 'c'
model {
components {
main(NativeExecutableSpec) {
sources {
generatedC(CSourceSet) {
generatedBy tasks.generateCSources
}
c.lib sources.generatedC
}
}
}
}
"""
then:
executableBuilt(app)
}
def "can have library composed of generated sources"() {
given:
def app = new CHelloWorldApp()
app.executable.writeSources(file("src/main"))
app.library.writeSources(file("src/input"))
degenerateInputSources()
when:
buildFile << """
apply plugin: 'c'
model {
components {
main(NativeExecutableSpec) {
sources {
c.lib library: 'hello', linkage: 'static'
}
}
hello(NativeLibrarySpec) {
sources {
c {
generatedBy tasks.generateCSources
}
}
}
}
}
"""
then:
executableBuilt(app)
}
def "can depend on header-only library composed of generated sources"() {
given:
// Write sources to src/main, headers to src/hello
def app = new CHelloWorldApp()
app.executable.writeSources(file("src/main"))
app.library.sourceFiles*.writeToDir(file("src/main"))
app.library.headerFiles*.writeToDir(file("src/input"))
degenerateInputSources()
when:
buildFile << """
apply plugin: 'c'
model {
components {
main(NativeExecutableSpec) {
sources {
c {
lib library: 'hello', linkage: 'api'
}
}
}
hello(NativeLibrarySpec) {
sources {
c {
generatedBy tasks.generateCSources
}
}
}
}
}
"""
then:
executableBuilt(app)
}
def "generator task produces cpp sources"() {
given:
def app = new CppHelloWorldApp()
app.writeSources(file("src/input"))
degenerateInputSources()
when:
buildFile << """
apply plugin: 'cpp'
task generateCppSources(type: GenerateSources) {
inputDir project.file("src/input")
headerDir project.file("build/src/generated/headers")
sourceDir project.file("build/src/generated/cpp")
}
model {
components {
main(NativeExecutableSpec) {
sources {
cpp.generatedBy tasks.generateCppSources
}
}
}
}
"""
then:
executableBuilt(app)
}
def "generator task produces assembler sources"() {
given:
def app = new MixedLanguageHelloWorldApp(AbstractInstalledToolChainIntegrationSpec.toolChain)
def asmSources = app.sourceFiles.findAll({it.path == 'asm'})
def mainSources = app.headerFiles + app.sourceFiles.findAll({it.path != 'asm'})
mainSources.removeAll {it.path == 'asm'}
mainSources*.writeToDir(file("src/main"))
asmSources*.writeToDir(file("src/input"))
degenerateInputSources()
when:
buildFile << app.pluginScript
buildFile << app.extraConfiguration
buildFile << """
task generateAsmSources(type: GenerateSources) {
inputDir project.file("src/input")
sourceDir project.file("build/src/generated/asm")
}
model {
components {
main(NativeExecutableSpec) {
sources {
asm.generatedBy tasks.generateAsmSources
}
}
}
}
"""
then:
executableBuilt(app)
}
@RequiresInstalledToolChain(VISUALCPP)
def "generator task produces windows resources"() {
given:
def app = new WindowsResourceHelloWorldApp()
def rcSources = app.sourceFiles.findAll {it.path == 'rc'}
def mainSources = app.headerFiles + app.sourceFiles - rcSources
mainSources*.writeToDir(file("src/main"))
rcSources*.writeToDir(file("src/input"))
degenerateInputSources()
when:
buildFile << app.pluginScript
buildFile << app.extraConfiguration
buildFile << """
task generateRcSources(type: GenerateSources) {
inputDir project.file("src/input")
sourceDir project.file("build/src/generated/rc")
}
model {
components {
main(NativeExecutableSpec) {
sources {
rc.generatedBy tasks.generateRcSources
}
}
}
}
"""
then:
executableBuilt(app)
}
def "produces reasonable error message when generator task does not have sourceDir property"() {
when:
buildFile << """
apply plugin: 'c'
task generateSources {
}
model {
components {
main(NativeExecutableSpec) {
sources {
c.generatedBy tasks.generateSources
}
}
}
}
"""
and:
fails "mainExecutable"
then:
failure.assertHasCause "Exception thrown while executing model rule: NativeComponentModelPlugin.Rules#configureGeneratedSourceSets"
failure.assertHasCause "Could not get unknown property 'sourceDir' for task ':generateSources' of type org.gradle.api.DefaultTask."
}
def "can explicitly configure source and header directories from generator task"() {
given:
def app = new CHelloWorldApp()
app.writeSources(file("src/input"))
degenerateInputSources()
when:
buildFile << """
apply plugin: 'c'
model {
components {
main(NativeExecutableSpec) {
sources {
c {
builtBy tasks.generateCSources
source {
srcDirs tasks.generateCSources.sourceDir
}
exportedHeaders {
srcDirs tasks.generateCSources.headerDir
}
}
}
}
}
}
"""
then:
executableBuilt(app)
}
def "can configure generator task properties after wiring"() {
given:
def app = new CHelloWorldApp()
app.writeSources(file("src/input"))
degenerateInputSources()
when:
buildFile << """
apply plugin: 'c'
task lateConfiguredGenerator(type: GenerateSources)
model {
components {
main(NativeExecutableSpec) {
sources {
c.generatedBy tasks.lateConfiguredGenerator
}
}
}
}
lateConfiguredGenerator {
inputDir project.file("src/input")
headerDir project.file("build/src/generated/headers")
sourceDir project.file("build/src/generated/c")
}
"""
then:
executableBuilt(app)
}
def "creates visual studio project including generated sources"() {
given:
def app = new CHelloWorldApp()
app.writeSources(file("src/input"))
degenerateInputSources()
and:
buildFile << """
apply plugin: 'visual-studio'
apply plugin: 'c'
model {
components {
main(NativeExecutableSpec) {
sources {
c.generatedBy tasks.generateCSources
}
}
}
}
"""
when:
succeeds "mainVisualStudio"
then:
final mainSolution = new SolutionFile(file("mainExe.sln"))
mainSolution.assertHasProjects("mainExe")
and:
final projectFile = new ProjectFile(file("mainExe.vcxproj"))
projectFile.sourceFiles as Set == [
"build.gradle",
"build/src/generated/c/hello.c",
"build/src/generated/c/main.c",
"build/src/generated/c/sum.c"
] as Set
projectFile.headerFiles.sort() == [ "build/src/generated/headers/common.h", "build/src/generated/headers/hello.h" ]
projectFile.projectConfigurations.keySet() == ['debug'] as Set
with (projectFile.projectConfigurations['debug']) {
// TODO - should not include the default location
includePath == "src/main/headers;build/src/generated/headers"
}
}
def executableBuilt(def app) {
succeeds "mainExecutable"
assert executable("build/exe/main/main").exec().out == app.englishOutput
true
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy