2

I am trying to write a script that uses a library compiled with clang and another library compiled with G++, I get the following error:

ld.lld: error: undefined symbol: myFunction()

Which (according to this Difference between string and char[] types in C++) is apparently due to std::string meaning different things in different versions of G++ and clang.

Does this mean I have to rewrite the Makefile of my target library to use the same version of G++/Clang? Because that seems like an awful amount of effort just to link a prewritten library, and I think I must be missing something here.

More info

I am compiling v8_shell using ninja -C out/debug

defines = -DUSE_UDEV -DUSE_AURA=1 -DUSE_GLIB=1 -DUSE_NSS_CERTS=1 -DUSE_X11=1 -DNO_TCMALLOC -DMEMORY_TOOL_REPLACES_ALLOCATOR -DMEMORY_SANITIZER_INITIAL_SIZE -DADDRESS_SANITIZER -DFULL_SAFE_BROWSING -DSAFE_BROWSING_CSD -DSAFE_BROWSING_DB_LOCAL -DCHROMIUM_BUILD -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_GNU_SOURCE -DCR_CLANG_REVISION=\"353250-1\" -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DCOMPONENT_BUILD -D_LIBCPP_ABI_UNSTABLE -D_LIBCPP_ABI_VERSION=Cr -DCR_LIBCXX_REVISION=349080 -DCR_LIBCXXABI_REVISION=347903 -D_LIBCPP_ENABLE_NODISCARD -DCR_SYSROOT_HASH=e7c53f04bd88d29d075bfd1f62b073aeb69cbe09 -D_DEBUG -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DWTF_USE_DYNAMIC_ANNOTATIONS=1 -DENABLE_DISASSEMBLER -DV8_TYPED_ARRAY_MAX_SIZE_IN_HEAP=64 -DENABLE_GDB_JIT_INTERFACE -DENABLE_MINOR_MC -DOBJECT_PRINT -DVERIFY_HEAP -DV8_TRACE_MAPS -DV8_ENABLE_ALLOCATION_TIMEOUT -DV8_ENABLE_FORCE_SLOW_PATH -DV8_INTL_SUPPORT -DENABLE_HANDLE_ZAPPING -DV8_USE_SNAPSHOT -DV8_USE_EXTERNAL_STARTUP_DATA -DV8_CONCURRENT_MARKING -DV8_CHECK_MICROTASKS_SCOPES_CONSISTENCY -DV8_EMBEDDED_BUILTINS -DV8_ENABLE_CHECKS -DV8_DEPRECATION_WARNINGS -DV8_IMMINENT_DEPRECATION_WARNINGS -DV8_TARGET_ARCH_X64 -DDEBUG -DDISABLE_UNTRUSTED_CODE_MITIGATIONS -DUSING_V8_SHARED -DV8_ENABLE_CHECKS -DV8_DEPRECATION_WARNINGS -DV8_IMMINENT_DEPRECATION_WARNINGS -DU_USING_ICU_NAMESPACE=0 -DU_ENABLE_DYLOAD=0 -DUSE_CHROMIUM_ICU=1 -DICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_FILE -DUCHAR_TYPE=uint16_t -DUSING_V8_BASE_SHARED -DUSING_V8_PLATFORM_SHARED
include_dirs = -I../.. -Igen -I../.. -Igen -I../../include -Igen/include -I../../third_party/icu/source/common -I../../third_party/icu/source/i18n -I../../include
cflags = -fno-strict-aliasing --param=ssp-buffer-size=4 -fstack-protector -Wno-builtin-macro-redefined -D__DATE__= -D__TIME__= -D__TIMESTAMP__= -funwind-tables -fPIC -B../../third_party/binutils/Linux_x64/Release/bin -pthread -fcolor-diagnostics -fmerge-all-constants -Xclang -mllvm -Xclang -instcombine-lower-dbg-declare=0 -no-canonical-prefixes -fcomplete-member-pointers -m64 -march=x86-64 -Wall -Werror -Wextra -Wimplicit-fallthrough -Wthread-safety -Wno-missing-field-initializers -Wno-unused-parameter -Wno-c++11-narrowing -Wno-unneeded-internal-declaration -Wno-undefined-var-template -Wno-ignored-pragma-optimize -fno-omit-frame-pointer -g2 -gsplit-dwarf -ggnu-pubnames -gcolumn-info -fsanitize=address -fsanitize-address-use-after-scope -fsanitize-blacklist=../../tools/memory/asan/blacklist.txt -fvisibility=hidden -Wheader-hygiene -Wstring-conversion -Wtautological-overlap-compare -Wmissing-field-initializers -Wextra-semi -Winconsistent-missing-override -Wunreachable-code -Wshorten-64-to-32 -O2 -fno-ident -fdata-sections -ffunction-sections
cflags_cc = -Wno-undefined-bool-conversion -Wno-tautological-undefined-compare -std=c++14 -fno-exceptions -fno-rtti -nostdinc++ -isystem../../buildtools/third_party/libc++/trunk/include -isystem../../buildtools/third_party/libc++abi/trunk/include --sysroot=../../build/linux/debian_sid_amd64-sysroot -fvisibility-inlines-hidden
label_name = v8_shell
target_out_dir = obj
target_output_name = v8_shell

build obj/v8_shell/shell.o: cxx ../../samples/shell.cc || obj/generate_bytecode_builtins_list.stamp obj/run_torque.stamp obj/v8_dump_build_config.stamp obj/src/inspector/protocol_generated_sources.stamp obj/third_party/icu/icudata.stamp

build ./v8_shell: link obj/v8_shell/shell.o obj/build/config/sanitizers/liboptions_sources.a | ./libv8.so.TOC ./libv8_libbase.so.TOC ./libv8_libplatform.so.TOC ./libicui18n.so.TOC ./libicuuc.so.TOC ./libc++.so.TOC || obj/build/win/default_exe_manifest.stamp obj/v8_dump_build_config.stamp obj/build/config/executable_deps.stamp
  ldflags = -pie -Wl,--fatal-warnings -fPIC -Wl,-z,noexecstack -Wl,-z,relro -fuse-ld=lld -Wl,--color-diagnostics -m64 -Werror -Wl,--gdb-index -rdynamic -nostdlib++ --sysroot=../../build/linux/debian_sid_amd64-sysroot -L../../build/linux/debian_sid_amd64-sysroot/usr/local/lib/x86_64-linux-gnu -Wl,-rpath-link=../../build/linux/debian_sid_amd64-sysroot/usr/local/lib/x86_64-linux-gnu -L../../build/linux/debian_sid_amd64-sysroot/lib/x86_64-linux-gnu -Wl,-rpath-link=../../build/linux/debian_sid_amd64-sysroot/lib/x86_64-linux-gnu -L../../build/linux/debian_sid_amd64-sysroot/usr/lib/x86_64-linux-gnu -Wl,-rpath-link=../../build/linux/debian_sid_amd64-sysroot/usr/lib/x86_64-linux-gnu -fsanitize=address -fsanitize-address-use-after-scope -pie -Wl,-rpath-link=. -Wl,--disable-new-dtags -Wl,-rpath=\$$ORIGIN/. -Wl,-rpath-link=. -Wl,-O2 -Wl,--gc-sections -Wl,-u_sanitizer_options_link_helper -fsanitize=address -fsanitize-address-use-after-scope
  libs =  -L . -ldl -lpthread -lrt
  output_extension =
  output_dir = .
  solibs = ./libtester.so ./libv8.so ./libv8_libbase.so ./libv8_libplatform.so ./libicui18n.so ./libicuuc.so ./libc++.so

Link to code is here: https://github.com/v8/v8/blob/master/samples/shell.cc

All I have done is add a test library that returns a std::string and this is called from shell.cc.

This test library is compiled with

clang++ -shared -o libtester tester.cpp  -fPIC -L .    -lpthread 

Which yields undefined symbol errors.

I can get it to compile by forcing libc++ that v8 seems to use, but then I get a whole host of core dumps and other errors at runtime, so I don't think thats a legitimate fix.

clang++ -shared -o libtester.so tester.cpp  -fPIC -std=c++11 -L .    -stdlib=libc++ -lpthread 

Example code snippet:

tester.cpp

std::string myFunction() {
std::string newstring; 
 // do something
return newstring;
}

shell.cc

std::string test = myFunction();
cout << test;

