So, I upgraded to Mavericks as well as the newest version of Xcode (5.02), and — as expected, was unable to compile any new Ruby gems which include C extensions. This happens specifically with my own project, NMatrix, which includes C and C++ code.
I reinstalled the command line tools for Xcode. Then I upgraded homebrew. Then I uninstalled rbenv, ruby-build, and my custom GCC versions (except for 4.7, which was installed manually rather than through brew).
Next, I used brew to install gcc48 (and gcc49 for good measure). I instructed my gem to build with GCC-4.8.2 rather than the dev snapshot of GCC 4.9.
The good news is that my gem now compiles properly. The bad news is that it won't link. Here is just the linking step:
$ bundle exec rake compile
cd tmp/x86_64-darwin13.0.0/nmatrix/2.0.0
make
linking shared-object nmatrix.bundle
ld: warning: directory not found for option '-L/usr/lib64/atlas'
0 0x10ef3f724 __assert_rtn + 144
1 0x10ef7425e archive::File<x86_64>::makeObjectFileForMember(archive::File<x86_64>::Entry const*) const + 1118
2 0x10ef73c3b archive::File<x86_64>::justInTimeforEachAtom(char const*, ld::File::AtomHandler&) const + 139
3 0x10ef883fe ld::tool::InputFiles::searchLibraries(char const*, bool, bool, bool, ld::File::AtomHandler&) const + 210
4 0x10ef8f181 ld::tool::Resolver::resolveUndefines() + 189
5 0x10ef911a5 ld::tool::Resolver::resolve() + 79
6 0x10ef3fb17 main + 669
A linker snapshot was created at:
/tmp/nmatrix.bundle-2013-10-15-085036.ld-snapshot
ld: Assertion failed: (memberIndex != 0), function makeObjectFileForMember, file /SourceCache/ld64/ld64-224.1/src/ld/parsers/archive_file.cpp, line 355.
collect2: error: ld returned 1 exit status
make: *** [nmatrix.bundle] Error 1
rake aborted!
Command failed with status (2): [make...]
This is weird for a couple of reasons.
It's a sporadic error. We've seen it a couple of times and it always seems to go away for reasons that are unclear.
I don't think the
ld: warning
line is relevant, but it might be. ATLAS is provided by Xcode's Accelerate framework, and in the current version of Xcode, it no longer seems to be at/usr/lib64/atlas
(or maybe it never was). That path is only one of the possible installation locations, and the correct path (/usr/local/atlas
) is properly included.When I search for the function prototypes given above, I see a lot of LLVM stuff. It's all Mac OS X errors. So this is Mac-specific. But why would it be using LLVM at all when I'm providing the GCC? Is it using the correct version of GCC for compilation but trying to link with the wrong version?
The last is probably the best hypothesis. It seems like this error only shows up on computers where you can't override the default GCC installation (Macs, namely).
I can't install a new ATLAS because there's no known way to turn off throttling on a MacBook Air — a prerequisite for ATLAS installation, so I can't eliminate the ld
warning.
Does anyone have any thoughts as to what these errors might mean? Compiler/linker gurus? Anyone?
Update
It occurred to me to look in mkmf.log
, and I found some additional information. Sure enough, it's an ATLAS problem. But I'm not really sure why it's only looking in the one directory.
ld: warning: directory not found for option '-L/usr/lib64/atlas'
Undefined symbols for architecture x86_64:
"_ATL_dgemm", referenced from:
_cblas_dgemm in libcblas.a(cblas_dgemm.o)
"_ATL_dsyreflect", referenced from:
_cblas_dgemm in libcblas.a(cblas_dgemm.o)
"_ATL_dsyrk", referenced from:
_cblas_dgemm in libcblas.a(cblas_dgemm.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
checked program was:
/* begin */
1: #include "ruby.h"
2:
3: #include <cblas.h>
4:
5: /*top*/
6: extern int t(void);
7: int t(void) { void ((*volatile p)()); p = (void ((*)()))cblas_dgemm; return 0; }
8: int main(int argc, char **argv)
9: {
10: if (argc > 1000000) {
11: printf("%p", &t);
12: }
13:
14: return 0;
15: }
/* end */
"gcc -o conftest -I/Users/jwoods/.rbenv/versions/2.0.0-p247/include/ruby-2.0.0/x86_64-darwin13.0.0 -I/Users/jwoods/.rbenv/versions/2.0.0-p247/include/ruby-2.0.0/ruby/backward -I/Users/jwoods/.rbenv/versions/2.0.0-p247/include/ruby-2.0.0 -I../../../../ext/nmatrix -I/usr/local/atlas/include -I/usr/include/atlas -Wall -Werror=return-type -I/Users/jwoods/.rbenv/versions/2.0.0-p247/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT -Wall -Werror=return-type -O3 -Wno-error=shorten-64-to-32 -pipe conftest.c -L. -L/Users/jwoods/.rbenv/versions/2.0.0-p247/lib -L/usr/local/atlas/lib -L/usr/local/lib -L/usr/lib -L/usr/lib64/atlas -L. -L/Users/jwoods/.rbenv/versions/2.0.0-p247/lib -L/usr/local/lib -lcblas -llapack -lruby-static -lcblas -llapack -lpthread -ldl -lobjc "
conftest.c:7:27: error: too few arguments to function call, expected 14, have 0
int t(void) { cblas_dgemm(); return 0; }
~~~~~~~~~~~ ^
/usr/local/atlas/include/cblas.h:470:1: note: 'cblas_dgemm' declared here
void cblas_dgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,
^
1 error generated.
checked program was:
/* begin */
1: #include "ruby.h"
2:
3: #include <cblas.h>
4:
5: /*top*/
6: extern int t(void);
7: int t(void) { cblas_dgemm(); return 0; }
8: int main(int argc, char **argv)
9: {
10: if (argc > 1000000) {
11: printf("%p", &t);
12: }
13:
14: return 0;
15: }
/* end */
I believe I found an answer. One of the lib search directories in the
extconf.rb
(which generates the Makefile) was/usr/lib64/
, which doesn't exist on the system. So once I removed that from the search path, it compiled and linked properly.I also added an entry to the
$libs
definition which may or may not have been useful.It went from being
$libs += " -llapack -lcblas -latlas "
to:But that last bit solved issues after linking, not during.