Skip to content

Commit

Permalink
Merge pull request #21405 macOS M1 toolchain integration for aarch64
Browse files Browse the repository at this point in the history
Extension of #20310 , but enables native integration tests on M1.

The production code changes are mercifully small:
 - `MachineArchitecture.java` - defines a new AMD64 attribute
 - `GenerateXcodeProjectFileTask.java` - samples MachineArchitecture value to generate M1-compatible Xcode project
  - `default.xcsettings` - modify default Xcode project template to support "new build system" for future compatibility
  - `AbstractGccCompatibleToolChain.java` - Passes correct compiler flag when building on M1; from contributor in #20310

The remaining changes to tests and fixtures pass on my local environment, nevertheless I had to disable several tests due to the old Xcode versions present on our CI infrastructure.

Co-authored-by: Kyle Moore <kmoore@gradle.com>
  • Loading branch information
bot-gradle and DPUkyle committed Sep 10, 2022
2 parents 0f52f76 + 759350f commit bd51a00
Show file tree
Hide file tree
Showing 27 changed files with 72 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,7 @@ import org.gradle.buildinit.plugins.fixtures.ScriptDslFixture
import org.gradle.integtests.fixtures.ToBeFixedForConfigurationCache
import org.gradle.nativeplatform.fixtures.AvailableToolChains
import org.gradle.nativeplatform.fixtures.ExecutableFixture
import org.gradle.util.Requires

import static org.gradle.util.TestPrecondition.NOT_MAC_OS_X_M1

@Requires(NOT_MAC_OS_X_M1)
class CppApplicationInitIntegrationTest extends AbstractInitIntegrationSpec {

public static final String SAMPLE_APP_CLASS = "app.cpp"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ import org.gradle.nativeplatform.fixtures.AvailableToolChains
import org.gradle.nativeplatform.fixtures.ExecutableFixture
import org.gradle.nativeplatform.fixtures.RequiresInstalledToolChain
import org.gradle.nativeplatform.fixtures.ToolChainRequirement
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition

@RequiresInstalledToolChain(ToolChainRequirement.SWIFTC)
@Requires(TestPrecondition.NOT_MAC_OS_X_M1) // M1 Macs need modern Xcode to compile aarch64 binaries
class SwiftApplicationInitIntegrationTest extends AbstractInitIntegrationSpec {

public static final String SAMPLE_APPLICATION_CLASS = "main.swift"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ import org.gradle.nativeplatform.fixtures.AvailableToolChains.InstalledToolChain
import org.gradle.nativeplatform.fixtures.RequiresInstalledToolChain
import org.gradle.nativeplatform.fixtures.SharedLibraryFixture
import org.gradle.nativeplatform.fixtures.ToolChainRequirement
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition

@RequiresInstalledToolChain(ToolChainRequirement.SWIFTC)
@Requires(TestPrecondition.NOT_MAC_OS_X_M1) // M1 Macs need modern Xcode to compile aarch64 binaries
class SwiftLibraryInitIntegrationTest extends AbstractInitIntegrationSpec {

public static final String SAMPLE_LIBRARY_CLASS = "Hello.swift"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import org.gradle.nativeplatform.fixtures.app.CppSourceElement
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition

@Requires(TestPrecondition.NOT_MAC_OS_X_M1)
abstract class AbstractXcodeCppProjectIntegrationTest extends AbstractXcodeNativeProjectIntegrationTest {
@Override
protected void assertXcodeProjectSources(List<String> rootChildren) {
Expand All @@ -34,9 +33,9 @@ abstract class AbstractXcodeCppProjectIntegrationTest extends AbstractXcodeNativ
@Override
protected abstract CppSourceElement getComponentUnderTest()

@Requires(TestPrecondition.XCODE)
@Requires([TestPrecondition.XCODE, TestPrecondition.NOT_MAC_OS_X_M1]) // TODO KM: Not sure why error message is different on M1
@ToBeFixedForConfigurationCache
def "returns meaningful errors from xcode when component product is unbuildable due architecture"() {
def "returns meaningful errors from xcode when component product is unbuildable due to architecture"() {
useXcodebuildTool()

given:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,7 @@ package org.gradle.ide.xcode

import org.gradle.ide.xcode.fixtures.AbstractXcodeIntegrationSpec
import org.gradle.integtests.fixtures.ToBeFixedForConfigurationCache
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition


@Requires(TestPrecondition.XCODE)
class XcodeCompositeBuildIntegrationTest extends AbstractXcodeIntegrationSpec {

@ToBeFixedForConfigurationCache
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,10 @@ import org.gradle.ide.xcode.internal.DefaultXcodeProject
import org.gradle.integtests.fixtures.ToBeFixedForConfigurationCache
import org.gradle.nativeplatform.fixtures.app.CppAppWithLibrariesWithApiDependencies
import org.gradle.nativeplatform.fixtures.app.CppAppWithLibrary
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
import spock.lang.Ignore

import static org.gradle.ide.xcode.internal.XcodeUtils.toSpaceSeparatedList

@Requires([TestPrecondition.XCODE, TestPrecondition.NOT_MAC_OS_X_M1])
class XcodeMultipleCppProjectIntegrationTest extends AbstractXcodeIntegrationSpec {
def setup() {
useXcodebuildTool()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,10 @@ import org.gradle.nativeplatform.fixtures.app.SwiftAppWithLibrary
import org.gradle.nativeplatform.fixtures.app.SwiftAppWithLibraryTest
import org.gradle.nativeplatform.fixtures.app.SwiftGreeterUsingCppFunction
import org.gradle.nativeplatform.fixtures.app.SwiftSum
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
import spock.lang.Ignore

import static org.gradle.ide.xcode.internal.XcodeUtils.toSpaceSeparatedList

@Requires([TestPrecondition.XCODE, TestPrecondition.NOT_MAC_OS_X_M1])
class XcodeMultipleSwiftProjectIntegrationTest extends AbstractXcodeIntegrationSpec {
def setup() {
settingsFile << """
Expand All @@ -44,7 +41,6 @@ class XcodeMultipleSwiftProjectIntegrationTest extends AbstractXcodeIntegrationS
}

@ToBeFixedForConfigurationCache
@Ignore("https://github.com/gradle/gradle-native-private/issues/273")
def "can create xcode project for Swift application"() {
given:
buildFile << """
Expand Down Expand Up @@ -99,7 +95,6 @@ class XcodeMultipleSwiftProjectIntegrationTest extends AbstractXcodeIntegrationS
}

@ToBeFixedForConfigurationCache
@Ignore("https://github.com/gradle/gradle-native-private/issues/273")
def "can create xcode project for Swift application with transitive dependencies"() {
def app = new SwiftAppWithLibraries()

Expand Down Expand Up @@ -170,7 +165,6 @@ class XcodeMultipleSwiftProjectIntegrationTest extends AbstractXcodeIntegrationS
}

@ToBeFixedForConfigurationCache
@Ignore("https://github.com/gradle/gradle-native-private/issues/273")
def "can create xcode project for Swift application with binary-specific dependencies"() {
def app = new SwiftAppWithLibraries()

Expand Down Expand Up @@ -247,7 +241,6 @@ class XcodeMultipleSwiftProjectIntegrationTest extends AbstractXcodeIntegrationS
}

@ToBeFixedForConfigurationCache
@Ignore("https://github.com/gradle/gradle-native-private/issues/273")
def "can create xcode project for Swift application with dependency on c++ library"() {
def cppGreeter = new CppGreeterFunction()
def swiftGreeter = new SwiftGreeterUsingCppFunction(cppGreeter)
Expand Down Expand Up @@ -328,7 +321,6 @@ class XcodeMultipleSwiftProjectIntegrationTest extends AbstractXcodeIntegrationS
}

@ToBeFixedForConfigurationCache
@Ignore("https://github.com/gradle/gradle-native-private/issues/273")
def "can create xcode project for Swift application with dependency on a static c++ library"() {
def cppGreeter = new CppGreeterFunction()
def swiftGreeter = new SwiftGreeterUsingCppFunction(cppGreeter)
Expand Down Expand Up @@ -413,7 +405,7 @@ class XcodeMultipleSwiftProjectIntegrationTest extends AbstractXcodeIntegrationS
}

@ToBeFixedForConfigurationCache
@Ignore("https://github.com/gradle/gradle-native-private/issues/273")
@Ignore('The project contains no build configurations - it may have been damaged')
def "can clean xcode project with transitive dependencies"() {
def app = new SwiftAppWithLibraries()

Expand Down Expand Up @@ -478,8 +470,8 @@ class XcodeMultipleSwiftProjectIntegrationTest extends AbstractXcodeIntegrationS
sharedLib("log/build/lib/main/debug/Log").assertExists()
}

@Ignore("https://github.com/gradle/gradle-native-private/issues/274")
@ToBeFixedForConfigurationCache
@Ignore('could not determine if xcodebuild is using the correct environment, did xcode task run?')
def "can create xcode project for Swift application inside composite build"() {
requireSwiftToolChain()

Expand Down Expand Up @@ -543,6 +535,7 @@ class XcodeMultipleSwiftProjectIntegrationTest extends AbstractXcodeIntegrationS
}

@ToBeFixedForConfigurationCache
@Ignore('The project contains no build configurations - it may have been damaged')
def "can run tests for Swift library within multi-project from xcode"() {
given:
buildFile << """
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import org.gradle.util.TestPrecondition

import static org.gradle.ide.xcode.internal.XcodeUtils.toSpaceSeparatedList

@Requires([TestPrecondition.NOT_WINDOWS, TestPrecondition.NOT_MAC_OS_X_M1])
class XcodeSingleCppProjectIntegrationTest extends AbstractXcodeIntegrationSpec {
@ToBeFixedForConfigurationCache
def "can create xcode project for C++ application"() {
Expand Down Expand Up @@ -348,7 +347,7 @@ class XcodeSingleCppProjectIntegrationTest extends AbstractXcodeIntegrationSpec
fixture(releaseBinary).assertHasDebugSymbolsFor(app.sourceFileNamesWithoutHeaders)
}

@Requires(TestPrecondition.XCODE)
@Requires([TestPrecondition.XCODE, TestPrecondition.NOT_MAC_OS_X_M1])
@ToBeFixedForConfigurationCache
def "can build C++ executable from Xcode with multiple architecture"() {
useXcodebuildTool()
Expand Down Expand Up @@ -439,7 +438,7 @@ apply plugin: 'cpp-library'
fixture(releaseBinary).assertHasDebugSymbolsFor(lib.sourceFileNamesWithoutHeaders)
}

@Requires(TestPrecondition.XCODE)
@Requires([TestPrecondition.XCODE, TestPrecondition.NOT_MAC_OS_X_M1])
@ToBeFixedForConfigurationCache
def "can build C++ library from Xcode with multiple architecture"() {
useXcodebuildTool()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ class XcodeSingleSwiftProjectIntegrationTest extends AbstractXcodeIntegrationSpe

@Requires(TestPrecondition.XCODE)
@ToBeFixedForConfigurationCache
@Ignore("https://github.com/gradle/gradle-native-private/issues/274")
def "can configure test only when xctest plugin is applied"() {
useXcodebuildTool()

Expand Down Expand Up @@ -369,6 +370,7 @@ class XcodeSingleSwiftProjectIntegrationTest extends AbstractXcodeIntegrationSpe

@Requires(TestPrecondition.XCODE)
@ToBeFixedForConfigurationCache
@Ignore("https://github.com/gradle/gradle-native-private/issues/274")
def "can run tests for Swift library from xcode"() {
useXcodebuildTool()
def lib = new SwiftLibWithXCTest()
Expand Down Expand Up @@ -399,6 +401,7 @@ class XcodeSingleSwiftProjectIntegrationTest extends AbstractXcodeIntegrationSpe

@Requires(TestPrecondition.XCODE)
@ToBeFixedForConfigurationCache
@Ignore("https://github.com/gradle/gradle-native-private/issues/274")
def "can run tests for Swift application from xcode"() {
useXcodebuildTool()
def app = new SwiftAppWithXCTest()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import org.gradle.language.swift.SwiftVersion
import org.gradle.nativeplatform.MachineArchitecture
import org.gradle.nativeplatform.OperatingSystemFamily
import org.gradle.nativeplatform.fixtures.AvailableToolChains
import org.gradle.nativeplatform.fixtures.HostPlatform
import org.gradle.nativeplatform.fixtures.NativeBinaryFixture
import org.gradle.nativeplatform.fixtures.ToolChainRequirement
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
Expand All @@ -34,8 +35,8 @@ import org.gradle.util.TestPrecondition

import static org.junit.Assume.assumeTrue

@Requires(TestPrecondition.NOT_MAC_OS_X_M1)
class AbstractXcodeIntegrationSpec extends AbstractIntegrationSpec {
@Requires([TestPrecondition.XCODE, TestPrecondition.NOT_MAC_OS_X_M1]) // M1 Macs need modern Xcode to compile aarch64 binaries
class AbstractXcodeIntegrationSpec extends AbstractIntegrationSpec implements HostPlatform {
AvailableToolChains.InstalledToolChain toolChain = null

def setup() {
Expand Down Expand Up @@ -165,51 +166,54 @@ rootProject.name = "${rootProjectName}"
void assertTargetIsDynamicLibrary(ProjectFile.PBXTarget target, String expectedProductName, String expectedBinaryName = expectedProductName) {
target.assertIsDynamicLibrary()
target.assertProductNameEquals(expectedProductName)
target.assertSupportedArchitectures(MachineArchitecture.X86_64)
target.assertSupportedArchitectures(archName == 'aarch64' ? MachineArchitecture.ARM64 : MachineArchitecture.X86_64)
assert target.name == expectedProductName
assert target.productReference.path == sharedLib("build/lib/main/debug/$expectedBinaryName").absolutePath
assert target.buildArgumentsString == '-Porg.gradle.internal.xcode.bridge.ACTION="${ACTION}" -Porg.gradle.internal.xcode.bridge.PRODUCT_NAME="${PRODUCT_NAME}" -Porg.gradle.internal.xcode.bridge.CONFIGURATION="${CONFIGURATION}" -Porg.gradle.internal.xcode.bridge.BUILT_PRODUCTS_DIR="${BUILT_PRODUCTS_DIR}" :_xcode__${ACTION}_${PRODUCT_NAME}_${CONFIGURATION}'

def expectedArchitecture = archName == 'aarch64' ? 'arm64e' : 'x86_64'
assert target.buildConfigurationList.buildConfigurations[0].name == DefaultXcodeProject.BUILD_DEBUG
assert target.buildConfigurationList.buildConfigurations[0].buildSettings.ARCHS == "x86_64"
assert target.buildConfigurationList.buildConfigurations[0].buildSettings.ARCHS == expectedArchitecture
assert target.buildConfigurationList.buildConfigurations[0].buildSettings.CONFIGURATION_BUILD_DIR == file("build/lib/main/debug").absolutePath

assert target.buildConfigurationList.buildConfigurations[1].name == DefaultXcodeProject.BUILD_RELEASE
assert target.buildConfigurationList.buildConfigurations[1].buildSettings.ARCHS == "x86_64"
assert target.buildConfigurationList.buildConfigurations[1].buildSettings.ARCHS == expectedArchitecture
assert target.buildConfigurationList.buildConfigurations[1].buildSettings.CONFIGURATION_BUILD_DIR == file("build/lib/main/release/stripped").absolutePath
}

void assertTargetIsStaticLibrary(ProjectFile.PBXTarget target, String expectedProductName, String expectedBinaryName = expectedProductName) {
target.assertIsStaticLibrary()
target.assertProductNameEquals(expectedProductName)
target.assertSupportedArchitectures(MachineArchitecture.X86_64)
target.assertSupportedArchitectures(archName == 'aarch64' ? MachineArchitecture.ARM64 : MachineArchitecture.X86_64)
assert target.name == expectedProductName
assert target.productReference.path == staticLib("build/lib/main/debug/$expectedBinaryName").absolutePath
assert target.buildArgumentsString == '-Porg.gradle.internal.xcode.bridge.ACTION="${ACTION}" -Porg.gradle.internal.xcode.bridge.PRODUCT_NAME="${PRODUCT_NAME}" -Porg.gradle.internal.xcode.bridge.CONFIGURATION="${CONFIGURATION}" -Porg.gradle.internal.xcode.bridge.BUILT_PRODUCTS_DIR="${BUILT_PRODUCTS_DIR}" :_xcode__${ACTION}_${PRODUCT_NAME}_${CONFIGURATION}'

def expectedArchitecture = archName == 'aarch64' ? 'arm64e' : 'x86_64'
assert target.buildConfigurationList.buildConfigurations[0].name == DefaultXcodeProject.BUILD_DEBUG
assert target.buildConfigurationList.buildConfigurations[0].buildSettings.ARCHS == "x86_64"
assert target.buildConfigurationList.buildConfigurations[0].buildSettings.ARCHS == expectedArchitecture
assert target.buildConfigurationList.buildConfigurations[0].buildSettings.CONFIGURATION_BUILD_DIR == file("build/lib/main/debug").absolutePath

assert target.buildConfigurationList.buildConfigurations[1].name == DefaultXcodeProject.BUILD_RELEASE
assert target.buildConfigurationList.buildConfigurations[1].buildSettings.ARCHS == "x86_64"
assert target.buildConfigurationList.buildConfigurations[1].buildSettings.ARCHS == expectedArchitecture
assert target.buildConfigurationList.buildConfigurations[1].buildSettings.CONFIGURATION_BUILD_DIR == file("build/lib/main/release").absolutePath
}

void assertTargetIsTool(ProjectFile.PBXTarget target, String expectedProductName, String expectedBinaryName = expectedProductName) {
target.assertIsTool()
target.assertProductNameEquals(expectedProductName)
target.assertSupportedArchitectures(MachineArchitecture.X86_64)
target.assertSupportedArchitectures(archName == 'aarch64' ? MachineArchitecture.ARM64 : MachineArchitecture.X86_64)
assert target.name == expectedProductName
assert target.productReference.path == exe("build/install/main/debug/lib/$expectedBinaryName").absolutePath
assert target.buildArgumentsString == '-Porg.gradle.internal.xcode.bridge.ACTION="${ACTION}" -Porg.gradle.internal.xcode.bridge.PRODUCT_NAME="${PRODUCT_NAME}" -Porg.gradle.internal.xcode.bridge.CONFIGURATION="${CONFIGURATION}" -Porg.gradle.internal.xcode.bridge.BUILT_PRODUCTS_DIR="${BUILT_PRODUCTS_DIR}" :_xcode__${ACTION}_${PRODUCT_NAME}_${CONFIGURATION}'

def expectedArchitecture = archName == 'aarch64' ? 'arm64e' : 'x86_64'
assert target.buildConfigurationList.buildConfigurations[0].name == DefaultXcodeProject.BUILD_DEBUG
assert target.buildConfigurationList.buildConfigurations[0].buildSettings.ARCHS == "x86_64"
assert target.buildConfigurationList.buildConfigurations[0].buildSettings.ARCHS == expectedArchitecture
assert target.buildConfigurationList.buildConfigurations[0].buildSettings.CONFIGURATION_BUILD_DIR == file("build/install/main/debug/lib").absolutePath

assert target.buildConfigurationList.buildConfigurations[1].name == DefaultXcodeProject.BUILD_RELEASE
assert target.buildConfigurationList.buildConfigurations[1].buildSettings.ARCHS == "x86_64"
assert target.buildConfigurationList.buildConfigurations[1].buildSettings.ARCHS == expectedArchitecture
assert target.buildConfigurationList.buildConfigurations[1].buildSettings.CONFIGURATION_BUILD_DIR == file("build/install/main/release/lib").absolutePath
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,8 @@ private static String toXcodeArchitecture(String architectureName) {
return "i386";
} else if (architectureName.equals(MachineArchitecture.X86_64)) {
return "x86_64";
} else if (architectureName.equals(MachineArchitecture.ARM64)) {
return "arm64e";
}

return architectureName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildSystemType</key>
<string>Original</string>
<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
<false/>
</dict>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ class ProjectFile {
}

void assertSupportedArchitectures(String... architectures) {
def toXcodeArchitecture = [x86: 'i386', 'x86-64': 'x86_64'].withDefault { it }
def toXcodeArchitecture = [x86: 'i386', 'x86-64': 'x86_64', aarch64: 'arm64e'].withDefault { it }
String expectedValidArchitectures = architectures.collect { toXcodeArchitecture.get(it) }.join(" ")
assert this.buildConfigurationList.buildConfigurations.every { it.buildSettings.VALID_ARCHS == expectedValidArchitectures }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition

@Requires(TestPrecondition.NOT_MAC_OS_X_M1)
class DifferentJnaVersionInPluginIntegrationSpec extends AbstractIntegrationSpec {
@Requires(TestPrecondition.NOT_MAC_OS_X_M1)
def 'can build a plugin with a different jna version'() {
given:
buildScript """
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,8 @@ import org.gradle.nativeplatform.fixtures.HostPlatform
import org.gradle.nativeplatform.fixtures.ToolChainRequirement
import org.gradle.nativeplatform.fixtures.app.CppApp
import org.gradle.nativeplatform.fixtures.app.CppCompilerDetectingTestApp
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
import org.junit.Assume

@Requires(TestPrecondition.NOT_MAC_OS_X_M1)
class CppMissingToolchainIntegrationTest extends AbstractIntegrationSpec implements HostPlatform {
@ToBeFixedForConfigurationCache
def "user receives reasonable error message when no tool chains are available"() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import org.gradle.util.TestPrecondition
import static org.gradle.nativeplatform.fixtures.ToolChainRequirement.GCC_COMPATIBLE

@RequiresInstalledToolChain(GCC_COMPATIBLE)
@Requires(TestPrecondition.NOT_WINDOWS)
@Requires([TestPrecondition.NOT_WINDOWS, TestPrecondition.NOT_MAC_OS_X])
class MixedObjectiveCIntegrationTest extends AbstractNativeLanguageIntegrationTest {

@Override
Expand Down

0 comments on commit bd51a00

Please sign in to comment.