Go: cmd/link: 支持 msvc 目标文件

创建于 2017-07-11  ·  222评论  ·  资料来源: golang/go

我知道 go 链接器当前无法链接 msvc 目标文件,并且也认识到此问题的优先级可能较低。 但是,支持它会很好,因为它会在一定程度上简化 Windows 工作流程。 这个问题主要是为了了解这将需要多少努力和/或需要什么。

Builders FeatureRequest NeedsInvestigation OS-Windows

最有用的评论

嘿,从这个帖子的底部看来,您已经解决了 MSVC 问题。 但是,如果您遇到任何问题,我会加入 MSVC 团队。 随时在 github 或电子邮件上 ping 我 ([email protected])

所有222条评论

/cc @alexbrainman

@xoviat

谢谢

亚历克斯

PS:我要到七月底才有电脑。 我会看看这个。

你有什么问题?

我还没有尝试过,但我想通过将它们作为 .syso 链接到 go 链接器来专门调用 msvc 对象文件中的 c 函数。 我读过的所有内容都表明这是不可能的,但我将创建一个程序来重现发生的特定错误。

通过将它们作为 .syso 与 go 链接器链接来专门调用 msvc 目标文件中的 c 函数

您是否尝试将这些构建到 DLL 中,并从 DLL 内部使用它们?

我将创建一个程序来重现发生的特定错误。

请,做。 谢谢你。

亚历克斯

您是否尝试将这些构建到 DLL 中,并从 DLL 内部使用它们?

这其实是我最初的计划。 我正在使用 swig,因此单独编译生成的 c 代码然后将函数重写为 DLL 导出不太方便。 这并不难,但是当 gcc 的工作流程只是go generate; go build时就很烦人。

好的,我有一个程序。 从这些文件开始:

你好去:

package main

/*
    extern void hello();
*/
import "C"

func main() {
    C.hello()
}

你好ç:

#include <stdio.h>

extern void hello()
{
    printf("Hello World from C");
}

然后运行这些命令(在路径上使用 msvc):

cl /c hello.c
mv hello.obj hello.syso
mv hello.c hello.c.bak
go build

结果:
Warning: corrupt .drectve at end of def file

运行生成的文件时:

Exception 0xc0000005 0x8 0x13 0x13
PC=0x13
signal arrived during external code execution

main._Cfunc_hello()
        _//_obj/_cgo_gotypes.go:41 +
main.main()
        C://hello.go:9 +0x27

goroutine 17 [syscall, locked to thread]:
runtime.goexit()
        C:/Program Files/Go/src/runtime/asm_amd64.s:2197 +0x1
rax     0x4a5960
rbx     0xc042045f78
rcx     0x4a9a20
rdi     0xc042045f78
rsi     0x4adc60
rbp     0xc042045f38
rsp     0x6dfd68
r8      0xc042016340
r9      0x0
r10     0xc04204faa0
r11     0x4783c2
r12     0x0
r13     0x6
r14     0x0
r15     0xf1
rip     0x13
rflags  0x10216
cs      0x33
fs      0x53
gs      0x2b

我的电脑上没有安装 cl 命令。 我如何安装 msvc?

谢谢你。

亚历克斯

您需要此处的“构建工具 2017”。 微软现在实际上允许任何人免费使用visual studio,只要它不是用于商业开发。 如果太麻烦,如果你想要,我可以给你目标文件。

如果只有 C++ 不是一回事,我就不必担心这一点。 但就是这样,所以痛苦还在继续……

您需要此处的“构建工具 2017”。

知道了。 谢谢你。

如果太麻烦,如果你想要,我可以给你目标文件。

是的,请在某处发布 hello.obj。

想多了。 您实际上是在使用 gcc 来链接使用 msvc 编译器编译的目标文件。 你能试着做你的练习,但是用 gcc 将 hello.obj 链接到 C 程序来替换“go build”步骤吗? 也许以前已经做过了。 我怀疑,如果我们知道如何做到这一点,我们也许可以用 Go 做类似的事情。

亚历克斯

AFAIK lld https://github.com/llvm-mirror/lld支持 msvc 对象文件。

目标文件在这里: https :

lld https://github.com/llvm-mirror/lld支持 msvc 对象文件

Go 在 Windows 上使用 gcc 链接器(不是 lld)。

目标文件在这里: https :

我八月份回家时会尝试一下。 谢谢你。

亚历克斯

Go 在 Windows 上使用 gcc 链接器(不是 lld)。

我知道。 但是lld是msvc对象格式最好的开源文档。

我实际上从 ld 得到同样的错误,所以错误肯定来自 ld。

我实际上从 ld 得到同样的错误,所以错误肯定来自 ld。

是的。 我们需要通过msvc编译部分,和gcc链接来研究如何构建C程序。

亚历克斯

请原谅我的无知,但是 gcc 链接究竟是什么? 它是链接 go 链接器的输出吗?

对目标文件运行 objconv 以转换为 elf:

objconv -felf hello.obj hello.syso

我们现在有这些错误:

hello.syso: In function `__local_stdio_printf_options':
(.text$mn+0x3): undefined reference to `?_OptionsStorage@?1??__local_stdio_printf_options@@9<strong i="9">@9</strong>'
hello.syso: In function `_vfprintf_l':
(.text$mn+0x3a): undefined reference to `__stdio_common_vfprintf'
hello.syso: In function `printf':
(.text$mn+0x28): undefined reference to `__acrt_iob_func'
collect2.exe: error: ld returned 1 exit status

可能 stdio 是禁区?

请原谅我的无知,但是 gcc 链接究竟是什么? 它是链接 go 链接器的输出吗?

您使用 2 个程序来构建您的 Go 程序:

  • 编译器将您的 .go 文件(当时 1 个包)转换为存储在 %GOPATH%/pkg 目录下的目标文件;
  • 从 %GOPATH%/pkg 下的目标文件构建最终 .exe 文件的链接器。

有时(当你的一个包使用 Cgo 时),Go 链接器调用外部链接器来查找在 C 中实现的所有位。想象你从 C 代码中调用 printf。 C printf 编译的代码需要成为 Go 可执行文件的一部分,但 Go 链接器不知道从哪里获取它。 所以 Go 链接器调用外部链接器来包含该代码。

当前的 Go 使用 gcc 编译器/链接器来编译和链接 C 代码(我们使用 mingw gcc)。 如果要使用不同的编译器(由 Microsoft)编译 C 代码,则必须使用相应的链接器(由 Microsoft)来查找编译器创建的所有外部 C 代码。

所以,我想,我建议使用 gcc 链接器是错误的。 对于一般情况,您必须同时使用 Microsoft 编译器和链接器。 我们必须弄清楚 Microsoft 链接器需要什么作为输入并匹配它。

如果您的 C 代码没有任何外部代码,您可能会在没有 MC 链接器的情况下逃脱。 请尝试一些非常简单的 C 程序(例如添加 2 个整数之类的程序)。 这可能就像你上面描述的那样工作。

亚历克斯

可能 stdio 是禁区?

我怀疑您需要调用 Microsoft 链接器才能找到该代码。

亚历克斯

我不确定但是

objconv -felf hello.obj hello.syso

也许,您应该尝试使用 coff 或 omf 而不是 elf?

也许,您应该尝试使用 coff 或 omf 而不是 elf?

@xoviat是的,您不应该将 .obj 文件转换为 elf,Windows 版本的 gcc 会像任何其他 Windows 编译器一样生成 pe/coff 文件。

亚历克斯

Go 链接器调用外部链接器来查找在 C 中实现的所有位。

使用的具体命令是什么? 如果我知道 mingw 命令,那么也许我可以沿着文件比较路径继续尝试让 msvc 匹配 mingw 输出的内容。

您可以通过运行go build -ldflags=-v来查看确切的注释。

好吧,据我所知:

ld (link -> go.obj) + (gcc -> obj files) ==> a.out.exe

Go 似乎用这些文件创建了一个临时目录。 有没有办法保留临时目录,以便我可以检查其内容?

试试go build -work

WORK=C:\Users\mattn\AppData\Local\Temp\go-build566171254

目标文件保留在此目录中。

-work选项实际上不会保留链接器创建的临时文件。 目前,您只需要编辑链接器源即可不删除目录。 我们可能应该为此添加一个选项,以一种或另一种方式。

目前,您只需要编辑链接器源即可不删除目录。

如果你不介意,我会等到这个在 HEAD 中实现,这样我就不必做重复的工作了。

有没有办法保留临时目录,以便我可以检查其内容?

cmd/link 程序为此具有 -tmpdir 标志。 你可以这样使用它:

c:\Users\Alex\dev\src\a>dir
 Volume in drive C has no label.
 Volume Serial Number is 9012-A870

 Directory of c:\Users\Alex\dev\src\a

06/08/2017  02:02 PM    <DIR>          .
06/08/2017  02:02 PM    <DIR>          ..
06/08/2017  02:02 PM                77 main.go
               1 File(s)             77 bytes
               2 Dir(s)  430,809,088,000 bytes free

c:\Users\Alex\dev\src\a>type main.go
package main

import "fmt"
import "C"

func main() {
        fmt.Println("Hello")
}

c:\Users\Alex\dev\src\a>go build -o a.exe -ldflags="-tmpdir=c:\Users\Alex\dev\src\a" main.go

c:\Users\Alex\dev\src\a>dir
 Volume in drive C has no label.
 Volume Serial Number is 9012-A870

 Directory of c:\Users\Alex\dev\src\a

06/08/2017  02:02 PM    <DIR>          .
06/08/2017  02:02 PM    <DIR>          ..
06/08/2017  02:02 PM             2,055 000000.o
06/08/2017  02:02 PM            22,376 000001.o
06/08/2017  02:02 PM         2,017,382 a.exe
06/08/2017  02:02 PM               135 fix_debug_gdb_scripts.ld
06/08/2017  02:02 PM         2,402,226 go.o
06/08/2017  02:02 PM                77 main.go
06/08/2017  02:02 PM                24 trivial.c
               7 File(s)      4,444,275 bytes
               2 Dir(s)  430,804,631,552 bytes free

c:\Users\Alex\dev\src\a>

亚历克斯

这仅供我自己参考,但这需要移植到msvc:

_cgo_sys_thread_start(ThreadStart *ts)
{
    uintptr_t thandle;

    thandle = _beginthread(threadentry, 0, ts);
    if(thandle == -1) {
        fprintf(stderr, "runtime: failed to create new OS thread (%d)\n", errno);
        abort();
    }
}

static void
threadentry(void *v)
{
    ThreadStart ts;

    ts = *(ThreadStart*)v;
    free(v);

    ts.g->stackhi = (uintptr)&ts;
    ts.g->stacklo = (uintptr)&ts - STACKSIZE + 8*1024;

    /*
     * Set specific keys in thread local storage.
     */
    __asm {
          "movq %0, %%gs:0x28\n"    // MOVL tls0, 0x28(GS)
          "movq %%gs:0x28, %%rax\n" // MOVQ 0x28(GS), tmp
          "movq %1, 0(%%rax)\n" // MOVQ g, 0(GS)
          :: "r"(ts.tls), "r"(ts.g) : "%rax"
    }

    crosscall_amd64(ts.fn);
}

我不会低估完成这项任务所需的时间,因为我对装配完全不熟悉。

  • [x] 了解程序集的作用
  • [x] 到 MSVC 程序集的端口
  • [x] 理解_beginthread vs CreateThread
  • [x] 切换到 CreateThread

此外,未定义的符号:

  • [x] timeBeginPeriod --> winmm.lib
  • [x] timeBeginPeriod
  • [x] WSAGetOverlappedResult --> Ws2_32.lib
  • [x] WSAGetOverlappedResult
  • [x] _cgo_18b6f6fc815b_Cfunc_hello
  • [x] x_cgo_init --> msvc_windows_amd64.c
  • [x] x_cgo_thread_start --> msvc_windows_amd64.c
  • [x] x_cgo_sys_thread_create --> msvc_windows_amd64.c
  • [x] x_cgo_notify_runtime_init_done --> gcc_libinit_windows.c
  • [x] x_cgo_set_context_function --> gcc_libinit_windows.c

好的,所以在这里比预期的要快!

全部: asm_amd64.s是由 go 的汇编程序(使用奇数汇编)还是 gcc 的汇编程序组装的?

好像gcc不会汇编它,这意味着它可能是go assembly。 然后问题就变成了:如何用 go 汇编器把它组装成一个对象。

目的是将 runtime/cgo/asm_amd64.s 组装成一个 Go 对象,然后 cmd/link 将它与所有其他 Go 对象链接到一个单一的系统对象中,然后系统链接器链接该单一系统对象加上所有cgo 依赖项进入最终程序。

现在有没有办法组装该对象以进行测试? 像gcc -c asm_amd64.s除了 go?

目的是将 runtime/cgo/asm_amd64.s 组装成一个 Go 对象,然后 cmd/link 将它与所有其他 Go 对象链接到一个单一的系统对象中,然后系统链接器链接该单一系统对象加上所有cgo 依赖项进入最终程序。

到目前为止,我发现了这些对象:

  • go.o :显然来自 go 工具链
  • _cgo_.o : 由 gcc 生成,无法使用
  • 000000.o : 由 gcc 生成,不可用
  • 000001.o :更新:实际上由 go 链接器生成,但包含 gcc 符号。 无法使用。

go.o是最大的对象。

@ianlancetaylor

我不认为你说的是​​正确的。 crosscall_amd64位于 000001.o,但该文件没有“所有 go 代码”:

000001.o:     file format pe-x86-64

SYMBOL TABLE:
[201](sec  1)(fl 0x00)(ty  20)(scl   2) (nx 0) 0x0000000000000440 crosscall_amd64
[206](sec  0)(fl 0x00)(ty  20)(scl   2) (nx 0) 0x0000000000000000 free

这个文件显然是gcc生成的,在过程中已经来不及了。

现在有没有办法组装该对象以进行测试? 像 gcc -c asm_amd64.s 一样,除了 go?

asm_amd64.s 是运行时包的一部分。 您可以看到“go build”命令如何使用 asm_amd64.s 文件,例如:

$ touch asm_amd64.s
$ GOOS=windows go build -x runtime 2>&1 | grep asm_amd64.s
/home/a/go/pkg/tool/linux_amd64/asm -trimpath $WORK -I $WORK/runtime/_obj/ -I /home/a/go/pkg/include -D GOOS_windows -D GOARCH_amd64 -o $WORK/runtime/_obj/asm_amd64.o ./asm_amd64.s
$

亚历克斯

谢谢。

符号crosscall_amd64在文件 runtime/cgo/gcc_amd64.s 中定义。 该文件由 GCC 编译(所有 runtime/cgo/gcc_* 文件也是如此)。 所以它没有合并到包含所有 Go 代码的单个 go.o 文件中。 我们之前讨论的文件 runtime/cgo/asm_amd64.s 定义了符号crosscall2 。 你会在 go.o 中找到那个符号。

谢谢。

好的,我已经设法链接了一个在访问冲突时崩溃的可执行文件
go.runtime.rt0_go+5F --> go.___acrt_stdio_initializer。

这就是我现在所有的时间; 稍后我会回到这个话题。

@alexbrainman没错。

@alexbrainman您需要 MSVC 才能继续。 让我知道您是否需要这方面的帮助。

您需要 MSVC 才能继续。

我正在安装这个https://www.visualstudio.com/downloads/#build -tools-for-visual-studio-2017

安装后我应该怎么做?

亚历克斯

安装后,您需要构建“libgo”,即 go 库。 从cgo 文件夹复制以下文件:

  • gcc_amd64.S
  • gcc_fatalf.c
  • gcc_libinit_windows.c
  • gcc_util.c
  • gcc_windows_amd64.c
  • libcgo.h

我们需要调整 gcc_windows_amd64.c 以兼容 MSVC。 修改函数如下:

static void
threadentry(void *v)
{
    fprintf(stderr, "threadentry: started");
    abort();

    ThreadStart ts;

    ts = *(ThreadStart*)v;
    free(v);

    ts.g->stackhi = (uintptr)&ts;
    ts.g->stacklo = (uintptr)&ts - STACKSIZE + 8*1024;

    /*
     * Set specific keys in thread local storage.
     */
    __writegsqword(0x28, (unsigned long long) ts.tls);
    *(void **)ts.tls = (void *) ts.g;

    crosscall_amd64(ts.fn);
}

在包含所有这些文件的文件夹中创建一个名为“build.bat”的新文件:

REM TMP use gcc for assmebly file, in future port to ml64
gcc -c gcc_amd64.S
cl -c gcc_fatalf.c
cl -c gcc_libinit_windows.c
cl -c gcc_windows_amd64.c
cl -c gcc_util.c

ren gcc_amd64.o gcc_amd64.obj

lib gcc_amd64.obj gcc_fatalf.obj gcc_libinit_windows.obj ^
    gcc_windows_amd64.obj gcc_util.obj ^
    /OUT:libgo.lib

当您按照要求构建文件夹时,请告诉我。

顺便说一句,感谢您为此所做的工作和继续工作。 你们创造了一种真正神奇的语言。

当您按照要求构建文件夹时,请告诉我。

我设法构建了 libgo.lib,如您在此处所述https://github.com/golang/go/issues/20982#issuecomment -327365063
我接下来该怎么做?

亚历克斯

好的,现在我们需要以下文件:

  • 粘性物
  • hello.cgo2.o
  • 你好ç

hello.c 如下:

#include <stdio.h>

extern void hello()
{
    printf("Hello World from C");
}

要获得hello.cgo2.ogo.o ,您需要从以下文件开始:

package main

/*
    extern void hello();
*/
import "C"
import "fmt"

func main() {
    fmt.Println("Hello from Go!")
    C.hello()
}

称为“hello.go”

设置一个从 $ env:TMP连续复制文件的 powershell 脚本:

while ($true) {  cp -r $env:TMP\go-* C:\Users\User\Downloads }

然后在文件夹中使用hello.chello.go运行go build 。 您应该能够从它们被复制到的位置恢复所需的文件。

获得上面指定的文件后,您可以使用以下命令进行构建:

cl libgo.lib go.o hello.cgo2.o hello.c Ws2_32.lib Winmm.lib -link /DEBUG:FULL

如果您有任何问题,请告诉我。

cl libgo.lib go.o hello.cgo2.o hello.c Ws2_32.lib Winmm.lib -link / DEBUG:FULL

这会创建 go.exe 可执行文件,但它不会运行。 我在那里看不到任何合理的汇编代码。 第一条指令只是无处可去。 这只是一团糟。

也许你应该从一些非常简单的事情开始。 使用执行“INT $3”的单个 asm 函数编写一个 asm 文件(Go asm 文件)。 并尝试从中构建一个可执行程序 - 该程序应该在一开始就运行您的功能。

也许首先使用 Go 工具构建它(如果需要也使用 gcc),然后尝试使用 MSVC 执行相同的操作。

亚历克斯

亚历克斯,谢谢你的帮助。 我会努力的。

我将把这两篇文章附在这里供我自己参考。 否则,我没有任何进一步的更新。

我实际上有一个相当复杂的 go 程序,它只使用 msvc 库。 事实证明,vanilla msvc 链接器和 llvm-lld 都没有正确处理.bss部分。

一旦我修补了链接器,程序就可以运行了。

不幸的是go build在生成_cgo_.o / _all.o时会中断。 是否有可能阐明在 cgo 中生成这两个文件背后的基本原理?

您可以运行go tool cgo直接运行 cgo。 来源在这里: https :

另外,如果你能让它运行,那就太棒了。 我只是没有花时间在这上面,所以没有任何进展。 对于那个很抱歉。

我已经有了可以通过一系列手工拼接正确运行的程序——我在这里尝试做的是看看这个过程是否可以重新集成到 go 中以减少痛苦。 :-)

如果你能记录手工缝合的过程,那么我也许可以提供帮助。

仅从外观上看, _cgo_.o似乎是这样生成的(简化):

gcc [*.c] [*.cxx] -o _cgo_.o

从这里: https :

理想情况下,我们会编写一个 go 程序来预处理目标文件,以便它们与link.exe兼容以最小化摩擦,但这是一个延伸目标。

谢谢你的指点——我很快就会写下这个过程。

不幸的是,我不认为链接可以通过link.exe除非我们更改 gcc 以在.data部分而不是.bss部分发出未初始化的数据——但我们可以绝对修复llvm-lld以识别.bss部分(这是我所做的)。

我们需要分别处理_cgo_.o_all.o 。 我对他们有几个问题:

(1) _cgo_.o似乎不是最终的可执行文件,因为它不包含 go 运行时。 看起来编译器会查看它的 DWARF 符号来找出结构的定义。 问题是,如果您要链接到外部的许多库,尤其是由 msvc 生成的库,则很难生成可执行文件。

是否可以避免这一步?

(2) 当前 go 使用 GNU ld _all.o通过在 GCC 中传递-Wl,-r将所有目标文件拼接到_all.o -Wl,-r中。 这是有问题的,因为 (1) 其他链接器似乎没有此功能,并且 (2) 命令受CGO_LDFLAGS 。 例如,以下命令会生成错误的结果:

CGO_LDFLAGS="-Wl,-T,my-linker-script"
gcc .... $CGO_LDFLAGS -Wl,-r,...

它生成可执行文件而不是捆绑的目标文件。

是否可以通过将所有目标文件直接放入生成的.a来完全避免此步骤?

@zooba让 MSFT 使用此补丁更新link.exe的机会有多大?

不幸的是,我不认为链接可以通过 link.exe 完成,除非我们更改 gcc 以在 .data 部分而不是 .bss 部分发出未初始化的数据——但我们绝对可以修复 llvm-lld 以识别 .bss 部分(这是我所做的)。

因此,假设 MSFT 不更新link.exe (这是可能的),最好使用cl.exe而不是gcc编译目标文件。

似乎_cgo_.o不是最终的可执行文件,因为它不包含 go 运行时。

没错,基本上有两组目标文件(我认为)最终链接在一起。 go.o文件(IIRC)包含所有的 go 代码 + 运行时,其他对象包含 C 代码。 有汇编例程可以在两组对象之间跳转。

此外,我们需要clang来编译 Unix 汇编文件。

出于我们的目的, -Wl,-r将与运行lib.exe [object files] /OUT:obj 。 该选项的意思是“增量链接”,意思是“获取一些输入文件,做一些工作,然后吐出另一个目标文件”。 如果我们暂时不担心“做一些工作”部分,我们可以将要求视为“获取一些输入文件和/或目标文件并吐出另一个目标文件”,除非在我们的情况下目标文件将是图书馆。

您可以使用选项-fno-zero-initialized-in-bss告诉 GCC 避免将变量放在 .data 部分而不是 .bss 部分。

请注意,提示我们在构建 cgo 代码时不再使用-Wl,-r

cmd/link 不需要理解 MSVC 对象文件,以便将它们用作.syso文件。 无论如何,这些文件只是传递给外部链接器。 所以我认为这里需要的是调用 MSVC 链接器作为外部链接器,你应该能够通过使用-extld选项来做到这一点。 如果你已经这样做了,我很抱歉; 在这种情况下,失败是什么?

如果你已经这样做了,我很抱歉; 在这种情况下,失败是什么?

IIRC, link.exe barfs 在 gcc 生成的对象上。

没错,您还必须通过适当地设置CC环境变量来使用 MSVC C 的编译器。 我认为将 GCC 对象和 MSVC 对象组合在一个链接中是行不通的。

但是随后您会遇到预编译运行时 C 库的问题。 如果您尝试重新编译它们,则会遇到cl无法编译 unix 程序集的问题。 所以你移植了运行时库的一部分并尝试链接它们,这就是我所做的但失败了。

在此过程中, cl编译了代码的关键部分。 我解决这个问题的想法是将 MSVC 代码分解成一个带有平面 C API 的 DLL,然后逐步编译更多的运行时库,直到它停止工作。

@haohui解决问题的想法不同。 他没有解决问题的根源,而是通过修补链接器来解决它。 显然他比我更成功,但这可能是因为事后看来,他的方法比我的更有可能奏效。

在这一点上我建议(恕我直言)是使用cl增量编译更多运行时库,直到它停止工作或直到您没有剩下的 gcc 代码。 然后你就知道问题出在哪里了。

使用链接器补丁,不需要 DLL。

llvm-lld 的补丁可在https://bugs.llvm.org/show_bug.cgi?id=35283 获得

我会花一些时间来提供一个例子。

+1 @haohui 非常感谢您提出这个问题!

@haohui您的补丁适用于哪个版本的 llvm? 有关如何使用补丁以及如何链接 MSVC 文件的任何说明?

关于_cgo_.o_all.o文件,我遇到了同样的问题,所以也许解决这个问题也可以解决另一个问题: https :

感谢您为此所做的所有工作。 听起来正在取得良好的进展。 新功能在 Go 1.11 之前被冻结,所以改变了里程碑。

所以我昨晚跳进了这个。 可以通过msvc:cl构建所有内容,然后通过msvc:link链接所有内容

所以除了像msvc:cl不完全支持 C99 这样的简单问题(现在我们无法处理类型 _Complex)。 将 go internals 构建的 PE 库和 msvc 构建的 PE 库结合起来存在更多系统性问题。 特别是msvc:link吹走了 .bss 段(我认为它可能只是将这些数据扔到 .data 中)这是一个问题,因为它看起来像 go assembler SB(伪 reg)导致如果 .bss 被移动则寻址不正确.

我最初的想法是尝试让汇编程序将进入 .bss 和 .noptrbss 的内容分别放入 .data 和 .noptrdata 中。 我什至不确定这是否可能; 我对它的摆弄没有成功,并且寻址完全被冲洗掉了。

我认为目前无法使用 link.exe。 我认为我们应该从 lld-link.exe 开始

