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

WindowsRegistry is not supported on this operating system. #274

Open
ncimino opened this issue Mar 30, 2021 · 7 comments
Open

WindowsRegistry is not supported on this operating system. #274

ncimino opened this issue Mar 30, 2021 · 7 comments

Comments

@ncimino
Copy link

ncimino commented Mar 30, 2021

I'm hitting an exception, and I presume it is because of my companies anti-virus/malware software is blocking Gradle from reading the registry key \\HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir. First thing to note is, I am working with my IT department to resolve this...

However, it doesn't seem like Gradle should stop the flow here. It could consult with the PATH environment variable to locate vswhere.exe as a workaround or even skip this step entirely and look for the tool-chains in PATH. Any of these would be infinitely better then just throwing an exception and stopping the flow with no way to disable or bypass it.

Here is the exception:

Caused by: org.gradle.internal.nativeintegration.NativeIntegrationUnavailableException: WindowsRegistry is not supported on this operating system.
	at org.gradle.internal.nativeintegration.services.NativeServices$BrokenService.invoke(NativeServices.java:345)
	at com.sun.proxy.$Proxy112.getStringValue(Unknown Source)
	at org.gradle.nativeplatform.toolchain.internal.msvcpp.version.DefaultVswhereVersionLocator.getVswhereInstall(DefaultVswhereVersionLocator.java:48)
	at org.gradle.nativeplatform.toolchain.internal.msvcpp.version.CommandLineToolVersionLocator.locateInstalls(CommandLineToolVersionLocator.java:56)
	at org.gradle.nativeplatform.toolchain.internal.msvcpp.version.AbstractVisualStudioVersionLocator.getVisualStudioInstalls(AbstractVisualStudioVersionLocator.java:32)
	at org.gradle.nativeplatform.toolchain.internal.msvcpp.DefaultVisualStudioLocator.locateInstallsWith(DefaultVisualStudioLocator.java:108)
	at org.gradle.nativeplatform.toolchain.internal.msvcpp.DefaultVisualStudioLocator.initializeVisualStudioInstalls(DefaultVisualStudioLocator.java:97)
	at org.gradle.nativeplatform.toolchain.internal.msvcpp.DefaultVisualStudioLocator.locateComponent(DefaultVisualStudioLocator.java:86)
	at org.gradle.nativeplatform.toolchain.internal.msvcpp.VisualCppToolChain.checkAvailable(VisualCppToolChain.java:175)

To locate the Visual Studios tools DefaultVswhereVersionLocator asks the registry for the Program Files or Program Files (x86) location and then appends Microsoft Visual Studio/Installer along with vswhere.exe. This action happens here:

    public File getVswhereInstall() {
        for (String programFilesKey : PROGRAM_FILES_KEYS) {
            File programFilesDir;
            try {
                programFilesDir = new File(windowsRegistry.getStringValue(WindowsRegistry.Key.HKEY_LOCAL_MACHINE, REGISTRY_PATH_WINDOWS, programFilesKey));
            } catch (MissingRegistryEntryException e) {
                // We'll get this when we try to look up "ProgramFilesDir (x86)" on a 32-bit OS
                continue;
            }

            File candidate = new File(programFilesDir, VISUAL_STUDIO_INSTALLER + "/" + VSWHERE_EXE);
            if (candidate.exists() && candidate.isFile()) {
                return candidate;
            }
        }

        return os.findInPath(VSWHERE_EXE);
    }

The exception is thrown at:

                programFilesDir = new File(windowsRegistry.getStringValue(WindowsRegistry.Key.HKEY_LOCAL_MACHINE, REGISTRY_PATH_WINDOWS, programFilesKey));

This windowsRegistry object is an instance of: net.rubygrapefruit.platform.WindowsRegistry

Perhaps one alternative would be to catch NativeIntegrationUnavailableException here.

The reason this is so problematic is it is one of the first things that happens in native tool-chain resolution. It is just initializing all of the tool-chains/install locations we haven't even got to where we select the tools yet. From the aforementioned stack-trace you can see this method ( in DefaultVisualStudioLocator):

    private void initializeVisualStudioInstalls() {
        if (!initialised) {
            locateInstallsWith(commandLineLocator);   // <--- We are here when this throws
            locateInstallsWith(windowsRegistryLocator);
            if (foundInstalls.isEmpty()) {
                locateInstallsWith(systemPathLocator);
            }

            initialised = true;
        }
    }

We are still in commandLineLocator as it is trying to use vswhere.exe to locate the tools. Even if that fails and windowsRegistryLocator I think it would make sense to continue on to systemPathLocator, but we cannot even get to where it would locate tools using the PATH which would at least let me workaround this issue.

If you have any ideas I'd love to hear them because I'm not able to run C++ builds on Windows right now.

@melix
Copy link

melix commented Aug 23, 2021

The very same error seems to happen when using Java Toolchains support and GitHub actions windows runners (runs-on: windows-2016).

@lacasseio
Copy link

I can confirm the same exception on GitHub actions windows runner:windows-latest (which is windows-2019). The error is a bit strange as the I'm able to run tests on Windows. However, I haven't tried on Windows 2019 due to not having access to such a machine.

@melix
Copy link

melix commented Feb 3, 2022

Any workaround for this problem? It currently blocks testing Windows builds on GitHub actions... I should mention that in my case it seems to happen with TestKit: the Gradle build which starts the tests actually works properly.

@ncimino
Copy link
Author

ncimino commented Feb 3, 2022

We never did fix this, but I think you could easily create a extended class that wraps the windowsRegistry.getStringValue call with a catch for NativeIntegrationUnavailableException and if that fails then skip the registry code and move on to PATH resolution.

@wolfs
Copy link
Member

wolfs commented Feb 4, 2022

@melix Did you already open an issue on gradle/gradle for this problem? I suppose we could do different things when we can't detect the toolchains from the registry and fall back to some known locations. You can also disable toolchain detection and provide the list of paths manually I suppose.

@melix
Copy link

melix commented Feb 4, 2022

There was an issue in gradle/gradle which was closed in favor of this one: gradle/gradle#16656

Since yesterday I have setup a Windows 10 VM and I can confirm the same behavior happens in a VM, so it's not specific to GitHub actions.

@guai
Copy link

guai commented Mar 21, 2022

bump.
In my case the error is different:

Caused by: org.gradle.internal.nativeintegration.NativeIntegrationUnavailableException: WindowsRegistry is not supported on this operating system.
        at org.gradle.internal.nativeintegration.services.NativeServices$BrokenService.invoke(NativeServices.java:445)
        at com.sun.proxy.$Proxy48.getSubkeys(Unknown Source)
        at org.gradle.jvm.toolchain.internal.WindowsInstallationSupplier.getVersions(WindowsInstallationSupplier.java:76)
        at org.gradle.jvm.toolchain.internal.WindowsInstallationSupplier.find(WindowsInstallationSupplier.java:67)
        at org.gradle.jvm.toolchain.internal.WindowsInstallationSupplier.findAdoptOpenJdk(WindowsInstallationSupplier.java:84)
        at org.gradle.jvm.toolchain.internal.WindowsInstallationSupplier.findInstallationsInRegistry(WindowsInstallationSupplier.java:52)
        at org.gradle.jvm.toolchain.internal.WindowsInstallationSupplier.findCandidates(WindowsInstallationSupplier.java:46)
        at org.gradle.jvm.toolchain.internal.AutoDetectingInstallationSupplier.get(AutoDetectingInstallationSupplier.java:41)
        at org.gradle.jvm.toolchain.internal.AutoDetectingInstallationSupplier.get(AutoDetectingInstallationSupplier.java:26)

It tries to read SOFTWARE\AdoptOpenJDK\JDK under HKEY_LOCAL_MACHINE.
Last week everything was ok, dunno what happened.

gradle 7.4.1
Microsoft Windows 10 Enterprise 10.0.19044 Build 19044
JVM:          11.0.11 (Oracle Corporation 11.0.11+9-LTS-194)

PS: I have no Adopt installed

mbland added a commit to mbland/tomcat-servlet-testing-example that referenced this issue Dec 23, 2023
Removing gradle-node-plugin cuts the project's dependency footprint
slightly, and enables Windows builds to succeed.

Executing `pnpm` from a Gradle task proved straightforward. Also added a
frontendInstall task, removed the separate "Install Node packages" step
from run-tests.yaml, and refined `inputs` and `outputs` for more precise
dependency tracking.

Specifically learned about using `outputs.upToDateWhen { true }` as a
means to prevent `frontendInstall` from always running from:

- https://discuss.gradle.org/t/why-does-my-task-run-even-though-non-of-its-inputs-has-changed/5350/2

---

I entertained the notion of fixing Windows builds by removing
gradle-node-plugin after a couple of days of trying to fix that plugin.

The moral of the following story:

- Sometimes you really _shouldn't_ add a dependency if you can do what
  you need to do without it.

