Closed vault-thirteen closed 3 days ago
CC @golang/compiler maybe?
Hello, @mknyszek.
Well, using another compiler can unveil a whole box of surprises. Take native compilers for Windows OS for example ...
By the way, is it possible to use Microsoft's compiler from Visual Studio Community 2022 together with Golang's CGO ? I am using Windows OS, and GCC compiler does not support many things which I need on the Windows platform. Using a compiler from Unix / Linux world on Windows looks very strange, to say the least.
P. S.
D.1.6 Disallowed Implicit int and Implicit Function Declarations
6.5.2.2 Function calls
Implicit declarations are no longer allowed in the 1999 C standard as they were in the 1990 C standard. Previous versions of the C compiler issued warning messages about implicit definitions only with -v (verbose). These messages and new additional warnings about implicit definitions, are now issued whenever identifiers are implicitly defined as int or functions.
This change is very likely to be noticed by nearly all users of this compiler because it can lead to a large number of warning messages. Common causes include a failure to include the appropriate system header files that declare functions being used, like printf which needs
included. The 1990 C standard behavior of accepting implicit declarations silently can be restored using -xc99=none.
https://docs.oracle.com/cd/E19205-01/819-5265/bjazh/index.html
Looks like the reason was in the Cygwin64.
I deleted it and used another bundle of 64-bit MinGW. Now, a new problem arose.
# test/b .\main.go:48:2: could not determine kind of name for C.free
Compilation finished with exit code 1
OK. I have added a header file for stdlib
.
// #include
import "C"
Now the error is different.
.\main.go:47:18: cannot use ret (variable of type uintptr) as *_Ctype_char value in argument to (_Cfunc_GoString)
How do I cast Go's uintptr to C's pointer to char ?
s := C.GoString((C.char)(unsafe.Pointer(ret))) fmt.Printf("Error: %s\n", s) C.free((C.char)(unsafe.Pointer(ret)))
leads to an error:
cannot use _cgo0 (variable of type *_Ctype_char) as unsafe.Pointer value in argument to _Cfunc_free
Full code is following.
package main
// #include <stdlib.h>
import "C"
import (
"fmt"
"log"
"runtime"
"syscall"
"unsafe"
)
const (
SDL_INIT_TIMER = 0x00000001
SDL_INIT_AUDIO = 0x00000010
SDL_INIT_VIDEO = 0x00000020
SDL_INIT_JOYSTICK = 0x00000200
SDL_INIT_HAPTIC = 0x00001000
SDL_INIT_GAMECONTROLLER = 0x00002000
SDL_INIT_EVENTS = 0x00004000
SDL_INIT_SENSOR = 0x00008000
SDL_INIT_NOPARACHUTE = 0x00100000
SDL_INIT_EVERYTHING = SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_SENSOR
)
func main() {
runtime.LockOSThread()
err := x()
if err != nil {
log.Fatal(err)
}
}
func x() (err error) {
var sdl2 = syscall.NewLazyDLL("SDL2.dll")
SDL_Init := sdl2.NewProc("SDL_Init")
SDL_GetError := sdl2.NewProc("SDL_GetError")
var ret uintptr
ret, _, _ = SDL_Init.Call(SDL_INIT_EVERYTHING)
fmt.Printf("Return: %d\n", ret)
ret, _, _ = SDL_GetError.Call()
fmt.Printf("Return: %d\n", ret)
s := C.GoString((*C.char)(unsafe.Pointer(ret)))
fmt.Printf("Error: %s\n", s)
C.free((*C.char)(unsafe.Pointer(ret)))
return nil
}
Looks like, the C.free
function expects an unsafe.Pointer
type instead of C's char*
type. Why ?
If I change the last statement
C.free((*C.char)(unsafe.Pointer(ret)))
to
C.free((unsafe.Pointer(ret)))
It compiles and runs.
Return: 0 Return: 140722205880947 Error:
Process finished with the exit code -1073740940 (0xC0000374)
https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/beginthread-beginthreadex it seems _beginthread
is declared in process.h, which runtime/cgo/gcc_libinit_windows.c includes. Does your C toolchain not declare _beginthread
?
By the way, is it possible to use Microsoft's compiler from Visual Studio Community 2022 together with Golang's CGO ?
Issue #20982 is about MSVC support. Is there anything you expect beyond that issue?
Thanks.
Does your C toolchain not declare _beginthread?
I have no idea about Cygwin64. This project is very strange to me. Neither do I use the GCC compiler if I have a choice.
I prefer MS Visual Studio with its MSVC compiler and LLVM with its CLang compiler, but it looks like they are both not supported by Google at this moment.
And, for some reason Golang does not provide a way to select a compiler for C language in CGO. This looks like a selection between one choice. It is weird.
Is there anything you expect beyond that issue?
I expect that Google adds a possibility to change a compiler for C language in CGO in Golang. I mean, a real possibility to choose any compiler that I want, not the fake choice between GCC and GCC.
P. S.
There is a great thing in this field. LLVM.
The LLVM project tries to unify compilers of different languages and different vendors and make it possible to use a common standard for compiling and linking executables. I think, Google should think about supporting this truly cross-platform solution.
Here is an extract from Wikipedia about it.
Due to its permissive license, many vendors release their own tuned forks of LLVM. This is officially recognized by LLVM's documentation, which suggests against using version numbers in feature checks for this reason. Some of the vendors include:
- AMD's AMD Optimizing C/C++ Compiler is based on LLVM, Clang, and Flang.
- Apple maintains an open-source fork for Xcode.
- ARM maintains a fork of LLVM 9 as the "Arm Compiler".
- Flang, Fortran project in development as of 2022.
- IBM is adopting LLVM in its C/C++ and Fortran compilers.
- Intel has adopted LLVM for their next generation Intel C++ Compiler.
- The Los Alamos National Laboratory has a parallel-computing fork of LLVM 8 called "Kitsune".
- Nvidia uses LLVM in the implementation of its NVVM CUDA Compiler. The NVVM compiler is distinct from the "NVPTX" backend mentioned in the Backends section, although both generate PTX code for Nvidia GPUs.
- Sony has been using LLVM's primary front-end Clang compiler in the software development kit (SDK) of its PlayStation 4 console.
LLVM with its CLang compiler
I think we do support LLVM based C compiler for Windows. Have you tried that?
The LLVM project tries to unify compilers of different languages and different vendors
We have "gollvm" project that uses LLVM backend for Go https://go.googlesource.com/gollvm . You're welcome to try that. It doesn't support Windows yet, though. But that is beyond the scope of this issue. Thanks.
I tried to compile CGO code with CLang compiler, but it threw a lot of errors about GCC parameters passed to CLang.
It doesn't support Windows yet
Why ?
I hit this issue using "Git for Windows SDK" for my mingw, turns out I had forgotten to add the environment variable "MSYSTEM" = "MINGW64" after a clean windows install. Hopefully this information can help someone else.
I tried to compile CGO code with CLang compiler, but it threw a lot of errors about GCC parameters passed to CLang.
Can you show us the exact output? Thanks.
@ianlancetaylor
go build .
D:\Program Files\Go\pkg\tool\windows_amd64\link.exe: running D:\Program Files\LLVM\bin\clang.exe failed: exit status 1104
LINK : warning LNK4044: unrecognized option '/-tsaware'; ignored
LINK : warning LNK4044: unrecognized option '/-nxcompat'; ignored
LINK : warning LNK4044: unrecognized option '/-major-os-version=6'; ignored
LINK : warning LNK4044: unrecognized option '/-minor-os-version=1'; ignored
LINK : warning LNK4044: unrecognized option '/-major-subsystem-version=6'; ignored
LINK : warning LNK4044: unrecognized option '/-minor-subsystem-version=1'; ignored
LINK : warning LNK4044: unrecognized option '/-dynamicbase'; ignored
LINK : warning LNK4044: unrecognized option '/-high-entropy-va'; ignored
LINK : warning LNK4044: unrecognized option '/T'; ignored
LINK : warning LNK4044: unrecognized option '/-start-group'; ignored
LINK : warning LNK4044: unrecognized option '/-end-group'; ignored
LINK : fatal error LNK1104: cannot open file 'mingwex.lib'
clang: error: linker command failed with exit code 1104 (use -v to see invocation)
Those errors are all coming from the linker. We currently expect that clang will be used with a clang linker such as lld.
Is it possible for a user to change the linker ?
I'm sure it is, because I see that lld supports Windows. But I don't know enough about Windows to tell you how to do it. Sorry.
@ianlancetaylor , do you mean Linux's symlinks ? This does not look like a setting to me :-)
I mean a variable, as CC
for C compiler. CL
for C linker ?
I have not found anything about setting path to linker in description of cgo
package – https://pkg.go.dev/cmd/cgo.
Sorry, I don't understand what you mean about symlinks. When I mention lld I mean https://lld.llvm.org/.
The Go tools use the environment variable CC
for both compiling and linking. They expect the compiler to invoke the linker when necessary. That is how clang works.
There must be some way to install clang on Windows such that it runs lld as the linker.
CMake has an interesting feature. It is possible to tell CMake how to use the linker.
cmake -DCMAKE_LINKER=/path/to/linker -DCMAKE_CXX_LINK_EXECUTABLE="
-o "
https://stackoverflow.com/questions/1867745/cmake-use-a-custom-linker
I thought about something like this.
Is it possible in CGO to pass a custom argument to the compiler specified in CC
variable ?
I know how to tell the CLang compiler use the LLD (-fuse-ld=lld
), but I do not know how to make CGO use it :-)
Set CFLAGS
in the environment.
I tried to run the CLang compiler with LLD (SET CGO_CFLAGS=-fuse-ld=lld
), but nothing changed.
Looks like CGO is using the compiler (and/or linker) not properly :)
Is there a verbose mode in CGO to print all the executed commands into stdout for debugging ?
Oh. I have found it. It is go build -x ...
Why the heck -x
instead of normal -v
? (O.o)
CFLAGS
and CGO_CFLAGS
are not the same.
What is the difference between CFLAGS and CGO_CFLAGS ? I thought that C is used in Go only via CGO.
Bother, you're right. My apologies. It should be CGO_CFLAGS
. But actually since you are linking you might have to set CGO_LDFLAGS
.
Actually, it is not clear from the documentation (https://pkg.go.dev/cmd/cgo), how to use these variables.
It looks like CFLAGS
sets arguments and CGO_CFLAGS
appends additional arguments.
But what happens when this variable is set in a Go file as a // #cgo CFLAGS: ...
directive ?
Which order of values is used ... is not clear.
What happens when all three are set ? :-)
In general the flags from the environment variables follow the flags from a #cgo
line.
@vault-thirteen Are you still seeing the implicit declaration error? Should we leave this issue open?
@mknyszek , if I install the Cygwin64, then I will see it, so yes, it is not working with Cygwin64.
I ran into the same problem:
`
$ CGO_ENABLED=1 GOOS=windows GOARCH=arm64 go build -x -buildmode=c-shared -o ct-lib.dll main.go
WORK=C:\msys64\tmp\go-build3598144249
mkdir -p $WORK\b300\
cd C:\Program Files\Go\src\runtime\cgo
TERM='dumb' CGO_LDFLAGS='"-O2" "-g"' "C:\\Program Files\\Go\\pkg\\tool\\windows_arm64\\cgo.exe" -objdir "$WORK\\b300\\" -importpath runtime/cgo -import_runtime_cgo=false -import_syscall=false "-exportheader=$WORK\\b300\\_cgo_install.h" -- -I "$WORK\\b300\\" -O2 -g -Wall -Werror -fno-stack-protector "C:\\Program Files\\Go\\src\\runtime\\cgo\\cgo.go"
cd $WORK\b300
TERM='dumb' gcc -I "C:\\Program Files\\Go\\src\\runtime\\cgo" -mthreads -Wl,--no-gc-sections -fmessage-length=0 "-fdebug-prefix-map=$WORK\\b300=/tmp/go-build" -gno-record-gcc-switches -I "$WORK\\b300\\" -O2 -g -Wall -Werror -fno-stack-protector "-fdebug-prefix-map=C:\\Program Files\\Go\\src\\runtime\\cgo=\\\\_\\_\\runtime\\cgo" -o "$WORK\\b300\\_x001.o" -c _cgo_export.c
TERM='dumb' gcc -I "C:\\Program Files\\Go\\src\\runtime\\cgo" -mthreads -Wl,--no-gc-sections -fmessage-length=0 "-fdebug-prefix-map=$WORK\\b300=/tmp/go-build" -gno-record-gcc-switches -I "$WORK\\b300\\" -O2 -g -Wall -Werror -fno-stack-protector "-fdebug-prefix-map=C:\\Program Files\\Go\\src\\runtime\\cgo=\\\\_\\_\\runtime\\cgo" -o "$WORK\\b300\\_x002.o" -c cgo.cgo2.c
cd C:\Program Files\Go\src\runtime\cgo
TERM='dumb' gcc -I "C:\\Program Files\\Go\\src\\runtime\\cgo" -mthreads -Wl,--no-gc-sections -fmessage-length=0 "-fdebug-prefix-map=$WORK\\b300=/tmp/go-build" -gno-record-gcc-switches -I "$WORK\\b300\\" -O2 -g -Wall -Werror -fno-stack-protector "-fdebug-prefix-map=C:\\Program Files\\Go\\src\\runtime\\cgo=\\\\_\\_\\runtime\\cgo" -o "$WORK\\b300\\_x003.o" -c gcc_context.c
TERM='dumb' gcc -I "C:\\Program Files\\Go\\src\\runtime\\cgo" -mthreads -Wl,--no-gc-sections -fmessage-length=0 "-fdebug-prefix-map=$WORK\\b300=/tmp/go-build" -gno-record-gcc-switches -I "$WORK\\b300\\" -O2 -g -Wall -Werror -fno-stack-protector "-fdebug-prefix-map=C:\\Program Files\\Go\\src\\runtime\\cgo=\\\\_\\_\\runtime\\cgo" -o "$WORK\\b300\\_x004.o" -c gcc_libinit_windows.c
# runtime/cgo
gcc_libinit_windows.c: In function ‘_cgo_beginthread’:
gcc_libinit_windows.c:136:27: error: implicit declaration of function ‘_beginthread’; did you mean ‘_cgo_beginthread’? [-Werror=implicit-function-declaration]
136 | thandle = _beginthread(func, 0, arg);
| ^~~~~~~~~~~~
| _cgo_beginthread
cc1: all warnings being treated as errors
`
I see no problem within the code for: gcc_libinit_windows.c:136:27
, and not sure why the compiler has a problem with this.
_beginthread
is defined in process.h
as: (I also see no preprocessor exclusions been made)
_ACRTIMP uintptr_t __cdecl _beginthread(
_In_ _beginthread_proc_type _StartAddress,
_In_ unsigned _StackSize,
_In_opt_ void* _ArgList
);
I will be trying this out later: https://github.com/goreleaser/goreleaser-cross
I further checked the location of the process.h file, on my machine it's located here: (maybe the compiler is finding another header file?) -- investigating this now.
C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\ucrt\process.h
and when I run this I can see where gcc is looking:
echo "#include <bogus.h>" > t.c; gcc -v t.c; rm t.c
It's not finding the windows sdk header... but some other header file.
After using the CGO_FLAGS to specify additional search paths for gcc, I got this type of errors, and adding more paths, adds more errors... all the way up to vcruntime.h
-- it's rabbit hole...
CGO_CFLAGS="-I'/c/Program Files (x86)/Windows Kits/10/Include/10.0.22621.0/ucrt/' -I'/c/Program Files (x86)/Windows Kits/10/Include/10.0.22621.0/um/' -I'/c/Program Files (x86)/Windows Kits/10/Include/10.0.22621.0/shared'" CGO_ENABLED=1 GOOS=windows GOARCH=arm64 go build -x -buildmode=c-shared -o ct-lib.dll main.go
WORK=C:\msys64\tmp\go-build2264873858
mkdir -p $WORK\b300\
echo > $WORK\b300\preferlinkext
cd C:\Program Files\Go\src\runtime\cgo
TERM='dumb' CGO_LDFLAGS='"-O2" "-g"' "C:\\Program Files\\Go\\pkg\\tool\\windows_arm64\\cgo.exe" -objdir "$WORK\\b300\\" -importpath runtime/cgo -import_runtime_cgo=false -import_syscall=false "-exportheader=$WORK\\b300\\_cgo_install.h" -- -I "$WORK\\b300\\" -I'C:/Program Files "(x86)/Windows" Kits/10/Include/10.0.22621.0/ucrt/' -I'/c/Program Files "(x86)/Windows" Kits/10/Include/10.0.22621.0/um/' -I'/c/Program Files "(x86)/Windows" Kits/10/Include/10.0.22621.0/shared' -Wall -Werror -fno-stack-protector "C:\\Program Files\\Go\\src\\runtime\\cgo\\cgo.go"
# runtime/cgo
In file included from C:/Program Files (x86)/Windows Kits/10/Include/10.0.22621.0/ucrt/stddef.h:12,
from cgo-builtin-prolog:1:
C:/Program Files (x86)/Windows Kits/10/Include/10.0.22621.0/ucrt/corecrt.h:10:10: fatal error: vcruntime.h: No such file or directory
10 | #include <vcruntime.h>
| ^~~~~~~~~~~~~
compilation terminated.
this got me unblocked: (using mingw64
from the Windows GIT-SDK
- also set the windows environment variable MSYSTEM=MINGW64
- not sure if this made any difference)
CGO_ENABLED=1 GOOS=windows GOARCH=amd64 CXX=x86_64-w64-mingw32-g++ CC=x86_64-w64-mingw32-gcc go build -buildmode=c-shared -o ct-lib.dll main.go
Also I am not yet able to target windows arm64
- I assume I need to wait for Windows GIT-SDK / MINGW64 to support windows arm64
that happen because you installed gcc through cygwin64
so, try to install MinGW.
download it from this link https://github.com/niXman/mingw-builds-binaries/releases
make sure to choose a compatible version if you have Windows 64 choose mingw64 and so
then extract it into Windows partition in my case was C:\ partition
then change the gcc path in environment variables in my case the path after the update was "C:\mingw64\bin"
then restart vs code if it opens then try the command again.
if it needs to CG_ENABELED=1 then open powershell as admin and write this command "go env -w CGO_ENABLED=1"
删除 其他的gcc 环境 只是用tdm-gcc ,就可以编译成功
this got me unblocked: (using
mingw64
from theWindows GIT-SDK
- also set the windows environment variableMSYSTEM=MINGW64
- not sure if this made any difference)CGO_ENABLED=1 GOOS=windows GOARCH=amd64 CXX=x86_64-w64-mingw32-g++ CC=x86_64-w64-mingw32-gcc go build -buildmode=c-shared -o ct-lib.dll main.go
Also I am not yet able to target windows
arm64
- I assume I need to wait for Windows GIT-SDK / MINGW64 to support windowsarm64
In this package, the search process.h
https://packages.msys2.org/package/mingw-w64-x86_64-headers-git
You just need to download https://packages.msys2.org/package/mingw-w64-x86_64-gcc?repo=mingw64 and all the dependencies will catch up.
删除 其他的gcc 环境 只是用tdm-gcc ,就可以编译成功
Thanks @injuryzy ,it works on my windows11!
Change https://go.dev/cl/627935 mentions this issue: runtime/cgo: report a meaningful error message when using Cygwin
What version of Go are you using (
go version
)?1.20.3
Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env
)?Windows 10 Intel x86-64
What did you do?
I tried to run a simple code to execute a function from a DLL file.
CGO is enabled, gcc is installed with Cygwin64 and has version 11.3.0-1. SDL is the latest version, 2.26.5.
What did you expect to see?
I expected not to see errors at compile time.
What did you see instead?