如果这背后的想法是我们可以修补 lld-link 以不移动 .bss 数据,我理解它的吸引力。 实际上,如果目标是支持实际的 msvc 工具链,则需要解决将数据放入 .bss/.noptrbss 的内部编译。

我们不能用 go 重新分发 lld-link.exe 吗? 只要未启用 LTCG,这似乎是支持 MSVC 对象文件的最低风险路径。 我知道这并不理想,但我们面临资源限制。

它还允许渐进式进步,这是最好的策略。

好的,一些好的后续消息,我可以在午餐时间花一个小时来研究这个。

目前我有这个问题早期的例子:

- hello.go:
package main

/*
    extern void hello();
*/
import "C"

func main() {
    C.hello()
}

- extern.c
#include <stdio.h>

extern void hello()
{
    printf("Hello World from C");
}
>ac.out.exe
Hello World from C

该二进制文件完全使用 MSVC 和 Go 工具链构建(未安装 GCC 或其他 LLVM)。

发现:

  • 让 Go tools/link.exe 将内部程序集的 .bss 数据输出到 .data 最终相当简单
  • 必须为 msvc 调整几个 ASM 部分
  • 一些 GCC #defs 被填充
  • 必须对一些 cgo 生成的 .c 文件进行一些小的调整
  • 复数将需要填充,此时它们不受支持
  • 很可能需要直接添加额外的标志来构建或链接以获得 msvc 支持,ldflags 等是不够的

下一步:
如果我这个周末有时间,我将把我的更改放到一个 fork 中,但是在 build/link.js 中标记背后的功能。 之后我会得到一个 PR 进行审查,这样我们就可以确定种类。 我不是 100% 确信移动 .bss 数据不会在某处产生某种影响。

我能想到的唯一缺点是它会炸毁二进制文件的大小,但应该没问题。

好的!

对不起,我花了几天时间才把它放在一起。 所以补丁的初稿可以在这里找到: https : https://github.com/cchamplin/go/tree/msvc_toolchain_support

这仍然很粗糙,但我已经成功地使用 msvc 构建了代码。

如果人们现在就可以开始测试这个并将错误报告给我,这样我就可以在上游更好的地方得到它,那会很棒。 此外,如果有人想编写测试,那将是惊人的!

用法:

go build -compiler msvc [path]
  • 目前不支持复数,直到我弄清楚我们是否可以使它们工作。
  • 我不知道如果您尝试使用 msvc 编译器构建 go 运行时会发生什么。
  • gco 仍然需要并使用 gcc 在编译时获取定义和类型数据,它不用于构建任何东西)。 我不知道我们是否能解决这个问题,msvc 没有什么可以做同样的侏儒和#define 转储代码......如果有人对此有想法那就太好了

链接的补丁会产生引导问题。

@alexbrainman如何以及在哪里确定在toolchain1 boostrapping 阶段将哪些文件复制到pkg/boostrap/src/bootstrap中?

抄送@alexbrainman

链接的补丁会产生引导问题。

我不知道现在引导是如何工作的。 但我相信其他人( @rsc和 @ianlancetaylor)可以提供帮助。

如果引导不起作用,我想知道@cchamplin如何运行 make.bat。

亚历克斯

@xoviat我不知道问题是什么,但引导目录列表在 cmd/dist/buildtool.go 中。

@alexbrainman@ianlancetaylor@xoviat对不起,我想我应该更彻底地验证。

我已经更新了这里的分支https://github.com/cchamplin/go/commit/69a5cfc1dd0106fd8a2928a83e4c7001e81e89b8修复了引导问题,我认为它现在应该正确引导。

我确实必须将一些 /src/internal/syscall 目录复制到 cmd/internal/msvc 中。 这会是一个很大的问题吗? 我不确定如何在不使用 src/internal 的情况下访问注册表。

我确实必须将一些 /src/internal/syscall 目录复制到 cmd/internal/msvc 中。 这会是一个很大的问题吗? 我不确定如何在不使用 src/internal 的情况下访问注册表。

我不知道现在它是如何完成的,但我怀疑 cmd/dist 可以在没有您手动复制源文件的情况下做到这一点。 我敢肯定,当您准备好提交代码时,Russ 或 Ian 会帮助您。

我认为现在是@bradfitz@ianlancetaylor决定如何在此进行的时候了。 我们是否希望 Go 支持 Microsoft 构建工具以及 gcc? 我们必须在我们的构建器上安装相应的 Microsoft 工具(我们必须在开始接受 CL 之前这样做)。 我们可能不得不引入新的环境变量。 新文档。

如果答案是肯定的,那么@cchamplin将必须按照https://golang.org/doc/contribute.html提交他的代码更改,您愿意这样做吗? 改动挺大的,需要拆成更小的CL,单独审核提交。 每次更改都必须让 all.bat PASS 才能提交。 如果我们能在开始提交第一个 CL 之前查看所有 CL,那就太好了。

谢谢你。

亚历克斯

我们是否希望 Go 支持 Microsoft 构建工具以及 gcc?

请注意,这个补丁也有助于#17014,我已经有一个补丁正在处理中。

如果答案是肯定的,那么@cchamplin将必须按照https://golang.org/doc/contribute.html提交他的代码更改,您愿意这样做吗? 改动挺大的,需要拆成更小的CL,单独审核提交。

是的,分手应该没什么大不了的。 在我努力清理所有代码、编写文档、创建测试等之前,我只需要知道这是否可能会发生。

我们是否希望 Go 支持 Microsoft 构建工具以及 gcc?

在我看来,答案是肯定的。 编译器本身在 VS 社区中是免费的,没有完整的 Windows 支持真的很令人沮丧。 我不应该站起来编译github.com/Microsoft/hcsshim (例如),因为不支持 Windows 工具链。

不支持 Windows 工具链的原因是什么?

我认为原则上支持 MSVC 对象文件是可以的。 我们需要一个建造者。

我主要关心的是在 Windows 或 MSVC 版本之间格式可能会发生多少变化。 大多数其他平台上使用的 ELF 格式非常稳定; 除了添加对新处理器的支持之外,我们很少需要以任何方式调整 ELF 支持。 MSVC 文件格式是否同样稳定?

与 MSVC 工具链相关的格式相当稳定。 最大的问题将是支持工具本身。 Microsoft 倾向于在 Visual Studio 的版本之间移动(文件和注册表项)。 其中大部分是可配置的(至少在我编写的补丁中),但是当 Visual Studio 的新主要版本发布时,如果不更改 Go,它可能无法作为构建工具链兼容。 但是,所有受支持的 Visual Studio 先前版本都将继续工作。

据我所知,如果您只接触 C ABI(而不是 C++),COFF 格式具有合理的稳定性。 它还被广泛记录,并且 LLVM 提供了参考实现。

@cchamplin我建议要求用户在与 MSVC 链接之前调用 vcvarsall.bat。 这将大大减少维护到接近零。

我们需要一个建造者。

@ianlancetaylor一旦 MSVC 对象被证明可以按预期工作,您是否认为需要同时使用 msys/cygwin 构建器和 MSVC 构建器,还是只需要一个 MSVC 构建器?

我相信有些人会更喜欢使用 cygwin 工具,他们已经可以工作了,我们希望他们继续工作,所以我认为我们需要两个构建器。

嘿,从这个帖子的底部看来,您已经解决了 MSVC 问题。 但是,如果您遇到任何问题,我会加入 MSVC 团队。 随时在 github 或电子邮件上 ping 我 ([email protected])

我们需要一个建造者。

是的。 我们应该从改变我们现有的构建器开始安装 MS 构建工具。 所以我们可以使用它们,因为我们接受了这个问题的 CL。

我们可以在所有构建器上安装 gcc 工具和 microsoft 工具。 我们可以一次运行测试 gcc 和 microsoft 工具的 all.bat 吗? 如果没有,那么我们需要为不同的工具配置不同的构建器。 控制使用哪些外部编译器和链接器的参数是什么?

我主要关心的是在 Windows 或 MSVC 版本之间格式可能会发生多少变化。

您没有随 Windows 安装编译器。 你必须自己安装它。 就像我们对 gcc 所做的一样。 我们安装我们喜欢的任何版本。 我们甚至可以在不同的构建器上运行不同的 gcc 版本。

MSVC 文件格式是否同样稳定?

我对此一无所知。 我怀疑您只是使用提供的工具。

亚历克斯

我主要关心的是在 Windows 或 MSVC 版本之间格式可能会发生多少变化。 大多数其他平台上使用的 ELF 格式非常稳定; 除了添加对新处理器的支持之外,我们很少需要以任何方式调整 ELF 支持。 MSVC 文件格式是否同样稳定?

是的,COFF 非常稳定。

@bradfitz@ianlancetaylor我们需要什么才能让 Windows 构建器可用于测试此问题的更改? 在https://github.com/golang/go/issues/20982#issuecomment -370719472 查看我的问题

谢谢

亚历克斯

go 现在支持 msvc 对象了吗?

更改https://golang.org/cl/110555提到这个问题: debug/pe: parse the import directory correctly

@alexbrainman @bradfitz @ianlancetaylor

我已经完成了大部分必要的工作,我相信将补丁清理干净并分解成更易消化的碎片。 我相信我已经准备好实际提交项目了。 我想我需要知道我是否应该在提交代码之前等待有关构建器情况的消息还是尽快完成?

您可以随时发送 CL,但确实需要有人设置构建器。 否则我们无法测试它们。

@johnsonj ,您能否将 MSVC 编译器工具添加到我们的 Windows 映像中?

理想情况下,我不希望添加新的主机类型,只让 1-3 种现有的 Windows 主机类型具有除 Cygwin 之外的 MSVC 工具。 然后我们可以在这些修改后的主机类型之上添加更多构建器配置。

/cc @andybons @bcmills仅供参考(关于 Windows 的事情是如何发生的......我们向杰夫求助:))

@johnsonj ,您能否将 MSVC 编译器工具添加到我们的 Windows 映像中?

@cchamplin我建议您尝试自己添加构建器所需的任何工具。 没有其他人,但您知道需要什么。 您可以在 golang.org/x/build/env/windows 目录中查看完整说明。 特别是您,可能想在 startup.ps1 中添加更多行。 一旦您知道该主管需要更改的内容,请进行更改并通过https://golang.org/doc/contribute.html发送您的更改以供审核。一旦接受,我们可以使用这些说明更新构建器。

理想情况下,我不希望添加新的主机类型,只让 1-3 种现有的 Windows 主机类型具有除 Cygwin 之外的 MSVC 工具。 然后我们可以在这些修改后的主机类型之上添加更多构建器配置。

我们总是在 Windows 上使用 Mingw (gcc) C 编译器和链接器。 我们从来没有不同的 C 构建工具集。 一旦我们添加了对 Microsoft C 编译器的支持,是否可以通过一次运行 all.bat 来测试 Mingw 和 Microsoft C 函数? 还是 Mingw 或 Microsoft C 相互排斥? 我们是否必须设置一些环境变量来指向 Mingw 或 Microsoft,但永远不要同时指向两者? 我想我正在尝试了解如何构建和测试代码。 这也将决定我们需要多少不同的构建器。

亚历克斯

我将研究烘焙图像中的二进制文件

更改https://golang.org/cl/112036提到这个问题: env/windows: add visual studio tools to image

@johnsonj @bradfitz :感谢您将其纳入构建器。

@alexbrainman @bradfitz @ianlancetaylor :就测试策略而言,我不确定要做什么。 我们可以采取在 window 上对两个工具链都运行 dist test 的路径并执行两次测试,还是应该只测试两次 cgo 测试(一次用于 gcc,一次用于 msvc)?

因此,就测试策略而言,我不确定要做什么。 我们可以采取在 window 上对两个工具链都运行 dist test 的路径并执行两次测试,还是应该只测试两次 cgo 测试(一次用于 gcc,一次用于 msvc)?

@cchamplin我没有回答你的问题。 我怀疑伊恩知道答案。

亚历克斯

运行所有测试两次而不是只运行 cgo 的成本是多少?

@mxplusb ,我们可以为 Windows 运行一个新的构建配置,它会与我们现有的 3 并行运行。新的构建器配置很好。 我们定期添加它们。

告诉我如何让它与众不同:设置一个不同的/新的环境变量,然后我假设会有一些东西会得到它?

可能需要做一些事情才能使其正常工作。

我们需要在 shell/环境中运行,在运行/调用适当的 vsvars.bat 之后,dist 测试执行的 go 测试将在其中运行

或者我们可以让 dist 执行适当的 vsvars 并提取它需要的环境变量,然后设置/传递这些变量以进行测试。

我们可能还需要一些环境变量来告诉 dist 或 make.bat 我们想要使用 -compiler msvc set 运行测试。

我们需要在 shell/环境中运行,在运行/调用适当的 vsvars.bat 之后,dist 测试执行的 go 测试将在其中运行

或者我们可以让 dist 执行适当的 vsvars 并提取它需要的环境变量,然后设置/传递这些变量以进行测试。

如果我们不从 dist.exe 或 go.exe 运行批处理文件,我会更喜欢。 处理批处理文件很麻烦。

我们可能还需要一些环境变量来告诉 dist 或 make.bat 我们想要使用 -compiler msvc set 运行测试。

我希望伊恩知道这里最好的方法是什么。 据我所知,我们在 Unix 上也支持不同的 C 编译器(gcc 或 clang)。 当然,我们的构建过程允许我们测试不同的 C 编译器。

亚历克斯

我之前没有注意到您打算使用go build -compiler msvc 。 那没有意义。 go build -compiler选项采用 Go 编译器的名称(当前为 gc 或 gccgo)。 它不采用 C 编译器的名称。 C 编译器在CC环境变量中传递。 默认 C 编译器是通过在运行 make.bat 时设置CC_FOR_TARGET环境变量来设置的,如 make.bat 中的注释中所述。

我希望我们会有一个构建器,我们可以在运行 all.bat 之前将CC_FOR_TARGET环境变量设置为 msvc。 我不明白为什么我们必须做任何其他事情。

C 编译器在 CC 环境变量中传递。 默认 C 编译器是通过在运行 make.bat 时设置 CC_FOR_TARGET 环境变量来设置的,如 make.bat 中的注释中所述。

谢谢伊恩的解释。

@cchamplin我希望您可以调整您的更改以适应现有模型。 如果您有任何问题,请告诉我们。 谢谢你。

我希望我们会有一个构建器,我们可以在运行 all.bat 之前将 CC_FOR_TARGET 环境变量设置为 msvc。

我们在https://build.golang.org上有 3 个 amd64 窗口构建器

亚历克斯

@ianlancetaylor @alexbrainman了解 -compiler 标志。 我不认为有一种简单的方法可以让CC="msvc" (或真的CC="cl.exe" )工作。 CC 仍然需要指向 GCC 位置才能使 MSVC 构建工作。 msvc 编译器工具集没有允许 CGO 执行它需要的内省(定义查找、类型解析)的工具,因此在 MSVC 构建中仍然需要 GCC,只是在实际编译/链接阶段不使用 GCC。

添加一个新标志来构建等是否可以接受(工具链或其他东西)? 我相信我已经不得不向 cgo 添加一个工具链标志。

在 all.bat 之前设置CC_FOR_TARGET看起来可能会产生负面影响,因为它会影响引导中使用的编译器。 我不相信 MSVC 可以在引导过程中使用(我不是 100%,我还没有真正尝试过,但我非常怀疑它会起作用)

我明白了,对于 MSVC,我们需要同时拥有 GCC 和 MSVC? GCC 仅由 cgo 工具使用的地方? 这似乎有点不幸,因为这意味着我们将绝对依赖 GCC 和 MSVC 实现完全相同的 ABI,但我想这很有可能。

我想我们可以添加另一个环境变量CC_FOR_CGO ,它可以设置为 GCC。

make.bat 使用的CC_FOR_TARGET将用于构建 runtime/cgo。 如果 runtime/cgo 不是由您使用的 C 编译器构建的,我不清楚 cgo 如何工作。

也许我们应该首先在调用 make.bat 时开始工作,将CC_FOR_TARGETcl并将CGO_ENABLED0

谢谢@ianlancetaylor

我明白了,对于 MSVC,我们需要同时拥有 GCC 和 MSVC? GCC 仅由 cgo 工具使用的地方? 这似乎有点不幸,因为这意味着我们将绝对依赖 GCC 和 MSVC 实现完全相同的 ABI,但我想这很有可能。

我同意这是不幸的,并且很高兴了解一些替代方案,我还没有找到。 以这种方式构建肯定存在风险(例如,正在构建的 cgo 代码具有不同的类型 defs 或定义,具体取决于它认为它是由什么编译器构建的)。 因此,如果不进行一些调整,构建可能并不总是成功或正常工作(在我的实现中有一种机制可以处理这个问题,但它是一个手动过程)。 可悲的是,我认为如果人们想使用 MSVC 工具链,这是一个必须承担的风险,我们现在所能做的就是将其记录下来。

同样,在 MSVC 构建的 cgo 程序中提供 complex64 和 complex128 支持仍然没有真正的前进道路,因为 MSVC 编译器不符合 c99。

我想我们可以添加另一个环境变量CC_FOR_CGO ,它可以设置为 GCC。

因此,我目前的实现是,如果指示 go build 使用 MSVC 进行构建,它将默认在路径上查找 cl.exe,但这可以用环境变量 MSCC 覆盖。 CGO 将继续使用 CC 环境变量回退到 gcc/生成的 zdefaultcc.go 中的任何内容

make.bat 使用的CC_FOR_TARGET将用于构建 runtime/cgo。 如果 runtime/cgo 不是由您使用的 C 编译器构建的,我不清楚 cgo 如何工作。

在当前的实现中,即使整个 go 工具链已经由 gcc 构建,cgo 也会很高兴地为 msvc 二进制文件工作。 例如 MSVC 代码被添加到 go/src。 all.bat 运行使用 gcc 构建 go 环境。 之后,可以使用 go/bin/go.exe 使用 msvc 工具链进行构建(假设提供了标志)。 不过,我可能会误解你在这里所说的。

围绕这个的复杂性,因为告诉 go 我们想用 msvc 构建比将编译器切换到 cl 更复杂。 MSVC 工具链与 gcc 工具链非常不同。 在 MSVC 中,需要通过在 vcvars.bat 中运行来设置环境(或执行 v8 所做的操作,例如运行 vcvars.bat 并从它设置的环境变量中提取所需的所有信息,然后在其构建中使用它过程)。 进入MSVC环境后,主要区别在于工具本身cl.exe用于编译C和C++文件,ml.exe和ml64.exe用于汇编文件,最后link.exe(ms)用于编译将一切联系在一起。 因此,它不仅仅是设置CC=cl.exe并将正确的标志传递给它。 这有意义/有助于澄清事情吗?

为了进一步澄清

make.bat 使用的 CC_FOR_TARGET 将用于构建运行时/cgo。 如果 runtime/cgo 不是由您使用的 C 编译器构建的,我不清楚 cgo 如何工作。

go build是在构建过程中从 runtime/cgo 中选择适当的文件(例如go build / go test / go run -- 而不是构建过程),当已选择 msvc 工具链。

我愿意接受关于它应该如何工作的建议,但它不应该需要 go 工具的新命令行选项。 我们可以编写一个纯 Go 程序,就 go 工具而言,它的作用类似于 GCC,但实际上运行的是 MSVC?

我们可以编写一个纯 Go 程序,就 go 工具而言,它的作用类似于 GCC,但实际上运行的是 MSVC?

我相信这可能是可行的,让我看看我是否可以在这条道路上取得进展。

另外,我想我需要澄清向其他工具添加命令行标志是否也会成为问题。 目前,针对此问题的综合补丁正在各种工具中创建几个新的命令行标志

  • cmd/cgo

    • -toolchain [gcc,msvc] (默认为 gcc) 构建 cgo 输出文件时使用的工具链

  • 命令/链接

    • -rlocbss(默认为 false)将 .bss 重定位到 .data

    • -toolchain [gcc,msvc](默认为 gcc)用于外部链接的工具链

我们还创建了以下构建选项/cgo 环境变量:

  • MSCXX
  • MSCC
  • MSCFLAGS
  • MSCPPFLAGS
  • MSCXXFLAGS
  • MSLDFLAGS

经过几分钟的思考,如果我们只是将编译器命令代理为一个不同的程序,那么可能会遇到一些难以克服的障碍

  1. go build需要知道外部工具链是什么来确定要构建哪些运行时/cgo 文件,否则最终只会将不兼容的 gcc 版本传递给我们的代理命令。 我们也许可以在代理本身内部解决这个问题,但是如果将额外的文件添加到运行时/cgo,它会很脆弱并且可能会损坏。
  2. cmd/cgo 需要知道使用哪种外部工具链来选择要使用的输出 C 代码的版本
  3. 代理程序需要某种机制来知道它是否应该执行 gcc(当被 cmd/cgo 调用时)或执行可以传入的 cl.exe 但这意味着调用者需要知道工具链是什么或者我们会让 cmd/cgo 将不存在的标志传递给 gcc。
  4. go build调用 cmd/link ,它也需要知道工具链是什么,以便它可以执行 .bss 到 .data 重定位,以便它可以将特定标志传递给链接器(我们可能能够处理后者虽然参与代理本身)

指定环境变量以让go build用于确定 msvc 构建是否有效? 尽管我认为它为只想用 msvc 构建程序的人设置了更高的标准,因为除了在 vsvars.bat 中运行之外,他们现在还必须设置多个环境变量(至少CCUNDECIDED_TURN_ON_MSVC_BUILD_VAR )

另一种选择是让go build在指定的CC上运行一个虚假的 noop 命令,然后解析徽标/标头以检测它是 msvc 还是 gcc 并在此时继续进行适当的工具链调整...不确定这有多脆弱,也不知道它如何与 msvc 兼容的工具链(如 clang)一起使用。

最近发现了这个 Github 问题,这个工作让我很兴奋。 我希望这会在不久的将来出现在某个地方。

我的目的是在 Windows 上使用 CGo 作为一些使用 MSVC 构建的第三方代码的包装器,我不能只使用mingw-w64从源代码重建。 我有一些相对严肃的测试用例来运行它,所以可以很好地验证它。

无论如何,感谢@cchamplin和其他正在处理它的人,无论如何请让我知道我可以提供帮助。

@cchamplin我对 Windows 和 cgo 中的编译器工具链有足够的了解,我可能会提供帮助。 你能帮我了解一下你一直在做的一些事情吗? 我会看看我能做些什么来提供帮助。 我知道@deadprogram的用例所以当我们准备好测试时,我有一个很好的高级测试平台。

@mxplusb ,补丁实际上或多或少已经准备好了。 如果我能找到时间,我会在今晚或明天将更改提交给 gerrit,这将使我们着手对所有内容进行审查、更新和批准。

更改https://golang.org/cl/133937提到这个问题: cmd/link: Add flag rlocbss to relocate .bss data to .data

更改https://golang.org/cl/133938提到这个问题: runtime/cgo: MSVC toolchain support in cgo native code

更改https://golang.org/cl/133939提到这个问题: cmd/cgo: Add toolchain flag to cgo command for MSVC support

更改https://golang.org/cl/133946提到这个问题: cmd/compile: Add support for MSVC toolchain to go build

看起来我在一些提交中打错了这个问题。 我会让审核过程开始并确定最佳修复方法。

更改https://golang.org/cl/133943提到了这个问题: cmd/cgo: Add support for CC_FOR_CGO environment variable

更改https://golang.org/cl/133942提到这个问题: tests: Update various tests to prepare for MSVC compiler toolchain

更改https://golang.org/cl/133940提到这个问题: misc/cgo: Adjust tests to be compatible with MSVC toolchain support

更改https://golang.org/cl/133941提到了这个问题: runtime: Add runtime.CompilerType to denote between host compiler type

更改https://golang.org/cl/133945提到了这个问题: cmd/link: Add external toolchain support for MSVC

更改https://golang.org/cl/133944提到这个问题: cmd/compile, cgo: Add support for MSVC flags

@cchamplin你能描述一下最终的决定是什么吗? MSVC 支持如何? 将添加哪些命令行标志? 除了下载 MSVC 之外,用户还必须对其环境做什么? 谢谢

另外,我们如何尝试这个补丁? 我在 repo 上找不到你的提交。

@rasky随着更改的审核,它仍然处于不断变化中。 可能不需要设置任何特定的命令行标志,只需构建 cgo 应用程序,其中 CC 环境变量指向 MSVC 或未设置 CC,cl.exe 在路径上但 gcc 不在。

@blizzardplus与上述类似,现在随着评论的出现变化很大,所以现在开始尝试可能有点早(不过取决于你)。 所有相关的更改都由 gopherbot 回发到这个问题,你可以在那里找到它们。

@cchamplin是否支持使用gccclang进行交叉编译? 如果是这样,它们是否经过测试?

@cchamplin自 9/11 以来,我在 CL 上没有看到任何活动,这方面是否有进展或是否需要额外资源?

@cchamplin使其适用于 c-archive

此外,为了使其适用于 c-shared,必须对要导出的函数进行修饰 __declspec(dllexport),但我似乎无法找到 //export 的这种扩展发生的位置。

@blizzardplus有一个后续补丁来支持 clang-MSVC。 我不确定在这种情况下交叉编译是什么意思? 您将无法在非 Windows 系统上使用 MSVC 工具链。 其他交叉编译功能不应改变。

@kshelton不幸的是,这对我来说是一年中非常忙碌的时间,因为我有其他项目正在进行中,我正在参加会议。 在 12 月之前,我可能无法重新开始在补丁中进行所需的重构。

