Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"zig cc" doesn't work with cgo (golang) #7342

Closed
lu4p opened this issue Dec 8, 2020 · 39 comments
Closed

"zig cc" doesn't work with cgo (golang) #7342

lu4p opened this issue Dec 8, 2020 · 39 comments
Labels
downstream An issue with a third party project that uses Zig. zig cc Zig as a drop-in C compiler feature
Milestone

Comments

@lu4p
Copy link

lu4p commented Dec 8, 2020

I would like to use "zig cc" for easily cross compiling cgo dependent go code, however the "drop-in" c compiler replacement doesn't work.

Example cgo code

main.go

package main

//int Add(int a, int b){
//    return a+b;
//}
import "C"
import "fmt"

func main() {
	a := C.int(10)
	b := C.int(20)
	c := C.Add(a, b)
	fmt.Println(c) // 30
}

other compilers

go build main.go //build works fine (uses gcc)
CC="clang" go build main.go //build works fine (uses clang)

zig cc

$ CC="zig cc" go build main.go
# runtime/cgo
info: Usage: zig [command] [options]

Commands:

  build            Build project from build.zig
  build-exe        Create executable from source or object files
  build-lib        Create library from source or object files
  build-obj        Create object from source or assembly
  cc               Use Zig as a drop-in C compiler
  c++              Use Zig as a drop-in C++ compiler
  env              Print lib path, std path, compiler id and version
  fmt              Parse file and render in canonical zig format
  init-exe         Initialize a `zig build` application in the cwd
  init-lib         Initialize a `zig build` library in the cwd
  libc             Display native libc paths file or validate one
  run              Create executable and run immediately
  translate-c      Convert C code to Zig code
  targets          List available compilation targets
  test             Create and run a test build
  version          Print version number and exit
  zen              Print zen of zig and exit

General Options:

  --help           Print command-specific usage

error: unknown command: -E
go version go1.15.5 linux/amd64
@andrewrk andrewrk added the zig cc Zig as a drop-in C compiler feature label Dec 8, 2020
@andrewrk andrewrk added this to the 0.8.0 milestone Dec 8, 2020
@andrewrk andrewrk added the downstream An issue with a third party project that uses Zig. label Dec 8, 2020
@andrewrk
Copy link
Member

andrewrk commented Dec 8, 2020

So this looks like go is inserting flags before it passes cc. This will either need to be fixed in go, or you will have to work around this by creating a shell script like this:

#!/bin/sh
zig cc $@

And then putting that as your CC. This way zig gets invoked with zig cc -E ... instead of zig -E ...

@andrewrk
Copy link
Member

andrewrk commented Dec 8, 2020

Downstream issue filed: golang/go#43078

@lu4p
Copy link
Author

lu4p commented Dec 8, 2020

#!/bin/sh
zig cc $@

This indeed works, but another weird thing is, that I get these errors:

$ CC="zig-wrap" go build  main.go
# runtime/cgo
error: unable to create compilation: AccessDenied
# runtime/cgo
gcc_context.c:1:1: error: unable to build C object: AccessDenied
# runtime/cgo
gcc_fatalf.c:1:1: error: unable to build C object: AccessDenied
# runtime/cgo
gcc_libinit.c:1:1: error: unable to build C object: AccessDenied
# runtime/cgo
gcc_linux_amd64.c:1:1: error: unable to build C object: AccessDenied
# runtime/cgo
gcc_mmap.c:1:1: error: unable to build C object: AccessDenied
# runtime/cgo
gcc_setenv.c:1:1: error: unable to build C object: AccessDenied
# runtime/cgo
gcc_sigaction.c:1:1: error: unable to build C object: AccessDenied
# runtime/cgo
gcc_traceback.c:1:1: error: unable to build C object: AccessDenied
# runtime/cgo
gcc_util.c:1:1: error: unable to build C object: AccessDenied
# runtime/cgo
gcc_amd64.S:1:1: error: unable to build C object: AccessDenied

Unless I use sudo, which produces a working binary:

$ sudo CC="zig-wrap" go build  main.go                
# command-line-arguments
warning: unsupported linker arg: --compress-debug-sections=zlib-gnu

@andrewrk
Copy link
Member

andrewrk commented Dec 8, 2020

That error message would be more useful if it printed the path, sorry about that. Anyway that's a separate issue. Could you try using strace to find out which file paths are getting AccessDenied?

My hunch is that it is the global cache, and go is running the compiler within a chroot or something. You can try messing with these options within your wrapper script:

  --cache-dir [path]        Override the local cache directory
  --global-cache-dir [path] Override the global cache directory

Make sure they are writable paths. They are allowed to be the same.

@lu4p
Copy link
Author

lu4p commented Dec 8, 2020

strace example of what went wrong (I think, never used strace before)

59864 openat(AT_FDCWD, "zig-cache", O_RDONLY|O_CLOEXEC|O_PATH|O_DIRECTORY)             = 5
...
59864 openat(5, "h", O_RDONLY|O_CLOEXEC|O_PATH|O_DIRECTORY)             = 6
...
59864 openat(6, "a1156d94bd5502d8ca9db1c6a76c576f.txt", O_RDWR|O_CREAT|O_CLOEXEC, 0666)             = -1 EACCES (Permission denied)

@lu4p
Copy link
Author

lu4p commented Dec 8, 2020

My hunch is that it is the global cache, and go is running the compiler within a chroot or something. You can try messing with these options within your wrapper script:

 --cache-dir [path]        Override the local cache directory
 --global-cache-dir [path] Override the global cache directory

My zig cc doesn't have those options:

error: Unknown Clang option: '--cache-dir=

@andrewrk
Copy link
Member

andrewrk commented Dec 8, 2020

Thanks, that strace output is exactly what I needed to see. This is a bit confusing - zig successfully was able to open zig-cache/o/ but then when it tried to create zig-cache/o/a1156d94bd5502d8ca9db1c6a76c576f.txt it got EACCES. When you ran the strace output, I think you might have had leftover cache artifacts from when you ran the command with sudo (never use sudo to work around an EACCES problem, you will only create more problems for yourself). Can you try this again with all the root-owned file system stuff deleted?

My zig cc doesn't have those options:

Ah, sorry about that. I forgot this was the zig cc CLI not the regular zig CLI. I'll need to introduce environment variables to control those paths when using zig cc.

I'll look into this myself and see if I can get it working. Thanks for your help.

@lu4p
Copy link
Author

lu4p commented Dec 8, 2020

Can you try this again with all the root-owned file system stuff deleted?

Then it's just:

62606 mkdirat(AT_FDCWD, "zig-cache", 0755 = -1 EACCES (Permission denied)

This is because the permissions of /usr/lib/go/src/runtime/cgo are restricted to root access:

Access: (0755/drwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)

@andrewrk
Copy link
Member

andrewrk commented Dec 8, 2020

Thanks - I'll look into a solution for this. I'm not sure why Go is preventing Zig from using a project-local directory as a cache folder. That seems like a reasonable thing for a compiler to do. But I'll add support for configuring the cache directory via an environment variable so that it can be modified when using zig cc.

@lu4p
Copy link
Author

lu4p commented Dec 8, 2020

It's not because of a project local cache folder, it's because zig tries to create a directory inside a stdlib package.

@lu4p
Copy link
Author

lu4p commented Dec 8, 2020

I think zig cc should put all caches inside --global-cache-dir.

@andrewrk
Copy link
Member

andrewrk commented Dec 8, 2020

After 2759313 (which I just pushed to master) and the following zcc script:

#!/bin/sh
ZIG_LOCAL_CACHE_DIR="$HOME/misc/gozig" zig cc $@

(where $HOME/misc/gozig is my project path)

It produced a viable binary.

[nix-shell:~/misc/gozig]$ ./main 
30

It gave the following harmless linker warning:

warning: unsupported linker arg: --compress-debug-sections=zlib-gnu

You could also try passing /tmp or any other writable directory for that value.

@andrewrk
Copy link
Member

andrewrk commented Dec 8, 2020

I think zig cc should put all caches inside --global-cache-dir.

I reviewed the logic for choosing a local cache directory, and I do think there is room to modify it when only compiling C objects:

zig/src/main.zig

Lines 1641 to 1668 in 2759313

var local_cache_directory: Compilation.Directory = l: {
if (override_local_cache_dir) |local_cache_dir_path| {
const dir = try fs.cwd().makeOpenPath(local_cache_dir_path, .{});
cleanup_local_cache_dir = dir;
break :l .{
.handle = dir,
.path = local_cache_dir_path,
};
}
if (arg_mode == .run) {
break :l global_cache_directory;
}
const cache_dir_path = blk: {
if (root_pkg) |pkg| {
if (pkg.root_src_directory.path) |p| {
break :blk try fs.path.join(arena, &[_][]const u8{ p, "zig-cache" });
}
}
break :blk "zig-cache";
};
const cache_parent_dir = if (root_pkg) |pkg| pkg.root_src_directory.handle else fs.cwd();
const dir = try cache_parent_dir.makeOpenPath("zig-cache", .{});
cleanup_local_cache_dir = dir;
break :l .{
.handle = dir,
.path = cache_dir_path,
};
};

You can see that in some cases, for example zig run, we do select the global cache directory as the local one. Clearly in this case with cgo, zig is not making an effective choice for the local cache directory.

@lu4p
Copy link
Author

lu4p commented Dec 8, 2020

https://github.com/ziglang/zig/wiki/Building-Zig-From-Source#option-a-use-your-system-installed-build-tools

I tried to compile zig from the current master source code, but I got the following errors, I followed the above procedure:

Logs:
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang_cc1_main.cpp.o): warning: relocation against `_ZTVN5clang28ObjectFilePCHContainerReaderE' in read-only section `.text._ZN5clang28ObjectFilePCHContainerReaderC2Ev[_ZN5clang28ObjectFilePCHContainerReaderC5Ev]'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangSourceManager_getFilename':
/home/luap/zig/src/zig_clang.cpp:1636: undefined reference to `clang::SourceManager::getFilename(clang::SourceLocation) const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangSourceManager_getSpellingLineNumber':
/home/luap/zig/src/zig_clang.cpp:1643: undefined reference to `clang::SourceManager::getSpellingLineNumber(clang::SourceLocation, bool*) const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangSourceManager_getSpellingColumnNumber':
/home/luap/zig/src/zig_clang.cpp:1649: undefined reference to `clang::SourceManager::getSpellingColumnNumber(clang::SourceLocation, bool*) const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangSourceManager_getCharacterData':
/home/luap/zig/src/zig_clang.cpp:1655: undefined reference to `clang::SourceManager::getCharacterData(clang::SourceLocation, bool*) const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangASTContext_getPointerType':
/home/luap/zig/src/zig_clang.cpp:1659: undefined reference to `clang::ASTContext::getPointerType(clang::QualType) const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangASTUnit_visitLocalTopLevelDecls':
/home/luap/zig/src/zig_clang.cpp:1679: undefined reference to `clang::ASTUnit::visitLocalTopLevelDecls(void*, bool (*)(void*, clang::Decl const*))'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangASTUnit_getLocalPreprocessingEntities_begin':
/home/luap/zig/src/zig_clang.cpp:1687: undefined reference to `clang::ASTUnit::getLocalPreprocessingEntities() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangASTUnit_getLocalPreprocessingEntities_end':
/home/luap/zig/src/zig_clang.cpp:1694: undefined reference to `clang::ASTUnit::getLocalPreprocessingEntities() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangVarDecl_getAlignedAttribute':
/home/luap/zig/src/zig_clang.cpp:1767: undefined reference to `clang::AlignedAttr::getAlignment(clang::ASTContext&) const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangFieldDecl_getAlignedAttribute':
/home/luap/zig/src/zig_clang.cpp:1777: undefined reference to `clang::AlignedAttr::getAlignment(clang::ASTContext&) const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangFunctionDecl_getAlignedAttribute':
/home/luap/zig/src/zig_clang.cpp:1787: undefined reference to `clang::AlignedAttr::getAlignment(clang::ASTContext&) const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangParmVarDecl_getOriginalType':
/home/luap/zig/src/zig_clang.cpp:1794: undefined reference to `clang::ParmVarDecl::getOriginalType() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangDecl_getDeclKindName':
/home/luap/zig/src/zig_clang.cpp:1839: undefined reference to `clang::Decl::getDeclKindName() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangFunctionDecl_doesDeclarationForceExternallyVisibleDefinition':
/home/luap/zig/src/zig_clang.cpp:1908: undefined reference to `clang::FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangType_getPointeeType':
/home/luap/zig/src/zig_clang.cpp:2026: undefined reference to `clang::Type::getPointeeType() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangType_getTypeClassName':
/home/luap/zig/src/zig_clang.cpp:2076: undefined reference to `clang::Type::getTypeClassName() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangType_getAsRecordType':
/home/luap/zig/src/zig_clang.cpp:2087: undefined reference to `clang::Type::getAsStructureType() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangType_getAsUnionType':
/home/luap/zig/src/zig_clang.cpp:2093: undefined reference to `clang::Type::getAsUnionType() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangStmt_getBeginLoc':
/home/luap/zig/src/zig_clang.cpp:2099: undefined reference to `clang::Stmt::getBeginLoc() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangExpr_getBeginLoc':
/home/luap/zig/src/zig_clang.cpp:2124: undefined reference to `clang::Stmt::getBeginLoc() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangExpr_EvaluateAsBooleanCondition':
/home/luap/zig/src/zig_clang.cpp:2132: undefined reference to `clang::Expr::EvaluateAsBooleanCondition(bool&, clang::ASTContext const&, bool) const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangExpr_EvaluateAsFloat':
/home/luap/zig/src/zig_clang.cpp:2142: undefined reference to `clang::Expr::EvaluateAsFloat(llvm::APFloat&, clang::ASTContext const&, clang::Expr::SideEffectsKind, bool) const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangExpr_EvaluateAsConstantExpr':
/home/luap/zig/src/zig_clang.cpp:2151: undefined reference to `clang::Expr::EvaluateAsConstantExpr(clang::Expr::EvalResult&, clang::Expr::ConstExprUsage, clang::ASTContext const&, bool) const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangAPValue_getLValueBase':
/home/luap/zig/src/zig_clang.cpp:2260: undefined reference to `clang::APValue::getLValueBase() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangLoadFromCommandLine':
/home/luap/zig/src/zig_clang.cpp:2267: undefined reference to `clang::CompilerInstance::createDiagnostics(clang::DiagnosticOptions*, clang::DiagnosticConsumer*, bool, clang::CodeGenOptions const*)'
/usr/bin/ld: /home/luap/zig/src/zig_clang.cpp:2278: undefined reference to `clang::ASTUnit::LoadFromCommandLine(char const**, char const**, std::shared_ptr<clang::PCHContainerOperations>, llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine>, llvm::StringRef, bool, clang::CaptureDiagsKind, llvm::ArrayRef<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, llvm::MemoryBuffer*> >, bool, unsigned int, clang::TranslationUnitKind, bool, bool, bool, clang::SkipFunctionBodiesScope, bool, bool, bool, bool, llvm::Optional<llvm::StringRef>, std::unique_ptr<clang::ASTUnit, std::default_delete<clang::ASTUnit> >*, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>)'
/usr/bin/ld: /home/luap/zig/src/zig_clang.cpp:2326: undefined reference to `clang::FullSourceLoc::getFileLoc() const'
/usr/bin/ld: /home/luap/zig/src/zig_clang.cpp:2334: undefined reference to `clang::SourceManager::getPresumedLoc(clang::SourceLocation, bool) const'
/usr/bin/ld: /home/luap/zig/src/zig_clang.cpp:2347: undefined reference to `clang::FullSourceLoc::getBufferData(bool*) const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangASTUnit_delete':
/home/luap/zig/src/zig_clang.cpp:2369: undefined reference to `clang::ASTUnit::~ASTUnit()'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangVarDecl_getTLSKind':
/home/luap/zig/src/zig_clang.cpp:2389: undefined reference to `clang::VarDecl::getTLSKind() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangVarDecl_hasInit':
/home/luap/zig/src/zig_clang.cpp:2409: undefined reference to `clang::VarDecl::hasInit() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangVarDecl_evaluateValue':
/home/luap/zig/src/zig_clang.cpp:2414: undefined reference to `clang::VarDecl::evaluateValue() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangFloatingLiteral_getValueAsApproximateDouble':
/home/luap/zig/src/zig_clang.cpp:2499: undefined reference to `clang::FloatingLiteral::getValueAsApproximateDouble() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangMacroQualifiedType_getModifiedType':
/home/luap/zig/src/zig_clang.cpp:2579: undefined reference to `clang::MacroQualifiedType::getModifiedType() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangIntegerLiteral_EvaluateAsInt':
/home/luap/zig/src/zig_clang.cpp:2611: undefined reference to `clang::Expr::EvaluateAsInt(clang::Expr::EvalResult&, clang::ASTContext const&, clang::Expr::SideEffectsKind, bool) const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangIntegerLiteral_isZero':
/home/luap/zig/src/zig_clang.cpp:2627: undefined reference to `clang::Expr::EvaluateAsInt(clang::Expr::EvalResult&, clang::ASTContext const&, clang::Expr::SideEffectsKind, bool) const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangRecordDecl_field_begin':
/home/luap/zig/src/zig_clang.cpp:2954: undefined reference to `clang::RecordDecl::field_begin() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `ZigClangFieldDecl_isAnonymousStructOrUnion':
/home/luap/zig/src/zig_clang.cpp:2968: undefined reference to `clang::FieldDecl::isAnonymousStructOrUnion() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::RecordType::getDecl() const':
/usr/include/clang/AST/Type.h:4628: undefined reference to `clang::TagType::getDecl() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::EnumType::getDecl() const':
/usr/include/clang/AST/Type.h:4651: undefined reference to `clang::TagType::getDecl() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::QualType::getUnqualifiedType() const':
/usr/include/clang/AST/Type.h:6486: undefined reference to `clang::QualType::getSplitUnqualifiedTypeImpl(clang::QualType)'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::Type::getAsArrayTypeUnsafe() const':
/usr/include/clang/AST/Type.h:7215: undefined reference to `clang::Type::getUnqualifiedDesugaredType() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::APValue::~APValue()':
/usr/include/clang/AST/APValue.h:342: undefined reference to `clang::APValue::DestroyDataAndMakeUninit()'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::DeclContext::getRedeclContext() const':
/usr/include/clang/AST/DeclBase.h:1972: undefined reference to `clang::DeclContext::getRedeclContext()'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::VarDecl::getInit() const':
/usr/include/clang/AST/Decl.h:1230: undefined reference to `clang::VarDecl::getInit()'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::FunctionDecl::isDefined() const':
/usr/include/clang/AST/Decl.h:2035: undefined reference to `clang::FunctionDecl::isDefined(clang::FunctionDecl const*&) const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::FunctionDecl::getDefinition()':
/usr/include/clang/AST/Decl.h:2041: undefined reference to `clang::FunctionDecl::isDefined(clang::FunctionDecl const*&) const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::FunctionDecl::isThisDeclarationADefinition() const':
/usr/include/clang/AST/Decl.h:2074: undefined reference to `clang::Decl::hasDefiningAttr() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::FunctionDecl::getParamDecl(unsigned int) const':
/usr/include/clang/AST/Decl.h:2426: undefined reference to `clang::FunctionDecl::getNumParams() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::EnumDecl::getDefinition() const':
/usr/include/clang/AST/Decl.h:3605: undefined reference to `clang::TagDecl::getDefinition() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::EnumDecl::enumerator_begin() const':
/usr/include/clang/AST/Decl.h:3638: undefined reference to `clang::DeclContext::decls_begin() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::RecordDecl::getDefinition() const':
/usr/include/clang/AST/Decl.h:3976: undefined reference to `clang::TagDecl::getDefinition() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::ASTContext::getTypeInfo(clang::QualType) const':
/usr/include/clang/AST/ASTContext.h:2070: undefined reference to `clang::ASTContext::getTypeInfo(clang::Type const*) const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::ASTContext::getAsConstantArrayType(clang::QualType) const':
/usr/include/clang/AST/ASTContext.h:2437: undefined reference to `clang::ASTContext::getAsArrayType(clang::QualType) const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::SourceManager::getFileID(clang::SourceLocation) const':
/usr/include/clang/Basic/SourceManager.h:1068: undefined reference to `clang::SourceManager::getFileIDSlow(unsigned int) const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::SourceManager::getSpellingLoc(clang::SourceLocation) const':
/usr/include/clang/Basic/SourceManager.h:1178: undefined reference to `clang::SourceManager::getSpellingLocSlowCase(clang::SourceLocation) const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::SourceManager::getLoadedSLocEntry(unsigned int, bool*) const':
/usr/include/clang/Basic/SourceManager.h:1662: undefined reference to `clang::SourceManager::loadSLocEntry(unsigned int, bool*) const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::PreprocessingRecord::iterator::operator*() const':
/usr/include/clang/Lex/PreprocessingRecord.h:449: undefined reference to `clang::PreprocessingRecord::getPreprocessedEntity(clang::PreprocessingRecord::PPEntityID)'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::UnaryOperator::getBeginLoc() const':
/usr/include/clang/AST/Expr.h:2256: undefined reference to `clang::Stmt::getBeginLoc() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::ImplicitCastExpr::getBeginLoc() const':
/usr/include/clang/AST/Expr.h:3517: undefined reference to `clang::Stmt::getBeginLoc() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::BinaryOperator::getBeginLoc() const':
/usr/include/clang/AST/Expr.h:3699: undefined reference to `clang::Stmt::getBeginLoc() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::Expr::EvalResult::EvalResult(clang::Expr::EvalResult const&)':
/usr/include/clang/AST/Expr.h:606: undefined reference to `clang::APValue::APValue(clang::APValue const&)'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::Mergeable<clang::FieldDecl>::getFirstDecl() const':
/usr/include/clang/AST/Redeclarable.h:331: undefined reference to `clang::getPrimaryMergedDecl(clang::Decl*)'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::SectionAttr* clang::Decl::getAttr<clang::SectionAttr>() const':
/usr/include/clang/AST/DeclBase.h:544: undefined reference to `clang::Decl::getAttrs() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::PackedAttr* clang::Decl::getAttr<clang::PackedAttr>() const':
/usr/include/clang/AST/DeclBase.h:544: undefined reference to `clang::Decl::getAttrs() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `clang::AlignedAttr* clang::Decl::getAttr<clang::AlignedAttr>() const':
/usr/include/clang/AST/DeclBase.h:544: undefined reference to `clang::Decl::getAttrs() const'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `std::default_delete<clang::ASTUnit>::operator()(clang::ASTUnit*) const':
/usr/include/c++/10.2.0/bits/unique_ptr.h:85: undefined reference to `clang::ASTUnit::~ASTUnit()'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `llvm::RefCountedBase<clang::DiagnosticsEngine>::Release() const':
/usr/include/llvm/ADT/IntrusiveRefCntPtr.h:82: undefined reference to `clang::DiagnosticsEngine::~DiagnosticsEngine()'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang.cpp.o): in function `void __gnu_cxx::new_allocator<clang::PCHContainerOperations>::construct<clang::PCHContainerOperations>(clang::PCHContainerOperations*)':
/usr/include/c++/10.2.0/ext/new_allocator.h:150: undefined reference to `clang::PCHContainerOperations::PCHContainerOperations()'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang_driver.cpp.o): in function `CreateAndPopulateDiagOpts(llvm::ArrayRef<char const*>, bool&)':
/home/luap/zig/src/zig_clang_driver.cpp:277: undefined reference to `clang::driver::getDriverOptTable()'
/usr/bin/ld: /home/luap/zig/src/zig_clang_driver.cpp:282: undefined reference to `clang::ParseDiagnosticArgs(clang::DiagnosticOptions&, llvm::opt::ArgList&, clang::DiagnosticsEngine*, bool)'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang_driver.cpp.o): in function `ZigClang_main':
/home/luap/zig/src/zig_clang_driver.cpp:340: undefined reference to `clang::noteBottomOfStack()'
/usr/bin/ld: /home/luap/zig/src/zig_clang_driver.cpp:352: undefined reference to `clang::driver::ToolChain::getTargetAndModeFromProgramName(llvm::StringRef)'
/usr/bin/ld: /home/luap/zig/src/zig_clang_driver.cpp:463: undefined reference to `clang::TextDiagnosticPrinter::TextDiagnosticPrinter(llvm::raw_ostream&, clang::DiagnosticOptions*, bool)'
/usr/bin/ld: /home/luap/zig/src/zig_clang_driver.cpp:466: undefined reference to `clang::DiagnosticIDs::DiagnosticIDs()'
/usr/bin/ld: /home/luap/zig/src/zig_clang_driver.cpp:468: undefined reference to `clang::DiagnosticsEngine::DiagnosticsEngine(llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>, llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions>, clang::DiagnosticConsumer*, bool)'
/usr/bin/ld: /home/luap/zig/src/zig_clang_driver.cpp:473: undefined reference to `clang::serialized_diags::create(llvm::StringRef, clang::DiagnosticOptions*, bool)'
/usr/bin/ld: /home/luap/zig/src/zig_clang_driver.cpp:474: undefined reference to `clang::DiagnosticsEngine::setClient(clang::DiagnosticConsumer*, bool)'
/usr/bin/ld: /home/luap/zig/src/zig_clang_driver.cpp:478: undefined reference to `clang::ProcessWarningOptions(clang::DiagnosticsEngine&, clang::DiagnosticOptions const&, bool)'
/usr/bin/ld: /home/luap/zig/src/zig_clang_driver.cpp:480: undefined reference to `clang::driver::Driver::Driver(llvm::StringRef, llvm::StringRef, clang::DiagnosticsEngine&, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>)'
/usr/bin/ld: /home/luap/zig/src/zig_clang_driver.cpp:494: undefined reference to `clang::driver::Driver::BuildCompilation(llvm::ArrayRef<char const*>)'
/usr/bin/ld: /home/luap/zig/src/zig_clang_driver.cpp:499: undefined reference to `clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*> >&)'
/usr/bin/ld: /home/luap/zig/src/zig_clang_driver.cpp:533: undefined reference to `clang::driver::Driver::generateCompilationDiagnostics(clang::driver::Compilation&, clang::driver::Command const&, llvm::StringRef, clang::driver::Driver::CompilationDiagnosticReport*)'
/usr/bin/ld: /home/luap/zig/src/zig_clang_driver.cpp:468: undefined reference to `clang::DiagnosticsEngine::~DiagnosticsEngine()'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang_driver.cpp.o): in function `clang::DiagnosticBuilder::Emit()':
/usr/include/clang/Basic/Diagnostic.h:1121: undefined reference to `clang::DiagnosticsEngine::EmitCurrentDiagnostic(bool)'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang_driver.cpp.o): in function `clang::DiagnosticConsumer::DiagnosticConsumer()':
/usr/include/clang/Basic/Diagnostic.h:1532: undefined reference to `vtable for clang::DiagnosticConsumer'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang_driver.cpp.o): in function `clang::ChainedDiagnosticConsumer::ChainedDiagnosticConsumer(std::unique_ptr<clang::DiagnosticConsumer, std::default_delete<clang::DiagnosticConsumer> >, std::unique_ptr<clang::DiagnosticConsumer, std::default_delete<clang::DiagnosticConsumer> >)':
/usr/include/clang/Frontend/ChainedDiagnosticConsumer.h:32: undefined reference to `vtable for clang::ChainedDiagnosticConsumer'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang_driver.cpp.o): in function `std::default_delete<clang::driver::Compilation>::operator()(clang::driver::Compilation*) const':
/usr/include/c++/10.2.0/bits/unique_ptr.h:85: undefined reference to `clang::driver::Compilation::~Compilation()'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang_driver.cpp.o): in function `llvm::RefCountedBase<clang::DiagnosticIDs>::Release() const':
/usr/include/llvm/ADT/IntrusiveRefCntPtr.h:82: undefined reference to `clang::DiagnosticIDs::~DiagnosticIDs()'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang_cc1_main.cpp.o): in function `cc1_main(llvm::ArrayRef<char const*>, char const*, void*)':
/home/luap/zig/src/zig_clang_cc1_main.cpp:187: undefined reference to `clang::CompilerInstance::CompilerInstance(std::shared_ptr<clang::PCHContainerOperations>, clang::InMemoryModuleCache*)'
/usr/bin/ld: /home/luap/zig/src/zig_clang_cc1_main.cpp:188: undefined reference to `clang::DiagnosticIDs::DiagnosticIDs()'
/usr/bin/ld: /home/luap/zig/src/zig_clang_cc1_main.cpp:205: undefined reference to `clang::DiagnosticsEngine::DiagnosticsEngine(llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>, llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions>, clang::DiagnosticConsumer*, bool)'
/usr/bin/ld: /home/luap/zig/src/zig_clang_cc1_main.cpp:206: undefined reference to `clang::CompilerInvocation::CreateFromArgs(clang::CompilerInvocation&, llvm::ArrayRef<char const*>, clang::DiagnosticsEngine&, char const*)'
/usr/bin/ld: /home/luap/zig/src/zig_clang_cc1_main.cpp:221: undefined reference to `clang::CompilerInvocation::GetResourcesPath[abi:cxx11](char const*, void*)'
/usr/bin/ld: /home/luap/zig/src/zig_clang_cc1_main.cpp:224: undefined reference to `clang::CompilerInstance::createDiagnostics(clang::DiagnosticConsumer*, bool)'
/usr/bin/ld: /home/luap/zig/src/zig_clang_cc1_main.cpp:233: undefined reference to `clang::TextDiagnosticBuffer::FlushDiagnostics(clang::DiagnosticsEngine&) const'
/usr/bin/ld: /home/luap/zig/src/zig_clang_cc1_main.cpp:240: undefined reference to `clang::ExecuteCompilerInvocation(clang::CompilerInstance*)'
/usr/bin/ld: /home/luap/zig/src/zig_clang_cc1_main.cpp:256: undefined reference to `clang::CompilerInstance::createOutputFile(llvm::StringRef, bool, bool, llvm::StringRef, llvm::StringRef, bool, bool)'
/usr/bin/ld: /home/luap/zig/src/zig_clang_cc1_main.cpp:262: undefined reference to `clang::CompilerInstance::clearOutputFiles(bool)'
/usr/bin/ld: /home/luap/zig/src/zig_clang_cc1_main.cpp:205: undefined reference to `clang::DiagnosticsEngine::~DiagnosticsEngine()'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang_cc1_main.cpp.o): in function `clang::TextDiagnosticBuffer::TextDiagnosticBuffer()':
/usr/include/clang/Frontend/TextDiagnosticBuffer.h:25: undefined reference to `vtable for clang::TextDiagnosticBuffer'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang_cc1_main.cpp.o): in function `clang::ObjectFilePCHContainerWriter::ObjectFilePCHContainerWriter()':
/usr/include/clang/CodeGen/ObjectFilePCHContainerOperations.h:18: undefined reference to `vtable for clang::ObjectFilePCHContainerWriter'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang_cc1_main.cpp.o): in function `clang::ObjectFilePCHContainerReader::ObjectFilePCHContainerReader()':
/usr/include/clang/CodeGen/ObjectFilePCHContainerOperations.h:34: undefined reference to `vtable for clang::ObjectFilePCHContainerReader'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang_cc1as_main.cpp.o): in function `(anonymous namespace)::AssemblerInvocation::CreateFromArgs((anonymous namespace)::AssemblerInvocation&, llvm::ArrayRef<char const*>, clang::DiagnosticsEngine&)':
/home/luap/zig/src/zig_clang_cc1as_main.cpp:180: undefined reference to `clang::driver::getDriverOptTable()'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang_cc1as_main.cpp.o): in function `cc1as_main(llvm::ArrayRef<char const*>, char const*, void*)':
/home/luap/zig/src/zig_clang_cc1as_main.cpp:566: undefined reference to `clang::TextDiagnosticPrinter::TextDiagnosticPrinter(llvm::raw_ostream&, clang::DiagnosticOptions*, bool)'
/usr/bin/ld: /home/luap/zig/src/zig_clang_cc1as_main.cpp:568: undefined reference to `clang::DiagnosticIDs::DiagnosticIDs()'
/usr/bin/ld: /home/luap/zig/src/zig_clang_cc1as_main.cpp:569: undefined reference to `clang::DiagnosticsEngine::DiagnosticsEngine(llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>, llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions>, clang::DiagnosticConsumer*, bool)'
/usr/bin/ld: /home/luap/zig/src/zig_clang_cc1as_main.cpp:582: undefined reference to `clang::driver::getDriverOptTable()'
/usr/bin/ld: /home/luap/zig/src/zig_clang_cc1as_main.cpp:569: undefined reference to `clang::DiagnosticsEngine::~DiagnosticsEngine()'
/usr/bin/ld: zigcpp/libzigcpp.a(zig_clang_cc1as_main.cpp.o): in function `clang::getLastArgIntValue(llvm::opt::ArgList const&, llvm::opt::OptSpecifier, int, clang::DiagnosticsEngine&, unsigned int)':
/usr/include/clang/Driver/OptionUtils.h:40: undefined reference to `clang::getLastArgIntValue(llvm::opt::ArgList const&, llvm::opt::OptSpecifier, int, clang::DiagnosticsEngine*, unsigned int)'
/usr/bin/ld: warning: creating DT_TEXTREL in a PIE
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/zig.dir/build.make:371: zig] Error 1
make[1]: *** [CMakeFiles/Makefile2:168: CMakeFiles/zig.dir/all] Error 2
make: *** [Makefile:149: all] Error 2

@andrewrk
Copy link
Member

andrewrk commented Dec 8, 2020

This looks like your LLVM, Clang, LLD libraries were compiled with a different compiler than you used to compile zig. If you are annoyed by this, welcome to the club, this is what C++ forces us to do.

@lu4p
Copy link
Author

lu4p commented Dec 8, 2020

Is there maybe a docker container or sth, which makes this easier?

@andrewrk
Copy link
Member

andrewrk commented Dec 8, 2020

https://github.com/ziglang/docker-zig

I don't think you need this though. The instructions have been tested on nearly every system out there. Anyway, in an hour or two the CI will have finished preparing a master branch tarball that includes the commit.

@andrewrk
Copy link
Member

andrewrk commented Dec 9, 2020

If you want to try a master branch binary tarball, the download page is now up-to-date, including the commit that adds support for environment variables to control cache directories.

@lu4p
Copy link
Author

lu4p commented Dec 9, 2020

Thanks it works now.
Would it be possible for "zig cc" to "guess", which of these targets https://ziglang.org/#Zig-ships-with-libc a user wants from the combination of GOOS and GOARCH?

(GOOS being the os e.g. linux and GOARCH the architecture e.g. amd64)

All possible targets for go:

$ go tool dist list
aix/ppc64
android/386
android/amd64
android/arm
android/arm64
darwin/amd64
darwin/arm64
dragonfly/amd64
freebsd/386
freebsd/amd64
freebsd/arm
freebsd/arm64
illumos/amd64
js/wasm
linux/386
linux/amd64
linux/arm
linux/arm64
linux/mips
linux/mips64
linux/mips64le
linux/mipsle
linux/ppc64
linux/ppc64le
linux/riscv64
linux/s390x
netbsd/386
netbsd/amd64
netbsd/arm
netbsd/arm64
openbsd/386
openbsd/amd64
openbsd/arm
openbsd/arm64
plan9/386
plan9/amd64
plan9/arm
solaris/amd64
windows/386
windows/amd64
windows/arm

Example: linux/amd64 would map to -target=x86_64-linux-gnu

Or is this out of scope for zig, and I should just write a wrapper?

@jonjohnsonjr
Copy link

jonjohnsonjr commented Dec 9, 2020

@lu4p FWIW only some of those targets are compatible with cgo:

$ go tool dist list -json | jq -r "map(select(.CgoSupported)) | .[] | .GOOS + \"/\" + .GOARCH"
aix/ppc64
android/386
android/amd64
android/arm
android/arm64
darwin/amd64
darwin/arm64
dragonfly/amd64
freebsd/386
freebsd/amd64
freebsd/arm
freebsd/arm64
illumos/amd64
linux/386
linux/amd64
linux/arm
linux/arm64
linux/mips
linux/mips64
linux/mips64le
linux/mipsle
linux/ppc64le
linux/s390x
netbsd/386
netbsd/amd64
netbsd/arm
netbsd/arm64
openbsd/386
openbsd/amd64
openbsd/arm
openbsd/arm64
solaris/amd64
windows/386
windows/amd64

Notably, these aren't supported:

$ go tool dist list -json | jq -r "map(select(.CgoSupported == false)) | .[] | .GOOS + \"/\" + .GOARCH"
js/wasm
linux/ppc64
linux/riscv64
plan9/386
plan9/amd64
plan9/arm
windows/arm

@andrewrk
Copy link
Member

andrewrk commented Dec 9, 2020

Or is this out of scope for zig, and I should just write a wrapper?

Hmm it's a good question. I'm not opposed to adding a bit of code to help support this use case, but I want to be careful to not do anything surprising. I'm imagining a developer who uses both Go and Zig and has GOOS/GOARCH env vars set up for their go project, and then is confused when zig starts changing its target in response to what they thought was unrelated.

Another idea would be introducing an environment variable ZIG_CGO=1. This would tell Zig that it can expect to be used by cgo, and it would then respect the go environment variables for the target, as well as make a better choice for the local cache directory. So you wouldn't have to care about cache directories either.

@jonjohnsonjr
Copy link

I'm mostly an interested observer here, but as a motivating use case (assuming I am reading this correctly) I believe this would enable us to build cross-platform multi-arch container images that require cgo in ko without requiring any kind of virtualization (e.g. using docker), which other approaches require.

Your idea to use ZIG_CGO=1 would allow this to work without any changes on our part (I believe), which would be nifty.

tl;dr for ko multiplatform: we spawn a few go build subprocesses with GOOS/GOARCH/GOARM set appropriately and stitch the resulting binaries back into container images; however, this currently only works for binaries that don't required CGO_ENABLED=1.

The minimal configuration in the linked issue would possibly resolve this limitation, and I would be able to stop hedging my recommendation to use ko with this caveat :)

@lu4p
Copy link
Author

lu4p commented Dec 9, 2020

Maybe zig could just reuse the CGO_ENABLED=1 env variable.

@ncruces
Copy link

ncruces commented Dec 9, 2020

Maybe zig could just reuse the CGO_ENABLED=1 env variable.

That doesn't solve the problem @andrewrk mentioned, which is that a Zig developer might find it surprising if Zig starts obeying Go environment variables out of the blue. It needs to be something Zig specific to kill that surprise.

I guess can see both ways on this issue. On the one hand, I agree, it's surprising to anyone unaware of it, and will be infuriating to anyone who spends potentially hours debugging it.

On the other hand, GOOS/GOARCH is not something you'd typically set in your environment. It's a variable you setup in your build scripts, or in one line build commands.

But I'd go with the principle of least surprise.

@andrewrk
Copy link
Member

Question - does cgo ever try to compile C++ files? Does it look at the CXX environment variables? (Zig provides this functionality as well)

@lu4p
Copy link
Author

lu4p commented Dec 10, 2020

Yes go also uses the CXX variable for c++ code.

@andrewrk
Copy link
Member

In this case I think golang/go#43078 will be a nice improvement, because then it will respect the sub-comands zig cc / zig c++. Zig should not infer C instead of C++ for example in "cgo mode", because in cgo mode it could be compiling C or C++ code.

For linux targets, zig provides the ability to cross compile for both (dynamic) glibc and for (static) musl, is there any go environment variable to choose one or the other?

@lu4p
Copy link
Author

lu4p commented Dec 10, 2020

For linux targets, zig provides the ability to cross compile for both (dynamic) glibc and for (static) musl, is there any go environment variable to choose one or the other?

There isn't.

@benesch
Copy link

benesch commented Dec 10, 2020

Just driving by, but thought I'd share my two cents since I previously maintained the cross-compilation toolchain for CockroachDB, which I have to imagine is somewhere near the top of the "cgo (ab)user" leaderboard. The common idiom for cross-compiling Go code that needs cgo is:

CGO_ENABLED=1 GOOS=linux GOARCH=amd64 CC=x86_64-unknown-linux-gnu-cc CXX=x86_64-unknown-linux-gnu-c++ go build

In other words, it's pretty well understood that you have to specify the target for every compiler involved. It's a mouthful, but it's not the hard part, and it's nicely explicit. (The hard part is installing the cross toolchain with a working sysroot, etc., and as I understand it that's the thing that zig cc solves!)

Translated directly to zig cc winds up with something like this, right?

CGO_ENABLED=1 GOOS=linux GOARCH=amd64 CC="zig cc -target x86_64-linux-gnu" CXX="zig c++ -target x86_64-linux-gnu"  go build

That seems 💯 great to me and I don't personally think there's much need for an ergonomic improvement. But I guess I wouldn't mind if any of the following did some magic introspection of GOOS/GOARCH.

CGO_ENABLED=1 GOOS=linux GOARCH=amd64 CC="zig cc -cgo" go build
CGO_ENABLED=1 GOOS=linux GOARCH=amd64 CC="zig cgo-cc" go build
CGO_ENABLED=1 GOOS=linux GOARCH=amd64 ZIG_CGO=1 CC="zig cc" go build

All contingent on something like https://golang.org/cl/276412 landing, of course.

For linux targets, zig provides the ability to cross compile for both (dynamic) glibc and for (static) musl, is there any go environment variable to choose one or the other?

Yeah, you have to do this manually, e.g. by using a musl-targeting toolchain and passing -static in the LDFLAGS, as in: https://github.com/cockroachdb/cockroach/blob/195eff7e989a263551fb6ba5acaa84aa6747619b/build/builder/mkrelease.sh#L50-L55

@andrewrk
Copy link
Member

andrewrk commented Dec 10, 2020

Translated directly to zig cc winds up with something like this, right?

Yes, and additionally with Zig you could do instead:

CGO_ENABLED=1 GOOS=linux GOARCH=amd64 CC="zig cc -target x86_64-linux-musl" CXX="zig c++ -target x86_64-linux-musl"  go build

To get a fully statically linked binary, even if you link in C++ code.

Also you can do something like this:

CGO_ENABLED=1 GOOS=linux GOARCH=amd64 CC="zig cc -target x86_64-linux-gnu.2.27" CXX="zig c++ -target x86_64-linux-gnu.2.27"  go build

Here I've specifically targeted glibc 2.27, presumably to match the version on the servers I want to deploy to. Yes you heard it right not only can zig cross compile for both glibc and musl it can also target any version of glibc.

You can also configure CPU features with -mcpu. I think the one good argument I have against explicit CGO integration in Zig is that it might lead people astray from finding the powerful CLI flags that have fine-grain control of the target settings.

That being said...

That seems 100 great to me and I don't personally think there's much need for an ergonomic improvement. But I guess I wouldn't mind if any of the following did some magic introspection of GOOS/GOARCH.

In the interest of discussion I went ahead and made a proof-of-concept: #7377

With this you can do:

CGO_ENABLED=1 GOOS=linux GOARCH=amd64 CC="zig cc" CXX="zig c++"  go build

And Zig infers the target from the GOOS/GOARCH environment variables.

And I also threw in a workaround for golang/go#43078 for good measure. I'm not promising this is going to land in master branch but it's there if anyone wants to toy with it.

@andrewrk
Copy link
Member

andrewrk commented Dec 10, 2020

I solved the cache directory issue with f7d6006.

Until https://golang.org/cl/276412 lands, zig can be used with cgo using a wrapper script, as demonstrated in #7342 (comment).

After that go patch lands, zig can be used with cgo without a wrapper, as demonstrated in #7342 (comment)

Feel free to discuss the topic further.

andrewrk added a commit that referenced this issue Dec 11, 2020
Previously, when choosing the local cache directory, if there was no
root source file, an explicitly chosen path, or other clues, zig would
choose cwd + zig-cache/ as the local cache directory.

This can be problematic if Zig is invoked with the CWD set to a
read-only directory, or a directory unrelated to the actual source files
being compiled. In the real world, we see this when using `zig cc` with
CGo, which for some reason changes the current working directory to the
read-only go standard library path before running the C compiler.

This commit conservatively chooses to use the global cache directory
as the local cache directory when there is no other reasonable choice,
and no longer will rely on the cwd path to choose a local cache directory.

As a reminder, the --cache-dir CLI flag and ZIG_LOCAL_CACHE_DIR
environment variable are available for overriding the decision. For the
zig build system, it will always choose the directory that build.zig is
+ zig-cache/.

Closes #7342
@andrewrk andrewrk modified the milestones: 0.8.0, 0.7.1 Dec 11, 2020
@andrewrk
Copy link
Member

I cherry-picked the new cache directory logic so that it will be available in the upcoming 0.7.1 release: 21236c0

aarvay pushed a commit to aarvay/zig that referenced this issue Jan 4, 2021
Previously, when choosing the local cache directory, if there was no
root source file, an explicitly chosen path, or other clues, zig would
choose cwd + zig-cache/ as the local cache directory.

This can be problematic if Zig is invoked with the CWD set to a
read-only directory, or a directory unrelated to the actual source files
being compiled. In the real world, we see this when using `zig cc` with
CGo, which for some reason changes the current working directory to the
read-only go standard library path before running the C compiler.

This commit conservatively chooses to use the global cache directory
as the local cache directory when there is no other reasonable choice,
and no longer will rely on the cwd path to choose a local cache directory.

As a reminder, the --cache-dir CLI flag and ZIG_LOCAL_CACHE_DIR
environment variable are available for overriding the decision. For the
zig build system, it will always choose the directory that build.zig is
+ zig-cache/.

Closes ziglang#7342
@dosgo
Copy link

dosgo commented Aug 19, 2021

I developed a small tool to automatically judge the compilation target based on the GOOS GOARCH environment.
github.com/dosgo/zigtool

@krumberg
Copy link

I developed a small tool to automatically judge the compilation target based on the GOOS GOARCH environment.
github.com/dosgo/zigtool

Thanks a lot for this!

@JohnDDuncanIII
Copy link

Until https://golang.org/cl/276412 lands, zig can be used with cgo using a wrapper script, as demonstrated in #7342 (comment).

For those unaware, I believe golang/go@742dcba replaced https://golang.org/cl/276412 to fix golang/go#43078.

akkuman added a commit to akkuman/rotateproxy that referenced this issue Jan 19, 2022
@akkuman
Copy link

akkuman commented Jan 19, 2022

@andrewrk

When I cross compile from linux to macos, compile error

cat $HOME/.bin/zcc
#!/bin/sh
ZIG_LOCAL_CACHE_DIR="$HOME/tmp" zig cc -target x86_64-macos-gnu

cat $HOME/.bin/zxx
#!/bin/sh
ZIG_LOCAL_CACHE_DIR="$HOME/tmp" zig c++ -target x86_64-macos-gnu

error

# github.com/akkuman/rotateproxy/cmd/rotateproxy
/opt/hostedtoolcache/go/1.17.6/x64/pkg/tool/linux_amd64/link: running zcc failed: exit status 1
warning: unsupported linker arg: -S
warning: unsupported linker arg: -no_pie
warning: unsupported linker arg: -pagezero_size
warning: unsupported linker arg: 4000000
warning: unsupported linker arg: --compress-debug-sections
warning: unsupported linker arg: zlib-gnu
warning(link): framework not found for '-framework CoreFoundation'
warning(link): framework not found for '-framework Security'
warning(link): Framework search paths:
error(link): undefined reference to symbol '_SecTrustSettingsCopyTrustSettings'
error(link):   first referenced in '/tmp/go-link-800811870/go.o'
error(link): undefined reference to symbol '_SecTrustSettingsCopyCertificates'
error(link):   first referenced in '/tmp/go-link-800811870/go.o'
error(link): undefined reference to symbol '_SecPolicyCopyProperties'
error(link):   first referenced in '/tmp/go-link-800811870/go.o'
error(link): undefined reference to symbol '_SecItemExport'
error(link):   first referenced in '/tmp/go-link-800811870/go.o'
error(link): undefined reference to symbol '_CFStringCreateWithBytes'
error(link):   first referenced in '/tmp/go-link-800811870/go.o'
error(link): undefined reference to symbol '_CFRelease'
error(link):   first referenced in '/tmp/go-link-800811870/go.o'
error(link): undefined reference to symbol '_CFNumberGetValue'
error(link):   first referenced in '/tmp/go-link-800811870/go.o'
error(link): undefined reference to symbol '_CFEqual'
error(link):   first referenced in '/tmp/go-link-800811870/go.o'
error(link): undefined reference to symbol '_CFDictionaryGetValueIfPresent'
error(link):   first referenced in '/tmp/go-link-800811870/go.o'
error(link): undefined reference to symbol '_CFDataGetLength'
error(link):   first referenced in '/tmp/go-link-800811870/go.o'
error(link): undefined reference to symbol '_CFDataGetBytePtr'
error(link):   first referenced in '/tmp/go-link-800811870/go.o'
error(link): undefined reference to symbol '_CFArrayGetValueAtIndex'
error(link):   first referenced in '/tmp/go-link-800811870/go.o'
error(link): undefined reference to symbol '_CFArrayGetCount'
error(link):   first referenced in '/tmp/go-link-800811870/go.o'
error: UndefinedSymbolReference

see https://github.com/akkuman/rotateproxy/runs/4863624753?check_suite_focus=true

@ostcar
Copy link

ostcar commented Jul 9, 2024

After reading this, I am not sure, what the current status is. Should it be possible to use cgo with zig without a wrapper script now?

I was able to cross compile a go app from linux to macos without a wrapper script using zig 0.11.0. But it stopped working with zig 0.12.0 or 0.13.0. I get the error:

# runtime/cgo
error: unable to create compilation: AccessDenied

The command I am running (that works with zig 0.11.0) is:

GOOS=darwin GOARCH=amd64 CC="zig cc -target x86_64-macos" CGO_ENABLED=1 go build -C host -buildmode c-archive -o ../platform/macos-x64.a

Should this work with newer versions of zig? Should I create a separate issue for that?

@kristoff-it
Copy link
Member

@ostcar yes it should work with Go >= 1.18, please open a separate issue.

@ostcar
Copy link

ostcar commented Jul 20, 2024

@ostcar yes it should work with Go >= 1.18, please open a separate issue.

Thanks. I created a new issue: #20689

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
downstream An issue with a third party project that uses Zig. zig cc Zig as a drop-in C compiler feature
Projects
None yet
Development

No branches or pull requests