EKR: March 2012 Archives


March 3, 2012

Something annoying but also instructive happened during my build of Chromium today. Everything started when I checked out a clean version and went to do a build, only to be greeted with the following exciting error:
ar: input.a is a fat file (use libtool(1) or lipo(1) and ar(1) on it)
ar: input.a: Inappropriate file type or format
rm: /Users/ekr/dev/chromium/src/out/Debug/obj.target/\
  webkit_system_interface/geni/adjust_visibility/self/cuDbUtils.o: No such file or directory
make: *** [out/Debug/libWebKitSystemInterfaceLeopardPrivateExtern.a] Error 1
make: *** Waiting for unfinished jobs....

Luckily, I've run into this problem before so I know what the problem is. The script third_party/WebKit/Source/WebCore/WebCore.gyp/mac/adjust_visibility.sh, which does some library mangling, uses file to determine what kind of library it's dealing with. Unfortunately, it invokes file with an unqualified name, and since MacPorts wants to put itself at the beginning of PATH this means that you get the file implementation from MacPorts which has a slightly different output than the system file. The result is that adjust_visibility.sh decides that you have a thin version of libWebKit...a and tries to run ar on it. When ar fails, so does the build.

The fix here is to move MacPorts below /usr/bin in your path. I'd already done this—or so I thought— but it turned out that MacPorts had inserted itself twice in .cshrc so I had to edit .cshrc and then run source .cshrc. I did this, and after correcting a typo things looked good and I and went to rerun the build, only to be greeted with:

  CXX(target) out/Debug/obj.target/base/base/sync_socket_posix.o
In file included from base/sync_socket_posix.cc:18:
./base/file_util.h:416:56: error: no type named 'set' in namespace 'std'
                                            const std::set& group_gids);
./base/file_util.h:416:59: error: expected ')'
                                            const std::set& group_gids);
./base/file_util.h:413:44: note: to match this '('
BASE_EXPORT bool VerifyPathControlledByUser(const FilePath& base,
2 errors generated.
make: *** [out/Debug/obj.target/base/base/sync_socket_posix.o]

I know what you're thinking here—or at least what I thought—someone forgot to #include <set> and for some reason the automated builds didn't catch it, perhaps due to some conditional compilation problem getting triggered on Lion. But checking the source quite clearly showed that set was being included. Moreover, other STL containers like vector work fine. Changing from clang to GCC didn't help here, so eventually I reverted to gcc -E. For those of you who don't know, this runs the preprocessor but not the compiler and so is really useful for diagnosing this kind of include error. Here's the relevant portion of the result:

# 18 "./base/file_util.h" 2

# 1 "./set" 1
# 24 "./base/file_util.h" 2

It's a little hard to read, but if you know what to look for, it's telling you that instead of including set from /Developer, where the system include files live, the compiler is getting it from the local directory. Now, you might ask what the heck a file named set is doing in the local directory, especially as when I looked it was totally empty. Naturally, it was my fault, but it took a minute to realize what. Remember I said that I had to correct a typo in .cshrc but now what the typo was. Well, the problem was that I had written:

>set OSVER=`uname -r`
Instead of
set OSVER=`uname -r`

Of course, when I ran this it create a file called set in the current directory and since the compile flags included the current directory in the include path, the compiler duly included it instead of the system include file. And since the file was empty, there wasn't any definition of std::set and we got a compile error. Time wasted by this error: 11 minutes (not including writing this up).