couchdb-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jan Lehnardt <...@apache.org>
Subject Help with linking against SpiderMonkey 60 on macOS
Date Sun, 05 Jan 2020 17:01:15 GMT
Hey all,

I’m trying to get the Mac binary build set up for the 3.0 release.

The biggest change in that regard is the new SpiderMonkey version.

To make my life here a little easier, I want to separate the building of SpiderMonkey and
CouchDB. To that end, I’ve set up a Homebrew Tap for SM60 that I then just depend on being
installed when building CouchDB.

This is my build script for SM60 itself: https://github.com/janl/homebrew-couchdb/blob/master/Formula/spidermonkey60.rb

It produces a .dylib (think .so, but for a Mac) that looks good from the outside:

> file /usr/local/lib/libmozjs-60.dylib 
/usr/local/lib/libmozjs-60.dylib: Mach-O 64-bit dynamically linked shared library x86_64

> otool -L /usr/local/lib/libmozjs-60.dylib 
/usr/local/lib/libmozjs-60.dylib:
	/usr/local/opt/spidermonkey60/lib/libmozjs-60.dylib (compatibility version 1.0.0, current
version 1.0.0)
	/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
	/System/Library/Frameworks/ExceptionHandling.framework/Versions/A/ExceptionHandling (compatibility
version 1.0.0, current version 13.0.0)
	@executable_path/libmozglue.dylib (compatibility version 1.0.0, current version 1.0.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)
	/usr/local/opt/icu4c/lib/libicui18n.64.dylib (compatibility version 64.0.0, current version
64.2.0)
	/usr/local/opt/icu4c/lib/libicuuc.64.dylib (compatibility version 64.0.0, current version
64.2.0)
	/usr/local/opt/icu4c/lib/libicudata.64.dylib (compatibility version 64.0.0, current version
64.2.0)
	/usr/local/opt/nspr/lib/libplds4.dylib (compatibility version 1.0.0, current version 1.0.0)
	/usr/local/opt/nspr/lib/libplc4.dylib (compatibility version 1.0.0, current version 1.0.0)
	/usr/local/opt/nspr/lib/libnspr4.dylib (compatibility version 1.0.0, current version 1.0.0)
	/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.11)
	/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)

Now I’m building CouchDB master. I have to add some more options to src/couch/rebar.config.script
to make things work:

@@ -153,7 +158,10 @@ CouchJSEnv = case SMVsn of
         [
             {"CXXFLAGS", JS_CFLAGS ++ " " ++ CURL_CFLAGS},
             {"LDFLAGS", JS_LDFLAGS ++ " " ++ CURL_LDFLAGS}
-        ]
+        ] ++ case os:type() of
+                {unix, darwin} -> [{"CC", "clang++"}];
+                _ -> []
+            end


This sets CC to clang++, the native C++ compiler. This might seem odd, normally rebar should
pick that up on its own, but it doesn’t. If I don’t do this, I get a number of other errors,
where research had convinced me to make this particular change:


Undefined symbols for architecture x86_64:
  "std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>
>::__init(char const*, unsigned long)", referenced from:
      std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>
>::basic_string<std::nullptr_t>(char const*) in util.o
… (full log https://gist.github.com/janl/05bda5498d1851c13966cbcd20f656f7)

Now I’m not so sure any more, maybe there is another way to resolve these undefined symbols
without introducing the next error.

With CC=clang++, the compilation step works all fine, but now the linker complains:

Undefined symbols for architecture x86_64:
  "_moz_arena_malloc", referenced from:
      js_malloc(unsigned long) in util.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ERROR: sh(clang++ priv/couch_js/60/http.o priv/couch_js/60/main.o priv/couch_js/60/utf8.o
priv/couch_js/60/util.o -L/usr/local/lib -lmozjs-60 -lm -std=c++14 -DHAVE_CURL -lcurl  -L"/usr/local/Cellar/erlang/22.2.1/lib/erlang/lib/erl_interface-3.13.1/lib"
-lerl_interface -lei -o priv/couchjs)
failed with return code 1 and the following output:
Undefined symbols for architecture x86_64:
  "_moz_arena_malloc", referenced from:
      js_malloc(unsigned long) in util.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

ERROR: compile failed while processing /Users/jan/Work/couchdb/src/couch: rebar_abort
make: *** [couch] Error 1


Which seems a lot more manageable, but I can’t for the life of me figure out what’s wrong
here.

The linker invocation looks fine pointing to /usr/local/lib/libmozjs-60.dylib.

our util.o indeed uses a JS_alloc() function. Said function is a macro defined in jsapi.h
pointing to js/Utility.js’s js_malloc, which in turn uses the _moz_arena_malloc.

The symbols are all available in the libmozjs-60.dylib:

nm -gC /usr/local/lib/libmozjs-60.dylib | grep malloc
000000000029da8b T JS_malloc(JSContext*, unsigned long)
                 U _malloc
                 U _moz_arena_malloc

The only point of note is that _moz_arena_malloc is a U and JS_malloc a T here. The no-C++
version garbles the JS_malloc symbol, but I’m not sure why that would make _moz_arena_malloc
unfindable:


nm -g /usr/local/lib/libmozjs-60.dylib | grep malloc
000000000029da8b T __Z9JS_mallocP9JSContextm
                 U _malloc
                 U _moz_arena_malloc


Inside SM60 moz_arena_malloc is defined in malloc_decls.h which gets included via mozmemory.h
and js/Utility.js which all seems cromulent. js_alloc() is an inline function, which is, I
think, why we get the _moz_arena_malloc missing reference in our util.h, because we are not
calling out to any external functions actually.

What I’m not sure about now is where to continue digging:

1. is my libmozjs-60.dylib somehow not up to snuff exporting all symbols correctly for our
C/C++ hybrid?

2. is the way we link against the dylib somehow missing options. I’ve experimented with
every which combination of -stdlib=libc++ -std=gnu++14 and whatever other settings I could
find online, to no avail.

3. is my attempt to swap in clang++ as the CC at fault and is there another way to fix the
“undefined std::__1::basic_string” errors (note that this route still also has a missing
reference for _moz_arena_malloc.


Either way, http://clang.llvm.org/compatibility.html#inline suggests that if js_malloc() were
an `inline` function, that would explain the situation, and a fix would be to mark it `static
inline`. Unfortunately it is already a `static inline`.

Ohey, while writing this, I found that when adding `-lc++` to LDFLAGS, I get rid of the “undefined
std::” errors, but the _moz_arena_malloc remains.

I would imagine that swapping in clang++ as CC automatically links against libc++, which is
why we get to the same place via two routes.

* * *

Any tips very much appreciated!

Best
Jan
-- 
Professional Support for Apache CouchDB:
https://neighbourhood.ie/couchdb-support/


Mime
View raw message