@kshelton谢谢。 我没有仔细检查补丁,我假设我开发它时假设 c-archive 不能在 MSVC 上工作,或者专门禁用它? 当我试图让插件/共享在 Windows 上工作时,我走上了尝试正确装饰导出的道路。 我相信还有其他问题,但我可能将两个问题混为一谈。 如何将共享代码放入 ELF 与 Windows .edata、idata 和 EAT 的 PLT/GOT 中存在实际问题。 我相信我面临的大多数问题都与搬迁和无法让他们工作有关。 如果有人对此有洞察力,那就太好了。 见#19282

@cchamplin我试着看看,如果我能在你的 CL 之上构建 Go

https://go-review.googlesource.com/c/go/+/133946/3

我用这个批处理文件来设置我的环境

set TERM=msys
set MYHOME=c:\users\alex\dev
set GOROOT=%MYHOME%\go
set GOROOT_BOOTSTRAP=%MYHOME%\go1.4.3
set GOPATH=%MYHOME%
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat"
set CC=cl
set PATH=%PATH%;%MYHOME%\my\bin\;%GOROOT%\bin
cd %GOROOT%\src
CMD

当我运行 make.bat 时出现此错误

C:\Users\Alex\Desktop>set TERM=msys

C:\Users\Alex\Desktop>set MYHOME=c:\users\alex\dev

C:\Users\Alex\Desktop>set GOROOT=c:\users\alex\dev\go

C:\Users\Alex\Desktop>set GOROOT_BOOTSTRAP=c:\users\alex\dev\go1.4.3

C:\Users\Alex\Desktop>set GOPATH=c:\users\alex\dev

C:\Users\Alex\Desktop>call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat"
**********************************************************************
** Visual Studio 2017 Developer Command Prompt v15.0.26730.12
** Copyright (c) 2017 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'
Microsoft Windows [Version 10.0.17134.407]
(c) 2018 Microsoft Corporation. All rights reserved.

c:\Users\Alex\dev\go\src>make
Building Go cmd/dist using c:\users\alex\dev\go1.4.3
go tool dist: cannot invoke C compiler "cl": exit status 2

Go needs a system C compiler for use with cgo.
To set a C compiler, set CC=the-compiler.
To disable cgo, set CGO_ENABLED=0.

Command output:

Microsoft (R) C/C++ Optimizing Compiler Version 19.11.25507.1 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

cl : Command line warning D9002 : ignoring unknown option '--help'
cl : Command line error D8003 : missing source filename

The system cannot find the batch label specified - fail

c:\Users\Alex\dev\go\src>

我在这里错过了什么?

谢谢你。

亚历克斯

@alexbrainman

我在这里错过了什么?

您可能至少需要设置 CC_FOR_CGO=gcc。 我也从未亲自尝试过使用 MSVC 自行构建。 我不确定这是否可行/是否应该得到支持。

-C

您可能至少需要设置 CC_FOR_CGO=gcc。

您的https://go-review.googlesource.com/c/go/+/133940包含一些测试。 我如何验证测试是否通过? 具体步骤是什么?

此外,Go 构建器https://build.golang.org运行 %GOROOT%\src\all.bat 以验证所有测试(包括在 https://go-review.googlesource.com/c/go/+/ 中列出的测试) 133940)通过。 您建议我们如何修改 Go 代码以让 %GOROOT%\src\all.bat 从https://go-review.googlesource.com/c/go/+/133940运行您调整后的测试

我也从未亲自尝试过使用 MSVC 自行构建。 我不确定这是否可行/是否应该得到支持。

您可以在不安装 gcc 的情况下运行 all.bat 以成功完成。 当前版本的 Go 只需要另一个版本的 Go(至少是 go1.4)来构建。 只有 Cgo 需要 C 编译器,我的印象是您的更改实现了由 MSVC 构建的 Cgo 版本。 但是,也许,我错了。 如果我错了,请纠正我。

谢谢你。

亚历克斯

@alexbrainman

您的https://go-review.googlesource.com/c/go/+/133940包含一些测试。 我如何验证测试是否通过? 具体步骤是什么?

也许 all.bat 可以同时测试 gcc 和 msvc 版本的测试。 也许我们可以使用一些环境变量来告诉 all.bat 要运行哪个版本的测试——然后我们可以让两个不同的构建器运行不同版本的测试。 你考虑过这一切吗?

是的,这个确切的机制在https://go-review.googlesource.com/c/go/+/133946/ 中使用。 由于所有调用都在 windows 上调用 run.bat,因此调用 cgo 测试的机制就放在那里。 因此,您或构建器将从正常设置 CC=gcc 开始。 然后你会设置 GOTESTMSVC=1 和 GOVSVARSPATH=some vsvars.bat 路径。 在使用 all.bat 构建之后,应该运行 gcc 和 msvc cgo 测试。

您可以在不安装 gcc 的情况下运行 all.bat 以成功完成。 当前版本的 Go 只需要另一个版本的 Go(至少是 go1.4)来构建。 只有 Cgo 需要 C 编译器,我的印象是您的更改实现了由 MSVC 构建的 Cgo 版本。 但是,也许,我错了。 如果我错了,请纠正我。

你是对的。 Go 本身应该构建良好。 进入测试时可能会出现问题,因为 run.bat 被修改为在 GOTESTMSVC=1 时设置一些环境变量。 我们可能会尝试检测 go 是否只是用 msvc 构建的,然后设置适当的 dist 环境变量,以便测试不会失败。

然后你会设置 GOTESTMSVC=1 和 GOVSVARSPATH=some vsvars.bat 路径。 在使用 all.bat 构建之后,应该运行 gcc 和 msvc cgo 测试。

我试过了。

我用了

commit e56d52f66b95b87001867a2487a11bd961f40d4d (HEAD)
Author: Caleb Champlin <[email protected]>
Date:   Sat Sep 8 00:26:32 2018 -0600

    cmd/compile: add support for MSVC toolchain to go build

    Allows building with MSVC as an external compiler/linker.

    Setting CC=cl.exe inside an MSVC environment will automatically
    build cgo executables using MSVC as the external compiler and
    linker.

    For the builders setting the environment variable GOVSVARSPATH
    to the location of a msvsvars.bat file and setting the
    environment variable GOTESTMSVC=1 will automatically cause
    all.bat to run tests and compiler with both gcc and MSVC.

    Updates #20982

    Change-Id: I44be1f43aa0d53a688c595bc8336e0364b809ced

我先运行这个批处理文件:

set TERM=msys
set MYHOME=c:\users\alex\dev
set GOROOT=%MYHOME%\go
set GOROOT_BOOTSTRAP=%MYHOME%\go1.4.3
set GOPATH=%MYHOME%
set MINGW=%MYHOME%\mingw64_4.9.1

set GOTESTMSVC=1
set GOVSVARSPATH="C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat"

set PATH=%PATH%;%MINGW%\bin;%MYHOME%\my\bin\;%GOROOT%\bin
cd %GOROOT%\src
CMD

然后运行all.batall.bat失败

--- FAIL: TestDocsUpToDate (0.00s)
    help_test.go:26: alldocs.go is not up to date; run mkalldocs.sh to regenerate it
go test proxy starting
go test proxy running at GOPROXY=http://127.0.0.1:52023/mod
go proxy: no archive w.1 v1.2.0
go proxy: no archive x.1 v1.0.0
go proxy: no archive z.1 v1.2.0
go proxy: no archive rsc.io v1.5.0
go proxy: no archive example.com/unused v0.0.0
go proxy: no archive example.com/unused v0.0.0
go proxy: no archive sub.1 v1.0.0
go proxy: no archive badsub.1 v1.0.0
go proxy: no archive versioned.1 v1.0.0
go proxy: no archive versioned.1 v1.1.0
go proxy: no archive golang.org/x/text/language 14c0d48
go proxy: no archive golang.org/x/text/language 14c0d48
go proxy: no archive golang.org/x/text/language 14c0d48
go proxy: no archive golang.org/x/text/foo 14c0d48
go proxy: no archive golang.org/x 14c0d48
go proxy: no archive golang.org 14c0d48
go proxy: no archive example.com/split/subpkg v1.0.0
FAIL
FAIL    cmd/go  147.247s
ok      cmd/go/internal/cache   13.115s
ok      cmd/go/internal/dirhash 0.518s
ok      cmd/go/internal/generate        0.180s
ok      cmd/go/internal/get     0.761s
ok      cmd/go/internal/imports 0.212s
ok      cmd/go/internal/load    1.050s
ok      cmd/go/internal/modconv 1.596s
ok      cmd/go/internal/modfetch        0.881s
ok      cmd/go/internal/modfetch/codehost       0.179s
ok      cmd/go/internal/modfile 0.193s
ok      cmd/go/internal/modload 2.820s
ok      cmd/go/internal/module  0.860s
ok      cmd/go/internal/mvs     0.255s
ok      cmd/go/internal/par     0.107s
ok      cmd/go/internal/search  0.087s
ok      cmd/go/internal/semver  0.140s
ok      cmd/go/internal/txtar   0.249s
ok      cmd/go/internal/web2    0.136s
ok      cmd/go/internal/work    0.200s
ok      cmd/gofmt       0.216s
ok      cmd/internal/buildid    0.522s
ok      cmd/internal/dwarf      0.077s
ok      cmd/internal/edit       0.160s
ok      cmd/internal/goobj      2.430s
ok      cmd/internal/obj        0.103s
ok      cmd/internal/obj/arm64  0.190s
ok      cmd/internal/obj/x86    0.845s
ok      cmd/internal/objabi     0.063s
ok      cmd/internal/src        0.093s
ok      cmd/internal/test2json  0.253s
ok      cmd/link        6.285s
ok      cmd/link/internal/ld    24.147s
ok      cmd/link/internal/sym   0.887s
ok      cmd/nm  7.678s
ok      cmd/objdump     2.772s
ok      cmd/pack        3.256s
ok      cmd/trace       0.449s
ok      cmd/vendor/github.com/google/pprof/internal/binutils    0.479s
ok      cmd/vendor/github.com/google/pprof/internal/driver      6.103s
ok      cmd/vendor/github.com/google/pprof/internal/elfexec     0.079s
ok      cmd/vendor/github.com/google/pprof/internal/graph       0.455s
ok      cmd/vendor/github.com/google/pprof/internal/measurement 0.066s
ok      cmd/vendor/github.com/google/pprof/internal/report      0.154s
ok      cmd/vendor/github.com/google/pprof/internal/symbolizer  0.096s
ok      cmd/vendor/github.com/google/pprof/internal/symbolz     0.078s
ok      cmd/vendor/github.com/google/pprof/profile      0.527s
ok      cmd/vendor/github.com/ianlancetaylor/demangle   0.109s
ok      cmd/vendor/golang.org/x/arch/arm/armasm 0.424s
ok      cmd/vendor/golang.org/x/arch/arm64/arm64asm     0.537s
ok      cmd/vendor/golang.org/x/arch/ppc64/ppc64asm     0.155s
ok      cmd/vendor/golang.org/x/arch/x86/x86asm 0.239s
ok      cmd/vendor/golang.org/x/crypto/ssh/terminal     0.174s
ok      cmd/vendor/golang.org/x/sys/windows     0.334s
ok      cmd/vendor/golang.org/x/sys/windows/registry    0.199s
ok      cmd/vendor/golang.org/x/sys/windows/svc 0.316s
ok      cmd/vendor/golang.org/x/sys/windows/svc/eventlog        0.089s
ok      cmd/vendor/golang.org/x/sys/windows/svc/mgr     0.432s
ok      cmd/vet 6.392s
ok      cmd/vet/internal/cfg    0.102s
2018/12/16 15:55:18 Failed: exit status 1

此外,设置 GOTESTMSVC 和 GOVSVARSPATH 可能适用于执行 all.bat 的人。 但是当他们需要将 MSVC 用于 Cgo 时,您更改的其他用户会怎么做? 你对此有什么计划?

亚历克斯

@alexbrainman
我不确定发生了什么。 那个测试对我来说失败了

> git status
On branch master
Your branch is up to date with 'origin/master'

> cd src\cmd\go
> go test .\help_test.go
--- FAIL: TestDocsUpToDate (0.00s)
    help_test.go:26: alldocs.go is not up to date; run mkalldocs.sh to regenerate it

在 help.go https://github.com/golang/go/blob/c040786f37246f40ae29402fbdb6e97031a21713/src/cmd/go/internal/help/help.go#L37
它遍历 base.Go.Commands。 在 main.go 中初始化https://github.com/golang/go/blob/c040786f37246f40ae29402fbdb6e97031a21713/src/cmd/go/main.go#L43
但我不确定该 init 函数将如何在测试可执行文件中被调用,所以我不知道 master 现在如何通过测试,因为我认为这应该全面失败。


此外,设置 GOTESTMSVC 和 GOVSVARSPATH 可能适用于执行 all.bat 的人。 但是当他们需要将 MSVC 用于 Cgo 时,您更改的其他用户会怎么做? 你对此有什么计划?

所以在你只想用 MSVC 构建一些 Cgo 代码的情况下

call vsvars64.bat
set CC_FOR_CGO=gcc
set CC=cl.exe
go build

