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.
The configuration for clang has been added since last stable version (1.3.19 as of today). Building from Mercurial solved this issue.