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

x/mobile/cmd/gomobile: not setting TMP directory on Windows #10928

Closed
merickson opened this issue May 21, 2015 · 9 comments
Closed

x/mobile/cmd/gomobile: not setting TMP directory on Windows #10928

merickson opened this issue May 21, 2015 · 9 comments

Comments

@merickson
Copy link

Bug Report

What version of Go are you using (go version)?

I'm using go version devel +3a3773c Fri May 8 17:01:24 2015 +0000 windows/amd64

What operating system and processor architecture are you using?

Windows 8.1 Pro, x86_64.

What did you do?

After setting up a development tip GOROOT, I installed gomobile and attempted to run gomobile init. I have successfully been able to do this on Linux / x86_64.

What did you expect to see?

The Android NDK setup and gomobile ready to bind packages.

What did you see instead?

I got the following error after running gomobile init -x -v:

gomobile: cannot get cmd/dist version: exit status 2 (go tool dist: mkdir C:\Windows\go-tool-dist-506627087: Access is denied.

Resolution

I discovered the problem's root with checkVersionMatch() at https://github.com/golang/mobile/blob/master/cmd/gomobile/init.go#L394 . Running dist.exe, as checkVersionMatch() attempts to do, will try to create a temporary file as part of its init process (see https://github.com/golang/go/blob/master/src/cmd/dist/build.go#L216 ). On Windows, os.TempDir will use GetTempPath to resolve where to create its temporary directory.

Note, then, the configuration of cmd.Env in checkVersionMatch() above. It lacks the appropriate envars for Windows to steer it correctly to the appropriate temp directory. I added the following code immediately after setting cmd.Env:

    if goos == "windows" {
        cmd.Env = append(cmd.Env, "TMP=" + os.Getenv("TMP"))
    }

One quick gomobile rebuild later, and gomobile init ran to completion successfully and as expected.

@alexbrainman
Copy link
Member

Windows is very particular about process environment. You have found that it needs TMP, but there are others. I suggest not to take chance to miss anything, and instead start with os.Environ and change / remove things instead of starting with blank environment.

exec.Command in checkVersionMatch is not the only one that needs fixing. There are others.

Alex

@alexbrainman alexbrainman changed the title checkVersionMatch() in gomobile init not setting TMP directory on Windows x/mobile/cmd/gomobile: not setting TMP directory on Windows May 21, 2015
@merickson
Copy link
Author

For what it's worth, I am now able to build and deploy golang bindings to Android on Windows after that one patch. I totally see your point about that however.

@crawshaw
Copy link
Member

Thanks for the detailed bug report. I believe https://golang.org/cl/10401 will fix this, but my windows setup currently isn't working to test it. (Hana has a working setup, I'll ask for login details when she gets back.)

@merickson
Copy link
Author

Looks good off the bat. I'm away from my Windows rig this week myself, otherwise I'd be happy to test.

@alexbrainman
Copy link
Member

Fixed by https://golang.org/cl/10401 But the change does not preserve any parent process environment variables - I expect this will break other functionality.

Alex

@crawshaw
Copy link
Member

crawshaw commented Jun 1, 2015

@alexbrainman we've had just as many bugs in gomobile init from preserving variables we didn't mean to as forgetting to pass them through (the last one was a spurious GOBIN), so I favor explicit lists. If you can think of anything in particular that may cause a problem, please let me know.

@alexbrainman
Copy link
Member

Environment variables is "global" resource. All software uses it. You should not be removing variables that you didn't set there. I don't remember details, but we had problems with random generator not working on some versions of Windows because we removed an environment variable. But it is your call.

As to your "spurious GOBIN". This is simple bug on your part. You should manage variables that affect your program.

Alex

@crawshaw
Copy link
Member

crawshaw commented Jun 3, 2015

I'm sorry I don't follow that argument. On unix environment variables are used by the binary being run. Are they put to some other use on windows?

In this case the binaries we are running are our own. Specifically src/cmd/dist. In the case of the GOBIN bug, make.bash. We should know all of the environment variables in play. So the two approaches both have risks:

  • explicit list only: we miss a variable (or a new variable is added to cmd/dist while we don't notice) and not setting it means gomobile behaves incorrectly. The implicit env may have provided the correct value.
  • explicit list + implicit env: we miss a variable (or a new one is added and we don't notice) and the implicit environment variable means it does the wrong thing. Excluding the variable may have been correct.

Both ways have bugs. Given the programs being run are small and ones we control the source for, I prefer the explicit list only because it's a little simpler. Hopefully bugs will just be builds misbehaving, rather than gomobile build interfering with people's go tool setup. (Something I very much want to avoid.)

I agree with the general principle that if the binaries being run were user binaries, we should plumb their environment through, as they understand their binaries better than we do. But that's not the case here, so I don't think that principle applies.

If I've misunderstood, please let me know. (And as always, thank you for your windows expertise @alexbrainman, I don't think Go would work on windows without you.)

@alexbrainman
Copy link
Member

I'm sorry I don't follow that argument. On unix environment variables are used by the binary being run. Are they put to some other use on windows?

I don't know about UNIX, but on Windows your program calls syscalls. Syscalls are just C functions that live inside system DLLs. These can (and do) use any environment variable. Simplest example is GetTempPath:

C:\go\path\mine\src\foo>type main.go
package main

import (
        "fmt"
        "os"
)

func main() {
        fmt.Println(os.TempDir())
        os.Clearenv()
        fmt.Println(os.TempDir())
}

C:\go\path\mine\src\foo>go run main.go
C:\DOCUME~1\brainman\LOCALS~1\Temp


C:\go\path\mine\src\foo>

but there are others. Like I said earlier, we have seen (as far as I remember) one of Windows syscalls that responsible for generating "random data" fail because we cleared environment and the syscall was expecting some variable to be set. It would happen only on some versions of Windows, but not on others (thus making debugging harder).

In general you cannot even rely on "system DLLs" to be the same everywhere. Some products (that people install) modify system DLLs if they need access to some functionality that otherwise unavailable. Like antivirus and similar. These can do things you never expect.

Also you need to consider every child process of src/cmd/dist today and in the future.

I don't think it is worth the risk. If you leave environment as you've found it no one can blame you.

rather than gomobile build interfering with people's go tool setup

I agree with that argument of yours. You should try and change as little as possible of user environment. And that includes not clearing all environment variables.

Alex

@golang golang locked and limited conversation to collaborators Jun 25, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants