Question

I've been trying to include GraphicsMagick into my project for the last couple days but without luck, hopefully someone here might be able to help me (See TL/DR at the end if this is too long).

As I need JPEG, PNG and lcms support, I previously downloaded and built them using the configure and make tools:

./configure CC=clang
make
sudo make install

All this seems to be working fine, so after downloading GraphicsMagick, I run configure again:

CC=clang CXX="clang++ -stdlib=libc++" CXXFLAGS="-stdlib=libc++" LDFLAGS="-stdlib=libc++" ./configure --enable-shared --disable-static --disable-openmp --without-xml --without-zlib --without-bzlib

Then make creates my dynamic libraries: libGraphicsMagick.3.dylib and libGraphicsMagick++.3.dylib. When I inspect libGraphicsMagick++ with MacDependency or with otool, I see that it is linking against /usr/lib/libc++.1.dylib (and not libstdc++)

Now if I create a new project using GraphicsMagick, add #include <Magick++.h> (installed by the previous step in /usr/local/include/GraphicsMagick), just that, not actually using any feature I get a link error:

clang++ -headerpad_max_install_names -stdlib=libc++ -arch x86_64 -o TestMagickApp.app/Contents/MacOS/TestMagickApp main.o widget.o moc_widget.o   -F/Library/Frameworks -L/Library/Frameworks -framework QtGui -framework QtCore 
Undefined symbols for architecture x86_64:
  "std::__1::basic_streambuf<char, std::__1::char_traits<char> >::gptr() const", referenced from:
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::seekoff(long long, std::__1::ios_base::seekdir, unsigned int) in widget.o
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::underflow() in widget.o
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::pbackfail(int) in widget.o
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::overflow(int) in widget.o
  "std::__1::basic_streambuf<char, std::__1::char_traits<char> >::pptr() const", referenced from:
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::seekoff(long long, std::__1::ios_base::seekdir, unsigned int) in widget.o
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::underflow() in widget.o
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::pbackfail(int) in widget.o
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::overflow(int) in widget.o
  "std::__1::basic_streambuf<char, std::__1::char_traits<char> >::eback() const", referenced from:
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::seekoff(long long, std::__1::ios_base::seekdir, unsigned int) in widget.o
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::underflow() in widget.o
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::pbackfail(int) in widget.o
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::overflow(int) in widget.o
  "std::__1::basic_streambuf<char, std::__1::char_traits<char> >::egptr() const", referenced from:
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::underflow() in widget.o
  "std::__1::basic_streambuf<char, std::__1::char_traits<char> >::epptr() const", referenced from:
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::seekoff(long long, std::__1::ios_base::seekdir, unsigned int) in widget.o
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::overflow(int) in widget.o
  "std::__1::basic_streambuf<char, std::__1::char_traits<char> >::pbase() const", referenced from:
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::seekoff(long long, std::__1::ios_base::seekdir, unsigned int) in widget.o
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::overflow(int) in widget.o
  "std::__1::basic_iostream<char, std::__1::char_traits<char> >::basic_iostream(std::__1::basic_streambuf<char, std::__1::char_traits<char> >*)", referenced from:
      std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >::basic_stringstream(unsigned int) in widget.o
  "std::__1::basic_streambuf<char, std::__1::char_traits<char> >::setg(char*, char*, char*)", referenced from:
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::seekoff(long long, std::__1::ios_base::seekdir, unsigned int) in widget.o
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::underflow() in widget.o
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::pbackfail(int) in widget.o
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::overflow(int) in widget.o
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::str(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) in widget.o
  "std::__1::basic_streambuf<char, std::__1::char_traits<char> >::setp(char*, char*)", referenced from:
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::seekoff(long long, std::__1::ios_base::seekdir, unsigned int) in widget.o
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::overflow(int) in widget.o
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::str(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) in widget.o
  "std::__1::basic_streambuf<char, std::__1::char_traits<char> >::pbump(int)", referenced from:
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::seekoff(long long, std::__1::ios_base::seekdir, unsigned int) in widget.o
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::overflow(int) in widget.o
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::str(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) in widget.o
  "std::__1::basic_streambuf<char, std::__1::char_traits<char> >::sputc(char)", referenced from:
      std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> >::overflow(int) in widget.o
  "std::__1::basic_ios<char, std::__1::char_traits<char> >::basic_ios()", referenced from:
      std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >::basic_stringstream(unsigned int) in widget.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [TestMagickApp.app/Contents/MacOS/TestMagickApp] Error 1
19:43:22: The process "/usr/bin/make" exited with code 2.
Error while building/deploying project TestMagickApp (kit: 4.8.5)
When executing step 'Make'

But that only happens when I try to use libc++, if I try using libstdc++ instead, it links without any issue (but it should error as soon as I try using any feature if I'm still thinking straight).

I tried including only certain files to narrow down the problem and it seems that it is caused by this piece of code inside /usr/local/include/GraphicsMagick/magick/common.h:

/*
  Support for __attribute__ was added in GCC 2.0.  It is not supported
  in strict ANSI mode which is indicated by __STRICT_ANSI__ being
  defined.

  http://www.ohse.de/uwe/articles/gcc-attributes.html

  Note that GCC 3.2 on MinGW does not define __GNUC__ or __GNUC_MINOR__.

*/
#if !defined(__attribute__)
#  if (!defined(__GNUC__) || (__GNUC__ < 2 || __STRICT_ANSI__))
#    define __attribute__(x) /*nothing*/
#  else
#    if (((__GNUC__) > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1))) /* 3.1+ */
#      define MAGICK_FUNC_DEPRECATED __attribute__((__deprecated__))
#    endif
#    if (__GNUC__ >= 3)  /* 3.0+ */
#      define MAGICK_FUNC_MALLOC __attribute__((__malloc__))
#    endif
#    if (((__GNUC__) > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)))  /* 3.3+ */
  /* Supports argument syntax like __attribute__((nonnull (1, 2))) but
     don't know how to support non-GCC fallback. */
#      define MAGICK_FUNC_NONNULL __attribute__((__nonnull__))
#    endif
#    if (((__GNUC__) > 3) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 5))) /* 2.5+ */
#      define MAGICK_FUNC_NORETURN __attribute__((__noreturn__))
#    endif
#    if ((__GNUC__) >= 3) /* 2.96+ */
#      define MAGICK_FUNC_PURE __attribute__((__pure__))
#    endif
#    if (((__GNUC__) > 3) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 7))) /* 2.7+ */
#      define MAGICK_FUNC_UNUSED __attribute__((__unused__))
#    endif
#    if (((__GNUC__) > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)))  /* 3.3+ */
#      define MAGICK_FUNC_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
#    endif
#    if (((__GNUC__) > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)))  /* 4.3+ */
#      define MAGICK_FUNC_ALLOC_SIZE_1ARG(arg_num) __attribute__((__alloc_size__(arg_num)))
#      define MAGICK_FUNC_ALLOC_SIZE_2ARG(arg_num1,arg_num2) __attribute__((__alloc_size__(arg_num1,arg_num2)))
#      define MAGICK_FUNC_HOT __attribute__((__hot__))
#      define MAGICK_FUNC_COLD __attribute__((__cold__))
#      define MAGICK_OPTIMIZE_FUNC(opt) __attribute__((__optimize__ (opt)))
#    endif
#    if (((__GNUC__) > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)))  /* 4.7+ */
#      define MAGICK_ASSUME_ALIGNED(exp,align) __builtin_assume_aligned(exp,align)
#      define MAGICK_ASSUME_ALIGNED_OFFSET(exp,align,offset) __builtin_assume_aligned(exp,align,offset)
#    endif
#  endif
#endif

Now I don't really understand this code but it seems to be enabling support for really old compilers (GCC version < 2!!). If I comment the whole section out, it seems to compile fine but as I don't know what it is doing, commenting it out feels a bit risky/weird and as it's a read-only file it sort of indicates me that I should not really be messing with it anyway I guess.

For what it's worth, the application using GraphicsMagick is using Qt 4.8.5 as well, and I'm using QtCreator and QMake, but I don't think it's relevant here. I tried with Qt 5.1 and 5.2 as well but without luck.

clang++ --version returns Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn) (I know it's not the latest version but I'd rather not change it).

TL / DR:

Has anyone got any experience/feedback on compiling GraphicsMagick with libc++?

Can someone explain to me what the last bit of code above is doing? And why would it work when I'm commenting it out?

Can you spot anything wrong in what I've done? I did the whole process a few times but maybe I forgot something obvious...

Any help would be very welcome.

Was it helpful?

Solution

The configuration for clang has been added since last stable version (1.3.19 as of today). Building from Mercurial solved this issue.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top