Update please see these posts that document it further C++ Undefined symbol related to std::string in static lib Can't link libFuzzer.a using clang with libc++

Theres no real answer apart from use libstdc++ rather than libc++ for everything, but thats not really an option to convert an entire project like v8 to libstdc++

ph0rex
  • 77
  • 3
  • 11
  • 1
    It shouldn't can you include your compile command in the question? – killer Feb 16 '19 at 13:48
  • I've added the compile commands. Thanks – ph0rex Feb 16 '19 at 14:00
  • I am currently reading this article http://gernotklingler.com/blog/creating-using-shared-libraries-different-compilers-different-operating-systems/ to try to help. – killer Feb 16 '19 at 14:14
  • The symbol `myFunction` has nothing to do with `std::string`. `tester` is not a good input file name for a C++ compiler. – n. m. could be an AI Feb 16 '19 at 14:22
  • myfunction is defined as std::string myFunction(). The tester was just a mistake in typing out the SO post, it should be tester.cpp, – ph0rex Feb 16 '19 at 14:24
  • Unless there were some radical changes in linking technology lately, return type doesn't participate in name mangling and therefore doesn't affect linking. Try changing the type to `int` and see if the error goes away. – n. m. could be an AI Feb 16 '19 at 14:41
  • The error goes away if I use int. std::string in the library (libstdc++) is a different type to std::string in libc++, therefore the symbol is undefined. So short of rewriting v8 to use libstdc++ im not sure what i can do – ph0rex Feb 16 '19 at 14:47
  • libc++ and libstdc++ are indeed binary incompatible. If your main project is built with libc++, you have to use libc++ in your test library. – n. m. could be an AI Feb 16 '19 at 15:31
  • I'm sorry I didn't read your question thoroughly the first time around. You cannot mix std::string or anything else from libc++ and libstdc++. It is very strange that you are getting a link error, IME you should be getting failures at run time, but the bottom line is that you cannot mix them. If v8 is built with libc++, you should build your test library with libc++. If you are getting failures at run time when all components are built with libc++, ask a question about these runtime failures. (To be cont'd) – n. m. could be an AI Feb 16 '19 at 17:09
  • Building v8 with libstdc++ is a lot of effort, is not guaranteed to work, and is not guaranteed to solve your problem. Indeed you don't know te reason of your rintine failures. You seem to assume that they have something to do with libc++, but this is just your guess. – n. m. could be an AI Feb 16 '19 at 17:12
  • What's the g++ part of your question? Do you actually use g++ anywhere? – Florian Weimer Feb 16 '19 at 19:41
  • I used g++ before moving to clang, I get the same errors. – ph0rex Feb 17 '19 at 11:57
  • I figured out what happens. When you compile with libstdc++, *and* you are using c++11 ABI, *and* the return type involves `std::string` or `std::list`, *then* these fact are reflected in the name mangling. So one object gets something like `_Z10myFunctionv` and the other one gets `_Z10myFunctionB5cxx11v`. Of course they are totally incompatible. clang++ and g++ behave in exactly the same way, it's the standard library and the ABIs that matter. – n. m. could be an AI Feb 17 '19 at 20:32

2 Answers2

1

The build recipe you use for V8 builds it with -D_LIBCPP_ABI_UNSTABLE -D_LIBCPP_ABI_VERSION=Cr -DCR_LIBCXX_REVISION=349080 -DCR_LIBCXXABI_REVISION=347903. According to libc++ ABI stability, these macros affect the library ABI. Your separate compilation uses just -stdlib=libc++, so it does not enable the incompatible ABI.

You might get better results if you use a different recipe for building V8, something that uses the system C++ standard library with its default (stable) ABI.

Florian Weimer
  • 32,022
  • 3
  • 48
  • 92
  • These were auto generated with gn (https://v8.dev/docs/build-gn), do you know how I choose the standard library instead? I can't find any reference to it in the docs. – ph0rex Feb 17 '19 at 11:27
1

This is the solution for compiling v8 with libstdc++.

Type the following command

gn args out/stdc

Add the following arguments to the args file:

is_clang = true
use_custom_libcxx_for_host=false
use_custom_libcxx=false
libcxx_abi_unstable=false

Build with

 ninja -C out/stdc
ph0rex
  • 77
  • 3
  • 11