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

Static linking against C Lib with C++ symbols failed to link with unresolved symbols #22244

Open
ic3man5 opened this issue Dec 15, 2024 · 6 comments
Labels
bug Observed behavior contradicts documented or intended behavior

Comments

@ic3man5
Copy link

ic3man5 commented Dec 15, 2024

Zig Version

0.13.0

Steps to Reproduce and Observed Behavior

I can't seem to figure out how to link static libraries in zig when the static library includes C++ symbols (which should be unused). exe.addObjectFile() and exe.linkSystemLibrary() exhibit the same behavior.

repository to fully reproduce this issue:
https://github.com/ic3man5/zig_static_lib

default project from zig init plus the following additions:

build.zig

    exe.addIncludePath(b.path("../mylib"));
    exe.addObjectFile(b.path("../mylib/build/libMyLib.a"));
    exe.linkLibCpp();

main.zig

const std = @import("std");
const print = std.debug.print;

const mylib = @cImport({
    @cInclude("mylib.h");
});

pub fn main() !void {
    print("Hello World!\n", .{});

    var result_str: [128]u8 = [_:0]u8{'a'} ** 128;

    const total = mylib.add(2, 2, &result_str, 128);
    print("Total: {}. {s}", .{ total, result_str });
}

C source files:

mylib.h

#pragma once

#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif

int add(int a, int b, const char* value, uint32_t len);

#ifdef __cplusplus
}
#endif // __cplusplus

mylib.cpp

int add(int a, int b, const char* value, uint32_t len) {
    auto total = a + b;

    std::stringstream ss;
    ss << "Value is " << total;

    auto min_size = std::minmax(len, static_cast<uint32_t>(ss.str().length())).first;
    strlcpy(const_cast<char*>(value), ss.str().c_str(), min_size);

    return total;
}

symbols inside the static library:

$ nm -C mylib/build/libMyLib.a 

mylib.cpp.o:
0000000000000000 T add
0000000000000000 V DW.ref.__gxx_personality_v0
                 U __gxx_personality_v0
                 U __stack_chk_fail
                 U strlcpy
                 U _Unwind_Resume
                 U std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::c_str() const
                 U std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::length() const
                 U std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >::str() const
                 U std::ostream::operator<<(int)
0000000000000000 W std::pair<unsigned int const&, unsigned int const&>::pair<unsigned int const&, unsigned int const&, true>(unsigned int const&, unsigned int const&)
0000000000000000 W std::pair<unsigned int const&, unsigned int const&>::pair<unsigned int const&, unsigned int const&, true>(unsigned int const&, unsigned int const&)
0000000000000000 n std::pair<unsigned int const&, unsigned int const&>::pair<unsigned int const&, unsigned int const&, true>(unsigned int const&, unsigned int const&)
                 U std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()
                 U std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >::basic_stringstream()
                 U std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >::~basic_stringstream()
000000000000000a r std::__detail::__integer_to_chars_is_unsigned<unsigned int>
000000000000000b r std::__detail::__integer_to_chars_is_unsigned<unsigned long>
000000000000000c r std::__detail::__integer_to_chars_is_unsigned<unsigned long long>
0000000000000000 W std::pair<unsigned int const&, unsigned int const&> std::minmax<unsigned int>(unsigned int const&, unsigned int const&)
                 U std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)

when building against this header and static lib the following errors happen:

run
└─ run zig
   └─ install
      └─ install zig
         └─ zig build-exe zig Debug native 8 errors
error: ld.lld: undefined symbol: std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char>>::basic_stringstream()
    note: referenced by mylib.cpp
    note:               mylib.cpp.o:(add) in archive /home/user/dev/c_lib_test/mylib/build/libMyLib.a
error: ld.lld: undefined symbol: std::basic_ostream<char, std::char_traits<char>>& std::operator<<<std::char_traits<char>>(std::basic_ostream<char, std::char_traits<char>>&, char const*)
    note: referenced by mylib.cpp
    note:               mylib.cpp.o:(add) in archive /home/user/dev/c_lib_test/mylib/build/libMyLib.a
error: ld.lld: undefined symbol: std::ostream::operator<<(int)
    note: referenced by mylib.cpp
    note:               mylib.cpp.o:(add) in archive /home/user/dev/c_lib_test/mylib/build/libMyLib.a
error: ld.lld: undefined symbol: std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char>>::str() const
    note: referenced by mylib.cpp
    note:               mylib.cpp.o:(add) in archive /home/user/dev/c_lib_test/mylib/build/libMyLib.a
    note: referenced by mylib.cpp
    note:               mylib.cpp.o:(add) in archive /home/user/dev/c_lib_test/mylib/build/libMyLib.a
error: ld.lld: undefined symbol: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::length() const
    note: referenced by mylib.cpp
    note:               mylib.cpp.o:(add) in archive /home/user/dev/c_lib_test/mylib/build/libMyLib.a
error: ld.lld: undefined symbol: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::~basic_string()
    note: referenced by mylib.cpp
    note:               mylib.cpp.o:(add) in archive /home/user/dev/c_lib_test/mylib/build/libMyLib.a
    note: referenced by mylib.cpp
    note:               mylib.cpp.o:(add) in archive /home/user/dev/c_lib_test/mylib/build/libMyLib.a
    note: referenced by mylib.cpp
    note:               mylib.cpp.o:(add) in archive /home/user/dev/c_lib_test/mylib/build/libMyLib.a
error: ld.lld: undefined symbol: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::c_str() const
    note: referenced by mylib.cpp
    note:               mylib.cpp.o:(add) in archive /home/user/dev/c_lib_test/mylib/build/libMyLib.a
error: ld.lld: undefined symbol: std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char>>::~basic_stringstream()
    note: referenced by mylib.cpp
    note:               mylib.cpp.o:(add) in archive /home/user/dev/c_lib_test/mylib/build/libMyLib.a
    note: referenced by mylib.cpp
    note:               mylib.cpp.o:(add) in archive /home/user/dev/c_lib_test/mylib/build/libMyLib.a
error: the following command failed with 8 compilation errors:
/usr/bin/zig build-exe /home/user/dev/c_lib_test/mylib/build/libMyLib.a -ODebug -I /home/user/dev/c_lib_test/mylib -Mroot=/home/user/dev/c_lib_test/zig/src/main.zig -lc++ --cache-dir /home/user/dev/c_lib_test/zig/.zig-cache --global-cache-dir /home/user/.cache/zig --name zig --listen=- 
Build Summary: 2/7 steps succeeded; 1 failed (disable with --summary none)
run transitive failure
└─ run zig transitive failure
   ├─ zig build-exe zig Debug native 8 errors
   └─ install transitive failure
      └─ install zig transitive failure
         └─ zig build-exe zig Debug native (reused)
error: the following build command failed with exit code 1:
/home/user/dev/c_lib_test/zig/.zig-cache/o/6ff1871015cedd4792cce63ee92abf89/build /usr/bin/zig /home/user/dev/c_lib_test/zig /home/user/dev/c_lib_test/zig/.zig-cache /home/user/.cache/zig --seed 0x79444c68 -Z54c6a0f436096e8f run

Expected Behavior

Expect zig to be able to link against the static lib without unresolved symbols

@ic3man5 ic3man5 added the bug Observed behavior contradicts documented or intended behavior label Dec 15, 2024
@alexrp
Copy link
Member

alexrp commented Dec 15, 2024

Are you building the static library with Zig?

@ic3man5
Copy link
Author

ic3man5 commented Dec 15, 2024

Are you building the static library with Zig?

cmake -B build .
cmake --build

cd zig
zig build run

I've tried with gcc and clang under arch Linux

@alexrp
Copy link
Member

alexrp commented Dec 15, 2024

Your static library is probably built against libstdc++. Zig uses libc++. Mixing the two is not going to work.

@ic3man5
Copy link
Author

ic3man5 commented Dec 16, 2024

So I managed to get my example to work with libc++ after a lot of wrestling of cmake and compilers (good luck if you need to use gcc). This is all "okay" if you have complete access to the libraries in question you are trying to static link with zig but I have static libraries that are closed source and linked against libstdc++.

Is going down the route having zig link against libstdc++.a in the build script a bad idea? I don't see any other options available here. I still have the option of dynamically linking and using the .so but I was trying to get both options working.

@alexrp
Copy link
Member

alexrp commented Dec 16, 2024

If you can get Zig to link libstdc++, I don't see anything technically wrong with that.

@ic3man5
Copy link
Author

ic3man5 commented Dec 16, 2024

It wasn't easy so I haven't tried it yet, it can't find the path with a simple exe.linkSystemLibrary("stdc++"). I believe this might be related: #3936

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Observed behavior contradicts documented or intended behavior
Projects
None yet
Development

No branches or pull requests

2 participants