-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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-shared should work on windows #11058
Comments
It would help to be more specific: different -buildmode options are, and always will be, supported on different systems. Which -buildmode options are you specifically interested in? |
Probably, most of windows users are looking for a way to generate dlls.:
or
|
I only need PS: Also hope fix #9510 in Go1.5! |
I would also like to see this happen. Is anyone currently working on this issue? Any CL's which may be reviewed? |
Unfortunately, I'm not aware of anyone working
on this issue right now.
|
I also need this. If I had some idea how much work was involved I might be willing to contribute an implementation. I know that Windows DLLs are fairly different from ELF style shared libraries, so if this is an enormous task it won't be something I can commit to. Is there any way to find out how much/what kind of work would be involved? |
@nadiasvertex The main thing is to make the function hostlink in cmd/link/internal/ld/lb.go do the right thing on Windows. On Darwin it invokes theC linker with -dynamiclib. On GNU/Linux it invokes the C linker with -Wl,-Bsymbolic -Wl,-z,relro -shared -Wl,-z,nodelete. Basically, if you produce a list of commands that will turn a Windows object file into a Windows DLL, change hostlink to invokes those commands. That said, it's possible that Windows needs to know the list of symbols that are callable from outside the DLL. It used to need to know that, but it's been many years since I looked at it. If you need that list of symbols, it's available by looping over the symbol table and looking for the Cgoexport field having a CgoExportStatic flag. |
Great! I'll look at it. I suspect that the challenge is mostly in knowing On Mon, Dec 7, 2015 at 10:58 AM Ian Lance Taylor [email protected]
|
@ianlancetaylor I started looking into this a little more, and it turns out that I have some questions about some fundamental parts of the architecture. For example:
In case it is helpful, the current trace output looks like: WORK=C:\Users\CHRIST command-line-argumentsHEADER = -H11 -T0x401000 -D0x0 -R0x1000 |
I don't think anybody we must require GCC, but clearly we do need some other toolchain. If somebody wants to add support for MSVC, I think that would be great. In any case, I think we do want to make it possible to suppose -buildmode=c-shared using GCC.
|
You might also have to worry about how thread-local storage works in a DLL (I have no idea how this sort of thing works on windows) |
If you just want to build a DLL that does not contain any C code, you don't have to use external linker. I am sure you can modify Go linker to produce what you want. Go linker does just that when it creates windows executables. I don't see how creating of DLL would be different. You will also have to deal with issues every windows DLL deals with. You must have set of mimimum functions required in DLL. You have to deal with your DLL exported functions called on different threads. You have to deal with exceptions.
What is wrong with the way thread-local storage works in Go windows executables now? Alex |
Let me be clear, I assume that go has already dealt with most of these On windows there were certain conventions for dll entry points. However, My personal need is to take go code, expose some of it via a C ABI, and On Mon, Dec 7, 2015, 7:27 PM Alex Brainman [email protected] wrote:
|
It's unusual to want to build a shared library/DLL if you don't have a C toolchain available. On Unix we decided to simply rely on that, rather than spend the time to teach the Go linker how to generate a shared library. On Windows, in which DLLs are more different from executables than they are on ELF, I would suggest following the same strategy. Since in the general case we must use external linking when generating a shared library, I don't think it's so bad to always require it. |
It is not true. There are variety of non C compilers on Windows that will allow you to build a DLL.
You don't have to use DLLs for that. You can also include your Go code as part of your final executable. But then you need to be specific about the tools you use to build that executable. Is that going to be gcc? If yes, then what Ian suggests is your path. I do not know much about gcc, so I am not familiar with what is required. You can also try and create DLL using gcc. Again, that is path that Ian suggested. If you don't want to rely on gcc to build your programs, then you would have to build windows DLL as part of Go linkers. The code lives in $GOROOT/src/cmd/link/internal/ld/pe.go. Current code produces Windows PE executable (among other things). You can modify it to output Windows DLL (with whatever DLL requires). I am familiar with pe.go, but I have never built a DLL from scratch. But happy to help. You should, probebly, try gcc approach first, because it has been implemented on some non-Windows OSes already. So, perhaps, it will be easy enough.
Perhaps I misunderstand you, but I disagree. I don't see how building Windows DLL is different from building Windows executable. Surely we require gcc for cgo, but other than that.
Fair enough.
There are advantages of not requiring gcc on Windows. Go just works out of the box. When things break, you have all source code with you; and source code is Go. You can build Go Windows executable on any other OS - you can use Plan9 computer to build Go Windows executable. Alex |
@alexbrainman This issue is specifically about -buildmode=c-shared. The only reason to use -buildmode=c-shared is to build a DLL that can be linked into a program written in C. My thinking is that people doing that are probably also writing a program in C, and therefore have a C compiler. But I'm obviously not a Windows developer, so I may be wrong. |
Fair enough. Similar I am not familiar with what -buildmode provides. What -buildmode flag should I use to build Windows DLL? DLL that can be called from any Windows executable or another DLL. These others (executables and DLLs) can be written in C, but don't have to be - they can be written in Go. We (Go executables we build) use system DLLs (produced by Microsoft) all the time. Do you see Go provide way to build DLLs just like these? Alex |
The intent is to write a plugin package that can be used to open Go shared libraries built with -buildmode=plugin. But this has not been implemented (see https://golang.org/s/execmodes for this and more about -buildmode). On Windows, it may already work to use -buildmode=c-shared and open the DLL from a Go program. The disadvantage would be that you can only use functions with a C style interface, and you would have two different Go heaps and garbage collectors--one in the main program and one in the DLL. That is, -buildmode=c-shared is intended to give you a complete DLL that can be opened by a program written in any language, so it includes a complete copy of the Go runtime. |
Thank you for explaining, Ian. Alex |
Nothing, but it works by assuming g lives at a fixed offset from $fs, and when you are in a dynamic library that's going to be loaded into another process, you can't assume a fixed offset because something in that process or another dynamic library might already be using that offset. Or at least, that's the sort of problem you get on an ELF system -- like I said, I don't know how windows works here. But I suspect you'll need to change something in the area. |
FTR, on windows, mingw doesn't have support for native
thread local storage (__thread keyword is emulated.)
That said, Go uses the ArbitraryUserPointer field in TIB
as TLS slot (https://golang.org/cl/5519054), which means
if you load a Go DLL into another process which also ues
ArbitraryUserPointer, then there could problems.
|
Yes. We would have to find different way to find TLS slot. Alex |
To provide some clarity on my motivation and goals: I want to build a .dll because I don't know what code will eventually consume the pieces I am responsible for. In some cases a static library is enough, but in other cases it is not. For example, JNI and C#'s PInvoke require a .dll file. If it turns out that making a go .dll via -buildmode=c-shared is a larger project than I can take on, I hope to fall back to creating a static library via -buildmode=c-archive and then write some C functions that call the Go code, and are themselves DLL exports. I understand that cgo already lets me register callbacks, and it certainly allows me to call into C code which may do just about anything. Consequently, I would imagine that the TLS problem has already been solved. I understand that a .dll adds some additional wrinkles to this situation, but I have to imagine that that is limited to the setup code. With respect to @mwhudson, I don't understand what problem you are describing. If you are saying that the $fs segment register is used as a base, I'm not sure why you think what some other process is doing matters. The entire register set contents are isolated per process. The code itself lives where it lives, and is updated through the GOT and PLT tables at dll initialization. I confess that it has been a long time since I dealt with any of this in detail so I certainly may be missing something important here. However, considering that this all works for non-Windows platforms, and considering that the Windows support for generating native go code is very good, I have to imagine that the vast majority of these issues are known and have been solved. I am very interested in specific guidance, and in known limitations of the go toolchain. I'm not terribly interested in generic 'thar be dragons" commentary because if this was really trivial it would be done already. :-) |
@amiracam that is odd, since I see the patches in the commit list for that branch. However, I will look into it. Thanks for pointing this out! With respect to the generated .h file, my patch doesn't have anything to do with that. They are compiler and linker changes only. I didn't touch the C FFI layer. I wonder if you are using a supported C compiler. |
@nadiasvertex , yes agreed, i had checked out the patches from within the GIT page and they do indeed show up there, then I took a shot at looking at the zip. I'm on Win 10 64 bit ,I believe its using GCC and indeed I use GCC to compile the project |
@nadiasvertex , so I can generate a .h and .dll and can import that into a c project and do a build which will generate an executable without any errors, however when I try to run the executable it runs without error but does nothing ie. it should have print to console, I can tomorrow morning submit my very trivial experiment, BTW, I'm using the TDM-GCC distribution |
@nadiasvertex package main import "fmt" func main(){} which via generates a hello.dll as well as hello.h C code (driver.c) : #include <stdio.h> int main(){ for which i use this will generate hello.exe which when executed will do absolutely nothing if I comment out the exported HelloWorld function and as well the include for the hello.h and compile , I do get a working exe but of course thats just a sanity check. Something about linking the shared object / dll generates a silent non-working executable. I'm new to C and well pretty new to GO as well, how can I go about debugging this ? thanks |
@amiracam Have you tried this under Linux or macOS? If so, does it work there? |
yes sir, works fine on MacOS Sierra , have not yet setup GO under Ubuntu but if it works on the Mac pretty sure it would work on Linux, ultimately we want to be cross platform Windows / Linux , I'll start testing there as well |
@amiracam okay. That is useful to know. I will look into it. |
@nadiasvertex but using a clean GO 1.8.3 distribution on Win 10 we can generate a working executable |
@nadiasvertex hi, do you now have a 1.9 rebase? thanks |
I am trying to make c-shared work on windows,. There is a codegenArg variable in cmd/go/internal/work/build.go:BuildModeInit - it controls the linker's -installsuffix argument. The codegenArg is blank for darwin, but it is set to "-shared" for other OSes. What should I set it for windows? It seems to work either way. Thank you. Alex |
Change https://golang.org/cl/68410 mentions this issue: |
@alexbrainman The |
TestUnexportedSymbols requires dup2 that my gcc installation does not have. TestSignalHandlersWithNotify fails with: undefined: syscall.SIGIO. TestSignalHandlers fails with: sched.h: No such file or directory. TestExportedSymbolsWithDynamicLoad fails with: dlfcn.h: No such file or directory. Also add t.Helper calls to better error messages. Updates #11058 Change-Id: I7eb514968464256b8337e45f57fcb7d7fe0e4693 Reviewed-on: https://go-review.googlesource.com/68410 TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
It does make sense. Thank you for explaining. That is how I read the code. It just both Alex |
Change https://golang.org/cl/68770 mentions this issue: |
Otherwise we end up with testp?.exe files after the tests run. Updates #11058 Change-Id: Ieccfc42da6192622bdab1f9a411ccd50bb59fd5b Reviewed-on: https://go-review.googlesource.com/68770 Run-TryBot: Alex Brainman <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
Change https://golang.org/cl/69091 mentions this issue: |
Change https://golang.org/cl/69090 mentions this issue: |
Updates #11058 Change-Id: I2a8bf4403b680ab8bf06fff18291f3bf67261e27 Reviewed-on: https://go-review.googlesource.com/69090 Reviewed-by: Ian Lance Taylor <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]>
No description provided.
The text was updated successfully, but these errors were encountered: