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/

Reply via email to