All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dev.nokee.platform.nativebase.internal.ToolChainSelectorInternal Maven / Gradle / Ivy

The newest version!
package dev.nokee.platform.nativebase.internal;

import dev.nokee.runtime.nativebase.TargetMachine;
import dev.nokee.runtime.nativebase.internal.DefaultMachineArchitecture;
import dev.nokee.runtime.nativebase.internal.DefaultOperatingSystemFamily;
import org.apache.commons.lang3.SystemUtils;
import org.gradle.internal.os.OperatingSystem;
import org.gradle.model.internal.registry.ModelRegistry;
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform;
import org.gradle.nativeplatform.platform.internal.NativePlatformInternal;
import org.gradle.nativeplatform.toolchain.internal.NativeLanguage;
import org.gradle.nativeplatform.toolchain.internal.NativeToolChainInternal;
import org.gradle.nativeplatform.toolchain.internal.NativeToolChainRegistryInternal;
import org.gradle.nativeplatform.toolchain.internal.PlatformToolProvider;
import org.gradle.nativeplatform.toolchain.internal.msvcpp.VisualCppToolChain;
import org.gradle.nativeplatform.toolchain.internal.swift.SwiftcToolChain;

import javax.inject.Inject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

import static java.util.Arrays.asList;

public class ToolChainSelectorInternal {
	private final ModelRegistry modelRegistry;
	private final NativePlatformFactory nativePlatformFactory = new NativePlatformFactory();

	@Inject
	public ToolChainSelectorInternal(ModelRegistry modelRegistry) {
		this.modelRegistry = modelRegistry;
	}

	public boolean isKnown(TargetMachine targetMachine) {
		return getToolChains().stream().anyMatch(it -> it.knows(targetMachine));
	}

	public boolean canBuild(TargetMachine targetMachine) {
		return getToolChains().stream().anyMatch(it -> it.canBuild(targetMachine));
	}

	public NativeToolChainInternal select(TargetMachine targetMachine) {
		NativePlatformInternal targetPlatform = nativePlatformFactory.create(targetMachine);
		NativeToolChainRegistryInternal registry = modelRegistry.realize("toolChains", NativeToolChainRegistryInternal.class);
		NativeToolChainInternal toolChain = (NativeToolChainInternal)registry.getForPlatform(targetPlatform);
		toolChain.assertSupported();

		return toolChain;
	}

	public NativeToolChainInternal selectSwift(TargetMachine targetMachine) {
		NativePlatformInternal targetPlatform = nativePlatformFactory.create(targetMachine);
		// HACK(daniel): Supa hacka! The way native platform match with the toolchain for Swift is a bit special.
		//  By using the "host" platform we can have the Swift toolchain selection happen. ;-)
		if (targetMachine.getOperatingSystemFamily().equals(DefaultOperatingSystemFamily.IOS)) {
			targetPlatform = DefaultNativePlatform.host();
		}
		NativeToolChainRegistryInternal registry = modelRegistry.realize("toolChains", NativeToolChainRegistryInternal.class);
		NativeToolChainInternal toolChain = (NativeToolChainInternal)registry.getForPlatform(NativeLanguage.SWIFT, targetPlatform);
		toolChain.assertSupported();

		return toolChain;
	}

	private Collection getToolChains() {
		List result = new ArrayList<>();
		result.add(new DomainKnowledgeToolChain());
		result.addAll(modelRegistry.realize("toolChains", NativeToolChainRegistryInternal.class).withType(NativeToolChainInternal.class).stream().map(SoftwareModelToolChain::new).collect(Collectors.toList()));
		return result;
	}

	private interface ToolChain {
		boolean knows(TargetMachine targetMachine);

		boolean canBuild(TargetMachine targetMachine);
	}

	private class SoftwareModelToolChain implements ToolChain {
		private final NativeToolChainInternal delegate;

		private SoftwareModelToolChain(NativeToolChainInternal delegate) {
			this.delegate = delegate;
		}

		@Override
		public boolean knows(TargetMachine targetMachine) {
			NativePlatformInternal targetPlatform = nativePlatformFactory.create(targetMachine);

			NativeLanguage nativeLanguage = NativeLanguage.CPP;
			if (delegate instanceof SwiftcToolChain) {
				nativeLanguage = NativeLanguage.SWIFT;
			}

			PlatformToolProvider toolProvider = delegate.select(nativeLanguage, targetPlatform);
			if (toolProvider.isAvailable()) {
				return true;
			}

			// Code an exception here as VisualCpp will return an unavailable (not unsupported) when the tool is not available
			// For VisualCpp toolchain where target is not Windows, return not supported.
			if (!toolProvider.isSupported() || (!targetPlatform.getOperatingSystem().isWindows() && delegate instanceof VisualCppToolChain)) {
				return false;
			}
			return true;
		}

		@Override
		public boolean canBuild(TargetMachine targetMachine) {
			NativePlatformInternal targetPlatform = nativePlatformFactory.create(targetMachine);

			NativeLanguage nativeLanguage = NativeLanguage.CPP;
			if (delegate instanceof SwiftcToolChain) {
				nativeLanguage = NativeLanguage.SWIFT;
			}

			PlatformToolProvider toolProvider = delegate.select(nativeLanguage, targetPlatform);
			if (toolProvider.isAvailable()) {
				return true;
			}
			return false;
		}
	}

	private static class DomainKnowledgeToolChain implements ToolChainSelectorInternal.ToolChain {
		@Override
		public boolean knows(TargetMachine targetMachine) {
			// Shortcut
			//   if we ...
			//      ... target linux and current host is not Linux
			//      or
			//      ... target macOS and current host is not macOS
			//   we know it is known and we should be able to compile for it
			if ((isTargetingLinuxButNotLinux(targetMachine) || isTargetingMacOsButNotMacOs(targetMachine) || isTargetingFreeBsdButNotFreeBsd(targetMachine) || isTargetingWindowsButNotWindows(targetMachine)) && isKnownArchitecture(targetMachine)) {
				return true;
			}
			return false;
		}

		private static boolean isKnownArchitecture(TargetMachine targetMachine) {
			return asList(DefaultMachineArchitecture.X86, DefaultMachineArchitecture.X86_64).contains(targetMachine.getArchitecture());
		}

		private static boolean isTargetingMacOsButNotMacOs(TargetMachine targetMachine) {
			return targetMachine.getOperatingSystemFamily().isMacOs() && !OperatingSystem.current().isMacOsX();
		}

		private static boolean isTargetingLinuxButNotLinux(TargetMachine targetMachine) {
			return targetMachine.getOperatingSystemFamily().isLinux() && !SystemUtils.IS_OS_LINUX;
		}

		private static boolean isTargetingFreeBsdButNotFreeBsd(TargetMachine targetMachine) {
			return targetMachine.getOperatingSystemFamily().isFreeBSD() && !SystemUtils.IS_OS_FREE_BSD;
		}

		private static boolean isTargetingWindowsButNotWindows(TargetMachine targetMachine) {
			return targetMachine.getOperatingSystemFamily().isWindows() && !SystemUtils.IS_OS_WINDOWS;
		}

		@Override
		public boolean canBuild(TargetMachine targetMachine) {
			// Shortcut, we need to model target host for the tool chain and their target platform
			//    We assume the same host should always be buildable and supported
			if (DefaultNativePlatform.getCurrentOperatingSystem().toFamilyName().equals(((DefaultOperatingSystemFamily)targetMachine.getOperatingSystemFamily()).getName())) {
				return true;
			}
			return false;
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy