Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for C++ source compatibility #8055

Closed
wants to merge 29 commits into from
Closed
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
73d01bf
Add CppSourceCompatibility enum
k-mack Nov 30, 2018
2621cb7
Add src compat property to CppComponent & CppCompile
k-mack Nov 30, 2018
05e5ee5
Rename enum
k-mack Dec 5, 2018
0f6ab15
Initial logic to determine std arg for gcc & clang
k-mack Dec 5, 2018
af3defb
Initial logic to wire DSL to CppCompile
k-mack Dec 5, 2018
d882753
Revert rename enum
k-mack Dec 12, 2018
941de7b
Toolchain must support src compat or throw IAE
k-mack Dec 12, 2018
0e36118
Use default src compat when toolchain is selected
k-mack Dec 12, 2018
46cb79c
Add compiler type & version to GCC arg transformer
k-mack Dec 13, 2018
8634ff9
Fix compiler errors
k-mack Dec 15, 2018
d2bf3ea
Add config src compat in compile task
k-mack Dec 15, 2018
151ff04
Fix compiler errors
k-mack Dec 15, 2018
e91a9bc
Add test for clang src compat
k-mack Dec 15, 2018
d037d98
Add integ tests that use sourceCompatibility
k-mack Dec 15, 2018
de5f935
Add test for gcc source compatibility & fix bug
k-mack Dec 17, 2018
1f808f9
Add more clang source compatibility tests
k-mack Dec 17, 2018
d353dbc
Add test for recompile when src compat changes
k-mack Dec 17, 2018
870036c
Bump newly introduced public APIs to 5.2
k-mack Dec 17, 2018
d7ccc95
Split test
k-mack Dec 29, 2018
1c526c2
Move common cpp app & lib tests to parent test spec
k-mack Dec 29, 2018
f35fe90
Rename vars of type CppSourceCompatibilities to sourceCompatibility
k-mack Dec 29, 2018
eac78d8
Do not inject objectfactory into task constructor
k-mack Dec 29, 2018
812ba28
Add test coverage for source compatibility not set on CppCompile task
k-mack Dec 29, 2018
239c7da
Fix clang's default C++ dialect based on version
k-mack Dec 30, 2018
56aea47
Fix gcc's default C++ dialect to GNU extensions
k-mack Dec 30, 2018
d1ddc5a
Avoid abbreviating IllegalArgumentException
k-mack Dec 30, 2018
dabba6e
Remove compiler specifics in CppSourceCompatibility javadocs
k-mack Dec 30, 2018
f29346b
Support applying default source compatibility for VS on a cpp binary
k-mack Dec 30, 2018
1955d51
Configure source compatibility at component level in tests
k-mack Dec 30, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -26,6 +26,7 @@ import org.gradle.nativeplatform.fixtures.app.CppAppWithLibraryAndOptionalFeatur
import org.gradle.nativeplatform.fixtures.app.CppAppWithOptionalFeature
import org.gradle.nativeplatform.fixtures.app.CppCompilerDetectingTestApp
import org.gradle.nativeplatform.fixtures.app.SourceElement
import spock.lang.Unroll

import static org.gradle.util.Matchers.containsText

Expand Down Expand Up @@ -1033,4 +1034,85 @@ class CppApplicationIntegrationTest extends AbstractCppIntegrationTest implement
executable("build/exe/main/debug/app").assertExists()
installation("build/install/main/debug").exec().out == app.expectedOutput(toolChain)
}

@RequiresInstalledToolChain(ToolChainRequirement.GCC_COMPATIBLE)
@Unroll
def "build fails when cpp source uses language features outside the requested source compatibility"() {
k-mack marked this conversation as resolved.
Show resolved Hide resolved
given:
buildFile << """
apply plugin: 'cpp-application'

application {
binaries.configureEach {
sourceCompatibility = CppSourceCompatibility.${sourceCompatibility}
}
}
"""

and:
file("src/main/cpp/cpp11.cpp") << """
#include <iostream>
#include <ctime>
#include <chrono>
int main () {
using namespace std::chrono;
system_clock::time_point today = system_clock::now();
time_t tt;
tt = system_clock::to_time_t ( today );
std::cout << "today is: " << ctime(&tt);
return 0;
}
"""

expect:
if (shouldFail) {
k-mack marked this conversation as resolved.
Show resolved Hide resolved
fails "assemble"
failure.assertHasDescription("Execution failed for task ':compileDebugCpp'.")
failure.assertHasCause("A build operation failed.")
failure.assertThatCause(containsText("C++ compiler failed while compiling cpp11.cpp"))
} else {
succeeds "assemble"
}

where:
sourceCompatibility || shouldFail
'Cpp11' || false
'Cpp98' || true
}