我想应该是你所需要的

我不确定该 init 函数将如何在测试可执行文件中被调用,所以我不知道 master 现在如何通过测试,因为我认为这应该全面失败。

当在 cmd/go 中使用go test文件时,go 工具将构建 cmd/go 包,然后构建测试,生成测试驱动程序,构建它,并将所有内容链接到一个新的主包中。 即使 cmd/go 本身是一个主包,也会发生这种情况。 也就是说, cmd/go/*.go 中的主包将被视为非主包进行测试。 这使测试能够在适当的情况下调用主包中定义的函数。

对不起,我回复的很慢。 但我没有空闲时间再研究这个。

我不确定发生了什么。 那个测试对我来说失败了

我没有使用大师。 我使用了你的 e56d52f66b95b87001867a2487a11bd961f40d4d 提交。 在将其发送以供审查之前,您没有在该提交上运行 all.bat 吗? all.bat 成功了吗? 您能否尝试在该提交上再次运行 all.bat 以查看是否与我的系统配置有关。 谢谢你。

所以在你只想用 MSVC 构建一些 Cgo 代码的情况下

call vsvars64.bat
set CC_FOR_CGO=gcc
set CC=cl.exe
go build

我想应该是你所需要的

2 环境变量对于普通用户来说可能太复杂了。 而CC_FOR_CGO=gcc对我来说看起来很奇怪 - 为什么我们使用 gcc 来构建带有 MSVC 的代码?

亚历克斯

@alexbrainman

我没有使用大师。 我使用了你的 e56d52f66b95b87001867a2487a11bd961f40d4d 提交。 在将其发送以供审查之前,您没有在该提交上运行 all.bat 吗? all.bat 成功了吗? 您能否尝试在该提交上再次运行 all.bat 以查看是否与我的系统配置有关。 谢谢你。

我认为这与我的系统配置有关,它在运行测试时给了我奇怪的结果。 我想我已经解决了这个问题并推送了一些对变更集的更新。

2 环境变量对于普通用户来说可能太复杂了。 而 CC_FOR_CGO=gcc 对我来说看起来很奇怪 - 为什么我们使用 gcc 来构建带有 MSVC 的代码?

它实际上应该是 CC_FOR_CGO=gcc.exe,我的错误。 但是要回答你的问题; 来自格里特:

PS1,第 1324 行:
cgo 仍然需要 gcc 可用于类型分析。 如果 CC 设置为 MSVC 编译器 cgo 需要一种调用 GCC 的方法,该方法由 CC_FOR_CGO 提供。 不幸的是,MSVC 工具链没有提供从 gcc 收集的相同类型信息的机制。 理论上,可以创建一个特定于 go 的工具来收集 cgo 使用的类型信息,但这可能超出范围并且可能需要相当大的努力(我个人从未编写过任何东西来执行 C/C++ 代码的静态类型分析)。

我似乎也破坏了 GCC 与 MSVC 运行之间的缓存清除,我不确定为什么有些测试仍然表现得好像它们被缓存了一样。

我想我已经解决了这个问题并推送了一些对变更集的更新。

这个设置https://github.com/golang/go/issues/20982#issuecomment -447618566 on

commit 5479fc9fe61fb998082fea5cb423314cc1afa649 (HEAD)
Author: Caleb Champlin <[email protected]>
Date:   Sat Sep 8 00:26:32 2018 -0600

    cmd/compile: add support for MSVC toolchain to go build

    Allows building with MSVC as an external compiler/linker.

    Setting CC=cl.exe inside an MSVC environment will automatically
    build cgo executables using MSVC as the external compiler and
    linker.

    For the builders setting the environment variable GOVSVARSPATH
    to the location of a msvsvars.bat file and setting the
    environment variable GOTESTMSVC=1 will automatically cause
    all.bat to run tests and compiler with both gcc and MSVC.

    Updates #20982

    Change-Id: I44be1f43aa0d53a688c595bc8336e0364b809ced

带我走得更远,但仍然失败

##### API check
+pkg go/build, type Context struct, CompilerType string
+pkg go/build, type Package struct, CgoMSCFLAGS []string
+pkg go/build, type Package struct, CgoMSCPPFLAGS []string
+pkg go/build, type Package struct, CgoMSCXXFLAGS []string
+pkg go/build, type Package struct, CgoMSLDFLAGS []string
+pkg os, method (*File) SyscallConn() (syscall.RawConn, error)

ALL TESTS PASSED

**********************************************************************
** Visual Studio 2017 Developer Command Prompt v15.0.26730.12
** Copyright (c) 2017 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'

# runtime/cgo
msvc_libinit_windows.c
msvc_libinit_windows.c(133): error C2220: warning treated as error - no 'object' file generated
msvc_libinit_windows.c(133): warning C4710: 'int fprintf(FILE *const ,const char *const ,...)': function not inlined
C:\Program Files (x86)\Windows Kits\10\include\10.0.15063.0\ucrt\stdio.h(826): note: see declaration of 'fprintf'
go tool dist: FAILED: go install -gcflags=all= -ldflags=all= std cmd: exit status 2

c:\Users\Alex\dev\go\src>

它实际上应该是 CC_FOR_CGO=gcc.exe,我的错误。

我不关心 gcc.exe 中的 .exe。 我的问题是

  • 您需要 gcc 和 MSVC 工具才能使用 MSVC(很难向我们的用户解释),但我知道对此无能为力;

  • 我需要设置 CC_FOR_CGO=gcc 和 CC=cl.exe 两个环境变量 - 也许我们可以假设 CC_FOR_CGO 始终设置为 gcc?

但是要回答你的问题; 来自格里特:

谢谢你的解释。

亚历克斯

@alexbrainman

# runtime/cgo
msvc_libinit_windows.c
msvc_libinit_windows.c(133): error C2220: warning treated as error - no 'object' file generated
msvc_libinit_windows.c(133): warning C4710: 'int fprintf(FILE *const ,const char *const ,...)': function not inlined
C:\Program Files (x86)\Windows Kits\10\include\10.0.15063.0\ucrt\stdio.h(826): note: see declaration of 'fprintf'
go tool dist: FAILED: go install -gcflags=all= -ldflags=all= std cmd: exit status 2

我不确定该警告将如何发生,除非您以某种方式拥有 msvc_libinit_windows.c 的不同/旧副本。 你能确认它有这行吗:

// src/runtime/cgo/msvc_libinit_windows.c
#pragma warning(disable:4668 4255 4710)

C4710 应该被禁止用于 stdio 包含。 我确实看到您的 MSVC 版本与我的略有不同,这也可能是罪魁祸首。 我不确定为什么他们会在不同的版本中主动忽略这种抑制。

无论如何,您也可以尝试进行更改以在全局范围内包含抑制

// src/cmd/go/internal/work/exec.go
// Line 2719
cgoMSCPPFLAGS = append(cgoMSCFLAGS, "/wd4668") // this should be cgoMSCFLAGS = append(cgoMSCFLAGS, "/wd4668") I'll fix the change set to correct
+cgoMSCFLAGS = append(cgoMSCFLAGS, "/wd4710") 

我需要设置 CC_FOR_CGO=gcc 和 CC=cl.exe 两个环境变量 - 也许我们可以假设 CC_FOR_CGO 始终设置为 gcc?

我认为如果未设置 CC_FOR_CGO,gco 检查 gcc 是否存在会很好。 CC_FOR_CGO 更适合像我这样没有 gcc 的人。 我的 CC_FOR_CGO 看起来像这样 CC_FOR_CGO=I:\Development\tmd-gcc\bingcc.exe。 如果我们不想支持 GCC 的用例不在 MSVC 构建的路径上,请告诉我,我可以一起摆脱环境变量。

我又试了这个版本

commit 6741b7009d1894b5bf535d82ad46f4a379651670 (HEAD)
Author: Caleb Champlin <[email protected]>
Date:   Sat Sep 8 00:26:32 2018 -0600

    cmd/compile: add support for MSVC toolchain to go build

    Allows building with MSVC as an external compiler/linker.

    Setting CC=cl.exe inside an MSVC environment will automatically
    build cgo executables using MSVC as the external compiler and
    linker.

    For the builders setting the environment variable GOVSVARSPATH
    to the location of a msvsvars.bat file and setting the
    environment variable GOTESTMSVC=1 will automatically cause
    all.bat to run tests and compiler with both gcc and MSVC.

    Updates #20982

    Change-Id: I44be1f43aa0d53a688c595bc8336e0364b809ced

我得到了同样的错误

##### API check
+pkg go/build, type Context struct, CompilerType string
+pkg go/build, type Package struct, CgoMSCFLAGS []string
+pkg go/build, type Package struct, CgoMSCPPFLAGS []string
+pkg go/build, type Package struct, CgoMSCXXFLAGS []string
+pkg go/build, type Package struct, CgoMSLDFLAGS []string
+pkg os, method (*File) SyscallConn() (syscall.RawConn, error)

ALL TESTS PASSED

**********************************************************************
** Visual Studio 2017 Developer Command Prompt v15.0.26730.12
** Copyright (c) 2017 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'

# runtime/cgo
msvc_libinit_windows.c
msvc_libinit_windows.c(133): error C2220: warning treated as error - no 'object' file generated
msvc_libinit_windows.c(133): warning C4710: 'int fprintf(FILE *const ,const char *const ,...)': function not inlined
C:\Program Files (x86)\Windows Kits\10\include\10.0.15063.0\ucrt\stdio.h(826): note: see declaration of 'fprintf'
go tool dist: FAILED: go install -gcflags=all= -ldflags=all= std cmd: exit status 2

c:\Users\Alex\dev\go\src>

你能确认它有这行吗:

// src/runtime/cgo/msvc_libinit_windows.c
#pragma warning(disable:4668 4255 4710)

这是我的 src/runtime/cgo/msvc_libinit_windows.c 文件的开头

// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build cgo

#define WIN64_LEAN_AND_MEAN
// Suppress MSVC specific warnings.
// C4668: symbol' is not defined as a preprocessor macro, 
// replacing with '0' for 'directives'.
// C4255: function' : no function prototype given: converting '()' 
// to '(void)'.
// C4710: function' : function not inlined
#pragma warning(disable:4668 4255 4710)
#include <windows.h>
#include <process.h>
...

无论如何,您也可以尝试进行更改以在全局范围内包含抑制

// src/cmd/go/internal/work/exec.go
// Line 2719
cgoMSCPPFLAGS = append(cgoMSCFLAGS, "/wd4668") // this should be cgoMSCFLAGS = append(cgoMSCFLAGS, "/wd4668") I'll fix the change set to correct
+cgoMSCFLAGS = append(cgoMSCFLAGS, "/wd4710") 

我做了这个改变:

c:\Users\Alex\dev\go\src>git diff
diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go
index 49d1d849f5..9fb442ab95 100644
--- a/src/cmd/go/internal/work/exec.go
+++ b/src/cmd/go/internal/work/exec.go
@@ -2717,6 +2717,7 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcMSCFLAGS, pc
        cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...)
        if cfg.BuildContext.CompilerType == "msvc" {
                cgoMSCFLAGS = append(cgoMSCFLAGS, "/wd4668")
+               cgoMSCFLAGS = append(cgoMSCFLAGS, "/wd4710")

                cgoMSCPPFLAGS = append(cgoMSCPPFLAGS, pcMSCFLAGS...)
                cgoMSCPPFLAGS = append(cgoMSCPPFLAGS, "/c")

c:\Users\Alex\dev\go\src>

但我看到了同样的错误

##### API check
+pkg go/build, type Context struct, CompilerType string
+pkg go/build, type Package struct, CgoMSCFLAGS []string
+pkg go/build, type Package struct, CgoMSCPPFLAGS []string
+pkg go/build, type Package struct, CgoMSCXXFLAGS []string
+pkg go/build, type Package struct, CgoMSLDFLAGS []string
+pkg os, method (*File) SyscallConn() (syscall.RawConn, error)

ALL TESTS PASSED

**********************************************************************
** Visual Studio 2017 Developer Command Prompt v15.0.26730.12
** Copyright (c) 2017 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'

# runtime/cgo
msvc_libinit_windows.c
msvc_libinit_windows.c(133): error C2220: warning treated as error - no 'object' file generated
msvc_libinit_windows.c(133): warning C4710: 'int fprintf(FILE *const ,const char *const ,...)': function not inlined
C:\Program Files (x86)\Windows Kits\10\include\10.0.15063.0\ucrt\stdio.h(826): note: see declaration of 'fprintf'
go tool dist: FAILED: go install -gcflags=all= -ldflags=all= std cmd: exit status 2

c:\Users\Alex\dev\go\src>

亚历克斯

我昨晚试图重现这一点,但我无法重现。 我想知道您是否遇到过这个问题: https :

您是否可以更新到最新的 SDK 和构建工具? 我在 SDK 10.0.17763.0 上。 和版本 15.9.28307.222 的构建工具/devenv

我正在尝试使用 MSVC 构建一个 Windows DLL,但看起来 Go 试图禁用一些数字超过 65535(或不是数字)的警告,这会导致 MSVC 停止。

image

不。 Werror是 GCC 选项,将每个警告视为错误。

对于 MSVC,您应该使用WX

@pravic好点,我该怎么做? 我没有设置它,我所做的就是:

set CC=cl.exe
go build -o next.dll .\main.go

@galich不幸的是,我

例如,与此线程相关的补丁在哪里? 在主人还是其他地方?

@pravic您可以在此处找到更改: https : //go-review.googlesource.com/c/go/+/133946/5

@mxplusb感谢您提供链接,看来我的 /Werror 特定问题已在那里解决。
你知道这什么时候进入测试版/每晚/稳定版吗?

您是否可以更新到最新的 SDK 和构建工具? 我在 SDK 10.0.17763.0 上。 和版本 15.9.28307.222 的构建工具/devenv

@cchamplin最后我设法更新了我的 MSVC。 我现在有了

c:\Users\Alex\dev\go\src>%GOVSVARSPATH%
**********************************************************************
** Visual Studio 2017 Developer Command Prompt v15.0
** Copyright (c) 2017 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'

c:\Users\Alex\dev\go\src>cl
Microsoft (R) C/C++ Optimizing Compiler Version 19.16.27030.1 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

usage: cl [ option... ] filename... [ /link linkoption... ]

c:\Users\Alex\dev\go\src>

我又试了这个版本

commit 6741b7009d1894b5bf535d82ad46f4a379651670 (HEAD)
Author: Caleb Champlin <[email protected]>
Date:   Sat Sep 8 00:26:32 2018 -0600

    cmd/compile: add support for MSVC toolchain to go build

    Allows building with MSVC as an external compiler/linker.

    Setting CC=cl.exe inside an MSVC environment will automatically
    build cgo executables using MSVC as the external compiler and
    linker.

    For the builders setting the environment variable GOVSVARSPATH
    to the location of a msvsvars.bat file and setting the
    environment variable GOTESTMSVC=1 will automatically cause
    all.bat to run tests and compiler with both gcc and MSVC.

    Updates #20982

    Change-Id: I44be1f43aa0d53a688c595bc8336e0364b809ced

并且 all.bat 成功完成。 但是我收到了这些警告。

##### ../misc/cgo/stdio

##### ../misc/cgo/life

##### ../misc/cgo/test
# _/c_/Users/Alex/dev/go/misc/cgo/test
issue28896.cgo2.c
.\issue28896.go(30): warning C4820: '<anonymous-tag>': '4' bytes padding added after data member 'g1'
.\issue28896.go(36): warning C4820: '<anonymous-tag>': '4' bytes padding added after data member 'f2'
# _/c_/Users/Alex/dev/go/misc/cgo/test
cthread_windows.c
c:\users\alex\dev\go\misc\cgo\test\cthread_windows.c(39) : warning C5045: Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified
c:\users\alex\dev\go\misc\cgo\test\cthread_windows.c(37) : note: index 'i' range checked by comparison on this line
c:\users\alex\dev\go\misc\cgo\test\cthread_windows.c(39) : note: feeds call on this line
PASS
scatter = 00007FF670706000
hello from C
sqrt is: 0
ok      _/c_/Users/Alex/dev/go/misc/cgo/test    3.534s
# _/c_/Users/Alex/dev/go/misc/cgo/test
issue28896.cgo2.c
.\issue28896.go(30): warning C4820: '<anonymous-tag>': '4' bytes padding added after data member 'g1'
.\issue28896.go(36): warning C4820: '<anonymous-tag>': '4' bytes padding added after data member 'f2'
# _/c_/Users/Alex/dev/go/misc/cgo/test
cthread_windows.c
c:\users\alex\dev\go\misc\cgo\test\cthread_windows.c(39) : warning C5045: Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified
c:\users\alex\dev\go\misc\cgo\test\cthread_windows.c(37) : note: index 'i' range checked by comparison on this line
c:\users\alex\dev\go\misc\cgo\test\cthread_windows.c(39) : note: feeds call on this line
PASS
scatter = 00007FF7DD026000
hello from C
sqrt is: 0
ok      _/c_/Users/Alex/dev/go/misc/cgo/test    3.229s
# _/c_/Users/Alex/dev/go/misc/cgo/test
issue28896.cgo2.c
.\issue28896.go(30): warning C4820: '<anonymous-tag>': '4' bytes padding added after data member 'g1'
.\issue28896.go(36): warning C4820: '<anonymous-tag>': '4' bytes padding added after data member 'f2'
# _/c_/Users/Alex/dev/go/misc/cgo/test
cthread_windows.c
c:\users\alex\dev\go\misc\cgo\test\cthread_windows.c(39) : warning C5045: Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified
c:\users\alex\dev\go\misc\cgo\test\cthread_windows.c(37) : note: index 'i' range checked by comparison on this line
c:\users\alex\dev\go\misc\cgo\test\cthread_windows.c(39) : note: feeds call on this line
PASS
scatter = 00007FF655CF6000
hello from C
sqrt is: 0
ok      _/c_/Users/Alex/dev/go/misc/cgo/test    3.172s

##### ../test/bench/go1
testing: warning: no tests to run
PASS
ok      _/c_/Users/Alex/dev/go/test/bench/go1   3.178s

##### ../test

##### API check
+pkg go/build, type Context struct, CompilerType string
+pkg go/build, type Package struct, CgoMSCFLAGS []string
+pkg go/build, type Package struct, CgoMSCPPFLAGS []string
+pkg go/build, type Package struct, CgoMSCXXFLAGS []string
+pkg go/build, type Package struct, CgoMSLDFLAGS []string
+pkg os, method (*File) SyscallConn() (syscall.RawConn, error)

ALL TESTS PASSED

---
Installed Go for windows/amd64 in c:\Users\Alex\dev\go
Installed commands in c:\Users\Alex\dev\go\bin
*** You need to add c:\Users\Alex\dev\go\bin to your PATH.

c:\Users\Alex\dev\go\src>

而且我还注意到您执行了两次所有测试。

...
##### API check
+pkg go/build, type Context struct, CompilerType string
+pkg go/build, type Package struct, CgoMSCFLAGS []string
+pkg go/build, type Package struct, CgoMSCPPFLAGS []string
+pkg go/build, type Package struct, CgoMSCXXFLAGS []string
+pkg go/build, type Package struct, CgoMSLDFLAGS []string
+pkg os, method (*File) SyscallConn() (syscall.RawConn, error)

ALL TESTS PASSED

**********************************************************************
** Visual Studio 2017 Developer Command Prompt v15.0
** Copyright (c) 2017 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'


##### Testing packages.
ok      archive/tar     0.256s
ok      archive/zip     2.070s
ok      bufio   (cached)
ok      bytes   1.624s
ok      compress/bzip2  (cached)
ok      compress/flate  1.067s
...

为什么?

亚历克斯

@alexbrainman这些测试的警告可能会被抑制,尤其是在这种情况下是幽灵警告。

对于执行两次的测试,我相信它是为构建器完成的,使用 gcc 编译运行一次测试,然后使用 MSVC(启用时)再次运行它们以确保使用两个工具链进行编译。 我不确定这里需要什么,所以我可以更改它,以便在启用 MSVC 的情况下调用 all.bat 时,我们只使用 MSVC 运行测试,让我知道。 在那种情况下,我假设需要为 MSVC 添加额外的构建器,而不是一些也使用 MSVC 构建的构建器?

同意在 Windows 上,需要使用 MinGW-W64 工具链运行一个构建器,并使用 MSVC 工具链运行另一个构建器,以便测试这两种场景。

我相信它是为构建器完成的,使用 gcc 编译运行一次测试,然后使用 MSVC(启用时)再次运行它们以确保使用两个工具链进行编译。

我同意这应该是首选行为,因此如果两个工具链都存在,则可以保证它不会破坏现有的工作负载。

这些测试的警告可能会被抑制,尤其是在这种情况下是幽灵警告。

Go 命令不显示警告,因此不应显示警告。

我还注意到go env命令不显示 CC_FOR_CGO 变量。 如果 CC_FOR_CGO 影响 go build 的工作方式,那么 CC_FOR_CGO 应该与其他人一起显示。 我们真的需要 CC_FOR_CGO 变量吗? 还有什么,但 CC_FOR_CGO=gcc 可以吗?

对于执行两次的测试,我相信它是为构建器完成的,使用 gcc 编译运行一次测试,然后使用 MSVC(启用时)再次运行它们以确保使用两个工具链进行编译。

许多测试不使用gcc。 包测试无缘无故运行两次是在浪费人/计算机的时间。 正如您从https://github.com/golang/go/issues/20982#issuecomment -480569880 archive/zip包测试运行两次 - 我认为不需要第二次运行。

我不确定如何安排,但也许您应该替换 run.bat 中go tool dist test调用,以仅执行测试 MSVC 构建所需的一系列测试。 例如,请参阅go tool dist test -h以了解如何仅选择某些特定测试。 @bradfitz也许我们可以创建一些标志或环境变量来告诉 dist 命令运行 MSVC 特定的测试。

但总的来说,您的https://go-review.googlesource.com/c/go/+/133946/5正在为我构建可执行文件。 例如,我可以使用 gcc 构建可执行文件:

c:\Users\Alex\dev\src\issue\go\20982\hello>type *

hello.c


#include <stdio.h>

extern void hello()
{
    printf("Hello World from C");
}

hello.go


package main

/*
        extern void hello();
*/
import "C"
import "fmt"

func main() {
    fmt.Println("Hello from Go!")
        C.hello()
}

c:\Users\Alex\dev\src\issue\go\20982\hello>go build

c:\Users\Alex\dev\src\issue\go\20982\hello>hello
Hello from Go!
Hello World from C
c:\Users\Alex\dev\src\issue\go\20982\hello>

然后我可以用 MSVC 构建可执行文件

c:\Users\Alex\dev\src\issue\go\20982\hello>%GOVSVARSPATH%
**********************************************************************
** Visual Studio 2017 Developer Command Prompt v15.0
** Copyright (c) 2017 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'

c:\Users\Alex\dev\src\issue\go\20982\hello>set CC=cl

c:\Users\Alex\dev\src\issue\go\20982\hello>go build
# issue/go/20982/hello
hello.c
C:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\ucrt\stdio.h(948): warning C4710: 'int printf(const char *const ,...)': function not inlined
C:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\ucrt\stdio.h(948): note: see declaration of 'printf'

c:\Users\Alex\dev\src\issue\go\20982\hello>hello
Hello from Go!
Hello World from C
c:\Users\Alex\dev\src\issue\go\20982\hello>

因此,使用 MSVC 构建将需要用户运行 MS 批处理文件来设置所有环境变量(请参阅我的输出中的 GOVSVARSPATH) - 我认为这是标准的,与 Go 无关。 还有set CC=cl 。 足够简单。

我发现这种方法的唯一问题是 MSVC 用户仍然需要安装 gcc。 cmd/cgo 使用 gcc 来发现所有 C 接口 - 这部分不是使用 MSVC 实现的。 对于不知道 cmd/cgo 如何工作的人来说,这听起来很不寻常,但事实就是如此。

@ianlancetaylor@bradfitz这一切听起来合理吗? 我们应该尝试在 go1.13 中提供它吗?

已安装 MSVC 的构建器可以测试所有新代码。 其他构建器将跳过测试。

亚历克斯

cmd/cgo 使用 gcc 来发现所有 C 接口 - 这部分不是使用 MSVC 实现的。

怎么能克服呢? 理想情况下,如果不需要 gcc,只需要 MSVC,那就太好了。

怎么能克服呢?

使用 gcc 的 cmd/cgo 部分需要重写以使用 MSVC。 如果可能的话。

亚历克斯

我想知道这个功能是否更接近于投入生产? 我看到它被标记为 1.13,并且刚刚发布。 我正在尝试使用链接到扩展代码的 Go c-archive 构建构建 Python 扩展,但 Python 需要 MSVC。

我不知道这个问题的状态是什么。 它从一个版本到另一个版本都被踢了,所以我要把它移到计划外。 如果它进入 1.14,那就太好了。

即使有双重编译器的要求,我也很希望看到当前的实现能够进入下一个版本。 它至少可以使用 MSVC 编译可执行文件/库,这总比没有好。

即使有双重编译器的要求,我也很希望看到当前的实现能够进入下一个版本。

我认为这将是一个很好的“测试版”实现。 它将允许清除错误并使实现开始成熟。 在它通过认真的审查之前还有什么需要做的?

因此,从我的角度以及我上次(大约 6 个月前)看到的情况来看,代码审查过程需要完成十几个清理项目。 可能还需要额外的工作来消除一些测试的重复数据,这些测试基本上是通过非常小的修改来复制以使用不同的工具链。 还需要查看和关闭某些 msvc 警告。

主要未决问题包括:

如果没有 gcc,我们就无法进行类型分析,对此没有简单或直接的解决方案。

完成设置以及一切将如何为建设者工作。

我相信在过去 6 个月中编译器和链接器发生了一些相当重要的变化,可能会严重影响当前为此所做的工作,但我无法确认这一点。 由于导航 Go 的编译器/链接器/工具链的复杂性和高学习曲线,我可能需要相当长的时间来让自己足够快,以计算出对这项工作的任何更改的影响。

不支持复数类型。 MSCVs C lib 根本不兼容。 我相信可能有一种方法可以用 C++ 来填补这个,但我不确定,也许熟悉 MSVC 工具链的 MS 的人可以加入。

不幸的是,生活和其他项目已经严重阻碍了我在这方面投入更多时间,但我会在接下来的几周内尝试花一些时间在这上面。

@manbearian这个问题是关于向 golang 添加 MSVC 支持。 MSVC 团队中的哪些人适合咨询 MSVC 问题?

@kesmit13@mxplusb

这个

https://go-review.googlesource.com/c/go/+/133946/5

@cchamplin最新的有效代码。

我目前对代码的担忧,不清楚如何使用它。 你运行什么命令? 我的环境需要如何设置?

我认为下一步是让某人尝试使用该代码,看看他们是否真的可以使用它。 如果可行,则需要记录这些步骤,以便其他人也可以使用该代码。 也许它太复杂了,或者不起作用。 比我们需要相应地调整代码。

一旦我们对代码的当前状态感到满意,我们就应该将其变基到 master 上。 更改调整了太多不同的文件,因此不容易rebase。 也许我们可以调整更改以减少更改,因此更容易rebase。

亚历克斯

@mxplusb @kesmit13当前的实现已经针对 master 进行了重新定位,可以在这里找到: https ://go-review.googlesource.com/c/go/+/133946/6

@alexbrainman

我目前对代码的担忧,不清楚如何使用它。 你运行什么命令? 我的环境需要如何设置?

我同意需要添加有关如何使用它的文档。 我不完全确定把它放在哪里,如果你有想法,请告诉我。 不知道它是否应该放在通过 MSVC 构建/运行的 cmd/go 文档下,或者它是否应该放在 CGO 文档下,或者可能完全在其他地方?

许多测试不使用gcc。 包测试无缘无故运行两次是在浪费人/计算机的时间。 正如您从 #20982(评论)中看到的那样,存档/zip 包测试运行了两次 - 我认为不需要第二次运行。

我不确定如何安排,但也许您应该替换 run.bat 中的 go tool dist test 调用,以仅执行测试 MSVC 构建所需的一系列测试。 例如,请参阅 go tool dist test -h 以了解如何仅选择某些特定测试。 @bradfitz也许我们可以创建一些标志或环境变量来告诉 dist 命令运行 MSVC 特定的测试。

更改已经包括一个添加到 dist 的环境变量,让它知道我们正在做 MSVC 的事情“GO_TEST_TESTINGMSVC”,我相信。 我不确定的是,如果我们不运行所有测试两次,我们将如何过滤要运行的测试到只有 MSVC 可能影响的内容。 可能只是将其限制为 CGO 相关测试,但我相信到处都有 CGO 测试,我不知道 dist 是否有过滤掉这些测试的机制?

我不完全确定把它放在哪里,如果你有想法,请告诉我。

我认为在更新任何文档之前,您应该在这里描述如何使用 MSVC 构建 Cgo 代码。 对于@mxplusb@kesmit13 ,他们可以尝试您的更改。

比如使用gcc构建Cgo代码,我

  1. 调整我的 %PATH% 以包含 gcc.exe
  2. 首先从%GOROOT%\src目录运行 make.bat
  3. 使用标准的go buildgo install命令

我如何对 MSVC 做同样的事情?

我不确定的是,如果我们不运行所有测试两次,我们将如何过滤要运行的测试到只有 MSVC 可能影响的内容。 可能只是将其限制为 CGO 相关测试,但我相信到处都有 CGO 测试,我不知道 dist 是否有过滤掉这些测试的机制?

我将从 %GOROOT%\misc\cgo 目录开始。 无论您可以在那里构建什么来源,都应该构建。 上面的任何事情都取决于你。

亚历克斯

@cchamplin很抱歉在这方面出现延误,我将在本周尽力对其进行测试,并让您知道进展如何。

大家好,很抱歉迟到了……我可以尝试回答有关 MSVC 功能的问题,或者将您转介给可以的人。 我通读了对话,但不幸的是,我对 go 不够熟悉,无法理解 MSVC 可能会或可能不会缺少所需的 GCC 功能。

嗨伙计,
这个功能是在 Go 1.14 中发布的吗?
如果发布,请分享任何可用的文件以使用它。
如果还没有发布,不知道什么时候发布?
热切等待 MSVC 的支持。
提前致谢 :)

嗨,没有人回应过我提供更多信息的请求,所以我不确定需要什么。 有人可以填写我吗?

不幸的是,我不知道是否有人正在积极研究这个问题。

嗨,没有人回应我的更多信息请求,...

你好@manbearian

那是哪个请求? 你需要什么信息?

亚历克斯

我在此线程中早些时候被标记以获取信息,但我不知道人们在寻找什么并且无法提供帮助。 如果不需要帮助,那就太好了。 请让我知道。

请让我知道。

@manbearian

谢谢你的报价。 我不知道是谁标记了你。 如果他们仍然需要帮助,他们会再次标记您。

亚历克斯

如果还没有发布,不知道什么时候发布?
热切等待 MSVC 的支持。

@dhinesherode91

代码在那里并且完整; 我相信唯一真正阻碍这一点的是人们测试更改并提供反馈,以便他们可以得到适当的审查和批准。 不过,我很犹豫要不要在当前 master 的基础上重新调整更改。 我已经做了 5-6 次,而且非常耗时,然后我没有得到任何测试/反馈。 除非有其他各方愿意参与测试,否则这个问题可能已经荡然无存。

除非有其他各方愿意参与测试,否则这个问题可能已经荡然无存。

@cchamplin依靠我来测试/调试您的更改。 我没有使用工具链的经验,但我已经查看了您的提交,它们的结构和文档似乎非常好。

@cchamplin
我有兴趣参与测试部分,但我是 GoLang 的初学者,也是 windows apis 的好学习者(几周前开始)。 我计划在 MS C++ 中使用 windows api,因为它看起来有很多官方资源可用。 但后来我开始寻找一种语言(用于我的系统编程),我可以将它用于我的多平台系统编程,我对 GoLang 印象深刻。 随时准备接受我的贡献,并且非常需要指导。

@cchamplin如果你变基,我会尝试在它之上构建。 我很想从我的一些工作项目中删除 mingw64 要求。 我的构建工具都是为 MSVC 设置的,所以除了使用您的补丁之外,我不需要做任何事情。

@cchamplin也是,我查看了你的 CL 并没有看到 cgo 工具的任何内容,所以我开始使用我自己的补丁。 有没有前期工作?

@ericlagergren

@cchamplin也是,我查看了你的 CL 并没有看到 cgo 工具的任何内容,所以我开始使用我自己的补丁。 有没有前期工作?

不确定我是否理解,在https://go-review.googlesource.com/c/go/+/133946/6 上,许多相关提交以某种身份直接触及 Go 的 cgo 部分。

@ccahoon好吧,我一定很想念他们。 如果没有更新 cgo 工具,我将提供这样做。

@ericlagergren

我很想从我的一些工作项目中删除 mingw64 要求

仅供参考。 这

https://go-review.googlesource.com/c/go/+/133946/6

改变仍然需要 Mingw 来工作。 您需要安装 Mingw 和 MSVC 工具才能使用@cchamplin更改。

亚历克斯

@cchamplin ,为什么还需要 Mingw? 删除这种依赖需要什么?

@alexbrainman会很棒。 但也像@cglong所说的那样,我不确定为什么这也需要 mingw64。

@ericlagergren @cglong CGO 需要收集有关正在编译的 C 代码的可用类型信息。 GCC 有一个标志,可以方便地解析格式输出类型数据。 据我所知,MSVC 没有提供相同信息的功能。 在 go 中构建工具不仅需要代码来 lex/parse C 和 C++ 代码,还需要理解和评估预处理器指令。 在 Go 中构建这样的东西将是一项相当大的任务。 也许某个地方已经有一个图书馆,尽管我们可以弄清楚如何采用?

@cchamplin gotcha ,这就是我的想法。 我知道像 libclang 和 cznic/cc 这样的第三方库。 但不幸的是,libclang 非常庞大,而且 cznic/cc 尚未在 Windows 或 macOS 上进行过测试。 PDB 是否没有提供足够的信息?

CGO 需要收集有关正在编译的 C 代码的可用类型信息。 GCC 有一个标志,可以方便地解析格式输出类型数据。 据我所知,MSVC 没有提供相同信息的功能。

也许@manbearian可以在这里提供一些指导?

我不会说 GCC 以特殊格式发出输出类型数据。 它发出供调试器使用的 DWARF 调试数据,cgo 使用 debug/dwarf 包读取该数据。 MSVC 大概也有调试格式。 如果该格式记录在任何地方,我们可以使用 cgo 读取它,就像我们读取 DWARF 数据一样。

@ianlancetaylor MSVC 可以发出 PDB 文件。 见https://github.com/Microsoft/microsoft-pdb

FWIW,当我在https://github.com/golang/go/issues/20982#issuecomment -648462003 中提到 cgo 工具时,我正在谈论阅读 MSVC 的调试输出

我不会说 GCC 以特殊格式发出输出类型数据。 它发出供调试器使用的 DWARF 调试数据,cgo 使用 debug/dwarf 包读取该数据。 MSVC 大概也有调试格式。 如果该格式记录在任何地方,我们可以使用 cgo 读取它,就像我们读取 DWARF 数据一样。

@ericlagergren @ianlancetaylor
所以我们确实需要 DWARF 数据,这是其中的很大一部分。 但是,理论上我们可以从 PDB 数据中获得相同的信息。

不过,我特别指的不仅仅是 GCC 生成的 DWARF 数据,而是 gcc -E -dM 的输出,它在预处理发生后输出所有 #define 的数据。 PDB 本身有可能提供相同的信息......我怀疑的是我们是否能够强制 MSVC 以任何身份转储调试信息/类型信息而无需实际编译编码。 现在 CGO 正在用 GCC 做这件事。

从内存中,/EP /d1PP 应该发出类似于 -E -dM 的内容。

从内存中,/EP /d1PP 应该发出类似于 -E -dM 的内容。

如果是这样那就太好了,我认为 /d1PP 是一个未记录的标志? 我以前从未见过。 那只会提前获取等效类型的信息。

@cchamplin是的,它没有记录。 许多 /dXXX 标志显然是。 使用未记录的标志是不幸的,但(IMO)至少在 Windows 上似乎并没有那么糟糕。 我看到 MSVC STL 开发人员在 reddit 线程上谈论它,但它也遍布整个互联网。

有人能给我一个关于 MSVC 支持当前状态的简短摘要吗? 我不太了解所有这些低级编译器的东西。 只是我有一个想要从 C#/UWP 使用的 go 库 - 并且它已经在使用 go build 和 buildmode c-shared。 但是:该应用程序永远不会被 Windows 应用商店接受,因为从 go 生成的 DLL 错过了一些(我假设)只能由 MSVC 工具链设置的编译器/链接器标志。

所以:我怎么能在这里测试呢? 任何建议表示赞赏! 谢谢!

该应用程序永远不会被 Windows 应用商店接受,因为从 go 生成的 DLL 错过了一些(我假设)只能由 MSVC 工具链设置的编译器/链接器标志。

@TopperDEL Windows Store 是否会告诉您缺少哪些编译器标志? 如果 mingw-64 支持它们,您可以在构建 dll 时始终使用带有正确标志的-extldflags

@qmuntal是的,他们这样做:
“在链接应用程序时应用所需的链接器选项 - SAFESEH、DYNAMICBASE、NXCOMPAT 和 APPCONTAINER。”

我已经试过了
go build -ldflags="-s -w '-extldflags=-Wl,--dynamicbase,--high-entropy-va'" -o storj_uplink.dll -buildmode c-shared

但这并没有改变关于商店提交的任何事情。 根据我的理解,至少 SAFESEH 是特定于 MSVC 的东西,对吧?

“在链接应用程序时应用所需的链接器选项 - SAFESEH、DYNAMICBASE、NXCOMPAT 和 APPCONTAINER。”

我不知道有什么简单的方法可以在 Mingw-w64 中启用 SAFESEH 和 APPCONTAINER 标志,也许这个项目https://github.com/status-im/mingw-windows10-uwp可以给你一些指导。

另一方面 DYNAMICBASE 和 NXCOMPAT 将在 go 1.16(见#41421)中默认启用,但正如前面提到的,已经可以与-extldflags一起使用,事实上我正在为一些项目这样做。

@qmuntal谢谢! 所以至少我上面的 extldflags 应该是对的?
我将看看 windows 10-uwp 的 mingw。

此页面是否有帮助?
0 / 5 - 0 等级