Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

heif: Unsupported feature: Unsupported codec (4.3000) #4050

Closed
1 task done
robbyemmert opened this issue Apr 2, 2024 · 22 comments
Closed
1 task done

heif: Unsupported feature: Unsupported codec (4.3000) #4050

robbyemmert opened this issue Apr 2, 2024 · 22 comments

Comments

@robbyemmert
Copy link

Possible bug

Is this a possible bug in a feature of sharp, unrelated to installation?

This is a bug with sharp at runtime. Installation happened fine. I am able to resize any type of image except for heic.

  • [x ] Running npm install sharp completes without error.
  • Running node -e "require('sharp')" completes without error.

If you cannot confirm both of these, please open an installation issue instead.

Are you using the latest version of sharp?

  • [ x] I am using the latest version of sharp as reported by npm view sharp dist-tags.latest.

If you cannot confirm this, please upgrade to the latest version and try again before opening an issue.

If you are using another package which depends on a version of sharp that is not the latest, please open an issue against that package instead.

What is the output of running npx envinfo --binaries --system --npmPackages=sharp --npmGlobalPackages=sharp?

System:
OS: Linux 5.19 Debian GNU/Linux 12 (bookworm) 12 (bookworm)
CPU: (2) x64 DO-Regular
Memory: 2.22 GB / 3.82 GB
Container: Yes
Shell: 5.2.15 - /bin/bash
Binaries:
Node: 20.12.0 - /usr/local/bin/node
Yarn: 4.1.1 - /usr/local/bin/yarn
npm: 10.5.0 - /usr/local/bin/npm
npmPackages:
sharp: ^0.33.3 => 0.33.3

What are the steps to reproduce?

async writeVariation(url: string, variation: ImageVariation) {
        const meta = await sharp(url).metadata()
        const maxDimension = meta.height > meta.width ? 'height' : 'width'
        const secondDimension = maxDimension === 'height' ? 'width' : 'height'

        const urlParts = parse(url)
        const process = sharp(url).resize({
            position: 'center',
            fit: 'inside',
            width: variation.maxWidth,
            height: variation.maxHeight,
        })

        await process.toFile(resolve(urlParts.dir, `${variation.name}_${urlParts.base}`))

        return await process.metadata()
    }

The toFile function fails when processing heic files.

I tried using the bundled binary, enabling every os and cpu architecture involved (and more) in my yarn config (yarn 4)

I tried using a custom installed version
I can run heif-convert --list-decoders and verify that heic/heif codecs are in fact installed.
I can use the exact example image I provided below to heif-convert to a jpg.
But whenever I try to parse a heic file I get the error heif: Unsupported feature: Unsupported codec (4.3000)

I have tried configuring Alpine linux and Debian and Mac OS.

It appears to work on my mac, but I get the codec error as soon as I deploy to any linux variation.

I have also tried running this in Node 16, Node 18, and Node 20, with yarn 1 and 4. I get the EXACT same issue in every case.

This looks like a runtime bug with sharp.

What is the expected behaviour?

I want to support iPhone images—THE most common photo use case for my application.

Please provide a minimal, standalone code sample, without other dependencies, that demonstrates this problem

see above

Please provide sample image(s) that help explain this problem

https://heic.digital/download-sample/sewing-threads.heic
or any heic file.

@robbyemmert
Copy link
Author

There are a bunch of others getting this same error. There doesn't seem to be a conclusive answer out there other than "upgrade to the latest version" which I have. I've also tried backdating to version 3.32.

I've also tried every workaround/fix in every issue with the same error, so I'm pretty sure this isn't a duplicate.

@robbyemmert
Copy link
Author

robbyemmert commented Apr 2, 2024

I can confirm, if I downgrade to 0.26.2 and it works as stated in #2518

This confirms it's not a problem with my setup or implementation, but a problem with sharp.

Is modern sharp going to support heic files anytime soon? I need to know, since using a pinned version is not going to be considered a viable option in my case for security reasons, long term.

Also, it might be worth mentioning that sharp 3+ does't support heic files in the readme until it's fixed.

@lovell lovell added installation and removed triage labels Apr 2, 2024
@lovell
Copy link
Owner

lovell commented Apr 2, 2024

The prebuilt binaries do not support the patented HEVC compression, as used by HEIC images. Processing HEIC images requires that sharp be built from source against a globally-installed libvips that itself has been compiled with support for libheif+libde256.

This works with the latest version of sharp, and requires some additional dependencies that are listed in the documentation.

https://sharp.pixelplumbing.com/install#custom-libvips

"To use a custom, globally-installed version of libvips instead of the provided binaries, make sure it is at least the version listed under engines.libvips in the package.json file and that it can be located using pkg-config --modversion vips-cpp.

The latest version of sharp v0.33.3 requires libvips v8.15.2.

"libvips": ">=8.15.2"

https://sharp.pixelplumbing.com/install#building-from-source

"Building from source requires:

  • C++11 compiler
  • node-addon-api version 7+
  • node-gyp version 9+ and its dependencies

At install time, sharp logs all decisions it makes relating to its ability to build from source.

If you are still having problems, please provide the complete output of running npm install sharp --build-from-source --verbose --foreground-scripts.

@robbyemmert
Copy link
Author

robbyemmert commented Apr 2, 2024

I'll provide more details shortly, but in debugging locally, I encountered this error:

<string>:114: SyntaxWarning: invalid escape sequence '\/'
gyp info spawn make
gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
  CC(target) Release/obj.target/nothing/../../node-addon-api/nothing.o
  LIBTOOL-STATIC Release/nothing.a
warning: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool: archive library: Release/nothing.a the table of contents is empty (no object file members in the library define global symbols)
  TOUCH Release/obj.target/libvips-cpp.stamp
  CXX(target) Release/obj.target/sharp-darwin-arm64/common.o
  CXX(target) Release/obj.target/sharp-darwin-arm64/metadata.o
../metadata.cc:233:46: error: no member named 'NewOrCopy' in 'Napi::Buffer<char>'
        info.Set("exif", Napi::Buffer<char>::NewOrCopy(env, baton->exif, baton->exifLength, sharp::FreeCallback));
                         ~~~~~~~~~~~~~~~~~~~~^
../metadata.cc:236:45: error: no member named 'NewOrCopy' in 'Napi::Buffer<char>'
        info.Set("icc", Napi::Buffer<char>::NewOrCopy(env, baton->icc, baton->iccLength, sharp::FreeCallback));
                        ~~~~~~~~~~~~~~~~~~~~^
../metadata.cc:239:46: error: no member named 'NewOrCopy' in 'Napi::Buffer<char>'
        info.Set("iptc", Napi::Buffer<char>::NewOrCopy(env, baton->iptc, baton->iptcLength, sharp::FreeCallback));
                         ~~~~~~~~~~~~~~~~~~~~^
../metadata.cc:242:45: error: no member named 'NewOrCopy' in 'Napi::Buffer<char>'
        info.Set("xmp", Napi::Buffer<char>::NewOrCopy(env, baton->xmp, baton->xmpLength, sharp::FreeCallback));
                        ~~~~~~~~~~~~~~~~~~~~^
../metadata.cc:246:31: error: no member named 'NewOrCopy' in 'Napi::Buffer<char>'
          Napi::Buffer<char>::NewOrCopy(env, baton->tifftagPhotoshop,
          ~~~~~~~~~~~~~~~~~~~~^
5 errors generated.
make: *** [Release/obj.target/sharp-darwin-arm64/metadata.o] Error 1
gyp ERR! build error 
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack at ChildProcess.<anonymous>

I installed libvips locally with brew install libvips and re-installed node_modules via yarn 4. It tried to rebuild sharp and failed with this error.

Any idea what that means, and why Napi::Buffer doesn't have NewOrCopy?

Thanks,

@robbyemmert
Copy link
Author

robbyemmert commented Apr 2, 2024

Actually, I got this error earlier, and installed the latest version of node-gyp (10.1.0) as a result.

harp: Detected globally-installed libvips v8.15.2
sharp: Attempting to build from source via node-gyp
sharp: Found node-addon-api
sharp: Found node-gyp version 10.1.0
sharp: See https://sharp.pixelplumbing.com/install#building-from-source
�[31m�[1mUsage Error�[22m�[39m: Couldn't find a script name "node-gyp" in the top-level (used by sharp@npm:0.33.3). This typically happens because some package depends on "node-gyp" to build itself, but didn't list it in their dependencies. To fix that, please run "yarn add node-gyp" into your top-level workspace. You also can open an issue on the repository of the specified package to suggest them to use an optional peer dependency.

EDIT: I think I got it. I was missing node-addon-api as well, which was documented in the link provided in the error. Somehow I missed this the first time around.

I will take some more diagnostic info from our beta environment, then we should be able to answer the original question.

@robbyemmert
Copy link
Author

robbyemmert commented Apr 2, 2024

Here's the response of npm install sharp --build-from-source --verbose --foreground-scripts from our debian based docker environment (the official node:20 image, base tag)

For context, this was run in a docker environment on an M1 mac (see specs above), reproducing our production builds, which happen in a linux x64 github action, and are run in an x64 linux environment (ubuntu)

The test docker image was built and run using: docker build --platform linux/arm64 -t my-app . && docker run -it --rm --name my-running-app my-app /bin/sh

npm verb cli /usr/local/bin/node /usr/local/bin/npm
npm info using npm@10.5.0
npm info using node@v20.12.0
npm verb title npm install sharp
npm verb argv "install" "sharp" "--build-from-source" "--loglevel" "verbose" "--foreground-scripts" "--legacy-peer-deps"
npm verb logfile logs-max:10 dir:/root/.npm/_logs/2024-04-02T20_16_54_670Z-
npm verb logfile /root/.npm/_logs/2024-04-02T20_16_54_670Z-debug-0.log
npm http fetch GET 200 https://registry.npmjs.org/sharp 251ms (cache hit)
npm verb reify failed optional dependency /app/node_modules/fsevents
npm verb reify failed optional dependency /app/node_modules/@img/sharp-win32-x64
npm verb reify failed optional dependency /app/node_modules/@img/sharp-win32-ia32
npm verb reify failed optional dependency /app/node_modules/@img/sharp-wasm32
npm verb reify failed optional dependency /app/node_modules/@emnapi/runtime
npm verb reify failed optional dependency /app/node_modules/@img/sharp-linuxmusl-x64
npm verb reify failed optional dependency /app/node_modules/@img/sharp-linux-x64
npm verb reify failed optional dependency /app/node_modules/@img/sharp-linux-s390x
npm verb reify failed optional dependency /app/node_modules/@img/sharp-linux-arm
npm verb reify failed optional dependency /app/node_modules/@img/sharp-libvips-linuxmusl-x64
npm verb reify failed optional dependency /app/node_modules/@img/sharp-libvips-linux-x64
npm verb reify failed optional dependency /app/node_modules/@img/sharp-libvips-linux-s390x
npm verb reify failed optional dependency /app/node_modules/@img/sharp-libvips-linux-arm
npm verb reify failed optional dependency /app/node_modules/@img/sharp-libvips-darwin-x64
npm verb reify failed optional dependency /app/node_modules/@img/sharp-libvips-darwin-arm64
npm verb reify failed optional dependency /app/node_modules/@img/sharp-darwin-x64
npm verb reify failed optional dependency /app/node_modules/@img/sharp-darwin-arm64
npm http fetch GET 200 https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.3.tgz 188ms (cache miss)
npm http fetch POST 200 https://registry.npmjs.org/-/npm/v1/security/advisories/bulk 242ms
npm http fetch GET 200 https://registry.npmjs.org/semver 76ms (cache miss)
npm http fetch GET 200 https://registry.npmjs.org/json5 88ms (cache miss)
npm http fetch GET 200 https://registry.npmjs.org/pac-resolver 187ms (cache miss)
npm http fetch GET 200 https://registry.npmjs.org/jsonwebtoken 191ms (cache miss)
npm http fetch GET 200 https://registry.npmjs.org/xlsx 214ms (cache miss)
npm http fetch GET 200 https://registry.npmjs.org/degenerator 218ms (cache miss)
npm http fetch GET 200 https://registry.npmjs.org/simple-update-notifier 58ms (cache miss)
npm http fetch GET 200 https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.2.tgz 552ms (cache miss)
npm http fetch GET 200 [REDACTED] 418ms (cache miss)
npm http fetch GET 200 https://registry.npmjs.org/find-babel-config 51ms (cache miss)
npm http fetch GET 200 https://registry.npmjs.org/pac-proxy-agent 70ms (cache miss)
npm http fetch GET 200 https://registry.npmjs.org/@nlpjs%2fxtables 496ms (cache miss)
npm http fetch GET 200 https://registry.npmjs.org/nodemon 108ms (cache miss)
npm http fetch GET 200 https://registry.npmjs.org/babel-plugin-module-resolver 55ms (cache miss)
npm http fetch GET 200 https://registry.npmjs.org/proxy-agent 66ms (cache miss)
npm http fetch GET 200 https://registry.npmjs.org/node-nlp 353ms (cache miss)
npm http fetch GET 200 https://registry.npmjs.org/superagent-proxy 72ms (cache miss)
npm http fetch GET 200 [REDACTED] 459ms (cache miss)
npm http fetch GET 200 https://registry.npmjs.org/docusign-esign 131ms (cache miss)

The obvious question is what are the optional dependencies, and why are they failing?

Just as a reminder, we are using yarn 4, so behavior might differ slightly from NPM

@lovell
Copy link
Owner

lovell commented Apr 2, 2024

Thanks for the log, the optional dependencies are not important here. Because you intend to build from source, what is important here is the lack of evidence of any install script having run.

Please ensure you are allowing scripts to run, for example ensure that you've not set ignore-scripts anywhere in any npm configuration such as .npmrc files (yarn has a similarly-named option).

https://docs.npmjs.com/cli/v10/commands/npm-install#ignore-scripts
https://yarnpkg.com/configuration/yarnrc#enableScripts

@robbyemmert
Copy link
Author

I must have run npm install first, and it probably skipped sharp because it was already built or something.

I ran the same command in the same environment, ensuring that there is no pre-existing node_modules folder, and I got something a lot more useful. It is too long to post the full output, but here is the part where it tries to build the binaries. The rest of it just looks like it's downloading dependencies.

gyp verb download contents checksum {"node-v20.12.0-headers.tar.gz":"aa2d7c2734287fbb757d2e64050ad8454b68ea6eda3c870b5cb386daf059e354"}
gyp verb validating download checksum for node-v20.12.0-headers.tar.gz (aa2d7c2734287fbb757d2e64050ad8454b68ea6eda3c870b5cb386daf059e354 == aa2d7c2734287fbb757d2e64050ad8454b68ea6eda3c870b5cb386daf059e354)
gyp verb get node dir target node version installed: 20.12.0
gyp verb build dir attempting to create "build" dir: /app/node_modules/bcrypt/build
gyp verb build dir "build" dir needed to be created? Yes
gyp verb build/config.gypi creating config file
gyp verb build/config.gypi writing out config file: /app/node_modules/bcrypt/build/config.gypi
gyp verb config.gypi checking for gypi file: /app/node_modules/bcrypt/config.gypi
gyp verb common.gypi checking for gypi file: /app/node_modules/bcrypt/common.gypi
gyp verb gyp gyp format was not specified; forcing "make"
gyp info spawn /usr/bin/python3
gyp info spawn args [
gyp info spawn args '/usr/local/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py',
gyp info spawn args 'binding.gyp',
gyp info spawn args '-f',
gyp info spawn args 'make',
gyp info spawn args '-I',
gyp info spawn args '/app/node_modules/bcrypt/build/config.gypi',
gyp info spawn args '-I',
gyp info spawn args '/usr/local/lib/node_modules/npm/node_modules/node-gyp/addon.gypi',
gyp info spawn args '-I',
gyp info spawn args '/root/.cache/node-gyp/20.12.0/include/node/common.gypi',
gyp info spawn args '-Dlibrary=shared_library',
gyp info spawn args '-Dvisibility=default',
gyp info spawn args '-Dnode_root_dir=/root/.cache/node-gyp/20.12.0',
gyp info spawn args '-Dnode_gyp_dir=/usr/local/lib/node_modules/npm/node_modules/node-gyp',
gyp info spawn args '-Dnode_lib_file=/root/.cache/node-gyp/20.12.0/<(target_arch)/node.lib',
gyp info spawn args '-Dmodule_root_dir=/app/node_modules/bcrypt',
gyp info spawn args '-Dnode_engine=v8',
gyp info spawn args '--depth=.',
gyp info spawn args '--no-parallel',
gyp info spawn args '--generator-output',
gyp info spawn args 'build',
gyp info spawn args '-Goutput_dir=.'
gyp info spawn args ]
gyp info ok #######] \ reify:@faker-js/faker: info run bcrypt@5.1.1 install node_modules/bcrypt node-pre-gyp install
gyp info it worked if it ends with oks/faker: info run bcrypt@5.1.1 install node_modules/bcrypt node-pre-gyp install
gyp verb cli [
gyp verb cli '/usr/local/bin/node',
gyp verb cli '/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js',
gyp verb cli 'build',
gyp verb cli '--fallback-to-build',
gyp verb cli '--module=/app/node_modules/bcrypt/lib/binding/napi-v3/bcrypt_lib.node',
gyp verb cli '--module_name=bcrypt_lib',
gyp verb cli '--module_path=/app/node_modules/bcrypt/lib/binding/napi-v3',
gyp verb cli '--napi_version=9',
gyp verb cli '--node_abi_napi=napi',
gyp verb cli '--napi_build_version=3',
gyp verb cli '--node_napi_label=napi-v3'
gyp verb cli ]
gyp info using node-gyp@10.0.1
gyp info using node@20.12.0 | linux | arm64
gyp verb build type Release
gyp verb architecture arm64
gyp verb node dev dir /root/.cache/node-gyp/20.12.0
gyp verb python /usr/bin/python3
gyp verb `which` succeeded for `make` /usr/bin/make
gyp verb bin symlinks created symlink to "/usr/bin/python3" in "/app/node_modules/bcrypt/build/node_gyp_bins" and added to PATH
gyp info spawn make
gyp info spawn args [ 'V=1', 'BUILDTYPE=Release', '-C', 'build' ]
make: Entering directory '/app/node_modules/bcrypt/build'
  cc -o Release/obj.target/nothing/node_modules/node-addon-api/nothing.o ../node_modules/node-addon-api/nothing.c '-DNODE_GYP_MODULE_NAME=nothing' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_GLIBCXX_USE_CXX11_ABI=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-D__STDC_FORMAT_MACROS' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' -I/root/.cache/node-gyp/20.12.0/include/node -I/root/.cache/node-gyp/20.12.0/src -I/root/.cache/node-gyp/20.12.0/deps/openssl/config -I/root/.cache/node-gyp/20.12.0/deps/openssl/openssl/include -I/root/.cache/node-gyp/20.12.0/deps/uv/include -I/root/.cache/node-gyp/20.12.0/deps/zlib -I/root/.cache/node-gyp/20.12.0/deps/v8/include  -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -O3 -fno-omit-frame-pointer  -MMD -MF ./Release/.deps/Release/obj.target/nothing/node_modules/node-addon-api/nothing.o.d.raw   -c
rm -f Release/obj.target/node_modules/node-addon-api/nothing.a Release/obj.target/node_modules/node-addon-api/nothing.a.ar-file-list; mkdir -p `dirname Release/obj.target/node_modules/node-addon-api/nothing.a`
ar crs Release/obj.target/node_modules/node-addon-api/nothing.a @Release/obj.target/node_modules/node-addon-api/nothing.a.ar-file-list
  ln -f "Release/obj.target/node_modules/node-addon-api/nothing.a" "Release/nothing.a" 2>/dev/null || (rm -rf "Release/nothing.a" && cp -af "Release/obj.target/node_modules/node-addon-api/nothing.a" "Release/nothing.a")
  g++ -o Release/obj.target/bcrypt_lib/src/blowfish.o ../src/blowfish.cc '-DNODE_GYP_MODULE_NAME=bcrypt_lib' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_GLIBCXX_USE_CXX11_ABI=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-D__STDC_FORMAT_MACROS' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' '-D_GNU_SOURCE' '-DBUILDING_NODE_EXTENSION' -I/root/.cache/node-gyp/20.12.0/include/node -I/root/.cache/node-gyp/20.12.0/src -I/root/.cache/node-gyp/20.12.0/deps/openssl/config -I/root/.cache/node-gyp/20.12.0/deps/openssl/openssl/include -I/root/.cache/node-gyp/20.12.0/deps/uv/include -I/root/.cache/node-gyp/20.12.0/deps/zlib -I/root/.cache/node-gyp/20.12.0/deps/v8/include -I/app/node_modules/bcrypt/node_modules/node-addon-api  -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -O3 -fno-omit-frame-pointer -fno-rtti -std=gnu++17 -MMD -MF ./Release/.deps/Release/obj.target/bcrypt_lib/src/blowfish.o.d.raw   -c
  g++ -o Release/obj.target/bcrypt_lib/src/bcrypt.o ../src/bcrypt.cc '-DNODE_GYP_MODULE_NAME=bcrypt_lib' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_GLIBCXX_USE_CXX11_ABI=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-D__STDC_FORMAT_MACROS' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' '-D_GNU_SOURCE' '-DBUILDING_NODE_EXTENSION' -I/root/.cache/node-gyp/20.12.0/include/node -I/root/.cache/node-gyp/20.12.0/src -I/root/.cache/node-gyp/20.12.0/deps/openssl/config -I/root/.cache/node-gyp/20.12.0/deps/openssl/openssl/include -I/root/.cache/node-gyp/20.12.0/deps/uv/include -I/root/.cache/node-gyp/20.12.0/deps/zlib -I/root/.cache/node-gyp/20.12.0/deps/v8/include -I/app/node_modules/bcrypt/node_modules/node-addon-api  -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -O3 -fno-omit-frame-pointer -fno-rtti -std=gnu++17 -MMD -MF ./Release/.deps/Release/obj.target/bcrypt_lib/src/bcrypt.o.d.raw   -c
  g++ -o Release/obj.target/bcrypt_lib/src/bcrypt_node.o ../src/bcrypt_node.cc '-DNODE_GYP_MODULE_NAME=bcrypt_lib' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_GLIBCXX_USE_CXX11_ABI=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-D__STDC_FORMAT_MACROS' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' '-D_GNU_SOURCE' '-DBUILDING_NODE_EXTENSION' -I/root/.cache/node-gyp/20.12.0/include/node -I/root/.cache/node-gyp/20.12.0/src -I/root/.cache/node-gyp/20.12.0/deps/openssl/config -I/root/.cache/node-gyp/20.12.0/deps/openssl/openssl/include -I/root/.cache/node-gyp/20.12.0/deps/uv/include -I/root/.cache/node-gyp/20.12.0/deps/zlib -I/root/.cache/node-gyp/20.12.0/deps/v8/include -I/app/node_modules/bcrypt/node_modules/node-addon-api  -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -O3 -fno-omit-frame-pointer -fno-rtti -std=gnu++17 -MMD -MF ./Release/.deps/Release/obj.target/bcrypt_lib/src/bcrypt_node.o.d.raw   -c
  g++ -o Release/obj.target/bcrypt_lib.node -shared -pthread -rdynamic  -Wl,-soname=bcrypt_lib.node -Wl,--start-group Release/obj.target/bcrypt_lib/src/blowfish.o Release/obj.target/bcrypt_lib/src/bcrypt.o Release/obj.target/bcrypt_lib/src/bcrypt_node.o Release/obj.target/node_modules/node-addon-api/nothing.a -Wl,--end-group 
  ln -f "Release/obj.target/bcrypt_lib.node" "Release/bcrypt_lib.node" 2>/dev/null || (rm -rf "Release/bcrypt_lib.node" && cp -af "Release/obj.target/bcrypt_lib.node" "Release/bcrypt_lib.node")
  ln -f "Release/bcrypt_lib.node" "/app/node_modules/bcrypt/lib/binding/napi-v3/bcrypt_lib.node" 2>/dev/null || (rm -rf "/app/node_modules/bcrypt/lib/binding/napi-v3/bcrypt_lib.node" && cp -af "Release/bcrypt_lib.node" "/app/node_modules/bcrypt/lib/binding/napi-v3/bcrypt_lib.node")
  touch Release/obj.target/action_after_build.stamp
make: Leaving directory '/app/node_modules/bcrypt/build'
gyp info ok 
node-pre-gyp info ok 
npm info run bcrypt@5.1.1 install { code: 0, signal: null }
npm info run puppeteer@13.7.0 install node_modules/puppeteer node install.js

> puppeteer@13.7.0 install
> node install.js

npm info run puppeteer@13.7.0 install { code: 0, signal: null }
npm info run sharp@0.33.3 install node_modules/sharp node install/check

> sharp@0.33.3 install
> node install/check

sharp: Detected --build-from-source flagaker: info run sharp@0.33.3 install node_modules/sharp node install/check
sharp: Attempting to build from source via node-gyp
sharp: Found node-addon-api
sharp: Found node-gyp version 10.1.0
sharp: See https://sharp.pixelplumbing.com/install#building-from-source
gyp info it worked if it ends with oks/faker: info run sharp@0.33.3 install node_modules/sharp node install/check
gyp verb cli [
gyp verb cli '/usr/local/bin/node',
gyp verb cli '/app/node_modules/.bin/node-gyp',
gyp verb cli 'rebuild',
gyp verb cli '--directory=src'
gyp verb cli ]
gyp info using node-gyp@10.1.0
gyp info using node@20.12.0 | linux | arm64
gyp info chdir src
gyp verb clean removing "build" directory
gyp verb find Python Python is not set from command line or npm configuration
gyp verb find Python Python is not set from environment variable PYTHON
gyp verb find Python checking if "python3" can be used
gyp verb find Python - executing "python3" to get executable path
gyp verb find Python - executable path is "/usr/bin/python3"
gyp verb find Python - executing "/usr/bin/python3" to get version
gyp verb find Python - version is "3.11.2"
gyp info find Python using Python version 3.11.2 found at "/usr/bin/python3"
gyp verb get node dir no --target version specified, falling back to host node version: 20.12.0
[##################] / reify:@faker-js/faker: info run sharp@0.33.3 install node_modules/sharp node install/check
gyp verb install input version string "20.12.0"
gyp verb install installing version: 20.12.0
gyp verb install --ensure was passed, so won't reinstall if already installed
gyp verb install version is already installed, need to check "installVersion"
gyp verb got "installVersion" 11
gyp verb needs "installVersion" 11
gyp verb install version is good
gyp verb get node dir target node version installed: 20.12.0
gyp verb build dir attempting to create "build" dir: /app/node_modules/sharp/src/build
gyp verb build dir "build" dir needed to be created? Yes
gyp verb build/config.gypi creating config file
gyp verb build/config.gypi writing out config file: /app/node_modules/sharp/src/build/config.gypi
gyp verb config.gypi checking for gypi file: /app/node_modules/sharp/src/config.gypiules/sharp node install/check
gyp verb common.gypi checking for gypi file: /app/node_modules/sharp/src/common.gypi
gyp verb gyp gyp format was not specified; forcing "make"
gyp info spawn /usr/bin/python3
gyp info spawn args [
gyp info spawn args '/app/node_modules/node-gyp/gyp/gyp_main.py',
gyp info spawn args 'binding.gyp',
gyp info spawn args '-f',
gyp info spawn args 'make',
gyp info spawn args '-I',
gyp info spawn args '/app/node_modules/sharp/src/build/config.gypi',
gyp info spawn args '-I',
gyp info spawn args '/app/node_modules/node-gyp/addon.gypi',
gyp info spawn args '-I',
gyp info spawn args '/root/.cache/node-gyp/20.12.0/include/node/common.gypi',
gyp info spawn args '-Dlibrary=shared_library',
gyp info spawn args '-Dvisibility=default',
gyp info spawn args '-Dnode_root_dir=/root/.cache/node-gyp/20.12.0',
gyp info spawn args '-Dnode_gyp_dir=/app/node_modules/node-gyp',
gyp info spawn args '-Dnode_lib_file=/root/.cache/node-gyp/20.12.0/<(target_arch)/node.lib',
gyp info spawn args '-Dmodule_root_dir=/app/node_modules/sharp/src',
gyp info spawn args '-Dnode_engine=v8',
gyp info spawn args '--depth=.',
gyp info spawn args '--no-parallel',
gyp info spawn args '--generator-output',
gyp info spawn args 'build',
gyp info spawn args '-Goutput_dir=.'
gyp info spawn args ]
gyp verb build type Releasey:@faker-js/faker: info run sharp@0.33.3 install node_modules/sharp node install/check
gyp verb architecture arm64
gyp verb node dev dir /root/.cache/node-gyp/20.12.0
gyp verb python /usr/bin/python3
gyp verb `which` succeeded for `make` /usr/bin/make
gyp verb bin symlinks created symlink to "/usr/bin/python3" in "/app/node_modules/sharp/src/build/node_gyp_bins" and added to PATH
gyp info spawn make
gyp info spawn args [ 'V=1', 'BUILDTYPE=Release', '-C', 'build' ]
make: Entering directory '/app/node_modules/sharp/src/build'
  cc -o Release/obj.target/nothing/../../node-addon-api/nothing.o ../../../node-addon-api/nothing.c '-DNODE_GYP_MODULE_NAME=nothing' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_GLIBCXX_USE_CXX11_ABI=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-D__STDC_FORMAT_MACROS' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' -I/root/.cache/node-gyp/20.12.0/include/node -I/root/.cache/node-gyp/20.12.0/src -I/root/.cache/node-gyp/20.12.0/deps/openssl/config -I/root/.cache/node-gyp/20.12.0/deps/openssl/openssl/include -I/root/.cache/node-gyp/20.12.0/deps/uv/include -I/root/.cache/node-gyp/20.12.0/deps/zlib -I/root/.cache/node-gyp/20.12.0/deps/v8/include  -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -O3 -fno-omit-frame-pointer  -MMD -MF ./Release/.deps/Release/obj.target/nothing/../../node-addon-api/nothing.o.d.raw   -c
rm -f Release/obj.target/../../node-addon-api/nothing.a Release/obj.target/../../node-addon-api/nothing.a.ar-file-list; mkdir -p `dirname Release/obj.target/../../node-addon-api/nothing.a`
ar crs Release/obj.target/../../node-addon-api/nothing.a @Release/obj.target/../../node-addon-api/nothing.a.ar-file-list
  ln -f "Release/obj.target/../../node-addon-api/nothing.a" "Release/nothing.a" 2>/dev/null || (rm -rf "Release/nothing.a" && cp -af "Release/obj.target/../../node-addon-api/nothing.a" "Release/nothing.a")
  touch Release/obj.target/libvips-cpp.stamp
  g++ -o Release/obj.target/sharp-linux-arm64/common.o ../common.cc '-DNODE_GYP_MODULE_NAME=sharp-linux-arm64' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_GLIBCXX_USE_CXX11_ABI=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-D__STDC_FORMAT_MACROS' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' '-DNAPI_VERSION=9' '-DNODE_ADDON_API_DISABLE_DEPRECATED' '-DNODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS' '-DBUILDING_NODE_EXTENSION' -I/root/.cache/node-gyp/20.12.0/include/node -I/root/.cache/node-gyp/20.12.0/src -I/root/.cache/node-gyp/20.12.0/deps/openssl/config -I/root/.cache/node-gyp/20.12.0/deps/openssl/openssl/include -I/root/.cache/node-gyp/20.12.0/deps/uv/include -I/root/.cache/node-gyp/20.12.0/deps/zlib -I/root/.cache/node-gyp/20.12.0/deps/v8/include -I../../../node-addon-api -I../. -I/glib-2.0 -I/app/node_modules/@img/sharp-libvips-linux-arm64/lib/glib-2.0/include  -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -O3 -fno-omit-frame-pointer -fno-rtti -fno-exceptions -std=gnu++17 -std=c++0x -fexceptions -Wall -Os -MMD -MF ./Release/.deps/Release/obj.target/sharp-linux-arm64/common.o.d.raw   -c
../common.cc:13:10: fatal error: vips/vips8: No such file or directory
   13 | #include <vips/vips8>
      |          ^~~~~~~~~~~~
compilation terminated.
make: *** [sharp-linux-arm64.target.mk:135: Release/obj.target/sharp-linux-arm64/common.o] Error 1
make: Leaving directory '/app/node_modules/sharp/src/build'
gyp ERR! build error 
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack at ChildProcess.<anonymous> (/app/node_modules/node-gyp/lib/build.js:209:23)
gyp ERR! System Linux 6.4.16-linuxkit
gyp ERR! command "/usr/local/bin/node" "/app/node_modules/.bin/node-gyp" "rebuild" "--directory=src"
gyp ERR! cwd /app/node_modules/sharp/src
gyp ERR! node -v v20.12.0
gyp ERR! node-gyp -v v10.1.0
gyp ERR! not ok 
npm info run sharp@0.33.3 install { code: 1, signal: null }
npm verb stack Error: command failed
npm verb stack     at ChildProcess.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/@npmcli/promise-spawn/lib/index.js:53:27)
npm verb stack     at ChildProcess.emit (node:events:518:28)
npm verb stack     at maybeClose (node:internal/child_process:1105:16)
npm verb stack     at ChildProcess._handle.onexit (node:internal/child_process:305:5)
npm verb pkgid sharp@0.33.3
npm verb cwd /app
npm verb Linux 6.4.16-linuxkit
npm verb node v20.12.0
npm verb npm  v10.5.0
npm ERR! code 1
npm ERR! path /app/node_modules/sharp
npm ERR! command failed
npm ERR! command sh -c node install/check
npm verb exit 1
npm verb unfinished npm timer reify 1712091429124
npm verb unfinished npm timer reify:build 1712091526765
npm verb unfinished npm timer build 1712091526768
npm verb unfinished npm timer build:deps 1712091526769
npm verb unfinished npm timer build:run:install 1712091526834
npm verb unfinished npm timer build:run:install:node_modules/sharp 1712091531145
npm verb code 1

npm ERR! A complete log of this run can be found in: /root/.npm/_logs/2024-04-02T20_57_08_920Z-debug-0.log
# 

@robbyemmert
Copy link
Author

Here are more details from the file it references at the end:

10372 info run bcrypt@5.1.1 install node_modules/bcrypt node-pre-gyp install --fallback-to-build
10373 info run bcrypt@5.1.1 install { code: 0, signal: null }
10374 timing build:run:install:node_modules/bcrypt Completed in 4241ms
10375 info run puppeteer@13.7.0 install node_modules/puppeteer node install.js
10376 info run puppeteer@13.7.0 install { code: 0, signal: null }
10377 timing build:run:install:node_modules/puppeteer Completed in 69ms
10378 info run sharp@0.33.3 install node_modules/sharp node install/check
10379 info run sharp@0.33.3 install { code: 1, signal: null }
10380 timing reify:rollback:createSparse Completed in 710ms
10381 timing reify:rollback:retireShallow Completed in 0ms
10382 timing command:install Completed in 103339ms
10383 verbose stack Error: command failed
10383 verbose stack     at ChildProcess.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/@npmcli/promise-spawn/lib/index.js:53:27)
10383 verbose stack     at ChildProcess.emit (node:events:518:28)
10383 verbose stack     at maybeClose (node:internal/child_process:1105:16)
10383 verbose stack     at ChildProcess._handle.onexit (node:internal/child_process:305:5)
10384 verbose pkgid sharp@0.33.3
10385 verbose cwd /app
10386 verbose Linux 6.4.16-linuxkit
10387 verbose node v20.12.0
10388 verbose npm  v10.5.0
10389 error code 1
10390 error path /app/node_modules/sharp
10391 error command failed
10392 error command sh -c node install/check
10393 verbose exit 1
10394 timing npm Completed in 103543ms
10395 verbose unfinished npm timer reify 1712091429124
10396 verbose unfinished npm timer reify:build 1712091526765
10397 verbose unfinished npm timer build 1712091526768
10398 verbose unfinished npm timer build:deps 1712091526769
10399 verbose unfinished npm timer build:run:install 1712091526834
10400 verbose unfinished npm timer build:run:install:node_modules/sharp 1712091531145
10401 verbose code 1

@lovell
Copy link
Owner

lovell commented Apr 3, 2024

What is the output of pkg-config --modversion vips-cpp?

@tnluan

This comment was marked as off-topic.

@robbyemmert
Copy link
Author

What is the output of pkg-config --modversion vips-cpp?

I'm going to be working on this today/tomorrow. Is there any additional diagnostic info besides this that you'd like to see? I will try to get you both at the same time.

@DidierHoarau
Copy link

DidierHoarau commented Apr 8, 2024

Hi,

I'm also facing the issue.

In case it can help, I've created a Dockerfile:

FROM node:20 as builder

WORKDIR /opt/src

RUN apt-get update && \
    apt-get install -y libvips libvips-dev libheif-dev libde265-dev

RUN npm install sharp --build-from-source --verbose --foreground-scripts

RUN wget https://heic.digital/download-sample/soundboard.heic

ARG CACHEBUST=1

RUN pkg-config --modversion vips-cpp

RUN pkg-config --cflags --libs libheif

RUN echo 'const sharp = require("sharp");' > script.js && \
    echo 'sharp("soundboard.heic").jpeg().toFile("output.jpg", (err, info) => { console.log(info, err); });' >> script.js && \
    node script.js

and then if build it with the following command: docker build --build-arg CACHEBUST=$(date +%s) --progress=plain .

I get the following:

#10 [6/8] RUN pkg-config --modversion vips-cpp
#10 0.440 8.14.1
#10 DONE 0.5s

#11 [7/8] RUN pkg-config --cflags --libs libheif
#11 0.449 -I/usr/include/x86_64-linux-gnu -lheif 
#11 DONE 0.5s

#12 [8/8] RUN echo 'const sharp = require("sharp");' > script.js &&     echo 'sharp("soundboard.heic").jpeg().toFile("output.jpg", (err, info) => { console.log(info, err); });' >> script.js &&     node script.js
#12 0.828 undefined Error: soundboard.heic: bad seek to 1220229
#12 0.828 heif: Unsupported feature: Unsupported codec (4.3000)
#12 0.828     at Sharp.toFile (/opt/src/node_modules/sharp/lib/output.js:89:19)
#12 0.828     at Object.<anonymous> (/opt/src/script.js:2:33)
#12 0.828     at Module._compile (node:internal/modules/cjs/loader:1369:14)
#12 0.828     at Module._extensions..js (node:internal/modules/cjs/loader:1427:10)
#12 0.828     at Module.load (node:internal/modules/cjs/loader:1206:32)
#12 0.828     at Module._load (node:internal/modules/cjs/loader:1022:12)
#12 0.828     at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:135:12)
#12 0.828     at node:internal/main/run_main_module:28:49
#12 DONE 0.9s

Anything that I'm missing in the Dockerfile?

Thank you in advance,

@lovell
Copy link
Owner

lovell commented Apr 8, 2024

https://sharp.pixelplumbing.com/install#custom-libvips

To use a custom, globally-installed version of libvips instead of the provided binaries, make sure it is at least the version listed under engines.libvips in the package.json file and that it can be located using pkg-config --modversion vips-cpp.

"libvips": ">=8.15.2"

@DidierHoarau

RUN pkg-config --modversion vips-cpp
8.14.1

You are using libvips 8.14.1, which does not satisfy the semver range >=8.15.2.

@DidierHoarau
Copy link

Hi,

Thanks, so I tried with the following Dockerfile (switched to Alpine because this is where I found the right version of libvips)

FROM node:20-alpine

WORKDIR /opt/src

RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/community" >> /etc/apk/repositories

RUN apk add --no-cache --update \
    build-base \
    vips-dev=8.15.2-r0 \
    fftw-dev \
    gcc \
    g++ \
    make \
    python3 \
    wget \
    vips-dev=8.15.2-r0

RUN npm install node-addon-api && \
    npm install node-gyp

RUN npm install sharp --build-from-source --verbose --foreground-scripts

ARG CACHEBUST=1

RUN wget https://heic.digital/download-sample/soundboard.heic
    
RUN pkg-config --modversion vips-cpp

RUN echo 'const sharp = require("sharp");' > script.js && \
    echo 'sharp("soundboard.heic").jpeg().toFile("output.jpg", (err, info) => { console.log(info, err); });' >> script.js && \
    node script.js

and building with docker build --build-arg CACHEBUST=$(date +%s) --progress=plain -f Dockerfile-alpine .

The results:

  • npm install sharp --build-from-source --verbose --foreground-scripts gives (skipping some lines at the beginning):
...
#9 105.7 gyp verb checksum data {"node-v20.12.1-headers.tar.gz":"170844da1e1e2c853ae8e998734ce2a4d888d922aa575975d279104b81455f46","node-v20.12.1-headers.tar.xz":"172cbe26f23b4f7d28dc4cdc1e05fa8c9586bc0be113a599be770f723b13e556","node-v20.12.1-linux-armv6l.tar.gz":"2b8cdbd2cdfcde118317ba76f979cebdee513af0f15fd6856fee3c4ddbe33138","node-v20.12.1-linux-armv6l.tar.xz":"967de95008a936a3377bf7ee27a65e3330fc709a6a0a072b49073e52e729b76c","node-v20.12.1-linux-loong64.tar.gz":"44030558cf92b12b54900931a140b79ae46f820362a3a9fe6f6a9718eee467f0","node-v20.12.1-linux-loong64.tar.xz":"1c14d9b3168af2f4bac1eef16a367df58efa8e11cc0054e98fd8f85e6843ee9b","node-v20.12.1-linux-riscv64.tar.gz":"f3f91299f31fed1fb764bb73cddaf63683d095b6197ca5c7682360bee18c578b","node-v20.12.1-linux-riscv64.tar.xz":"180c92ff4cf5b8d0e9121a1f0eb351baa7b756d6f7d0f2c80da0b10c1610a305","node-v20.12.1-linux-x64-musl.tar.gz":"20d17c399c5b3abea9d461b027d2def00a151f9ea61c0f51486ac1f4eed1caba","node-v20.12.1-linux-x64-musl.tar.xz":"510b531d09af7a86f34dcc6b600b5504794be1351105afa91b6a9986ac8bf2aa"}
#9 105.7 gyp verb download contents checksum {"node-v20.12.1-headers.tar.gz":"170844da1e1e2c853ae8e998734ce2a4d888d922aa575975d279104b81455f46"}
#9 105.7 gyp verb validating download checksum for node-v20.12.1-headers.tar.gz (170844da1e1e2c853ae8e998734ce2a4d888d922aa575975d279104b81455f46 == 170844da1e1e2c853ae8e998734ce2a4d888d922aa575975d279104b81455f46)
#9 105.7 gyp verb get node dir target node version installed: 20.12.1
#9 105.7 gyp verb build dir attempting to create "build" dir: /opt/src/node_modules/sharp/src/build
#9 105.7 gyp verb build dir "build" dir needed to be created? Yes
#9 105.7 gyp verb build/config.gypi creating config file
#9 105.7 gyp verb build/config.gypi writing out config file: /opt/src/node_modules/sharp/src/build/config.gypi
#9 105.7 gyp verb config.gypi checking for gypi file: /opt/src/node_modules/sharp/src/config.gypi
#9 105.7 gyp verb common.gypi checking for gypi file: /opt/src/node_modules/sharp/src/common.gypi
#9 105.7 gyp verb gyp gyp format was not specified; forcing "make"
#9 105.7 gyp info spawn /usr/bin/python3
#9 105.7 gyp info spawn args [
#9 105.7 gyp info spawn args '/opt/src/node_modules/node-gyp/gyp/gyp_main.py',
#9 105.7 gyp info spawn args 'binding.gyp',
#9 105.7 gyp info spawn args '-f',
#9 105.7 gyp info spawn args 'make',
#9 105.7 gyp info spawn args '-I',
#9 105.7 gyp info spawn args '/opt/src/node_modules/sharp/src/build/config.gypi',
#9 105.7 gyp info spawn args '-I',
#9 105.7 gyp info spawn args '/opt/src/node_modules/node-gyp/addon.gypi',
#9 105.7 gyp info spawn args '-I',
#9 105.7 gyp info spawn args '/root/.cache/node-gyp/20.12.1/include/node/common.gypi',
#9 105.7 gyp info spawn args '-Dlibrary=shared_library',
#9 105.7 gyp info spawn args '-Dvisibility=default',
#9 105.7 gyp info spawn args '-Dnode_root_dir=/root/.cache/node-gyp/20.12.1',
#9 105.7 gyp info spawn args '-Dnode_gyp_dir=/opt/src/node_modules/node-gyp',
#9 105.7 gyp info spawn args '-Dnode_lib_file=/root/.cache/node-gyp/20.12.1/<(target_arch)/node.lib',
#9 105.7 gyp info spawn args '-Dmodule_root_dir=/opt/src/node_modules/sharp/src',
#9 105.7 gyp info spawn args '-Dnode_engine=v8',
#9 105.7 gyp info spawn args '--depth=.',
#9 105.7 gyp info spawn args '--no-parallel',
#9 105.7 gyp info spawn args '--generator-output',
#9 105.7 gyp info spawn args 'build',
#9 105.7 gyp info spawn args '-Goutput_dir=.'
#9 105.7 gyp info spawn args ]
#9 106.5 gyp verb build type Release
#9 106.5 gyp verb architecture x64
#9 106.5 gyp verb node dev dir /root/.cache/node-gyp/20.12.1
#9 106.5 gyp verb python /usr/bin/python3
#9 106.5 gyp verb `which` succeeded for `make` /usr/bin/make
#9 106.5 gyp verb bin symlinks created symlink to "/usr/bin/python3" in "/opt/src/node_modules/sharp/src/build/node_gyp_bins" and added to PATH
#9 106.5 gyp info spawn make
#9 106.5 gyp info spawn args [ 'V=1', 'BUILDTYPE=Release', '-C', 'build' ]
#9 106.5 make: Entering directory '/opt/src/node_modules/sharp/src/build'
#9 106.5   cc -o Release/obj.target/nothing/../../node-addon-api/nothing.o ../../../node-addon-api/nothing.c '-DNODE_GYP_MODULE_NAME=nothing' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_GLIBCXX_USE_CXX11_ABI=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-D__STDC_FORMAT_MACROS' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' -I/root/.cache/node-gyp/20.12.1/include/node -I/root/.cache/node-gyp/20.12.1/src -I/root/.cache/node-gyp/20.12.1/deps/openssl/config -I/root/.cache/node-gyp/20.12.1/deps/openssl/openssl/include -I/root/.cache/node-gyp/20.12.1/deps/uv/include -I/root/.cache/node-gyp/20.12.1/deps/zlib -I/root/.cache/node-gyp/20.12.1/deps/v8/include  -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -m64 -O3 -fno-omit-frame-pointer  -MMD -MF ./Release/.deps/Release/obj.target/nothing/../../node-addon-api/nothing.o.d.raw   -c
#9 106.5 rm -f Release/obj.target/../../node-addon-api/nothing.a Release/obj.target/../../node-addon-api/nothing.a.ar-file-list; mkdir -p `dirname Release/obj.target/../../node-addon-api/nothing.a`
#9 106.5 ar crs Release/obj.target/../../node-addon-api/nothing.a @Release/obj.target/../../node-addon-api/nothing.a.ar-file-list
#9 106.5   ln -f "Release/obj.target/../../node-addon-api/nothing.a" "Release/nothing.a" 2>/dev/null || (rm -rf "Release/nothing.a" && cp -af "Release/obj.target/../../node-addon-api/nothing.a" "Release/nothing.a")
#9 106.5   touch Release/obj.target/libvips-cpp.stamp
#9 106.5   g++ -o Release/obj.target/sharp-linuxmusl-x64/common.o ../common.cc '-DNODE_GYP_MODULE_NAME=sharp-linuxmusl-x64' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_GLIBCXX_USE_CXX11_ABI=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-D__STDC_FORMAT_MACROS' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' '-DNAPI_VERSION=9' '-DNODE_ADDON_API_DISABLE_DEPRECATED' '-DNODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS' '-DSHARP_USE_GLOBAL_LIBVIPS' '-DBUILDING_NODE_EXTENSION' -I/root/.cache/node-gyp/20.12.1/include/node -I/root/.cache/node-gyp/20.12.1/src -I/root/.cache/node-gyp/20.12.1/deps/openssl/config -I/root/.cache/node-gyp/20.12.1/deps/openssl/openssl/include -I/root/.cache/node-gyp/20.12.1/deps/uv/include -I/root/.cache/node-gyp/20.12.1/deps/zlib -I/root/.cache/node-gyp/20.12.1/deps/v8/include -I../../../node-addon-api -I/usr/include/pango-1.0 -I/usr/include/harfbuzz -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/cairo -I/usr/include/freetype2 -I/usr/include/Imath -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/fribidi -I/usr/include/librsvg-2.0 -I/usr/include/webp -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/libpng16 -I/usr/include/pixman-1 -I/usr/include/OpenEXR -I/usr/include/openjpeg-2.5  -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -m64 -O3 -fno-omit-frame-pointer -fno-rtti -fno-exceptions -std=gnu++17 -std=c++0x -fexceptions -Wall -Os -MMD -MF ./Release/.deps/Release/obj.target/sharp-linuxmusl-x64/common.o.d.raw   -c
#9 109.1   g++ -o Release/obj.target/sharp-linuxmusl-x64/metadata.o ../metadata.cc '-DNODE_GYP_MODULE_NAME=sharp-linuxmusl-x64' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_GLIBCXX_USE_CXX11_ABI=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-D__STDC_FORMAT_MACROS' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' '-DNAPI_VERSION=9' '-DNODE_ADDON_API_DISABLE_DEPRECATED' '-DNODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS' '-DSHARP_USE_GLOBAL_LIBVIPS' '-DBUILDING_NODE_EXTENSION' -I/root/.cache/node-gyp/20.12.1/include/node -I/root/.cache/node-gyp/20.12.1/src -I/root/.cache/node-gyp/20.12.1/deps/openssl/config -I/root/.cache/node-gyp/20.12.1/deps/openssl/openssl/include -I/root/.cache/node-gyp/20.12.1/deps/uv/include -I/root/.cache/node-gyp/20.12.1/deps/zlib -I/root/.cache/node-gyp/20.12.1/deps/v8/include -I../../../node-addon-api -I/usr/include/pango-1.0 -I/usr/include/harfbuzz -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/cairo -I/usr/include/freetype2 -I/usr/include/Imath -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/fribidi -I/usr/include/librsvg-2.0 -I/usr/include/webp -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/libpng16 -I/usr/include/pixman-1 -I/usr/include/OpenEXR -I/usr/include/openjpeg-2.5  -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -m64 -O3 -fno-omit-frame-pointer -fno-rtti -fno-exceptions -std=gnu++17 -std=c++0x -fexceptions -Wall -Os -MMD -MF ./Release/.deps/Release/obj.target/sharp-linuxmusl-x64/metadata.o.d.raw   -c
#9 110.8   g++ -o Release/obj.target/sharp-linuxmusl-x64/stats.o ../stats.cc '-DNODE_GYP_MODULE_NAME=sharp-linuxmusl-x64' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_GLIBCXX_USE_CXX11_ABI=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-D__STDC_FORMAT_MACROS' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' '-DNAPI_VERSION=9' '-DNODE_ADDON_API_DISABLE_DEPRECATED' '-DNODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS' '-DSHARP_USE_GLOBAL_LIBVIPS' '-DBUILDING_NODE_EXTENSION' -I/root/.cache/node-gyp/20.12.1/include/node -I/root/.cache/node-gyp/20.12.1/src -I/root/.cache/node-gyp/20.12.1/deps/openssl/config -I/root/.cache/node-gyp/20.12.1/deps/openssl/openssl/include -I/root/.cache/node-gyp/20.12.1/deps/uv/include -I/root/.cache/node-gyp/20.12.1/deps/zlib -I/root/.cache/node-gyp/20.12.1/deps/v8/include -I../../../node-addon-api -I/usr/include/pango-1.0 -I/usr/include/harfbuzz -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/cairo -I/usr/include/freetype2 -I/usr/include/Imath -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/fribidi -I/usr/include/librsvg-2.0 -I/usr/include/webp -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/libpng16 -I/usr/include/pixman-1 -I/usr/include/OpenEXR -I/usr/include/openjpeg-2.5  -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -m64 -O3 -fno-omit-frame-pointer -fno-rtti -fno-exceptions -std=gnu++17 -std=c++0x -fexceptions -Wall -Os -MMD -MF ./Release/.deps/Release/obj.target/sharp-linuxmusl-x64/stats.o.d.raw   -c
#9 112.1   g++ -o Release/obj.target/sharp-linuxmusl-x64/operations.o ../operations.cc '-DNODE_GYP_MODULE_NAME=sharp-linuxmusl-x64' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_GLIBCXX_USE_CXX11_ABI=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-D__STDC_FORMAT_MACROS' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' '-DNAPI_VERSION=9' '-DNODE_ADDON_API_DISABLE_DEPRECATED' '-DNODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS' '-DSHARP_USE_GLOBAL_LIBVIPS' '-DBUILDING_NODE_EXTENSION' -I/root/.cache/node-gyp/20.12.1/include/node -I/root/.cache/node-gyp/20.12.1/src -I/root/.cache/node-gyp/20.12.1/deps/openssl/config -I/root/.cache/node-gyp/20.12.1/deps/openssl/openssl/include -I/root/.cache/node-gyp/20.12.1/deps/uv/include -I/root/.cache/node-gyp/20.12.1/deps/zlib -I/root/.cache/node-gyp/20.12.1/deps/v8/include -I../../../node-addon-api -I/usr/include/pango-1.0 -I/usr/include/harfbuzz -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/cairo -I/usr/include/freetype2 -I/usr/include/Imath -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/fribidi -I/usr/include/librsvg-2.0 -I/usr/include/webp -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/libpng16 -I/usr/include/pixman-1 -I/usr/include/OpenEXR -I/usr/include/openjpeg-2.5  -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -m64 -O3 -fno-omit-frame-pointer -fno-rtti -fno-exceptions -std=gnu++17 -std=c++0x -fexceptions -Wall -Os -MMD -MF ./Release/.deps/Release/obj.target/sharp-linuxmusl-x64/operations.o.d.raw   -c
#9 113.6   g++ -o Release/obj.target/sharp-linuxmusl-x64/pipeline.o ../pipeline.cc '-DNODE_GYP_MODULE_NAME=sharp-linuxmusl-x64' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_GLIBCXX_USE_CXX11_ABI=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-D__STDC_FORMAT_MACROS' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' '-DNAPI_VERSION=9' '-DNODE_ADDON_API_DISABLE_DEPRECATED' '-DNODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS' '-DSHARP_USE_GLOBAL_LIBVIPS' '-DBUILDING_NODE_EXTENSION' -I/root/.cache/node-gyp/20.12.1/include/node -I/root/.cache/node-gyp/20.12.1/src -I/root/.cache/node-gyp/20.12.1/deps/openssl/config -I/root/.cache/node-gyp/20.12.1/deps/openssl/openssl/include -I/root/.cache/node-gyp/20.12.1/deps/uv/include -I/root/.cache/node-gyp/20.12.1/deps/zlib -I/root/.cache/node-gyp/20.12.1/deps/v8/include -I../../../node-addon-api -I/usr/include/pango-1.0 -I/usr/include/harfbuzz -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/cairo -I/usr/include/freetype2 -I/usr/include/Imath -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/fribidi -I/usr/include/librsvg-2.0 -I/usr/include/webp -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/libpng16 -I/usr/include/pixman-1 -I/usr/include/OpenEXR -I/usr/include/openjpeg-2.5  -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -m64 -O3 -fno-omit-frame-pointer -fno-rtti -fno-exceptions -std=gnu++17 -std=c++0x -fexceptions -Wall -Os -MMD -MF ./Release/.deps/Release/obj.target/sharp-linuxmusl-x64/pipeline.o.d.raw   -c
#9 117.6   g++ -o Release/obj.target/sharp-linuxmusl-x64/utilities.o ../utilities.cc '-DNODE_GYP_MODULE_NAME=sharp-linuxmusl-x64' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_GLIBCXX_USE_CXX11_ABI=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-D__STDC_FORMAT_MACROS' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' '-DNAPI_VERSION=9' '-DNODE_ADDON_API_DISABLE_DEPRECATED' '-DNODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS' '-DSHARP_USE_GLOBAL_LIBVIPS' '-DBUILDING_NODE_EXTENSION' -I/root/.cache/node-gyp/20.12.1/include/node -I/root/.cache/node-gyp/20.12.1/src -I/root/.cache/node-gyp/20.12.1/deps/openssl/config -I/root/.cache/node-gyp/20.12.1/deps/openssl/openssl/include -I/root/.cache/node-gyp/20.12.1/deps/uv/include -I/root/.cache/node-gyp/20.12.1/deps/zlib -I/root/.cache/node-gyp/20.12.1/deps/v8/include -I../../../node-addon-api -I/usr/include/pango-1.0 -I/usr/include/harfbuzz -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/cairo -I/usr/include/freetype2 -I/usr/include/Imath -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/fribidi -I/usr/include/librsvg-2.0 -I/usr/include/webp -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/libpng16 -I/usr/include/pixman-1 -I/usr/include/OpenEXR -I/usr/include/openjpeg-2.5  -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -m64 -O3 -fno-omit-frame-pointer -fno-rtti -fno-exceptions -std=gnu++17 -std=c++0x -fexceptions -Wall -Os -MMD -MF ./Release/.deps/Release/obj.target/sharp-linuxmusl-x64/utilities.o.d.raw   -c
#9 118.9   g++ -o Release/obj.target/sharp-linuxmusl-x64/sharp.o ../sharp.cc '-DNODE_GYP_MODULE_NAME=sharp-linuxmusl-x64' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_GLIBCXX_USE_CXX11_ABI=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-D__STDC_FORMAT_MACROS' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' '-DNAPI_VERSION=9' '-DNODE_ADDON_API_DISABLE_DEPRECATED' '-DNODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS' '-DSHARP_USE_GLOBAL_LIBVIPS' '-DBUILDING_NODE_EXTENSION' -I/root/.cache/node-gyp/20.12.1/include/node -I/root/.cache/node-gyp/20.12.1/src -I/root/.cache/node-gyp/20.12.1/deps/openssl/config -I/root/.cache/node-gyp/20.12.1/deps/openssl/openssl/include -I/root/.cache/node-gyp/20.12.1/deps/uv/include -I/root/.cache/node-gyp/20.12.1/deps/zlib -I/root/.cache/node-gyp/20.12.1/deps/v8/include -I../../../node-addon-api -I/usr/include/pango-1.0 -I/usr/include/harfbuzz -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/cairo -I/usr/include/freetype2 -I/usr/include/Imath -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/fribidi -I/usr/include/librsvg-2.0 -I/usr/include/webp -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/libpng16 -I/usr/include/pixman-1 -I/usr/include/OpenEXR -I/usr/include/openjpeg-2.5  -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -m64 -O3 -fno-omit-frame-pointer -fno-rtti -fno-exceptions -std=gnu++17 -std=c++0x -fexceptions -Wall -Os -MMD -MF ./Release/.deps/Release/obj.target/sharp-linuxmusl-x64/sharp.o.d.raw   -c
#9 120.1   g++ -o Release/obj.target/sharp-linuxmusl-x64.node -shared -pthread -rdynamic -m64  -Wl,-soname=sharp-linuxmusl-x64.node -Wl,--start-group Release/obj.target/sharp-linuxmusl-x64/common.o Release/obj.target/sharp-linuxmusl-x64/metadata.o Release/obj.target/sharp-linuxmusl-x64/stats.o Release/obj.target/sharp-linuxmusl-x64/operations.o Release/obj.target/sharp-linuxmusl-x64/pipeline.o Release/obj.target/sharp-linuxmusl-x64/utilities.o Release/obj.target/sharp-linuxmusl-x64/sharp.o Release/obj.target/../../node-addon-api/nothing.a -Wl,--end-group -lvips-cpp -lvips -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl
#9 120.1   ln -f "Release/obj.target/sharp-linuxmusl-x64.node" "Release/sharp-linuxmusl-x64.node" 2>/dev/null || (rm -rf "Release/sharp-linuxmusl-x64.node" && cp -af "Release/obj.target/sharp-linuxmusl-x64.node" "Release/sharp-linuxmusl-x64.node")
#9 120.1   touch Release/obj.target/copy-dll.stamp
#9 120.2 make: Leaving directory '/opt/src/node_modules/sharp/src/build'
#9 120.2 gyp info ok 
#9 120.2 npm info run sharp@0.33.3 install { code: 0, signal: null }
  • pkg-config --modversion vips-cpp gives:
#11 [8/9] RUN pkg-config --modversion vips-cpp
#11 0.443 8.15.2
#11 DONE 0.5s
  • And the Node script gives:
#12 [9/9] RUN echo 'const sharp = require("sharp");' > script.js &&     echo 'sharp("soundboard.heic").jpeg().toFile("output.jpg", (err, info) => { console.log(info, err); });' >> script.js &&     node script.js
#12 0.726 undefined Error: Input file contains unsupported image format
#12 0.726     at Sharp.toFile (/opt/src/node_modules/sharp/lib/output.js:89:19)
#12 0.726     at Object.<anonymous> (/opt/src/script.js:2:33)
#12 0.726     at Module._compile (node:internal/modules/cjs/loader:1369:14)
#12 0.726     at Module._extensions..js (node:internal/modules/cjs/loader:1427:10)
#12 0.726     at Module.load (node:internal/modules/cjs/loader:1206:32)
#12 0.726     at Module._load (node:internal/modules/cjs/loader:1022:12)
#12 0.726     at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:135:12)
#12 0.726     at node:internal/main/run_main_module:28:49
#12 DONE 0.8s

There are some changes. Now it doesn't tell me anymore about the unsupported codec. But it seems that it can't handle the image.

Anything missing? Or anything I can test with?

Thanks in advance

@kleisauke
Copy link
Contributor

@DidierHoarau HEIC / AVIF support is available in the vips-heif optional package on Alpine.

@DidierHoarau
Copy link

Hi,

Thanks a lot.

So with this Dockerfile:

FROM node:20-alpine

WORKDIR /opt/src

RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/community" >> /etc/apk/repositories

RUN apk add --no-cache --update \
    build-base \
    vips-dev=8.15.2-r0 \
    fftw-dev \
    gcc \
    g++ \
    make \
    python3 \
    wget \
    vips-dev=8.15.2-r0 \
    vips-heif=8.15.2-r0

RUN npm install node-addon-api && \
    npm install node-gyp

RUN npm install sharp

ARG CACHEBUST=1

RUN wget https://heic.digital/download-sample/soundboard.heic
    
RUN pkg-config --modversion vips-cpp

RUN echo 'const sharp = require("sharp");' > script.js && \
    echo 'sharp("soundboard.heic").jpeg().toFile("output.jpg", (err, info) => { console.log(info, err); });' >> script.js && \
    node script.js

(So I didn't even have to add the --build-from-source, it it sees that the library is installed, it will auto-try to build)

This works:

#13 [9/9] RUN echo 'const sharp = require("sharp");' > script.js &&     echo 'sharp("soundboard.heic").jpeg().toFile("output.jpg", (err, info) => { console.log(info, err); });' >> script.js &&     node script.js
#13 1.906 {
#13 1.906   format: 'jpeg',
#13 1.906   width: 3000,
#13 1.906   height: 4000,
#13 1.906   channels: 3,
#13 1.906   premultiplied: false,
#13 1.906   size: 1052671
#13 1.906 } null
#13 DONE 2.0s

Great. Thanks again

@dvdkon
Copy link

dvdkon commented Apr 17, 2024

I was just solving the same issue, mine was caused by missing node-addon-api and node-gyp. Debugging took me so long be cause the failure was silent. Could you maybe make the installation fail or at least produce a visible warning (without verbose flags) if the dependencies are not found? Or possibly do that just when the new SHARP_FORCE_GLOBAL_LIBVIPS flag is used.

@lovell
Copy link
Owner

lovell commented Apr 17, 2024

@dvdkon Please see https://sharp.pixelplumbing.com/install#building-from-source

produce a visible warning (without verbose flags) if the dependencies are not found

sharp will always log decisions it makes at install-time.

sharp/install/check.js

Lines 11 to 25 in 52b9dc0

log('Attempting to build from source via node-gyp');
try {
require('node-addon-api');
log('Found node-addon-api');
} catch (err) {
log('Please add node-addon-api to your dependencies');
return;
}
try {
const gyp = require('node-gyp');
log(`Found node-gyp version ${gyp().version}`);
} catch (err) {
log('Please add node-gyp to your dependencies');
return;
}

You'll need to ensure your choice of package manager displays these; for npm this is controlled by the --foreground-scripts flag.

I've just opened nodejs/node-addon-api#1479 to expose the version from the upstream node-addon-api, which will allow us to improve this logging further.

@lovell
Copy link
Owner

lovell commented Apr 17, 2024

@robbyemmert Were you able to make any progress with this?

@Naktibalda
Copy link

I used heic-decode library as workaround.

import decodeHeic from "heic-decode";

const decodedImage = await decodeHeic({
  buffer: fileContent,
});

return sharp(decodedImage.data, {
  ...options,
  raw: {
    width: decodedImage.width,
    height: decodedImage.height,
    channels: 4,
  },
});

@lovell
Copy link
Owner

lovell commented Apr 29, 2024

@robbyemmert I'll close due to inactivity but please feel free to reopen with more details if further help is required.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants