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

Issues running on Windows #6

Closed
rocketraman opened this issue Oct 24, 2018 · 26 comments
Closed

Issues running on Windows #6

rocketraman opened this issue Oct 24, 2018 · 26 comments
Assignees
Labels
bug Something isn't working plugin

Comments

@rocketraman
Copy link

Ok, I don't use Windows myself (ugh), but some of my coworkers do. There are issues running this on Windows:

  1. The compiler is run with an invalid path that contains a leading "/". Here is the debug output from Gradle:
11:48:22.846 [INFO] [org.gradle.process.internal.DefaultExecHandle] Starting process 'command 'C:\jdk1.8.0_191\bin\java.exe''. Working directory: H:\source\myproject\lib-proto Command: C:\jdk1.8.0_191\bin\java.exe -Dfile.encoding=windows-1252 -Duser.country=US -Duser.language=en -Duser.variant -jar /C:/Users/Me/.gradle/caches/modules-2/files-2.1/com.github.marcoferrer.krotoplus/kroto-plus-compiler/0.1.3/620b2a278b4d4beed80320bb4800339967f850d7/kroto-plus-compiler-0.1.3.jar H:\source\myproject\lib-proto/src/main/proto H:\source\myproject\lib-proto\build/extracted-include-protos/main -default-out H:\source\myproject\lib-proto\build\generated\source\proto\main\kotlin -writers 3 -StubOverloads -o|H:\source\myproject\lib-proto\build\generated\source\proto\main\kotlin|-coroutines -MockServices -o|H:\source\myproject\lib-proto\build\generated\source\proto\main\kotlin -ProtoTypeBuilder
...
11:48:22.874 [ERROR] [system.err] Error: Unable to access jarfile /C:/Users/Me/.gradle/caches/modules-2/files-2.1/com.github.marcoferrer.krotoplus/kroto-plus-compiler/0.1.3/620b2a278b4d4beed80320bb4800339967f850d7/kroto-plus-compiler-0.1.3.jar

Note the leading slash on the -jar argument.

  1. I don't know if this is an issue in this plugin or in the upstream protobuf gradle plugin, but when adding the kroto code gen plugin to the protobuf plugin, the build fails with the error:
Execution failed for task ':generateProto'.
> protoc: stdout: . stderr: --kroto_out: protoc-gen-kroto: %1 is not a valid Win32 application.

Looking at the --debug logs, it looks like a --plugin parameter is addd to the call to protoc, with the following value:

 --plugin=protoc-gen-kroto=C:\Users\Me\.gradle\caches\modules-2\files-2.1\com.github.marcoferrer.krotoplus\protoc-gen-kroto-plus\0.1.3\3c41d071d04c8558822447643894490e33a857b7\protoc-gen-kroto-plus-0.1.3-jvm8.jar

but protoc is assuming the jar file is an executable it can run. I have tried associating ".jar" files with "java" (and this seems to have worked), but for some reason when running via protoc, the same "not a valid Win32 application" error still happens.

@rocketraman
Copy link
Author

This might be related to the second item mentioned above: google/protobuf-gradle-plugin#268

@marcoferrer
Copy link
Owner

marcoferrer commented Oct 24, 2018

It looks like the problem is that the script thats embedded in the jar via spring boot is not executable in windows. I dont think there is any issue with the gradle protobuf plugin.

The fix is probably going to involved distributing another artifact that is executable on windows. I dont have any way to test it out at the moment. But I think if you point the protobuf gradle plugin to an executable bat script that executes the jar via java it might work in mean time. This will give me a chance to work on the long term solution. I dont have much experience with windows batch scripts but try this if possible

@if "%DEBUG%" == "" @echo off

set CMD_LINE_ARGS=%*
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

"%JAVA_EXE%" -jar C:\Users\Me\.gradle\caches\modules-2\files-2.1\com.github.marcoferrer.krotoplus\protoc-gen-kroto-plus\0.1.3\3c41d071d04c8558822447643894490e33a857b7\protoc-gen-kroto-plus-0.1.3-jvm8.jar %CMD_LINE_ARGS%

build.gradle

protobuf {
  protoc {
    artifact = 'com.google.protobuf:protoc:3.6.1'
  }
  plugins {
    kroto {
      path = "absolute/path/to/script.bat"
    }
  }
  ...
}

If that works then I can come up with a gradle task to hold you over in the mean time.

@rocketraman
Copy link
Author

rocketraman commented Oct 24, 2018

@marcoferrer Thanks, the batch script solves works around problem 2. However, the build gets further and still encounters problem 1. The specific error is:

18:36:04.214 [INFO] [org.gradle.process.internal.DefaultExecHandle] Successfully started process 'command 'C:\jdk1.8.0_191\bin\java.exe''
18:36:04.214 [DEBUG] [org.gradle.process.internal.ExecHandleRunner] waiting until streams are handled...
18:36:04.235 [ERROR] [system.err] Error: Unable to access jarfile /C:/Users/Me/.gradle/caches/modules-2/files-2.1/com.github.marcoferrer.krotoplus/kroto-plus-compiler/0.1.3/620b2a278b4d4beed80320bb4800339967f850d7/kroto-plus-compiler-0.1.3.jar

I think that leading slash is the issue.

@marcoferrer
Copy link
Owner

Whats confusing for me is that the snippet you posted is referencing the old stand alone compiler "kroto-plus-compiler-0.1.3.jar" and not the protoc plugin "protoc-gen-kroto-plus-0.1.3-jvm8.jar" . If your using the kroto-plus gradle plugin for 0.1.3 you can disable it. If possible can you post a snippet of your gradle config?

@rocketraman
Copy link
Author

rocketraman commented Oct 25, 2018

Aha, looks like I still had a krotoPlus { ... } block from an earlier version. I've removed it and gotten everything working properly on Linux again. Now on to the next Windows issue:

Execution failed for task ':generateProto'.
> protoc: stdout: . stderr: \source\myproject\krotoPlusConfig.json:H:\source\myproject\build/generated/source/proto/main/java/: No such file or directory

The krotoplus config is:

outputSubDir = "java"

I've used the --debug output to obtain the actual protoc command line, and the argument passed was as follows:

--kroto_out=ConfigPath=H:\source\myproject\krotoPlusConfig.json:H:\source\myproject\build/generated/source/proto/main/java

so you can see that the first : in H: is being mistaken for the separator between the config and output directory, which is why it is looking for directory \source\myproject\krotoPlusConfig.json:H:\source\myproject\build/generated/source/proto/main/java/. If I manually edit the argument to look like this:

kroto_out=ConfigPath=\source\myproject\krotoPlusConfig.json:H:\source\myproject\build/generated/source/proto/main/java

then the protoc command exits without an error. Note the second H: after the : delimiter does seem to be necessary -- oddly, removing the second H: results in another No such file or directory error.

@rocketraman
Copy link
Author

rocketraman commented Oct 25, 2018

A workaround seems to be to do this to relativize the config path before passing it to protoc:

option "ConfigPath=${file('.').toPath().toAbsolutePath().relativize(krotoConfig.toPath().toAbsolutePath()).toString()}"

Messy, but it seems to work.

UPDATE: Use file(System.getProperty("user.dir")) instead of file('.') -- see below.

@marcoferrer
Copy link
Owner

If this can hold you over in the mean time I can work on getting better windows support into an upcoming release.

@rocketraman
Copy link
Author

If this can hold you over in the mean time I can work on getting better windows support into an upcoming release.

Yup, it can! I've got workarounds for all issues identified. Looking forward to the next release.

@marcoferrer
Copy link
Owner

So I think I have a good solution to this problem but wanted to hold off on releasing it too early. I didnt want to hold up the coroutines update but the next release after that should have something in it to address this.

@marcoferrer
Copy link
Owner

@brandmooffin as per our convo, You can use the documentation from here to implement the windows support outlined in this issue. deployment-script-customization

@marcoferrer
Copy link
Owner

@brandmooffin We can try doing what the maven protobuf plugin does and wrap the jar using this.
https://github.com/poidasmith/winrun4j

@marcoferrer marcoferrer added bug Something isn't working plugin labels Jan 8, 2019
@marcoferrer
Copy link
Owner

The other half of this issue is the fact that the protoc --xxx_out flag uses : as a delimiter for options. Since protoc 3.2.0 a new flag was made available for passing plugin options (--xxx_opt). Support for this new flag was discussed in the following issue google/protobuf-gradle-plugin#210. I currently have a PR open for adding support for this flag at google/protobuf-gradle-plugin#290

@rocketraman
Copy link
Author

A workaround seems to be to do this to relativize the config path before passing it to protoc:

option "ConfigPath=${file('.').toPath().toAbsolutePath().relativize(krotoConfig.toPath().toAbsolutePath()).toString()}"

Messy, but it seems to work.

One correction for anyone finding this from Google, and using these workarounds... this should be:

option "ConfigPath=${file(System.getProperty("user.dir")).toPath().toAbsolutePath().relativize(krotoConfig.toPath().toAbsolutePath()).toString()}"

The reason is that in Gradle file('.') returns the project directory, not the working directory. The path must be relative to the working directory, not the project directory.

@Abegemot
Copy link

after applying those changes I still unfortunately get an error:

Execution failed for task ':newproto:generateProto'.

protoc: stdout: . stderr: Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
Caused by: java.lang.NullPointerException
at com.github.marcoferrer.krotoplus.generators.GeneratorContext$currentWorkingDir$2.invoke(GeneratorContext.kt:40)

And I'm at a lost to understand what shall I do, many thank's for any hint.

@marcoferrer
Copy link
Owner

@Abegemot Can you post a snippet of your current build configuration?

@Abegemot
Copy link

Sure, thank you so much, I really found your work not only very interesting but in my opinion you and the other people trying to bring protobuf to kotlin in a gentle and convenient way ought to be supported by jetbrains to bring up an official answer to such a technical cornerstone such as protobuf .

  • the configuration file and bat file are exactly the same as in the examples.

protobuf{
protoc{
artifact=Deps2.protocc
}
plugins{
plugins{
id("kroto"){
path="H:\prg\artifactidfake\newproto\mykrotobat.bat" // *
}
}
}
generateProtoTasks{
val krotoConfig = file("krotoPlusConfig.asciipb") // *
all().forEach{task->
task.inputs.files ( krotoConfig)
task.plugins {
id("kroto") {
outputSubDir = "java"
option("ConfigPath=${file(System.getProperty("user.dir")).toPath().toAbsolutePath().relativize(krotoConfig.toPath().toAbsolutePath()).toString()}")

                   }
               }
   }

}

}

@marcoferrer marcoferrer reopened this May 16, 2019
@marcoferrer
Copy link
Owner

Looking at the stacktrace posted earlier, I think the null pointer is coming from this line

More specifically I think its the call to File(path).parentFile. It looks like the path isnt being relativized correctly. What output do you get when you run the following:

println("ConfigPath=${file(System.getProperty("user.dir")).toPath().toAbsolutePath().relativize(krotoConfig.toPath().toAbsolutePath()).toString()}")`?

Also could you give this a try?

option "ConfigPath=${krotoConfig.absolutePath.replace(rootProject.projectDir.path, "").drop(1)}"

@Abegemot
Copy link

Thank you that did the job, nevertheless unfortunately when I run the build I only get generated the messages but not the grpc calls, which is weird, and can't start up a server or do anything.
I guess I'm doing something wrong but I'm clueless....

@Brainfree
Copy link

Brainfree commented Jun 24, 2019

I managed to hack together a pure gradle solutions to fix the windows problem.
It will have gradle fetch the plugin jar, copy it, then generate a batch file, where it'll point protoc to it.


configurations {
    kroto_conf
}

dependencies {
    kroto_conf "com.github.marcoferrer.krotoplus:protoc-gen-grpc-coroutines:$krotoplus_version:jvm8@jar"
    kroto_conf "com.github.marcoferrer.krotoplus:protoc-gen-kroto-plus:$krotoplus_version:jvm8@jar"
}


ext.kroto_gen_kroto_plus = new File("$buildDir/kroto/gen_kroto_plus.bat")
ext.kroto_gen_grpc_coroutines = new File("$buildDir/kroto/gen_grpc_coroutines.bat")

task setupKroto(type: Copy) {
    from configurations.kroto_conf
    into "$buildDir/kroto"

    ext.batch = { jar ->
        """
    @if "%DEBUG%" == "" @echo off
    
    set CMD_LINE_ARGS=%*
    set JAVA_HOME=%JAVA_HOME:"=%
    set JAVA_EXE=%JAVA_HOME%/bin/java.exe
    
    "%JAVA_EXE%" -jar $jar %CMD_LINE_ARGS%
    """.stripIndent()
    }


    doLast {
        kroto_gen_kroto_plus.text = batch("$buildDir/kroto/protoc-gen-kroto-plus-$krotoplus_version-jvm8.jar")
        kroto_gen_grpc_coroutines.text = batch("$buildDir/kroto/protoc-gen-grpc-coroutines-$krotoplus_version-jvm8.jar")
    }

}



protobuf {
    //download the proto compiler
    protoc {
        artifact = "com.google.protobuf:protoc:$protobuf_version"
    }

    generatedFilesBaseDir = "$projectDir/gen"

    //noinspection GroovyAssignabilityCheck
    plugins {
        grpc { artifact = "io.grpc:protoc-gen-grpc-java:$grpc_version" }
        coroutines {
            artifact = "com.github.marcoferrer.krotoplus:protoc-gen-grpc-coroutines:$krotoplus_version:jvm8@jar"
            //https://github.com/marcoferrer/kroto-plus/issues/6#issuecomment-432782481
            if(Os.isFamily(Os.FAMILY_WINDOWS)) {
                path = kroto_gen_grpc_coroutines.absolutePath
            }
        }
        kroto {
            artifact = "com.github.marcoferrer.krotoplus:protoc-gen-kroto-plus:$krotoplus_version:jvm8@jar"
            //https://github.com/marcoferrer/kroto-plus/issues/6#issuecomment-432782481
            if(Os.isFamily(Os.FAMILY_WINDOWS)) {
                path = kroto_gen_kroto_plus.absolutePath
            }
        }
    }

    generateProtoTasks {

        def krotoConfig = file("krotoPlusConfig.asciipb") // Or .json

        all().each { task ->

            //setup kroto for windows
            task.dependsOn setupKroto

            // Adding the config file to the task inputs lets UP-TO-DATE checks
            // include changes to configuration
            task.inputs.files krotoConfig

            task.plugins {
                grpc {}
                coroutines {}
                kroto {
                    // The extendable-messages generator needs the outputSubDir
                    // to be the same as 'task.builtins.java.outputSubDir' since
                    // it relies on the insertion_point api from protoc.
                    outputSubDir = "java"
                    //https://github.com/marcoferrer/kroto-plus/issues/6#issuecomment-457261961
                    option "ConfigPath=${krotoConfig.absolutePath.substring(krotoConfig.absolutePath.lastIndexOf(":") + 1)}"
                }
            }
        }
    }
}

@Brainfree
Copy link

Also, it seems a better solution for the ConfigPath problem is to simply strip away the drive ("C:"), then you can use absolute paths. I had a problem with the above solution in multi-project setup, where without absolute paths, it would not be able to find the config, if I assembled from the parent project.
Solution:

task.plugins {
    kroto {
        option "ConfigPath=${krotoConfig.absolutePath.substring(krotoConfig.absolutePath.lastIndexOf(":") + 1)}"
    }
}

@marcoferrer marcoferrer pinned this issue Aug 2, 2019
@rocketraman
Copy link
Author

Also, it seems a better solution for the ConfigPath problem is to simply strip away the drive ("C:"), then you can use absolute paths.

That only works if you know everything is on the c:\ drive.

marcoferrer added a commit that referenced this issue Nov 19, 2019
* build and publish native artifacts #6

* update tests to use native artifact

* bugfix for plugin working directory resolution

* update build to resolve plugin config relatively

* bump project version
@mattdkerr
Copy link

mattdkerr commented Nov 20, 2019

I'm using val krotoConfig = File("${project.name}/krotoPlusConfig.yml") for loading the file in Windows, and it works fine. It starts relative to the root project, so this is fairly straight-forward.

@marcoferrer
Copy link
Owner

With 0.6.0 released, there is now an executable windows artifact available.

@fitzsia2
Copy link

Hello. I'm using kroto-generator in an Android project and I think that I still have this issue on Windows. When I build the project I receive:

Caused by: java.lang.IllegalStateException: Config file does not exist. 'C:\Users\Andrew\StudioProjects\my-app\C'

I think it may be related to my folder structure.

I have the following setup:
Project:

my-app
⨽ libraries
  ⨽ networking
    ⨽ build.gradle
// build.gradle
protobuf {
    protoc {
        artifact = Deps.protoc
    }
    plugins {
        grpc {
            artifact = Deps.grpcGenerator
        }
        javalite {
            artifact = Deps.javaLiteGenerator
        }
        kroto {
            artifact = Deps.krotoGenerator
        }
    }
    generateProtoTasks {
        def krotoConfig = file("krotoconfig.asciipb")
        all()*.plugins {
            javalite {}
        }
        ofNonTest()*.plugins {
            grpc {
                // Options added to --grpc_out
                option 'lite'
            }
            kroto {
                outputSubDir = "java"
                option "ConfigPath=$krotoConfig"
            }
        }
    }
}

I found that if I use @Brainfree's solution for Windows, then it works, but I expected that release 0.6.0 would resolve this.

Please let me know if there is some more information I can provide.

@marcoferrer
Copy link
Owner

@fitzsia2 So originally the kroto+ plugin was not able to execute on windows environments. Version 0.6.0 introduced a native executable to mitigate this issue. But the problem still exists where the : in the path to the configuration file is mistaken by the protobuf compiler as an option delimiter. Currently in windows you still need to perform a small amount of path transformation to the configuration file to resolve correctly. You can see here how the project still relies on it.

Considering you had issues discovering this means that its not immediately clear to users and should be better documented. Thank you for bringing this to light.

                kroto {
                    outputSubDir = "java"
                    if(osdetector.os == "windows") {
                        // We want to relativize the configuration path
                        // because absolute paths cause issues in windows
                        // environments
                        option "ConfigPath=${krotoConfig.absolutePath.replace(System.getProperty("user.dir"), "").drop(1)}"
                    } else {
                        option "ConfigPath=$krotoConfig"
                    }
                }

option "ConfigPath=${krotoConfig.absolutePath.replace(System.getProperty("user.dir"), "").drop(1)}"

@AlexOreshkevich
Copy link

AlexOreshkevich commented Jun 15, 2020

Hi guys,

we just experienced somethings similar using Maven (protobuf-maven-plugin):

 Failed to execute goal org.xolstice.maven.plugins:protobuf-maven-plugin:0.5.0:compile-custom (kroto-plus) on project entity-api: protoc failed to execute because: 'nativePluginParameter' contains illegal characters

We configured config path just like that:

<pluginParameter>
  ConfigPath=${project.basedir}/kroto.plus.config.asciipb
</pluginParameter>

(maven multimodule project)

Do we have some workaround for Maven & Windows like we have for Gradle please?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working plugin
Projects
None yet
Development

No branches or pull requests

8 participants