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/