When starting the project, I thought running Node.js from Gradle might
be tricky, so I searched for a plugin. As it turned out,
node-gradle/gradle-node-plugin was available, and seemed to work well on
macOS and Linux. However, it broke the project on Windows, because it
failed trying to execute `uname` on Windows.

I got the plugin successfully working on Windows by introducing the
following PowerShell command to replace uname (in
com.github.gradle.node.NodePlugin.addPlatform()):

```kotlin
if (name.toLowerCase().contains("windows")) {
    executable = "powershell.exe"
    args = listOf(
        "-Command",
        "& {Get-CimInstance Win32_OperatingSystem | " +
            "Select-Object -ExpandProperty OSArchitecture}"
    )
}
```

I also updated com.github.gradle.node.util.parseOsArch to handle the
"ARM 64-bit Processor" value returned by the command.

However, many tests continued to fail, which I realized was because no
`win-arm64` build of Node.js was available for the default Node.js
version 18.17.1:

- https://nodejs.org/dist/v18.17.1/

So I updated the default to 20.10.0 (and the npm version to 10.2.3,
which ships with 20.10.0). All the (very slow) tests began to pass
except for NpmProxy_integTest and YarnProxy_integTest.

After some creative debugging whereby I emitted the test-supplied values
for HTTP_PROXY and HTTPS_PROXY, I could see that Node couldn't see the
test-supplied values. Some digging revealed that past versions of Gradle
and its TestKit didn't have native support for arm64 that would allow
for setting environment variables:

- gradle/gradle: TestKit does not pass environment variables for older
  Gradle versions when running on M1 mac #22012:
  gradle/gradle#22012

It seemed that Gradle 7.5.1, the default used by gradle-node-plugin,
should be OK. However, it didn't seem to be.

And this is where the despair really started kicking in.

I tried various combinations of updating the JDK from 11 to 17.0.9,
Gradle from 7.5.1 to 8.5, and updating the build.gradle.kts file.

I thought updating to 17.0.9 might solve some problems, and it seemed as
high as I could go to still suport 7.5.1:

- https://docs.gradle.org/current/userguide/compatibility.html

One minor change to the build file involved moving merging entries from
the deprecated pluginBundle block to the existing gradlePlugin block:

- https://docs.gradle.org/current/userguide/upgrading_version_7.html#pluginbundle_dropped_in_plugin_publish_plugin

Another involved disabling the com.cinnober.gradle.semver-git plugin,
because launching subprocesses during the configuration phase is now an
error when using the configuration cache:

- https://docs.gradle.org/current/userguide/upgrading_version_7.html#use_providers_to_run_external_processes
- https://docs.gradle.org/current/userguide/configuration_cache.html#config_cache:requirements:external_processes

I also deleted the ill advised and useless org.gradle.test-retry plugin
and its configuration. The tests didn't appear to be unstable, so the
tests would run multiple times to keep failing in the same way. If they
didn't fail the same way, or sometimes passed, that'd've been even
worse. See:

- https://mike-bland.com/2023/09/13/the-inverted-test-pyramid.html

Then the build would fail while compiling Kotlin:

```text
  API version 1.3 is no longer supported; please, use version 1.4 or
  greater.
```

So I set in the build file:

```kotlin
tasks.compileKotlin {
    kotlinOptions {
        apiVersion = "1.9"
        languageVersion = "1.9"
```

I also boosted IntelliJ IDEA "Settings > Build, Execution, Deployment >
Compiler > Kotlin Compiler > Target JVM Version" setting to 17. Then I
updated the build file variable:

```kotlin
val compatibilityVersion = JavaVersion.VERSION_17
```

And then, finally, tests still failed because something funny happened
inside the Spock test framework, with a bunch of errors like:

```text
SystemVersion_integTest > use system node version and exec node, npm, npx and yarn program (#gv.version) > use system node version and exec node, npm, npx and yarn program (8.5) FAILED
    java.lang.reflect.InaccessibleObjectException: Unable to make field private final java.util.Map java.util.Collections$UnmodifiableMap.m accessible: module java.base does not "opens java.util" to unnamed module @609db546
        at org.junit.contrib.java.lang.system.EnvironmentVariables.getFieldValue(EnvironmentVariables.java:188)
        at org.junit.contrib.java.lang.system.EnvironmentVariables.getEditableMapOfVariables(EnvironmentVariables.java:150)
        at org.junit.contrib.java.lang.system.EnvironmentVariables.access$200(EnvironmentVariables.java:49)
        at org.junit.contrib.java.lang.system.EnvironmentVariables$EnvironmentVariablesStatement.restoreOriginalVariables(EnvironmentVariables.java:134)
        at org.junit.contrib.java.lang.system.EnvironmentVariables$EnvironmentVariablesStatement.evaluate(EnvironmentVariables.java:125)
        at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:54)
        at org.spockframework.junit4.AbstractRuleInterceptor.evaluateStatement(AbstractRuleInterceptor.java:66)
    [ ...snip... ]
```

I already decided at this point to get rid of gradle-node-plugin, and
developed this change. But then I decided to go a little further.

This appears to be related to:

- spock/spockframework: Cannot create mock due to module java.base does
  not "opens java.lang.invoke" #1406
  spockframework/spock#1406

This appears to be a consequence of:

- JEP 396: Strongly Encapsulate JDK Internals by Default
  https://openjdk.org/jeps/396

This apparently shipped in Java 16, and people noticed in in Spock after
upgrading to Java 17.

Based on the information in the spock issue, I tried adding the
following `jvmArgs` entry in the build file:

```kotlin
tasks.withType(Test::class) {
    useJUnitPlatform()
    systemProperty(
        // ...snip...
    )
    jvmArgs("--add-opens", "java.base/java.util=ALL-UNNAMED")
```

Reference for `--add-opens`:

- https://docs.oracle.com/en/java/javase/17/migrate/migrating-jdk-8-later-jdk-releases.html#GUID-12F945EB-71D6-46AF-8C3D-D354FD0B1781

This actually fixed the error, but on macOS, three tests failed with:

```text
> Task :npmInstall FAILED
npm WARN tarball tarball data for npm@https://registry.npmjs.org/npm/-/npm-10.2.3.tgz (sha512-lXdZ7titEN8CH5YJk9C/aYRU9JeDxQ4d8rwIIDsvH3SMjLjHTukB2CFstMiB30zXs4vCrPN2WH6cDq1yHBeJAw==) seems to be corrupted. Trying again.
npm ERR! code EINTEGRITY
npm ERR! sha512-lXdZ7titEN8CH5YJk9C/aYRU9JeDxQ4d8rwIIDsvH3SMjLjHTukB2CFstMiB30zXs4vCrPN2WH6cDq1yHBeJAw== integrity checksum failed when using sha512: wanted sha512-lXdZ7titEN8CH5YJk9C/aYRU9JeDxQ4d8rwIIDsvH3SMjLjHTukB2CFstMiB30zXs4vCrPN2WH6cDq1yHBeJAw== but got sha512-GbUui/rHTl0mW8HhJSn4A0Xg89yCR3I9otgJT1i0z1QBPOVlgbh6rlcUTpHT8Gut9O1SJjWRUU0nEcAymhG2tQ==. (2583937 bytes)
```

The tests being:

- NpmRule_integTest. succeeds to run npm module using npm_run_ when the
  package.json file contains local npm (8.5)
- NpmTask_integTest. execute npm command using the npm version specified
  in the package.json file (8.5)
- NpxTask_integTest. execute npx command using the npm version specified
  in the package.json file (8.5)

And on Windows, after all of that, the NpmProxy and YarnProxy tests
still failed. At least the changes in this commit will allow Windows to
build now, right...?

```text
* What went wrong:
Failed to calculate the value of task ':strcalc:compileJava' property
'javaCompiler'.
WindowsRegistry is not supported on this operating system.
```

Great:

- gradle/native-platform: WindowsRegistry is not supported on this
  operating system. #274
  gradle/native-platform#274 (comment)
- gradle/gradle: Support ARM64 Windows #21703
  gradle/gradle#21703

So much for Windows on arm64 for now.

This was obviously quite the learning journey, but it's only reminded me
again of how much I hate the Java ecosystem. Yet more days I wish I had
back in my life.
mbland added a commit to mbland/tomcat-servlet-testing-example that referenced this issue Dec 24, 2023
After #73, running `.\gradlew.bat build` on arm64 Windows would fail
with "WindowsRegistry is not supported on this operating system."
Removing the `java.toolchain` block from strcalc/build.gradle.kts allows
it to succeed, as Gradle no longer tries to query the Windows registry
to discover the Java toolchain. It will just pick up the toolchain from
the environment.

Running `.\gradlew.bat -q javaToolchains` will still produce the
failure, however.

See:
- https://docs.gradle.org/current/userguide/toolchains.html
- gradle/native-platform: WindowsRegistry is not supported on this
  operating system. #274
  gradle/native-platform#274 (comment)
- gradle/gradle: Support ARM64 Windows #21703
  gradle/gradle#21703
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants