zig
zig copied to clipboard
zig cc/c++: Statically linking libc++ can change program semantics
Zig Version
0.10.0-dev.3028+337147068
Steps to Reproduce
Hit this one on https://github.com/ziglang/zig/issues/11168 and realized it's a more general problem for libraries compiled with Zig.
// foo.cpp
#include <system_error>
std::error_condition foo() {
return std::generic_category().default_error_condition(ENOENT);
}
// main.cpp
#include <system_error>
std::error_condition foo();
int main() {
if (foo() != std::generic_category().default_error_condition(ENOENT)) {
fprintf(stderr, "error: errors compare unequal.\n");
}
}
With clang:
$ clang++ foo.cpp -o libfoo.so -shared
$ clang++ main.cpp -lfoo -L. -lstdc++ -rpath . -o main
$ ./main
With zig c++
:
$ zig c++ foo.cpp -o libfoo.so -shared
$ zig c++ main.cpp -lfoo -L. -lstdc++ -rpath . -o main
./build/zig c++ main.cpp -lfoo -L. -lstdc++ -rpath . -o main
zig: warning: -rpath .: 'linker' input unused [-Wunused-command-line-argument]
$ ./main
error: errors compare unequal.
Expected Behavior
Library should behave the same when compiled with Zig and with Clang.
Actual Behavior
Behavior diverges because Zig links libstdc++
statically by default
Related: https://github.com/ziglang/zig/pull/12085#pullrequestreview-1036761330
I believe one consequence of this is that you cannot use Zig to build LLVM/Clang correctly as a shared library (-DLLVM_BUILD_LLVM_DYLIB=ON -DLLVM_LINK_LLVM_DYLIB=ON
)
Wanted to briefly document the result of discussions on Discord (cc @kubkon). The current plan of action is to improve Zig's automatic handling of -lc++ so that it links libc++ dynamically:
- if libc++ appears anywhere in the dynamic dependency tree, OR
- if creating a shared library
In the meantime, users can workaround this by providing the libc++ .so
/ .tbd
file as an object to force dynamic linking (e.g. zig c++ main.cpp /path/to/libc++.so
)