Posts Tagged ‘clang’

Eigen Gotcha: sizeof Eigen::Index depends on system

Tuesday, December 19th, 2017

Part of the magic behind libigl’s header-only / static-library duality is making use of explicit template instantiations. Usually I can just literally copy the compiler “missing symbol” error lines, stick template in front of them and a semicolon ; at the end to add a symbol to the static library.

Unfortunately this falls apart for any templates that are defined via Eigen::Index (e.g., via Eigen::MatrixXi::Index).

My compiler (clang on Mac OS X) translates these to long in the output lines. And on Mac OSX with clang a long is 64 bits long.

Unfortunately, long is only 32 bits long on Windows and there Eigen::Index is translated to __int64 (which has 64 bits). So then I still get a missing symbol.

This is probably more of a clang compiler gotcha. I’m not sure Eigen could do anything to help me here.

Update: I take that back. Eigen could define EIGEN_DEFAULT_DENSE_INDEX_TYPE to a fixed size value (e.g., int64_t) rather than the system dependent std::ptrdiff_t, but there’s an obvious advantage to using the best type on this system rather than a fixed size that might be too big (or too small).

Run executable in debugger immediately, return if successful

Saturday, January 2nd, 2016

Here’re the flags for the lldb debugger to run a binary my_bin in the debugger immediately and return to the prompt if there were no errors. But if, say, an assertion fires, then it will stop as usual:

lldb -b -o r my_bin

SSE illegal instruction run-time error in Eigen

Monday, November 30th, 2015

While debugging the other day we ran into a runtime error:


`
0x0000000000655679 in _mm_set_epi32 (__q0=0, __q1=0, __q2=0, __q3=0)
    at /usr/lib/gcc/x86_64-linux-gnu/4.9/include/emmintrin.h:595
595       return __extension__ (__m128i)(__v4si){ __q0, __q1, __q2, __q3 };
(gdb) bt
#0  0x0000000000655679 in _mm_set_epi32 (__q0=0, __q1=0, __q2=0, __q3=0)
    at /usr/lib/gcc/x86_64-linux-gnu/4.9/include/emmintrin.h:595
#1  _mm_set1_epi32 (__A=0) at /usr/lib/gcc/x86_64-linux-gnu/4.9/include/emmintrin.h:635
#2  Eigen::internal::pset1(Eigen::internal::unpacket_traits::type const&) (from=@0x7fffffffd61c: 0) at /usr/local/include/eigen3/Eigen/src/Core/arch/SSE/PacketMath.h:115
#3  0x00000000006a88ee in Eigen::internal::scalar_constant_op::packetOp (this=0x7fffffffd61c)
    at /usr/local/include/eigen3/Eigen/src/Core/Functors.h:522
#4  0x00000000006a0ea4 in Eigen::CwiseNullaryOp, Eigen::Matrix >::packet<0> (this=0x7fffffffd610, index=0)
    at /usr/local/include/eigen3/Eigen/src/Core/CwiseNullaryOp.h:88
#5  0x0000000000698582 in Eigen::DenseCoeffsBase, 1>::copyPacket, Eigen::Matrix >, 1, 0> (
    this=0x7fffffffd6a0, index=0, other=...) at /usr/local/include/eigen3/Eigen/src/Core/DenseCoeffsBase.h:537
#6  0x000000000068f403 in Eigen::internal::assign_impl, Eigen::CwiseNullaryOp, Eigen::Matrix >, 3, 0, 0>::run (dst=..., 
    src=...) at /usr/local/include/eigen3/Eigen/src/Core/Assign.h:410
#7  0x000000000068416e in Eigen::DenseBase >::lazyAssign, Eigen::Matrix > > (this=0x7fffffffd6a0, 
    other=...) at /usr/local/include/eigen3/Eigen/src/Core/Assign.h:499
#8  0x000000000067980d in Eigen::PlainObjectBase >::lazyAssign, Eigen::Matrix > > (
    this=0x7fffffffd6a0, other=...) at /usr/local/include/eigen3/Eigen/src/Core/PlainObjectBase.h:414
#9  0x000000000066c1f8 in Eigen::internal::assign_selector, Eigen::CwiseNullaryOp, Eigen::Matrix >, false, false>::run (
    dst=..., other=...) at /usr/local/include/eigen3/Eigen/src/Core/Assign.h:520
#10 0x00000000006619b3 in Eigen::PlainObjectBase >::_set_noalias, Eigen::Matrix > > (
---Type  to continue, or q  to quit---
    this=0x7fffffffd6a0, other=...) at /usr/local/include/eigen3/Eigen/src/Core/PlainObjectBase.h:621
#11 0x000000000069e5b7 in Eigen::PlainObjectBase >::_set_selector, Eigen::Matrix > > (
    this=0x7fffffffd6a0, other=...) at /usr/local/include/eigen3/Eigen/src/Core/PlainObjectBase.h:606
#12 0x000000000069590c in Eigen::PlainObjectBase >::_set, Eigen::Matrix > > (this=0x7fffffffd6a0, 
    other=...) at /usr/local/include/eigen3/Eigen/src/Core/PlainObjectBase.h:598
#13 0x000000000068bc41 in Eigen::Matrix::operator=, Eigen::Matrix > > (this=0x7fffffffd6a0, other=...)
`

