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

cmd/go: -buildmode=c-archive should work on windows #13494

Closed
jimpark opened this issue Dec 5, 2015 · 33 comments
Closed

cmd/go: -buildmode=c-archive should work on windows #13494

jimpark opened this issue Dec 5, 2015 · 33 comments

Comments

@jimpark
Copy link

jimpark commented Dec 5, 2015

We'd like a way to use go as a library language on Windows. Since there is already issue #11058 that addresses the need for the c-shared build mode for generating DLLs, I am adding this request for getting static library support.

@jimpark jimpark changed the title -buildmode=c-archive should work on windows cmd/go: -buildmode=c-archive should work on windows Dec 5, 2015
@ianlancetaylor ianlancetaylor added this to the Unplanned milestone Dec 5, 2015
@nadiasvertex
Copy link
Contributor

Submitted a patch at https://go-review.googlesource.com/#/c/18057/

nadiasvertex added a commit to nadiasvertex/go that referenced this issue Dec 19, 2015
  * Add supporting files for runtime initialization
  * Add .ctors section on Windows to PE .o files.
  * Add INITENTRY to .ctors section for runtime initialization.
  * Add .text section symbol for .ctor relocations.
  * Use path.Join() in lib.go instead of Sprintf.
  * On Windows the go.o file may be empty when the 'ar' command is run to
   generate a C-style library archive. Adding an os.Stat() appears to force
   Windows to flush the contents of go.o in a way that makes them visible to
   the 'ar' process which runs directly after.
@gopherbot
Copy link

CL https://golang.org/cl/18057 mentions this issue.

@nadiasvertex
Copy link
Contributor

I've added 32-bit support to this code, however it no longer builds at all when I set GOARCH=386.

I get:

$ go build -v -x -buildmode=c-archive -o test.a calc.go
can't load package: no buildable Go source files in <path>

GOARCH=amd64 works perfectly fine.

Any ideas?

@alexbrainman
Copy link
Member

I can see rt0_windows_amd64.s changed in CL 18057. For 386 support, I suspect you want to make similar changes to rt0_windows_386.s ay the very least. No?

Alex

@nadiasvertex
Copy link
Contributor

I'm sorry, I should have been more clear. I have not pushed the 32-bit changes into the CL. I can do that, if you like. I made numerous changes, including rt0_windows_386.s. I admit that it is hard to diagnose a problem blind. I was thinking I just made some obvious beginner's mistake and perhaps you would might have seen something like this before.

@ianlancetaylor
Copy link
Contributor

It's just a guess, but perhaps you are getting no buildable Go source files in <path> because you have set GOARCH such that you are cross-compiling, but you did not explicitly set CGO_ENABLED=1.

@nadiasvertex
Copy link
Contributor

That was it exactly. The 32-bit Windows API does not support some of the runtime features I wrote for initialization. I will have to rewrite parts of that code.

@nadiasvertex
Copy link
Contributor

I am encountering very strange errors. Basically, hundreds of errors that look like:

'blah' referenced in section '.text' of 'blah' defined in discarded section '.text' of 'blah.../libkernel.a

I've tried to look through why this may be happening, but I'm afraid that I haven't come up with anything. Any ideas?

@mikioh mikioh closed this as completed Jan 3, 2016
@mikioh mikioh reopened this Jan 3, 2016
@alexbrainman
Copy link
Member

If implementing 32-bit is a problem, do not do it. Lets implement windows-amd64, and we'll worry about windows-386 later.

Alex

@nadiasvertex
Copy link
Contributor

Okay. I will disable the build commands for 32-bit, but I feel like I should leave the code in. The problem happens during the final link of the library. The support code should be correct, including the runtime and relocation bits. There's just something about the link command that needs to be figured out. Does that sound okay?

@jtsylve
Copy link
Contributor

jtsylve commented Jan 8, 2016

32-bit is also important to me. I'd like to help. I'm seeing those same link errors when I enable it with your patch.

Many errors like the following:

_free' referenced in section `.text' of C:/Program Files/mingw-w64/i686-5.1.0-p
osix-dwarf-rt_v4-rev0/mingw32/bin/../lib/gcc/i686-w64-mingw32/5.1.0/../../../../
i686-w64-mingw32/lib/../lib/dllcrt2.o: defined in discarded section `.text' of C
:/Program Files/mingw-w64/i686-5.1.0-posix-dwarf-rt_v4-rev0/mingw32/bin/../lib/g
cc/i686-w64-mingw32/5.1.0/../../../../i686-w64-mingw32/lib/../lib/libmsvcrt.a(dk
tbs01101.o)
`__initterm' referenced in section `.text' of C:/Program Files/mingw-w64/i686-5.
1.0-posix-dwarf-rt_v4-rev0/mingw32/bin/../lib/gcc/i686-w64-mingw32/5.1.0/../../.
./../i686-w64-mingw32/lib/../lib/dllcrt2.o: defined in discarded section `.text'
 of C:/Program Files/mingw-w64/i686-5.1.0-posix-dwarf-rt_v4-rev0/mingw32/bin/../
lib/gcc/i686-w64-mingw32/5.1.0/../../../../i686-w64-mingw32/lib/../lib/libmsvcrt
.a(dktbs00350.o)
`__amsg_exit' referenced in section `.text' of C:/Program Files/mingw-w64/i686-5
.1.0-posix-dwarf-rt_v4-rev0/mingw32/bin/../lib/gcc/i686-w64-mingw32/5.1.0/../../
../../i686-w64-mingw32/lib/../lib/dllcrt2.o: defined in discarded section `.text
' of C:/Program Files/mingw-w64/i686-5.1.0-posix-dwarf-rt_v4-rev0/mingw32/bin/..
/lib/gcc/i686-w64-mingw32/5.1.0/../../../../i686-w64-mingw32/lib/../lib/libmsvcr
t.a(dktbs00145.o)
`__initterm' referenced in section `.text' of C:/Program Files/mingw-w64/i686-5.
1.0-posix-dwarf-rt_v4-rev0/mingw32/bin/../lib/gcc/i686-w64-mingw32/5.1.0/../../.
./../i686-w64-mingw32/lib/../lib/dllcrt2.o: defined in discarded section `.text'
 of C:/Program Files/mingw-w64/i686-5.1.0-posix-dwarf-rt_v4-rev0/mingw32/bin/../
lib/gcc/i686-w64-mingw32/5.1.0/../../../../i686-w64-mingw32/lib/../lib/libmsvcrt
.a(dktbs00350.o)

@slimsag
Copy link

slimsag commented Jan 8, 2016

Can anyone shed some light on what might be causing the 32-bit link errors so others can look into it? From searching I found hints that it might be the order the libs are linked in.. but I had no luck changing the linking order of the libs to resolve the errors.

@ianlancetaylor
Copy link
Contributor

32-bit Windows uses a leading underscore on symbols. 64-bit WIndows does not. It may be related to that. Or it may not, it's just a guess.

@jtsylve
Copy link
Contributor

jtsylve commented Jan 8, 2016

before those errors I do see the following

Cannot export bad_proc_msg: symbol not found
Cannot export gosave: symbol not found
Cannot export masks: symbol not found
Cannot export setg_gcc: symbol not found
Cannot export shifts: symbol not found
Error: 0-bit reloc in dll

@alexbrainman
Copy link
Member

32-bit is also important to me. I'd like to help.

64-bit version does not work at this moment as far as I am concerned. We need testcarchive to PASS for us to even consider CL for inclusion. No point discussing 32-bit - it is only distracting everyone. If you want to help, help testcarchive to PASS.

Alex

@jtsylve
Copy link
Contributor

jtsylve commented Jan 8, 2016

testcarchive is only failing because the test is set up as a .bash file, which won't work on Windows.

I'll work on a test.bat now

@nadiasvertex
Copy link
Contributor

@alexbrainman The c-archive tests were rewritten by @ianlancetaylor and now they don't even compile on Windows. So... I'm really not sure how to make the tests pass at this point. I started rewriting the test.bash file in Go, but now that the signal handlers exist there's kind of no point.

  1. If it was rewritten in Go should it just be a "go run" file?
  2. What do you suggest we do about the test files?

@ianlancetaylor
Copy link
Contributor

Sorry about that. Signal handling is pretty hard to get right for c-archive and c-shared, so we needed the tests. I didn't really think about the effect on Windows. It's fine with me if you want to put in a main_windows.c.

Probably test.bash should be replaced by a archive_test.go file that is run using go test, like the one in misc/cgo/testshared.

@alexbrainman
Copy link
Member

I still prefer we use Go to write tests (in $GOROOT/src/cmd/dist/test.go or what Ian suggested). We can write test to do whatever is required for different OSes. But I will let you do what you want.

Alex

@nadiasvertex
Copy link
Contributor

I have added a main_windows.c, which contains the contents of main.c before @ianlancetaylor committed the signal handling changes. I updated test.bat to use that file instead of the other one.

Note that I am willing to rewrite the tests in Go, but I would like to get this patch accepted first. The c-archive tests pass for me on 32 and 64-bit.

@jtsylve
Copy link
Contributor

jtsylve commented Jan 11, 2016

I can also verify that c-archive now works for me on both 32 and 64 bit Windows

@nadiasvertex
Copy link
Contributor

I removed the InitOnce based synchronization for the runtime init. This allows the patch to compile on older versions of mingw.

@nadiasvertex
Copy link
Contributor

Just an update. The only problems left appear to be link errors with the 32-bit mode. This is causing an undefined reference to WinMain(). I am investigating this issue, but it doesn't appear related to my patch other than that cgo may not have worked properly at all on Windows 32-bit, and now we would like it to.

Anyone who is looking to help get this patch done sooner could investigate TestCgoExternalThreadPanic, TestCgoCrashHandler, TestCgoTraceback, etc.

I am looking into these failures too, but more eyes are better.

@nadiasvertex
Copy link
Contributor

I have verified the cause of the problem:

If I create a file:

//test.c
int main(int argc, char **argv) {
return _main(argc, argv);
}

and I include it in the build of the failing tests, the build completes normally.

This verifies that it is the underscore problem.

I have tried to adjust the code in pe.go which prepends the underscore to avoid doing that for main(), but it doesn't seem to have any effect.

@ianlancetaylor , @alexbrainman I am not sure where main() is defined for a cgo-enabled program on 32-bit windows. If someone could point me to that location, the fix appears to be trivial.

@minux
Copy link
Member

minux commented Jan 31, 2016 via email

@nadiasvertex
Copy link
Contributor

@minux, thank you. This bug has been fixed. The failing tests now pass. Please re-evaluate the patch for correctness.

@nadiasvertex
Copy link
Contributor

@alexbrainman I have addresses the issues you raised in the patch. Please re-evaluate it. Thanks!

@alexbrainman
Copy link
Member

@alexbrainman I have addresses the issues you raised in the patch.

Thank you for letting me know. But you don't need to comment about it on this issue. I can see all your new changes on Gerrit. Anyone who posts on your CL (and all nominated reviewers and CC) will get email every time you comment there or upload new patch.

Alex

nadiasvertex added a commit to nadiasvertex/go that referenced this issue Feb 14, 2016
   * Add supporting files for runtime initialization
   * Add .ctors section on Windows to PE .o files.
   * Add INITENTRY to .ctors section for runtime initialization.
   * Add .text section symbol for .ctor relocations.
   * Use path.Join() in lib.go instead of Sprintf.
   * On Windows the go.o file may be empty when the 'ar' command is run to
    generate a C-style library archive. Adding an os.Stat() appears to force
    Windows to flush the contents of go.o in a way that makes them visible to
    the 'ar' process which runs directly after.
   * Add test for c-archive functionality.
   * Add 32-bit support for runtime and init relocation.
   * Add a windows version of main.c for testcarchive.

Fixes golang#13494

Change-Id: I5a2f254d5cc09a69d1eed3d7a8618e49e75d114c
@nadiasvertex
Copy link
Contributor

@minux, @ianlancetaylor: There is some question about the right thing to do here:

// os1_windows.go
// Used by the C library build mode. On Linux this function would allocate a
// stack, but that's not necessary for Windows.
//go:nosplit
func newosproc0(mp *m, stk unsafe.Pointer) {
newosproc(mp, stk)
}

Some similar implementations of this function use //go:nosplit, others use //go:nowritebarrier
Neither @alexbrainman nor I know what the right thing to do here is. Can you please advise?

@ianlancetaylor
Copy link
Contributor

On Unix systems, newosproc0 is called at process startup time, with no stack guards installed. I assume the same is true in your Windows implementation. Therefore, it must be //go:nosplit. This is not optional. Also, it must only call //go:nosplit functions. This is unlike newosproc, which does not need to be //go:nosplit. But if you are going to have newosproc0 call newosproc, as implied above, then newosproc must also be //go:nosplit.

Similarly, newosproc0 is called before the GC is installed, and therefore any write barriers will fail, so //go:nowritebarrierrec is a good choice (nowritebarrierrec is better than nowritebarrier, as it means that not only must this function have no write barriers, every function it calls must have no write barriers). This is a warning option that does not affect code generation, so it's OK if it's not there. But since you are writing new code, you should add it. newosproc is normally //go:nowritebarrier because it is called from newm, where the comment explains why no write barriers are permitted.

@nadiasvertex
Copy link
Contributor

@alexbrainman or anyone else:

I rebased onto origin/master and I am getting a new error when I run all, but only on 64-bit architectures:

ok      cmd/fix 0.125s
--- FAIL: TestShadowingLogic (0.77s)
        go_test.go:244: running testgo [list -f ({{.ImportPath}}) ({{.ConflictDir}}) ./testdata/shadow/root1/src/math]
        go_test.go:259: standard output:
        go_test.go:260: (_/C_/Users/Christopher_Nelson/t/src/cmd/go/testdata/shadow/root1/src/math) (C:\Users\Christopher Nelson\t\src\math)

        go_test.go:1884: shadowed math is not shadowed; looking for (_/C_/Users/Christopher Nelson/t/src/cmd/go/testdata/shadow/root1/src/math) (C:\Users\Christopher Nelson\t\src\math)
        go_test.go:244: running testgo [list -f ({{.ImportPath}}) ({{.ConflictDir}}) ./testdata/shadow/root1/src/foo]
        go_test.go:259: standard output:
        go_test.go:260: (foo) ()

        go_test.go:244: running testgo [list -f ({{.ImportPath}}) ({{.ConflictDir}}) ./testdata/shadow/root2/src/foo]
        go_test.go:259: standard output:
        go_test.go:260: (_/C_/Users/Christopher_Nelson/t/src/cmd/go/testdata/shadow/root2/src/foo) (C:\Users\Christopher Nelson\t\src\cmd\go\testdata\shadow\root1\src\foo)

        go_test.go:1897: shadowed foo is not shadowed; looking for (_/C_/Users/Christopher Nelson/t/src/cmd/go/testdata/shadow/root2/src/foo) (C:\Users\Christopher Nelson\t\src\cmd\go\testdata\shadow\root1\src\foo)
        go_test.go:244: running testgo [install ./testdata/shadow/root2/src/foo]
        go_test.go:263: standard error:
        go_test.go:264: go install: no install location for C:\Users\Christopher Nelson\t\src\cmd\go\testdata\shadow\root2\src\foo: hidden by C:\Users\Christopher Nelson\t\src\cmd\go\testdata\shadow\root1\src\foo

        go_test.go:283: testgo failed as expected: exit status 1
FAIL
FAIL    cmd/go  92.031s

Any guidance, would be appreciated.

@ianlancetaylor
Copy link
Contributor

I doubt the cmd/go test failure has anything to do with your patch. It should probably be a separate issue.

@gopherbot
Copy link

CL https://golang.org/cl/20892 mentions this issue.

gopherbot pushed a commit that referenced this issue Mar 23, 2016
This is to support https://golang.org/cl/18057, which is going to add
Windows support to this directory.  Better to write the test in Go then
to have both test.bash and test.bat.

Update #13494.

Change-Id: I4af7004416309e885049ee60b9470926282f210d
Reviewed-on: https://go-review.googlesource.com/20892
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
@golang golang locked and limited conversation to collaborators Apr 5, 2017
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

9 participants