@RequiresInstalledToolChain(ToolChainRequirement.GCC_COMPATIBLE)
def "recompile when source compatibility changes"() {
k-mack marked this conversation as resolved.
Show resolved Hide resolved
k-mack marked this conversation as resolved.
Show resolved Hide resolved
when:
buildFile << """
apply plugin: 'cpp-application'

application {
binaries.configureEach {
sourceCompatibility = CppSourceCompatibility.Cpp98
k-mack marked this conversation as resolved.
Show resolved Hide resolved
}
}
"""

and:
file("src/main/cpp/main.cpp") << """
int main () {
return 0;
}
"""

then:
succeeds "assemble"

when:
buildFile << """
application {
binaries.configureEach {
sourceCompatibility = CppSourceCompatibility.Cpp11
}
}
"""

then:
executedAndNotSkipped(":assemble")
}
}
Expand Up @@ -24,6 +24,7 @@ import org.gradle.nativeplatform.fixtures.app.CppGreeterWithOptionalFeature
import org.gradle.nativeplatform.fixtures.app.CppLib
import org.gradle.nativeplatform.fixtures.app.SourceElement
import org.hamcrest.Matchers
import spock.lang.Unroll

import static org.gradle.util.Matchers.containsText

Expand Down Expand Up @@ -569,4 +570,49 @@ project(':greeter') {
result.assertTasksExecuted(tasks.debug.allToLink, ":assemble")
sharedLibrary("build/lib/main/debug/hello").assertExists()
}

@RequiresInstalledToolChain(ToolChainRequirement.GCC_COMPATIBLE)
@Unroll
def "build fails when cpp source uses language features outside the requested source compatibility"() {
k-mack marked this conversation as resolved.
Show resolved Hide resolved
given:
buildFile << """
apply plugin: 'cpp-library'

library {
binaries.configureEach {
sourceCompatibility = CppSourceCompatibility.${sourceCompatibility}
}
}
"""

and:
file("src/main/cpp/cpp11.cpp") << """
#include <iostream>
#include <ctime>
#include <chrono>
int main () {
using namespace std::chrono;
system_clock::time_point today = system_clock::now();
time_t tt;
tt = system_clock::to_time_t ( today );
std::cout << "today is: " << ctime(&tt);
return 0;
}
"""

expect:
if (shouldFail) {
fails "assemble"
failure.assertHasDescription("Execution failed for task ':compileDebugCpp'.")
failure.assertHasCause("A build operation failed.")
failure.assertThatCause(containsText("C++ compiler failed while compiling cpp11.cpp"))
} else {
succeeds "assemble"
}

where:
sourceCompatibility || shouldFail
'Cpp11' || false
'Cpp98' || true
}
}
Expand Up @@ -18,12 +18,13 @@

import org.gradle.api.Incubating;
import org.gradle.api.attributes.Attribute;
import org.gradle.api.component.BuildableComponent;
import org.gradle.api.file.FileCollection;
import org.gradle.api.provider.Provider;
import org.gradle.api.component.BuildableComponent;
import org.gradle.language.ComponentWithDependencies;
import org.gradle.language.cpp.tasks.CppCompile;
import org.gradle.language.nativeplatform.ComponentWithObjectFiles;
import org.gradle.nativeplatform.CppSourceCompatibility;
import org.gradle.nativeplatform.Linkage;

/**
Expand Down Expand Up @@ -85,4 +86,11 @@ public interface CppBinary extends ComponentWithObjectFiles, ComponentWithDepend
* @since 4.5
*/
Provider<CppCompile> getCompileTask();

/**
* Returns the C++ source compatibility to use to compile the source files.
*
* @since 5.2
*/
Provider<CppSourceCompatibility> getSourceCompatibility();
}
Expand Up @@ -27,6 +27,7 @@
import org.gradle.language.BinaryCollection;
import org.gradle.language.ComponentWithBinaries;
import org.gradle.language.ComponentWithDependencies;
import org.gradle.nativeplatform.CppSourceCompatibility;
import org.gradle.nativeplatform.TargetMachine;

/**
Expand Down Expand Up @@ -107,4 +108,11 @@ public interface CppComponent extends ComponentWithBinaries, ComponentWithDepend
* @since 5.1
*/
SetProperty<TargetMachine> getTargetMachines();

