윈도우에서 레일즈로 프로그래밍하면서 뭔가 한 번에 되는 것이 없다는 것을 자주 느끼곤 하는데, rmagick 이라는 gem을 설치할 때도 마찬가지 였다. rmagick은 오픈소스 이미지 프로세싱 라이브러리로 유명한 ImageMagick라는 라이브러리를 루비에서도 쓸 수 있게 wrapping한 gem이다. 전부가 그런 것은 아니고 C나 C++로 만들어진 대다수의 오픈소스 라이브러리는 크로스 컴파일을 지원하지만, 제일 컴파일하고 실행하기 좋은 환경은 리눅스 환경일 것이다. 어쨋든 rmagick을 윈도우에서 써야하는 이상 Gemfile에 rmagick을 넣고 bundle을 돌렸다. 역시나 에러 발생. 이런쪽 문제가 발생하면 구글에게 물어보라고 했던가, 검색하자마자 스택오버플로우 글 하나를 첫번째로 띄어주었다[1]. 글을 읽어보니 이전 포스팅에서 확인한 것과 같이 라이브러리를 설치해야한다는 것이였다. 별 생각없이 다운로드 받아서 실행해본 결과 역시나 실패. [1][2]의 글을 좀 열심히 읽어보니 라이브러리를 설치한 디렉토리에 빈칸이 있으면 안된다는 것이었다. “Program files”폴더에 설치 됬으니 당연히 빈칸이 들어갈 수 밖에… 지우고 다시 설치하였다. 그랬는데도 컴파일이 되지 않았다. 무엇 때문인지 하고 봤더니 ” c:\ImageMagick-6.8.0-3-Q16″에 “-“기호나 “.” 같은 특수문자 때문인듯 했다. 그래서 시키는 대로 “c:\ImageMagick” 폴더에 설치를 했다. 그랬더니 gem 설치가 성공하는 듯 했다. 하지만 이렇게 성공했다면 여기에 글을 남기지는 않았을 것이다. 역시나 안됬다. 에러를 뿌리면서 안됬는데 아래의 에러가 발생한다.
Building native extensions with: '--with-opt-lib=c:/ImageMagick/lib --with-opt-include=c:/ImageMagic k/include' This could take a while... ERROR: Error installing rmagick: ERROR: Failed to build gem native extension. C:/Ruby200/bin/ruby.exe extconf.rb --with-opt-lib=c:/ImageMagick/lib --with-opt-include=c:/Image Magick/include checking for Ruby version >= 1.8.5... yes checking for stdint.h... yes checking for sys/types.h... yes checking for wand/MagickWand.h... yes checking for snprintf() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/types.h,wand /MagickWand.h... yes checking for AcquireImage() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/types.h, wand/MagickWand.h... yes checking for AffinityImage() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/types.h ,wand/MagickWand.h... no checking for AffinityImages() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/types. h,wand/MagickWand.h... no checking for AutoGammaImageChannel() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys /types.h,wand/MagickWand.h... yes checking for AutoLevelImageChannel() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys /types.h,wand/MagickWand.h... yes checking for BlueShiftImage() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/types. h,wand/MagickWand.h... yes checking for ConstituteComponentTerminus() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint .h,sys/types.h,wand/MagickWand.h... no checking for DeskewImage() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/types.h,w and/MagickWand.h... yes checking for EncipherImage() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/types.h ,wand/MagickWand.h... yes checking for EqualizeImageChannel() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/ types.h,wand/MagickWand.h... yes checking for FloodfillPaintImage() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/t ypes.h,wand/MagickWand.h... yes checking for FunctionImageChannel() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/ types.h,wand/MagickWand.h... yes checking for GetAuthenticIndexQueue() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sy s/types.h,wand/MagickWand.h... yes checking for GetAuthenticPixels() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/ty pes.h,wand/MagickWand.h... yes checking for GetImageAlphaChannel() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/ types.h,wand/MagickWand.h... yes checking for GetVirtualPixels() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/type s.h,wand/MagickWand.h... yes checking for LevelImageColors() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/type s.h,wand/MagickWand.h... no checking for LevelColorsImageChannel() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,s ys/types.h,wand/MagickWand.h... yes checking for LevelizeImageChannel() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/ types.h,wand/MagickWand.h... yes checking for LiquidRescaleImage() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/ty pes.h,wand/MagickWand.h... yes checking for MagickLibAddendum() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/typ es.h,wand/MagickWand.h... yes checking for OpaquePaintImageChannel() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,s ys/types.h,wand/MagickWand.h... yes checking for QueueAuthenticPixels() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/ types.h,wand/MagickWand.h... yes checking for RemapImage() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/types.h,wa nd/MagickWand.h... yes checking for RemoveImageArtifact() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/t ypes.h,wand/MagickWand.h... yes checking for SelectiveBlurImageChannel() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h ,sys/types.h,wand/MagickWand.h... yes checking for SetImageAlphaChannel() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/ types.h,wand/MagickWand.h... yes checking for SetImageArtifact() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/type s.h,wand/MagickWand.h... yes checking for SetMagickMemoryMethods() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sy s/types.h,wand/MagickWand.h... yes checking for SparseColorImage() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/type s.h,wand/MagickWand.h... yes checking for SyncAuthenticPixels() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/t ypes.h,wand/MagickWand.h... yes checking for TransformImageColorspace() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h, sys/types.h,wand/MagickWand.h... yes checking for TransparentPaintImage() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys /types.h,wand/MagickWand.h... yes checking for TransparentPaintImageChroma() in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint .h,sys/types.h,wand/MagickWand.h... yes checking for QueryMagickColorname() new signature... yes checking for Image.type in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/types.h,wand /MagickWand.h... yes checking for DrawInfo.kerning in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/types. h,wand/MagickWand.h... yes checking for DrawInfo.interline_spacing in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h, sys/types.h,wand/MagickWand.h... yes checking for DrawInfo.interword_spacing in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h, sys/types.h,wand/MagickWand.h... yes checking for DitherMethod in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/types.h,wa nd/MagickWand.h... yes checking for MagickFunction in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/types.h, wand/MagickWand.h... yes checking for ImageLayerMethod in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/types. h,wand/MagickWand.h... yes checking for long double in assert.h,ctype.h,stdio.h,stdlib.h,math.h,time.h,stdint.h,sys/types.h,wan d/MagickWand.h... yes checking for AlphaChannelType.CopyAlphaChannel... yes checking for AlphaChannelType.BackgroundAlphaChannel... yes checking for CompositeOperator.BlurCompositeOp... yes checking for CompositeOperator.DistortCompositeOp... yes checking for CompositeOperator.LinearBurnCompositeOp... yes checking for CompositeOperator.LinearDodgeCompositeOp... yes checking for CompositeOperator.MathematicsCompositeOp... yes checking for CompositeOperator.PegtopLightCompositeOp... yes checking for CompositeOperator.PinLightCompositeOp... yes checking for CompositeOperator.VividLightCompositeOp... yes checking for CompressionType.DXT1Compression... yes checking for CompressionType.DXT3Compression... yes checking for CompressionType.DXT5Compression... yes checking for CompressionType.ZipSCompression... yes checking for CompressionType.PizCompression... yes checking for CompressionType.Pxr24Compression... yes checking for CompressionType.B44Compression... yes checking for CompressionType.B44ACompression... yes checking for DistortImageMethod.BarrelDistortion... yes checking for DistortImageMethod.BarrelInverseDistortion... yes checking for DistortImageMethod.BilinearForwardDistortion... yes checking for DistortImageMethod.BilinearReverseDistortion... yes checking for DistortImageMethod.DePolarDistortion... yes checking for DistortImageMethod.PolarDistortion... yes checking for DistortImageMethod.PolynomialDistortion... yes checking for DistortImageMethod.ShepardsDistortion... yes checking for DitherMethod.NoDitherMethod... yes checking for FilterTypes.KaiserFilter... yes checking for FilterTypes.WelshFilter... yes checking for FilterTypes.ParzenFilter... yes checking for FilterTypes.LagrangeFilter... yes checking for FilterTypes.BohmanFilter... yes checking for FilterTypes.BartlettFilter... yes checking for FilterTypes.SentinelFilter... yes checking for MagickEvaluateOperator.PowEvaluateOperator... yes checking for MagickEvaluateOperator.LogEvaluateOperator... yes checking for MagickEvaluateOperator.ThresholdEvaluateOperator... yes checking for MagickEvaluateOperator.ThresholdBlackEvaluateOperator... yes checking for MagickEvaluateOperator.ThresholdWhiteEvaluateOperator... yes checking for MagickEvaluateOperator.GaussianNoiseEvaluateOperator... yes checking for MagickEvaluateOperator.ImpulseNoiseEvaluateOperator... yes checking for MagickEvaluateOperator.LaplacianNoiseEvaluateOperator... yes checking for MagickEvaluateOperator.MultiplicativeNoiseEvaluateOperator... yes checking for MagickEvaluateOperator.PoissonNoiseEvaluateOperator... yes checking for MagickEvaluateOperator.UniformNoiseEvaluateOperator... yes checking for MagickEvaluateOperator.CosineEvaluateOperator... yes checking for MagickEvaluateOperator.SineEvaluateOperator... yes checking for MagickEvaluateOperator.AddModulusEvaluateOperator... yes checking for MagickFunction.ArcsinFunction... yes checking for MagickFunction.ArctanFunction... yes checking for MagickFunction.PolynomialFunction... yes checking for MagickFunction.SinusoidFunction... yes checking for ImageLayerMethod.FlattenLayer... yes checking for ImageLayerMethod.MergeLayer... yes checking for ImageLayerMethod.MosaicLayer... yes checking for ImageLayerMethod.TrimBoundsLayer... yes checking for VirtualPixelMethod.HorizontalTileVirtualPixelMethod... yes checking for VirtualPixelMethod.VerticalTileVirtualPixelMethod... yes checking for VirtualPixelMethod.HorizontalTileEdgeVirtualPixelMethod... yes checking for VirtualPixelMethod.VerticalTileEdgeVirtualPixelMethod... yes checking for VirtualPixelMethod.CheckerTileVirtualPixelMethod... yes checking for ruby/io.h... yes checking for rb_frame_this_func() in ruby.h,ruby/io.h... yes creating extconf.h creating Makefile ====================================================================== Thu 03Jul14 22:29:32 This installation of RMagick 2.13.2 is configured for Ruby 2.0.0 (i386-mingw32) and ImageMagick 6.8.9 ====================================================================== make "DESTDIR=" generating RMagick2-i386-mingw32.def compiling rmagick.c In file included from rmagick.c:13:0: rmagick.h:81:2: error: #error Specified QuantumDepth is not supported. rmagick.c: In function 'Magick_colors': rmagick.c:40:5: warning: implicit declaration of function 'GetExceptionInfo' [-Wimplicit-function-de claration] rmagick.c:42:5: warning: passing argument 2 of 'GetColorInfoList' from incompatible pointer type [en abled by default] In file included from c:/ImageMagick/include/magick/image.h:21:0, from c:/ImageMagick/include/magick/draw.h:22, from c:/ImageMagick/include/magick/fx.h:21, from c:/ImageMagick/include/magick/accelerate.h:21, from c:/ImageMagick/include/magick/MagickCore.h:73, from rmagick.h:47, from rmagick.c:13: c:/ImageMagick/include/magick/color.h:75:5: note: expected 'size_t *' but argument is of type 'long unsigned int *' rmagick.c: In function 'Magick_fonts': rmagick.c:90:5: warning: passing argument 2 of 'GetTypeInfoList' from incompatible pointer type [ena bled by default] In file included from c:/ImageMagick/include/magick/draw.h:24:0, from c:/ImageMagick/include/magick/fx.h:21, from c:/ImageMagick/include/magick/accelerate.h:21, from c:/ImageMagick/include/magick/MagickCore.h:73, from rmagick.h:47, from rmagick.c:13: c:/ImageMagick/include/magick/type.h:98:5: note: expected 'size_t *' but argument is of type 'long u nsigned int *' rmagick.c: In function 'Magick_init_formats': rmagick.c:178:5: warning: passing argument 2 of 'GetMagickInfoList' from incompatible pointer type [ enabled by default] In file included from c:/ImageMagick/include/magick/MagickCore.h:118:0, from rmagick.h:47, from rmagick.c:13: c:/ImageMagick/include/magick/magick.h:135:5: note: expected 'size_t *' but argument is of type 'lon g unsigned int *' make: *** [rmagick.o] Error 1 Gem files will remain installed in C:/Ruby200/lib/ruby/gems/2.0.0/gems/rmagick-2.13.2 for inspection . Results logged to C:/Ruby200/lib/ruby/gems/2.0.0/gems/rmagick-2.13.2/ext/RMagick/gem_make.out
또 열심히 구글링을 했더니 [3]의 문서를 발견하였다. 문서를 간단히 살펴보니 imagemagick 라이브러리의 버젼에 따라서 컴파일이 안된다는 말로 간단히 요약할 수 있었다. 직접 컴파일해서 연동하는 방법도 써있으니 필요하신분은 참고하시면 될 듯. 어쨋든 되는 버젼을 확인해보니 ‘ImageMagick-6.8.7-8-Q16-x86-dll’에서는 컴파일이 가능하다고 하여 다운로드 받아서 위와 같은 방법으로 실행해 보니 문제 없이 설치할 수 있었다. 이상으로 문제 해결!
– 필자는 Ruby 2.0 x86에서 테스트 했으며, ImageMagick라이브러리도 x86으로 준비하였음. 전에 64bit로 무리하게 진행하다가 고생한 선례가 있어 그나마 편하게 가고 싶으시면 x86을 추천함.
요 약
1. http://ftp.sunet.se/pub/multimedia/graphics/ImageMagick/binaries/ 에서 ImageMagick-6.8.7.8-Q16-x86-dll.exe 을 다운로드.
2. ImageMagick 설치시 경로를 “c:\ImageMagick” 으로 할 것. 그리고 설치시 체크하는 곳에서 “Add application directory to your path system”, “Install development headers and libraries for C and C++” 항목을 체크표시 할 것
3. rails 폴더에서 “gem install rmagick –platform=ruby — –with-opt-lib=c:/ImageMagick/lib –with-opt-include=c:/ImageMagick/include” 라고 명령 실행!
참고자료
[1] StackOverflow(I cant install gem on windows), http://stackoverflow.com/questions/4873276/i-cant-install-rmagick-gem-on-windows
[2] shubham’s blog(installing rmagick gem on windows 7), http://shoobm.wordpress.com/2013/01/03/installing-rmagick-gem-on-windows-7/
[3] 君の瞳はまるでルビー – Ruby 関連まとめサイト(RMagick を Windows 7 にインストールする方法), http://www.ownway.info/Ruby/index.php?rmagick%2Fhowtoinstall%2Fwindows