We were getting an “illegal instruction” trap. Finally we tracked down the issue to be that we’d compiled using the -msse4.2 flag on a machine that did not support SSE 4.2. In retrospect we should have suspected this from the header in which the error occurred (emmintrin.h). We had accidentally cross-compiled and then tried to run a bogus binary. To fix this issue we deleted the flag and replaced it with -march=native.

Retrieve system volume and mute status via objective-c

Saturday, July 25th, 2015

Here’s a little objective-c program to grab the Mac OS X system volume and mute status (and then multiply them to get the effective volume).

#import <AudioToolbox/AudioServices.h>
#import <Foundation/NSObject.h>

@interface Volume : NSObject
{
}
 +(AudioDeviceID)defaultOutputDeviceID;
 +(float)volume;
 +(bool)mute;
 +(float)effective_volume;
@end

@implementation Volume : NSObject
+(AudioDeviceID)defaultOutputDeviceID;
{
    AudioDeviceID   outputDeviceID = kAudioObjectUnknown;
    // get output device device
    UInt32 propertySize = 0;
    OSStatus status = noErr;
    AudioObjectPropertyAddress propertyAOPA;
    propertyAOPA.mScope = kAudioObjectPropertyScopeGlobal;
    propertyAOPA.mElement = kAudioObjectPropertyElementMaster;
    propertyAOPA.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
    if (!AudioHardwareServiceHasProperty(kAudioObjectSystemObject, &propertyAOPA))
    {
        NSLog(@"Cannot find default output device!");
        return outputDeviceID;
    }
    propertySize = sizeof(AudioDeviceID);
    status = AudioHardwareServiceGetPropertyData(kAudioObjectSystemObject, &propertyAOPA, 0, NULL, &propertySize, &outputDeviceID);
    if(status) 
    {
        NSLog(@"Cannot find default output device!");
    }
    return outputDeviceID;
}

+(float)volume 
{
    Float32         outputVolume;
    UInt32 propertySize = 0;
    OSStatus status = noErr;
    AudioObjectPropertyAddress propertyAOPA;
    propertyAOPA.mElement = kAudioObjectPropertyElementMaster;
    propertyAOPA.mSelector = kAudioHardwareServiceDeviceProperty_VirtualMasterVolume;
    propertyAOPA.mScope = kAudioDevicePropertyScopeOutput;
    AudioDeviceID outputDeviceID = [[self class] defaultOutputDeviceID];
    if (outputDeviceID == kAudioObjectUnknown)
    {
        NSLog(@"Unknown device");
        return 0.0;
    }
    if (!AudioHardwareServiceHasProperty(outputDeviceID, &propertyAOPA))
    {
        NSLog(@"No volume returned for device 0x%0x", outputDeviceID);
        return 0.0;
    }
    propertySize = sizeof(Float32);
    status = AudioHardwareServiceGetPropertyData(outputDeviceID, &propertyAOPA, 0, NULL, &propertySize, &outputVolume);
    if (status)
    {
        NSLog(@"No volume returned for device 0x%0x", outputDeviceID);
        return 0.0;
    }
    if (outputVolume < 0.0 || outputVolume > 1.0) return 0.0;
    return outputVolume;
}

+(bool)mute
{
    UInt32 mute;
    UInt32 propertySize = 0;
    OSStatus status = noErr;
    AudioObjectPropertyAddress propertyAOPA;
    propertyAOPA.mElement = kAudioObjectPropertyElementMaster;
    propertyAOPA.mSelector = kAudioDevicePropertyMute;
    propertyAOPA.mScope = kAudioDevicePropertyScopeOutput;
    AudioDeviceID outputDeviceID = [[self class] defaultOutputDeviceID];
    if (outputDeviceID == kAudioObjectUnknown)
    {
        NSLog(@"Unknown device");
        return 0.0;
    }
    if (!AudioHardwareServiceHasProperty(outputDeviceID, &propertyAOPA))
    {
        NSLog(@"No volume returned for device 0x%0x", outputDeviceID);
        return 0.0;
    }
    propertySize = sizeof(UInt32);
    status = AudioHardwareServiceGetPropertyData(outputDeviceID, &propertyAOPA, 0, NULL, &propertySize, &mute);
    if (status)
    {
        NSLog(@"No volume returned for device 0x%0x", outputDeviceID);
        return 0.0;
    }
    return mute;
}
+(float)effective_volume
{
  return [[self class] volume] * (![[self class] mute]);
}

@end

int main(int argc, const char * argv[])
{
  printf("%g",[Volume effective_volume]);
}

Compile with something like:

clang volume.m -o volume -framework Cocoa -framework AudioToolbox

Then when you run it will simply return a number representing the current effective volume:

0.25

Compiling OpenSubDiv on mac os x with gcc

Monday, March 16th, 2015

I had a bit of trouble compiling OpenSubDiv on Mac OS X Yosemite with gcc. I could at least manage to compile the cpu library with:

mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DNO_EXAMPLES=1 -DNO_GCD=1 -DNO_CUDA=1 ..
make osd_static_cpu

This creates lib/libosdCPU.a. It seems -DNO_GCD=1 is the most critical option as grand central dispatch uses apple’s “blocks” extension C which is only supported by clang.

Linker order error with matlab dynamic libraries and gcc on mac os x

Monday, November 3rd, 2014

I had a nasty time tracking down a runtime error in our libigl tutorials. It seems that the newest version of matlab comes with some dynamic libraries which do not agree with the stdc++ library of my gcc compiler. I had a link command that looked something like this:

/opt/local/bin/g++ -std=c++11
  /Applications/MATLAB_R2014b.app/bin/maci64/libmex.dylib \
  /Applications/MATLAB_R2014b.app/bin/maci64/libmx.dylib \
  ...

Here’s the debugger output of the error I got at runtime

* thread #1: tid = 0x153aa3, 0x00007fff86d08866 libsystem_kernel.dylib`__pthread_kill + 10, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
  * frame #0: 0x00007fff86d08866 libsystem_kernel.dylib`__pthread_kill + 10
    frame #1: 0x00007fff8341f35c libsystem_pthread.dylib`pthread_kill + 92
    frame #2: 0x00007fff8571fb1a libsystem_c.dylib`abort + 125
    frame #3: 0x00007fff8b1c007f libsystem_malloc.dylib`free + 411
    frame #4: 0x00000001001d47a0 libmex.dylib`std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::~basic_stringbuf() + 96
    frame #5: 0x0000000100451da2 libstdc++.6.dylib`std::basic_ostringstream<char, std::char_traits<char>, std::allocator<char> >::~basic_ostringstream() + 36

Seems like libmex and libmx were the culprits. I fixed this problem by telling the linker to find the stdc++ library before the matlab dynamic libraries:

/opt/local/bin/g++ -std=c++11
  -lstdc++ \
  /Applications/MATLAB_R2014b.app/bin/maci64/libmex.dylib \
  /Applications/MATLAB_R2014b.app/bin/maci64/libmx.dylib \
  ...

Using embree compiled with gcc from a program compiled with clang

Friday, September 12th, 2014

I compiled Embree using my standard compiler gcc 4.7 (I’m holding out on clang for openmp support), but for a specific project I need to use clang. When I try to link against libembree.a and libsys.a I get this sort of error:

  "std::string::find(char, unsigned long) const", referenced from:
      embree::AccelRegistry::create(std::string, embree::RTCGeometry*) in libembree.a(registry_accel.o)
      embree::BuilderRegistry::build(std::string, embree::TaskScheduler::Event*, embree::Accel*) in libembree.a(registry_builder.o)
      embree::IntersectorRegistry<embree::Intersector1>::get(std::string, std::string, embree::Accel*) in libembree.a(registry_intersector.o)
      embree::IntersectorRegistry<embree::Intersector4>::get(std::string, std::string, embree::Accel*) in libembree.a(registry_intersector.o)
  "std::string::compare(char const*) const", referenced from:
      embree::AccelRegistry::create(std::string, embree::RTCGeometry*) in libembree.a(registry_accel.o)
      embree::BuilderRegistry::build(std::string, embree::TaskScheduler::Event*, embree::Accel*) in libembree.a(registry_builder.o)
      embree::IntersectorRegistry<embree::Intersector1>::get(std::string, std::string, embree::Accel*) in libembree.a(registry_intersector.o)
      embree::IntersectorRegistry<embree::Intersector4>::get(std::string, std::string, embree::Accel*) in libembree.a(registry_intersector.o)
...

I tried using the flag -stdlib=libc++ but this doesn’t fix the problem. Using -stdlib=libstdc++ most errors go away except for:

  "std::ctype<char>::_M_widen_init() const", referenced from:
      embree::rtcBuildAccel(embree::RTCGeometry*, char const*) in libembree.a(embree.o)
      embree::BVHStatisticsT<embree::BVH2>::print() in libembree.a(bvh2.o)
      embree::BVHStatisticsT<embree::BVH4>::print() in libembree.a(bvh4.o)
      embree::BVHBuilderT<embree::BVH4, embree::HeuristicBinning<0> >::createLeafNode(unsigned long, embree::atomic_set<embree::PrimRefBlock>&, embree::HeuristicBinning<0>::PrimInfo const&) in libembree.a(bvh4.o)
      embree::BVHBuilderT<embree::BVH4, embree::HeuristicBinning<2> >::createLeafNode(unsigned long, embree::atomic_set<embree::PrimRefBlock>&, embree::HeuristicBinning<2>::PrimInfo const&) in libembree.a(bvh4.o)
      embree::BVHBuilderT<embree::BVH4, embree::HeuristicSpatial<0> >::createLeafNode(unsigned long, embree::atomic_set<embree::PrimRefBlock>&, embree::HeuristicSpatial<0>::PrimInfo const&) in libembree.a(bvh4.o)
      embree::BVHBuilderT<embree::BVH4, embree::HeuristicSpatial<2> >::createLeafNode(unsigned long, embree::atomic_set<embree::PrimRefBlock>&, embree::HeuristicSpatial<2>::PrimInfo const&) in libembree.a(bvh4.o)

This error seems trickier and to remove it I explicitly link against libgcc_s.a found in my gcc’s libraries: add the linker argument /opt/local/lib/gcc47/libstdc++.a. This gets me close, but there’s a new error:

  "___emutls_get_address", referenced from:
      ___cxa_get_globals_fast in libstdc++.a(eh_globals.o)
      ___cxa_get_globals in libstdc++.a(eh_globals.o)

Turns out that I need another library from gcc making the arguments now: /opt/local/lib/gcc47/libstdc++.a /opt/local/lib/gcc47/libgcc_s.1.dylib. And this finally works.

Update: Oddly it seems on the static libstdc++.a has the final problem. Linking to the dymnamic library libstdc++.dylib in the same directory works fine (maybe because I’m just avoiding the issue with this example).

Compiling C++ with C++11 support on bluehost servers

Monday, September 8th, 2014

I asked bluehost to install a modern version of gcc with C++11 support. They told me that only gcc4.3 was deemed stable.

So then I tried to compile gcc4.7 and gcc4.9 from scratch. This seemed promising but eventually I hit some apparent bug in the make routine of gcc giving me the error:

"cp: cannot stat `libgcc_s.so.1': No such file or directory"

Manually copying the file for make did not help.

So then I switched to trying to compile clang. This worked. I followed the instructions in this answer.

Namely, I added this to my .bashrc

export LD_LIBRARY_PATH=/usr/lib/gcc/x86_64-redhat-linux/4.4.7/:$LD_LIBRARY_PATH
export CC=/usr/bin/gcc
export CXX=/usr/bin/g++

Then issued the following:

source .bashrc
wget http://llvm.org/releases/3.3/cfe-3.3.src.tar.gz
tar xzf llvm-3.3.src.tar.gz && cd llvm-3.3.src/tools/ && tar xzf ../../cfe-3.3.src.tar.gz
cd llvm-3.3.src
mv tools/cfe-3.3.src tools/clang
./configure --prefix=$HOME/llvm-3.3.src/llvm
make -j8
make install

Now to test it out, I created a file test.cpp with this inside:

#include <iostream>
int main(int argc, char *argv[])
{
  const auto & hello = []()
  {
    std::cout<<"Hello, world."<<std::endl;
  };
  hello();
}

Then I could try to compile with:

llvm-3.3.src/llvm/bin/clang++ -std=c++11 test.cpp -o test

But I get the error:

In file included from test.cpp:1:
In file included from /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/iostream:40:
In file included from /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/ostream:40:
In file included from /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/ios:40:
In file included from /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/exception:148:
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/exception_ptr.h:143:13: error: unknown type name
      'type_info'
      const type_info*
            ^
1 error generated.

This seems to be a known bug with old “stable” versions of gcc’s standard library. The fix is to add a class declaration before the #include <iostream>:

#ifdef __clang__
    class type_info;
#endif
#include <iostream>
int main(int argc, char *argv[])
{
  const auto & hello = []()
  {
    std::cout<<"Hello, world."<<std::endl;
  };
  hello();
}

This compiles and runs.

gdb, lldb not showing line numbers for binaries compiled from stdin

Tuesday, June 17th, 2014

I recently figured out why my self-compiling C++ files didn’t play nicely with debuggers. It seems that when compiling with gcc (from Macports) and reading in the C++ code from standard input (using the -x c++ - arguments), the debuggers gdb and lldb won’t show high level information like code snippets or line numbers even if the -g option is present. Seems that gcc isn’t really including that information in the binary, rather it’s looking it up at run-time. You can verify this by changing the source file after compiling and then running the debugger. clang++ on the otherhand seems to embedd information from stdin into the executable so that it can be properly debugged.

In the meantime, I’ll keep using gcc but for self-compiling routines I need to use auxiliary files.

No `gdb` in OS X 10.9, Mavericks

Monday, April 21st, 2014

Use lldb, even works with binaries compiled with gcc.