/**
* Returns the C++ source compatibility for this component.
*
* @since 5.2
*/
Property<CppSourceCompatibility> getSourceCompatibility();
}
Expand Up @@ -37,6 +37,7 @@
import org.gradle.language.cpp.tasks.CppCompile;
import org.gradle.language.internal.DefaultNativeBinary;
import org.gradle.language.nativeplatform.internal.Names;
import org.gradle.nativeplatform.CppSourceCompatibility;
import org.gradle.nativeplatform.MachineArchitecture;
import org.gradle.nativeplatform.OperatingSystemFamily;
import org.gradle.nativeplatform.toolchain.internal.NativeToolChainInternal;
Expand All @@ -59,6 +60,7 @@ public class DefaultCppBinary extends DefaultNativeBinary implements CppBinary {
private final Configuration includePathConfiguration;
private final Property<CppCompile> compileTaskProperty;
private final NativeVariantIdentity identity;
private final Property<CppSourceCompatibility> sourceCompatibility;

public DefaultCppBinary(Names names, ObjectFactory objects, Provider<String> baseName, FileCollection sourceFiles, FileCollection componentHeaderDirs, ConfigurationContainer configurations, Configuration componentImplementation, CppPlatform targetPlatform, NativeToolChainInternal toolChain, PlatformToolProvider platformToolProvider, NativeVariantIdentity identity) {
super(names, objects, componentImplementation);
Expand All @@ -69,6 +71,7 @@ public DefaultCppBinary(Names names, ObjectFactory objects, Provider<String> bas
this.platformToolProvider = platformToolProvider;
this.compileTaskProperty = objects.property(CppCompile.class);
this.identity = identity;
this.sourceCompatibility = objects.property(CppSourceCompatibility.class);

// TODO - reduce duplication with Swift binary

Expand Down Expand Up @@ -178,6 +181,11 @@ public Property<CppCompile> getCompileTask() {
return compileTaskProperty;
}

@Override
public Property<CppSourceCompatibility> getSourceCompatibility() {
return sourceCompatibility;
}

public PlatformToolProvider getPlatformToolProvider() {
return platformToolProvider;
}
Expand Down
Expand Up @@ -32,6 +32,7 @@
import org.gradle.language.nativeplatform.internal.ComponentWithNames;
import org.gradle.language.nativeplatform.internal.DefaultNativeComponent;
import org.gradle.language.nativeplatform.internal.Names;
import org.gradle.nativeplatform.CppSourceCompatibility;
import org.gradle.nativeplatform.TargetMachine;

import javax.inject.Inject;
Expand All @@ -48,6 +49,7 @@ public abstract class DefaultCppComponent extends DefaultNativeComponent impleme
private final Names names;
private final DefaultBinaryCollection<CppBinary> binaries;
private final SetProperty<TargetMachine> targetMachines;
private final Property<CppSourceCompatibility> srcCompat;
k-mack marked this conversation as resolved.
Show resolved Hide resolved

@Inject
public DefaultCppComponent(String name, FileOperations fileOperations, ObjectFactory objectFactory) {
Expand All @@ -61,6 +63,7 @@ public DefaultCppComponent(String name, FileOperations fileOperations, ObjectFac
names = Names.of(name);
binaries = Cast.uncheckedCast(objectFactory.newInstance(DefaultBinaryCollection.class, CppBinary.class));
targetMachines = objectFactory.setProperty(TargetMachine.class);
srcCompat = objectFactory.property(CppSourceCompatibility.class);
}

@Override
Expand Down Expand Up @@ -128,4 +131,9 @@ public DefaultBinaryCollection<CppBinary> getBinaries() {
public SetProperty<TargetMachine> getTargetMachines() {
return targetMachines;
}

@Override
public Property<CppSourceCompatibility> getSourceCompatibility() {
return srcCompat;
}
}
Expand Up @@ -37,13 +37,19 @@
import org.gradle.language.cpp.tasks.CppCompile;
import org.gradle.language.nativeplatform.internal.Names;
import org.gradle.language.plugins.NativeBasePlugin;
import org.gradle.nativeplatform.CppSourceCompatibility;
import org.gradle.nativeplatform.platform.NativePlatform;
import org.gradle.nativeplatform.toolchain.internal.NativeToolChainInternal;
import org.gradle.nativeplatform.toolchain.internal.PlatformToolProvider;
import org.gradle.nativeplatform.toolchain.internal.ToolType;
import org.gradle.nativeplatform.toolchain.internal.clang.ClangVersionCppSourceCompatibilitySupport;
import org.gradle.nativeplatform.toolchain.internal.gcc.GccVersionCppSourceCompatibilitySupport;
import org.gradle.nativeplatform.toolchain.internal.gcc.metadata.GccMetadata;
import org.gradle.nativeplatform.toolchain.internal.metadata.CompilerMetadata;
import org.gradle.nativeplatform.toolchain.internal.plugins.StandardToolChainsPlugin;
import org.gradle.swiftpm.internal.NativeProjectPublication;
import org.gradle.swiftpm.internal.SwiftPmTarget;
import org.gradle.util.VersionNumber;

import javax.inject.Inject;
import java.io.File;
Expand Down Expand Up @@ -112,6 +118,7 @@ public void execute(CppCompile compile) {
compile.getTargetPlatform().set(currentPlatform);
compile.getToolChain().set(toolChain);
compile.getObjectFileDir().set(buildDirectory.dir("obj/" + names.getDirName()));
compile.getSourceCompatibility().set(binary.getSourceCompatibility());

if (binary instanceof CppSharedLibrary) {
compile.setPositionIndependentCode(true);
Expand All @@ -129,6 +136,39 @@ public Provider<? extends Directory> transform(CppCompile cppCompile) {
}
});

project.getComponents().withType(DefaultCppComponent.class, new Action<DefaultCppComponent>() {
@Override
public void execute(DefaultCppComponent component) {
component.getBinaries().whenElementKnown(DefaultCppBinary.class, new Action<DefaultCppBinary>() {
@Override
public void execute(DefaultCppBinary binary) {
Provider<CppSourceCompatibility> cppSourceCompatibilityProvider = project.provider(new Callable<CppSourceCompatibility>() {
@Override
public CppSourceCompatibility call() throws Exception {
component.getSourceCompatibility().finalizeValue();
CppSourceCompatibility cppSourceCompatibility = component.getSourceCompatibility().getOrNull();
if (cppSourceCompatibility == null) {
CompilerMetadata compilerMetadata = binary.getPlatformToolProvider().getCompilerMetadata(ToolType.CPP_COMPILER);
if (compilerMetadata instanceof GccMetadata) {
VersionNumber version = compilerMetadata.getVersion();
String vendor = compilerMetadata.getVendor().toLowerCase();
if (vendor.contains("clang")) {
return ClangVersionCppSourceCompatibilitySupport.getDefaultSourceCompatibility();
}
return GccVersionCppSourceCompatibilitySupport.getDefaultSourceCompatibility(version);
}
// TODO: VisualStudio support for CppSourceCompatibility
k-mack marked this conversation as resolved.
Show resolved Hide resolved
}
return cppSourceCompatibility;
}
});

binary.getSourceCompatibility().set(cppSourceCompatibilityProvider);
}
});
}
});

project.getComponents().withType(ProductionCppComponent.class, new Action<ProductionCppComponent>() {
@Override
public void execute(final ProductionCppComponent component) {
Expand Down
Expand Up @@ -16,20 +16,47 @@
package org.gradle.language.cpp.tasks;

import org.gradle.api.Incubating;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.CacheableTask;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Optional;
import org.gradle.language.cpp.tasks.internal.DefaultCppCompileSpec;
import org.gradle.language.nativeplatform.tasks.AbstractNativeSourceCompileTask;
import org.gradle.nativeplatform.CppSourceCompatibility;
import org.gradle.nativeplatform.toolchain.internal.NativeCompileSpec;

import javax.inject.Inject;

/**
* Compiles C++ source files into object files.
*/
@Incubating
@CacheableTask
public class CppCompile extends AbstractNativeSourceCompileTask {
private final Property<CppSourceCompatibility> srcCompat;
k-mack marked this conversation as resolved.
Show resolved Hide resolved

@Inject
public CppCompile(ObjectFactory objectFactory) {
srcCompat = objectFactory.property(CppSourceCompatibility.class);
k-mack marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Returns the source compatibility that augments the C++ compilers arguments.
*
* @return C++ source compatibility.
* @since 5.2
*/
@Input
@Optional
public Property<CppSourceCompatibility> getSourceCompatibility() {
return srcCompat;
}

@Override
protected NativeCompileSpec createCompileSpec() {
return new DefaultCppCompileSpec();
DefaultCppCompileSpec defaultCppCompileSpec = new DefaultCppCompileSpec();
defaultCppCompileSpec.setSourceCompatibility(srcCompat.getOrNull());
return defaultCppCompileSpec;
}

}