From 2129adfcc369ca59a2213f16740736e58766bac3 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Tue, 27 Oct 2015 22:41:15 +0000 Subject: [PATCH] Initial commit of local libvips binding/packaging Copy Windows DLLs into release dir as no rpath equivalent Use local libvips on Windows CI --- .gitignore | 2 + .npmignore | 1 + .travis.yml | 9 +- CONTRIBUTING.md | 1 - appveyor.yml | 16 +--- binding.gyp | 177 +++++++++++++++++++++++++++------------ binding.js | 111 ++++++++++++++++++++++++ index.js | 5 ++ package.json | 12 ++- packaging/build.sh | 28 +++++++ packaging/lin/Dockerfile | 99 ++++++++++++++++++++++ packaging/win/Dockerfile | 16 ++++ 12 files changed, 398 insertions(+), 79 deletions(-) mode change 100755 => 100644 binding.gyp create mode 100644 binding.js create mode 100755 packaging/build.sh create mode 100644 packaging/lin/Dockerfile create mode 100644 packaging/win/Dockerfile diff --git a/.gitignore b/.gitignore index 5fee4d2f..a2a5cc46 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ coverage test/bench/node_modules test/fixtures/output* test/leak/libvips.supp +bin lib include +packaging/libvips* .DS_Store diff --git a/.npmignore b/.npmignore index dda57203..f3a5a187 100644 --- a/.npmignore +++ b/.npmignore @@ -10,3 +10,4 @@ appveyor.yml mkdocs.yml lib include +packaging diff --git a/.travis.yml b/.travis.yml index 0a62f9e3..bc82efc0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,18 +2,15 @@ language: node_js node_js: - "0.10" - "0.12" - - "iojs-v2" - - "iojs-v3" - "4" -sudo: 9000 +sudo: false addons: apt: sources: - ubuntu-toolchain-r-test packages: - g++-4.8 -before_install: - - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 90 - - curl -s https://raw.githubusercontent.com/lovell/sharp/master/preinstall.sh | sudo bash - +env: + CXX=g++-4.8 after_success: - cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 740b4b3e..acab1694 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -47,7 +47,6 @@ Any change that modifies the existing public API should be added to the relevant | Release | WIP branch | | ------: | :--------- | -| v0.11.0 | knife | | v0.12.0 | look | | v0.13.0 | mind | diff --git a/appveyor.yml b/appveyor.yml index 0cc02787..5c0ae8b6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,26 +3,12 @@ version: "{build}" build: off platform: x64 environment: - VIPS_VERSION_MAJOR_MINOR: 8.1 - VIPS_VERSION_PATCH: 1 VIPS_WARNING: 0 matrix: - nodejs_version: "0.12" - nodejs_exec: "node" - - nodejs_version: "2" - nodejs_exec: "iojs" - - nodejs_version: "3" - nodejs_exec: "iojs" - nodejs_version: "4" - nodejs_exec: "node" install: - - ps: $env:VIPS_VERSION = "$env:VIPS_VERSION_MAJOR_MINOR.$env:VIPS_VERSION_PATCH" - - ps: Write-Output "Fetching http://www.vips.ecs.soton.ac.uk/supported/$env:VIPS_VERSION_MAJOR_MINOR/win32/vips-dev-$env:VIPS_VERSION.zip" - - ps: Start-FileDownload http://www.vips.ecs.soton.ac.uk/supported/$env:VIPS_VERSION_MAJOR_MINOR/win32/vips-dev-$env:VIPS_VERSION.zip -FileName c:\vips-dev-$env:VIPS_VERSION.zip - - ps: Invoke-Expression "& 7z -y x c:\vips-dev-$env:VIPS_VERSION.zip -oc:\ | FIND /V `"ing `"" - - ps: $env:VIPS_HOME = "c:\vips-dev-$env:VIPS_VERSION" - - ps: $env:PATH = "$env:VIPS_HOME\bin;$env:PATH" - ps: Install-Product node $env:nodejs_version x86 - npm install --arch=ia32 test_script: - - npm run-script test-win32-%nodejs_exec% + - npm run-script test-win32 diff --git a/binding.gyp b/binding.gyp old mode 100755 new mode 100644 index c5c4a916..0d4a090e --- a/binding.gyp +++ b/binding.gyp @@ -2,7 +2,34 @@ 'targets': [{ 'target_name': 'sharp', 'variables': { - 'runtime_link%':'shared', + 'variables': { + 'variables': { + 'conditions': [ + ['OS != "win"', { + 'pkg_config_path': '/dev/null 2>&1 && eval $(brew --env) && echo $PKG_CONFIG_LIBDIR || true):$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/lib/pkgconfig' + }, { + 'pkg_config_path': '' + }] + ] + }, + 'conditions': [ + ['OS != "win"', { + 'global_vips_version': '/dev/null 2>&1 && pkg-config --exists vips && pkg-config --modversion vips || true)' + }, { + 'global_vips_version': '' + }] + ], + 'pkg_config_path%': '<(pkg_config_path)' + }, + 'pkg_config_path%': '<(pkg_config_path)', + 'runtime_link%': 'shared', + 'conditions': [ + ['OS != "win"', { + 'use_global_vips': '/dev/null 2>&1 && eval $(brew --env) && echo $PKG_CONFIG_LIBDIR || true):$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/lib/pkgconfig' + 'download_vips': '&1 || true)" node -e "require(\'./binding\').download_vips()")' + }, + 'libraries': [ + '<(module_root_dir)/lib/libvips.so', + '<(module_root_dir)/lib/libglib-2.0.so', + '<(module_root_dir)/lib/libgobject-2.0.so', + '-Wl,-rpath=\'$${ORIGIN}/../../lib\'' + ] + }] + ] + }] ], 'cflags_cc': [ '-std=c++0x', @@ -69,28 +90,78 @@ '-O3' ], 'xcode_settings': { + 'MACOSX_DEPLOYMENT_TARGET': '10.7', 'OTHER_CPLUSPLUSFLAGS': [ '-std=c++11', '-stdlib=libc++', '-fexceptions', '-Wall', '-O3' - ], - 'MACOSX_DEPLOYMENT_TARGET': '10.7' - }, - 'msvs_settings': { - 'VCCLCompilerTool': { - 'ExceptionHandling': 1 # /EHsc - } + ] }, 'configurations': { 'Release': { 'msvs_settings': { 'VCCLCompilerTool': { - 'ExceptionHandling': 1, + 'ExceptionHandling': 1 } } } }, + }, { + 'target_name': 'win_copy_dlls', + 'type': 'none', + 'dependencies': [ + 'sharp' + ], + 'conditions': [ + ['OS == "win"', { + 'copies': [{ + 'destination': '<(module_root_dir)/build/Release', + 'files': [ + '<(module_root_dir)/lib/GNU.Gettext.dll', + '<(module_root_dir)/lib/libMagickCore-6.Q16-2.dll', + '<(module_root_dir)/lib/libMagickWand-6.Q16-2.dll', + '<(module_root_dir)/lib/libasprintf-0.dll', + '<(module_root_dir)/lib/libcairo-2.dll', + '<(module_root_dir)/lib/libcairo-gobject-2.dll', + '<(module_root_dir)/lib/libcairo-script-interpreter-2.dll', + '<(module_root_dir)/lib/libexif-12.dll', + '<(module_root_dir)/lib/libexpat-1.dll', + '<(module_root_dir)/lib/libffi-6.dll', + '<(module_root_dir)/lib/libfftw3-3.dll', + '<(module_root_dir)/lib/libfontconfig-1.dll', + '<(module_root_dir)/lib/libfreetype-6.dll', + '<(module_root_dir)/lib/libgcc_s_seh-1.dll', + '<(module_root_dir)/lib/libgdk_pixbuf-2.0-0.dll', + '<(module_root_dir)/lib/libgio-2.0-0.dll', + '<(module_root_dir)/lib/libglib-2.0-0.dll', + '<(module_root_dir)/lib/libgmodule-2.0-0.dll', + '<(module_root_dir)/lib/libgobject-2.0-0.dll', + '<(module_root_dir)/lib/libgsf-1-114.dll', + '<(module_root_dir)/lib/libgsf-win32-1-114.dll', + '<(module_root_dir)/lib/libgthread-2.0-0.dll', + '<(module_root_dir)/lib/libintl-8.dll', + '<(module_root_dir)/lib/libjpeg-62.dll', + '<(module_root_dir)/lib/liblcms2-2.dll', + '<(module_root_dir)/lib/libopenjpeg-1.dll', + '<(module_root_dir)/lib/libopenslide-0.dll', + '<(module_root_dir)/lib/libpango-1.0-0.dll', + '<(module_root_dir)/lib/libpangocairo-1.0-0.dll', + '<(module_root_dir)/lib/libpangowin32-1.0-0.dll', + '<(module_root_dir)/lib/libpixman-1-0.dll', + '<(module_root_dir)/lib/libpng14-14.dll', + '<(module_root_dir)/lib/libquadmath-0.dll', + '<(module_root_dir)/lib/libsqlite3-0.dll', + '<(module_root_dir)/lib/libssp-0.dll', + '<(module_root_dir)/lib/libstdc++-6.dll', + '<(module_root_dir)/lib/libtiff-5.dll', + '<(module_root_dir)/lib/libvips-42.dll', + '<(module_root_dir)/lib/libxml2-2.dll', + '<(module_root_dir)/lib/zlib1.dll' + ] + }] + }] + ] }] } diff --git a/binding.js b/binding.js new file mode 100644 index 00000000..bda0dbee --- /dev/null +++ b/binding.js @@ -0,0 +1,111 @@ +'use strict'; + +var fs = require('fs'); +var path = require('path'); +var zlib = require('zlib'); + +var semver = require('semver'); +var request = require('request'); +var tar = require('tar'); + +var tmp = require('os').tmpdir(); + +var distBaseUrl = 'https://dl.bintray.com/lovell/sharp/'; + +var vipsHeaderPath = path.join(__dirname, 'include', 'vips', 'vips.h'); + +// -- Helpers + +// Does this file exist? +var isFile = function(file) { + var exists = false; + try { + exists = fs.statSync(file).isFile(); + } catch (err) {} + return exists; +}; + +var unpack = function(tarPath) { + var extractor = tar.Extract({ + path: __dirname + }); + extractor.on('error', error); + extractor.on('end', function() { + if (!isFile(vipsHeaderPath)) { + error('Could not unpack ' + tarPath); + } + }); + fs.createReadStream(tarPath).on('error', error) + .pipe(zlib.Unzip()) + .pipe(extractor); +}; + +// Error +var error = function(msg) { + if (msg instanceof Error) { + msg = msg.message; + } + process.stderr.write('ERROR: ' + msg + '\n'); + process.exit(1); +}; + +// -- Binary downloaders + +module.exports.download_vips = function() { + // Has vips been installed locally? + if (!isFile(vipsHeaderPath)) { + // 32-bit + if (process.arch === 'ia32') { + error('32-bit systems require manual installation - see http://sharp.dimens.io/en/stable/install/'); + } + // Ensure libc >= 2.15 + var lddVersion = process.env.LDD_VERSION; + if (lddVersion) { + var libcVersion = lddVersion ? lddVersion.split(/\n/)[0].split(' ').slice(-1)[0].trim() : ''; + if (libcVersion && semver.lt(libcVersion + '.0', '2.15.0')) { + error('Unsupported version of libc:\n' + lddVersion + '\nPlease see http://sharp.dimens.io/en/stable/install/'); + } + } + // Platform-specific .tar.gz + var tarFilename = ['libvips', process.env.npm_package_config_libvips, process.platform.substr(0, 3)].join('-') + '.tar.gz'; + var tarPath = path.join(__dirname, 'packaging', tarFilename); + if (isFile(tarPath)) { + unpack(tarPath); + } else { + // Download + tarPath = path.join(tmp, tarFilename); + var tmpFile = fs.createWriteStream(tarPath).on('finish', function() { + unpack(tarPath); + }); + request(distBaseUrl + tarFilename).on('response', function(response) { + if (response.statusCode !== 200) { + error(distBaseUrl + tarFilename + ' status code ' + response.statusCode); + } + }).on('error', function(err) { + error('Download from ' + distBaseUrl + tarFilename + ' failed: ' + err.message); + }).pipe(tmpFile); + } + } +}; + +module.exports.use_global_vips = function() { + var useGlobalVips = false; + var globalVipsVersion = process.env.GLOBAL_VIPS_VERSION; + if (globalVipsVersion) { + useGlobalVips = semver.gte( + globalVipsVersion, + process.env.npm_package_config_libvips + ); + } + if (process.platform === 'darwin' && !useGlobalVips) { + if (globalVipsVersion) { + error( + 'Found libvips ' + globalVipsVersion + ' but require ' + process.env.npm_package_config_libvips + + '\nPlease upgrade libvips by running: brew update && brew upgrade' + ); + } else { + error('Please install libvips by running: brew install homebrew/science/vips --with-webp --with-graphicsmagick'); + } + } + process.stdout.write(useGlobalVips ? 'true' : 'false'); +}; diff --git a/index.js b/index.js index 0f569010..0062a9f8 100755 --- a/index.js +++ b/index.js @@ -11,6 +11,11 @@ var BluebirdPromise = require('bluebird'); var sharp = require('./build/Release/sharp'); var libvipsVersion = sharp.libvipsVersion(); +var libvipsVersionMin = require('./package.json').config.libvips; + +if (semver.lt(libvipsVersion, libvipsVersionMin)) { + throw new Error('Found libvips ' + libvipsVersion + ' but require at least ' + libvipsVersionMin); +} var maximum = { width: 0x3FFF, diff --git a/package.json b/package.json index ac1a52b3..58eaef9f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sharp", - "version": "0.11.4", + "version": "0.12.0", "author": "Lovell Fuller ", "contributors": [ "Pierre Inglebert ", @@ -25,8 +25,7 @@ "test": "VIPS_WARNING=0 node ./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha -- --slow=5000 --timeout=20000 ./test/unit/*.js", "test-clean": "npm run clean && npm install && npm test", "test-leak": "./test/leak/leak.sh", - "test-win32-node": "node ./node_modules/mocha/bin/mocha --slow=5000 --timeout=30000 ./test/unit/*.js", - "test-win32-iojs": "iojs ./node_modules/mocha/bin/mocha --slow=5000 --timeout=30000 ./test/unit/*.js" + "test-win32": "node ./node_modules/mocha/bin/mocha --slow=5000 --timeout=30000 ./test/unit/*.js" }, "main": "index.js", "repository": { @@ -49,7 +48,9 @@ "bluebird": "^3.0.5", "color": "^0.10.1", "nan": "^2.1.0", - "semver": "^5.0.3" + "semver": "^5.0.3", + "request": "^2.65.0", + "tar": "^2.2.1" }, "devDependencies": { "async": "^1.5.0", @@ -64,6 +65,9 @@ "bufferutil": "^1.2.1" }, "license": "Apache-2.0", + "config": { + "libvips": "8.1.1" + }, "engines": { "node": ">=0.10" } diff --git a/packaging/build.sh b/packaging/build.sh new file mode 100755 index 00000000..b543436e --- /dev/null +++ b/packaging/build.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +# Is docker available? + +if ! type docker >/dev/null; then + echo "Please install docker" + exit 1 +fi + +# TODO: docker v1.9.0 will allow build-time args - https://github.com/docker/docker/pull/15182 + +# Windows + +docker build -t vips-dev-win win +WIN_CONTAINER_ID=$(docker run -d vips-dev-win) +docker cp $WIN_CONTAINER_ID:/libvips-8.1.1-win.tar.gz . +docker rm $WIN_CONTAINER_ID + +# Linux + +docker build -t vips-dev-lin lin +LIN_CONTAINER_ID=$(docker run -d vips-dev-lin) +docker cp $LIN_CONTAINER_ID:/libvips-8.1.1-lin.tar.gz . +docker rm $LIN_CONTAINER_ID + +# Checksums + +sha256sum *.tar.gz diff --git a/packaging/lin/Dockerfile b/packaging/lin/Dockerfile new file mode 100644 index 00000000..d2fa193a --- /dev/null +++ b/packaging/lin/Dockerfile @@ -0,0 +1,99 @@ +FROM ubuntu:precise +MAINTAINER Lovell Fuller + +RUN apt-get update && apt-get install -y build-essential autoconf libtool nasm gtk-doc-tools texinfo + +ENV DEPS /deps +ENV TARGET /target +RUN mkdir ${DEPS} && mkdir ${TARGET} + +ENV PKG_CONFIG_PATH ${PKG_CONFIG_PATH}:${TARGET}/lib/pkgconfig +ENV PATH ${PATH}:${TARGET}/bin + +ENV CPPFLAGS -I${TARGET}/include +ENV LDFLAGS -L${TARGET}/lib +ENV MAKEFLAGS -j2 + +RUN mkdir ${DEPS}/zlib +RUN curl -Ls http://zlib.net/zlib-1.2.8.tar.xz | tar xJC ${DEPS}/zlib --strip-components=1 +WORKDIR ${DEPS}/zlib +RUN ./configure --prefix=${TARGET} && make install +RUN rm ${TARGET}/lib/libz.a + +RUN mkdir ${DEPS}/ffi +RUN curl -Ls ftp://sourceware.org/pub/libffi/libffi-3.2.1.tar.gz | tar xzC ${DEPS}/ffi --strip-components=1 +WORKDIR ${DEPS}/ffi +RUN ./configure --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking --disable-builddir && make install-strip + +RUN mkdir ${DEPS}/glib +RUN curl -Ls http://ftp.gnome.org/pub/gnome/sources/glib/2.46/glib-2.46.2.tar.xz | tar xJC ${DEPS}/glib --strip-components=1 +WORKDIR ${DEPS}/glib +RUN ./configure --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking && make install-strip + +RUN mkdir ${DEPS}/xml2 +RUN curl -Ls http://xmlsoft.org/sources/libxml2-2.9.2.tar.gz | tar xzC ${DEPS}/xml2 --strip-components=1 +WORKDIR ${DEPS}/xml2 +RUN ./configure --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking --without-python --with-zlib=${TARGET} && make install-strip + +RUN mkdir ${DEPS}/gsf +RUN curl -Ls http://ftp.gnome.org/pub/GNOME/sources/libgsf/1.14/libgsf-1.14.34.tar.xz | tar xJC ${DEPS}/gsf --strip-components=1 +WORKDIR ${DEPS}/gsf +RUN ./configure --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking && make install-strip + +RUN mkdir ${DEPS}/exif +RUN curl -Ls http://kent.dl.sourceforge.net/project/libexif/libexif/0.6.21/libexif-0.6.21.tar.bz2 | tar xjC ${DEPS}/exif --strip-components=1 +WORKDIR ${DEPS}/exif +RUN ./configure --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking && make install-strip + +RUN mkdir ${DEPS}/jpeg +RUN curl -Ls http://kent.dl.sourceforge.net/project/libjpeg-turbo/1.4.2/libjpeg-turbo-1.4.2.tar.gz | tar xzC ${DEPS}/jpeg --strip-components=1 +WORKDIR ${DEPS}/jpeg +RUN ./configure --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking --with-jpeg8 --without-turbojpeg && make install-strip + +RUN mkdir ${DEPS}/png +RUN curl -Ls http://kent.dl.sourceforge.net/project/libpng/libpng16/1.6.18/libpng-1.6.18.tar.xz | tar xJC ${DEPS}/png --strip-components=1 +WORKDIR ${DEPS}/png +RUN ./configure --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking && make install-strip + +RUN mkdir ${DEPS}/lcms2 +RUN curl -Ls http://kent.dl.sourceforge.net/project/lcms/lcms/2.7/lcms2-2.7.tar.gz | tar xzC ${DEPS}/lcms2 --strip-components=1 +WORKDIR ${DEPS}/lcms2 +RUN ./configure --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking && make install-strip + +RUN mkdir ${DEPS}/webp +RUN curl -Ls http://downloads.webmproject.org/releases/webp/libwebp-0.4.4.tar.gz | tar xzC ${DEPS}/webp --strip-components=1 +WORKDIR ${DEPS}/webp +RUN ./configure --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking && make install-strip + +RUN mkdir ${DEPS}/tiff +RUN curl -Ls http://download.osgeo.org/libtiff/tiff-4.0.6.tar.gz /deps/tiff.tar.gz | tar xzC ${DEPS}/tiff --strip-components=1 +WORKDIR ${DEPS}/tiff +RUN ./configure --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking && make install-strip +RUN rm ${TARGET}/lib/libtiffxx* + +RUN mkdir ${DEPS}/magick +RUN curl -Ls http://www.imagemagick.org/download/releases/ImageMagick-6.9.2-5.tar.xz | tar xJC ${DEPS}/magick --strip-components=1 +WORKDIR ${DEPS}/magick +RUN ./configure --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking --without-magick-plus-plus && make install-strip + +RUN mkdir ${DEPS}/vips +RUN curl -Ls http://www.vips.ecs.soton.ac.uk/supported/8.1/vips-8.1.1.tar.gz | tar xzC ${DEPS}/vips --strip-components=1 +WORKDIR ${DEPS}/vips +RUN ./configure --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking \ + --disable-debug --disable-introspection --without-python --without-fftw \ + --with-zip-includes=${TARGET}/include --with-zip-libraries=${TARGET}/lib \ + --with-jpeg-includes=${TARGET}/include --with-jpeg-libraries=${TARGET}/lib \ + && make install-strip +# Remove the C++ bindings +RUN rm ${TARGET}/lib/*.la +RUN rm ${TARGET}/lib/libvipsCC* +RUN rm ${TARGET}/lib/libvips-cpp.* +RUN rm ${TARGET}/include/vips/vipsc++.h +RUN rm ${TARGET}/include/vips/vipscpp.h +RUN rm ${TARGET}/include/vips/V*.h + +WORKDIR ${TARGET}/lib +RUN rm -rf pkgconfig .libs + +WORKDIR ${TARGET} +RUN GZIP=-9 tar czf /libvips-8.1.1-lin.tar.gz include lib diff --git a/packaging/win/Dockerfile b/packaging/win/Dockerfile new file mode 100644 index 00000000..764cde06 --- /dev/null +++ b/packaging/win/Dockerfile @@ -0,0 +1,16 @@ +FROM ubuntu:precise +MAINTAINER Lovell Fuller + +RUN apt-get update && apt-get install -y curl zip + +# Fetch and unzip +RUN mkdir /vips +WORKDIR /vips +RUN curl -O http://www.vips.ecs.soton.ac.uk/supported/8.1/win32/vips-dev-w64-8.1.1-2.zip +RUN unzip vips-dev-w64-8.1.1-2.zip + +# Clean and zip +WORKDIR /vips/vips-dev-8.1.1 +RUN rm bin/libvipsCC-42.dll bin/libvips-cpp-42.dll +RUN cp bin/*.dll lib/ +RUN GZIP=-9 tar czf /libvips-8.1.1-win.tar.gz include lib/libvips.lib lib/libglib-2.0.lib lib/libgobject-2.0.lib lib/*.dll