sassc-ruby: sassc is very slow to compile and install

When doing a bundle install for a new Rails 6 app, I noticed most of the time is spent compiling sassc (libsass really).

This takes easily up to 2 minutes on Linux, which feels really slow for one gem. A bit of a Nokogiri-like experience if you see what I mean. Speaking of Nokogiri, they now have a prerelease gem installing in just 1 second, maybe we can use a similar approach?

$ ruby -v
ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-linux]
$ time gem install sassc                 
Building native extensions. This could take a while...
Successfully installed sassc-2.2.1
1 gem installed
89.75s user 5.43s system 99% cpu 1:36.12 total

I’m not sure what’s the best way to address this but here are some ideas:

  • Use the Makefile of libsass to build libsass as a shared library, and just link the C extension to it (as it used to be).
  • Use make parallelism automatically, e.g., by setting MAKEFLAGS
  • Distribute a binary gem on Linux and macOS. This requires having an easy workaround for non-glibc (e.g., alpine) to install from source, or not depending on on glibc (by linking the libc statically?).
  • Changes in libsass so it compiles faster, such as #132.
  • I thought the -flto might slow things down but actually it seems to speed up compilation with g++ 8.3.1! time gem install sassc -- --disable-lto takes 113.71s user 6.01s system 99% cpu 2:00.70 total. Disabling all flags gives: time gem install sassc -- --disable-lto --disable-march-tune-native --disable-static-stdlib => 109.80s user 5.63s system 99% cpu 1:56.12 total.

Use the Makefile of libsass to build libsass as a shared library

That already builds quite a bit faster:

$ time BUILD=shared make       
...
70.53s user 3.94s system 99% cpu 1:14.93 total

I would think the main gain there is that’s compiled with -O2:

g++ -Wall -O2 -DLIBSASS_VERSION="3.6.1" -std=c++11 -I /home/eregon/code/libsass/include -fPIC -c -o src/remove_placeholders.o src/remove_placeholders.cpp

instead of (with gem install sassc):

g++ -I. -I/home/eregon/.rubies/ruby-2.6.5/include/ruby-2.6.0/x86_64-linux -I/home/eregon/.rubies/ruby-2.6.5/include/ruby-2.6.0/ruby/backward -I/home/eregon/.rubies/ruby-2.6.5/include/ruby-2.6.0 -I. -I./libsass/include -fPIC -O3 -ggdb3 -std=c++11 -march=native -mtune=native -flto -DLIBSASS_VERSION="3.6.1" -o remove_placeholders.o -c ./libsass/src/remove_placeholders.cpp

We can also parallelize it (I have 4 cores + 4 hyperthreads, i7-7700HQ CPU @ 2.80GHz):

$ time BUILD=shared MAKEFLAGS=-j4 make
81.15s user 4.51s system 387% cpu 22.132 total

That’s a reasonable install time!

Using just the MAKEFLAGS approach with gem install is not quite enough:

time MAKEFLAGS=-j4 gem install sassc 
Building native extensions. This could take a while...
Successfully installed sassc-2.2.1
1 gem installed
95.47s user 5.63s system 180% cpu 55.870 total

cc @bolandrm @glebm

Relates to #132

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 121
  • Comments: 43 (11 by maintainers)

Commits related to this issue

Most upvoted comments

Adding more data about the impact of this: I came to realise that Jekyll depends on saasc indirectly (via jekyll-sass-converter, which is a hard dependency).

This makes Jekyll (fairly popular) quite slow to deploy on platforms like Netlify (see https://community.netlify.com/t/ruby-gems-cache-seems-to-be-ineffective/14821 for an example, the install times is above 3 minutes. Caching is another problem ^_^).

I’ve opened an issue at https://github.com/jekyll/jekyll/issues/8184 to evaluate if sassc be made a soft dependency, but still wanted to provide this feedback: the impact of this is probably quite large on a number of projects.

Not sure what can be done and how I could help either yet, so for now just providing this data.

Are there plans to address this, specifically shipping pre-compiled binaries for Debian or other popular distros?

Up to version 2.1.0, sassc shipped precompiled Linux binaries, but as of 2.2.0, the only precompiled versions are for mingw32.

The problem, apparently (#141) was that on Alpine Linux (common in Docker images) rubygems would download the “Linux” version, precompiled with libc (not available on Alpine, which uses musl instead to keep the image size down).

Other gems (Nokogiri is one I’ve noticed in particular) seem to get around this somehow, though, using the precompiled version on Debian and RedHat and other glibc systems, while compiling from source on Alpine. I’m not sure why or how — as a mostly macOS and Docker/Alpine user, I only just noticed the existence of precompiled gems a few weeks ago when I noticed that bundle install in a Debian-based container was going much faster than my previous Alpine-based builds. 🙂 But it might be worth looking into.

In the meantime, a workaround might be to pin sassc-ruby to version 2.1.0.

This has always taken a lot of time to install, however, for some reason, lately this started taking over 10 minutes to install in Travis, which makes it cancel the build completely. Although I can work around this, it’s odd that this should really take over 10 minutes to install. It also wasn’t a one-off thing, travis quit when attempting to install sassc 10+ times in a row now.

Are there any more clever work arounds than increasing Travis’ timeout limit?

Turns out that it’s only bloody slow when it is installing with “native extensions”. 🤔

Got the same issue on netlify, took 5-10 minutes to install sassc 2.4.0.

If anyone finds this helpful, here is where it actually takes 2 minutes (I installed ffi separately because it’s a dependency and for comparison w/time):

gns@gns-mac1 ~ % docker run -it ruby:latest /bin/bash
root@4f4bf2280063:/# time gem install ffi
Building native extensions. This could take a while...
Successfully installed ffi-1.13.1
1 gem installed

real	0m7.137s
user	0m5.407s
sys	0m1.055s
root@4f4bf2280063:/# time gem install sassc --verbose
HEAD https://rubygems.org/api/v1/dependencies
200 OK
GET https://rubygems.org/api/v1/dependencies?gems=sassc
200 OK
GET https://rubygems.org/quick/Marshal.4.8/sassc-2.4.0.gemspec.rz
200 OK
GET https://rubygems.org/api/v1/dependencies?gems=ffi
200 OK
Downloading gem sassc-2.4.0.gem
GET https://rubygems.org/gems/sassc-2.4.0.gem
Fetching sassc-2.4.0.gem
200 OK
/usr/local/bundle/gems/sassc-2.4.0/.gitignore
/usr/local/bundle/gems/sassc-2.4.0/.gitmodules
/usr/local/bundle/gems/sassc-2.4.0/.travis.yml
/usr/local/bundle/gems/sassc-2.4.0/CHANGELOG.md
/usr/local/bundle/gems/sassc-2.4.0/CODE_OF_CONDUCT.md
/usr/local/bundle/gems/sassc-2.4.0/Gemfile
/usr/local/bundle/gems/sassc-2.4.0/LICENSE.txt
/usr/local/bundle/gems/sassc-2.4.0/README.md
/usr/local/bundle/gems/sassc-2.4.0/Rakefile
/usr/local/bundle/gems/sassc-2.4.0/ext/depend
/usr/local/bundle/gems/sassc-2.4.0/ext/extconf.rb
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/VERSION
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/contrib/plugin.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/include/sass.h
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/include/sass/base.h
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/include/sass/context.h
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/include/sass/functions.h
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/include/sass/values.h
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/include/sass/version.h
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/include/sass2scss.h
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/MurmurHash2.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/ast.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/ast.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/ast2c.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/ast2c.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/ast_def_macros.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/ast_fwd_decl.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/ast_fwd_decl.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/ast_helpers.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/ast_sel_cmp.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/ast_sel_super.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/ast_sel_unify.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/ast_sel_weave.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/ast_selectors.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/ast_selectors.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/ast_supports.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/ast_supports.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/ast_values.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/ast_values.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/b64/cencode.h
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/b64/encode.h
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/backtrace.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/backtrace.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/base64vlq.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/base64vlq.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/bind.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/bind.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/c2ast.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/c2ast.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/c99func.c
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/cencode.c
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/check_nesting.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/check_nesting.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/color_maps.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/color_maps.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/constants.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/constants.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/context.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/context.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/cssize.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/cssize.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/dart_helpers.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/debug.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/debugger.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/emitter.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/emitter.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/environment.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/environment.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/error_handling.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/error_handling.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/eval.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/eval.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/eval_selectors.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/expand.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/expand.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/extender.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/extender.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/extension.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/extension.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/file.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/file.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/fn_colors.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/fn_colors.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/fn_lists.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/fn_lists.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/fn_maps.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/fn_maps.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/fn_miscs.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/fn_miscs.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/fn_numbers.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/fn_numbers.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/fn_selectors.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/fn_selectors.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/fn_strings.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/fn_strings.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/fn_utils.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/fn_utils.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/inspect.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/inspect.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/json.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/json.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/kwd_arg_macros.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/lexer.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/lexer.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/listize.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/listize.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/mapping.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/memory.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/memory/allocator.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/memory/allocator.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/memory/config.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/memory/memory_pool.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/memory/shared_ptr.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/memory/shared_ptr.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/operation.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/operators.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/operators.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/ordered_map.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/output.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/output.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/parser.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/parser.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/parser_selectors.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/permutate.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/plugins.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/plugins.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/position.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/position.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/prelexer.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/prelexer.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/remove_placeholders.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/remove_placeholders.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/sass.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/sass.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/sass2scss.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/sass_context.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/sass_context.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/sass_functions.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/sass_functions.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/sass_values.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/sass_values.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/settings.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/source.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/source.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/source_data.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/source_map.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/source_map.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/stylesheet.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/stylesheet.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/to_value.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/to_value.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/units.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/units.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/utf8.h
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/utf8/checked.h
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/utf8/core.h
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/utf8/unchecked.h
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/utf8_string.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/utf8_string.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/util.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/util.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/util_string.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/util_string.hpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/values.cpp
/usr/local/bundle/gems/sassc-2.4.0/ext/libsass/src/values.hpp
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/dependency.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/engine.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/error.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/functions_handler.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/import_handler.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/importer.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/native.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/native/native_context_api.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/native/native_functions_api.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/native/sass2scss_api.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/native/sass_input_style.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/native/sass_output_style.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/native/sass_value.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/native/string_list.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/sass_2_scss.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/script.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/script/functions.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/script/value.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/script/value/bool.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/script/value/color.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/script/value/list.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/script/value/map.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/script/value/number.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/script/value/string.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/script/value_conversion.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/script/value_conversion/base.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/script/value_conversion/bool.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/script/value_conversion/color.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/script/value_conversion/list.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/script/value_conversion/map.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/script/value_conversion/number.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/script/value_conversion/string.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/util.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/util/normalized_map.rb
/usr/local/bundle/gems/sassc-2.4.0/lib/sassc/version.rb
/usr/local/bundle/gems/sassc-2.4.0/sassc.gemspec
/usr/local/bundle/gems/sassc-2.4.0/test/custom_importer_test.rb
/usr/local/bundle/gems/sassc-2.4.0/test/engine_test.rb
/usr/local/bundle/gems/sassc-2.4.0/test/error_test.rb
/usr/local/bundle/gems/sassc-2.4.0/test/fixtures/paths.scss
/usr/local/bundle/gems/sassc-2.4.0/test/functions_test.rb
/usr/local/bundle/gems/sassc-2.4.0/test/native_test.rb
/usr/local/bundle/gems/sassc-2.4.0/test/output_style_test.rb
/usr/local/bundle/gems/sassc-2.4.0/test/sass_2_scss_test.rb
/usr/local/bundle/gems/sassc-2.4.0/test/test_helper.rb
Building native extensions. This could take a while...
current directory: /usr/local/bundle/gems/sassc-2.4.0/ext
["/usr/local/bin/ruby", "-I", "/usr/local/lib/ruby/2.7.0", "-r", "./siteconf20200712-167-n5du3e.rb", "extconf.rb"]
creating Makefile
current directory: /usr/local/bundle/gems/sassc-2.4.0/ext
"make \"DESTDIR=\" clean"

current directory: /usr/local/bundle/gems/sassc-2.4.0/ext
"make \"DESTDIR=\""

This is where it took ~2 minutes.

compiling ./libsass/src/ast.cpp
compiling ./libsass/src/ast2c.cpp
compiling ./libsass/src/ast_fwd_decl.cpp
compiling ./libsass/src/ast_sel_cmp.cpp
compiling ./libsass/src/ast_sel_super.cpp
compiling ./libsass/src/ast_sel_unify.cpp
compiling ./libsass/src/ast_sel_weave.cpp
compiling ./libsass/src/ast_selectors.cpp
compiling ./libsass/src/ast_supports.cpp
compiling ./libsass/src/ast_values.cpp
compiling ./libsass/src/backtrace.cpp
compiling ./libsass/src/base64vlq.cpp
compiling ./libsass/src/bind.cpp
compiling ./libsass/src/c2ast.cpp
compiling ./libsass/src/c99func.c
compiling ./libsass/src/cencode.c
compiling ./libsass/src/check_nesting.cpp
compiling ./libsass/src/color_maps.cpp
compiling ./libsass/src/constants.cpp
compiling ./libsass/src/context.cpp
compiling ./libsass/src/cssize.cpp
compiling ./libsass/src/emitter.cpp
compiling ./libsass/src/environment.cpp
compiling ./libsass/src/error_handling.cpp
compiling ./libsass/src/eval.cpp
compiling ./libsass/src/eval_selectors.cpp
compiling ./libsass/src/expand.cpp
compiling ./libsass/src/extender.cpp
compiling ./libsass/src/extension.cpp
compiling ./libsass/src/file.cpp
compiling ./libsass/src/fn_colors.cpp
compiling ./libsass/src/fn_lists.cpp
compiling ./libsass/src/fn_maps.cpp
compiling ./libsass/src/fn_miscs.cpp
compiling ./libsass/src/fn_numbers.cpp
compiling ./libsass/src/fn_selectors.cpp
compiling ./libsass/src/fn_strings.cpp
compiling ./libsass/src/fn_utils.cpp
compiling ./libsass/src/inspect.cpp
compiling ./libsass/src/json.cpp
compiling ./libsass/src/lexer.cpp
compiling ./libsass/src/listize.cpp
compiling ./libsass/src/memory/allocator.cpp
compiling ./libsass/src/memory/shared_ptr.cpp
compiling ./libsass/src/operators.cpp
compiling ./libsass/src/output.cpp
compiling ./libsass/src/parser.cpp
compiling ./libsass/src/parser_selectors.cpp
compiling ./libsass/src/plugins.cpp
compiling ./libsass/src/position.cpp
compiling ./libsass/src/prelexer.cpp
compiling ./libsass/src/remove_placeholders.cpp
compiling ./libsass/src/sass.cpp
compiling ./libsass/src/sass2scss.cpp
compiling ./libsass/src/sass_context.cpp
compiling ./libsass/src/sass_functions.cpp
compiling ./libsass/src/sass_values.cpp
compiling ./libsass/src/source.cpp
compiling ./libsass/src/source_map.cpp
compiling ./libsass/src/stylesheet.cpp
compiling ./libsass/src/to_value.cpp
compiling ./libsass/src/units.cpp
compiling ./libsass/src/utf8_string.cpp
compiling ./libsass/src/util.cpp
compiling ./libsass/src/util_string.cpp
compiling ./libsass/src/values.cpp
linking shared-object sassc/libsass.so
current directory: /usr/local/bundle/gems/sassc-2.4.0/ext
"make \"DESTDIR=\" install"
/usr/bin/install -c -m 0755 libsass.so ./.gem.20200712-167-sm6aue/sassc
current directory: /usr/local/bundle/gems/sassc-2.4.0/ext
/usr/local/bin/ruby -I /usr/local/lib/ruby/2.7.0 -r ./siteconf20200712-167-n5du3e.rb extconf.rb
current directory: /usr/local/bundle/gems/sassc-2.4.0/ext
make "DESTDIR=" clean
current directory: /usr/local/bundle/gems/sassc-2.4.0/ext
make "DESTDIR="
current directory: /usr/local/bundle/gems/sassc-2.4.0/ext
make "DESTDIR=" install
Successfully installed sassc-2.4.0
1 gem installed

real	2m21.017s
user	2m11.993s
sys	0m8.384s

same case here, it takes more than 9 minutes to install causing the cancelation of the bundle install 😕

When doing a bundle install for a new Rails 6 app, I noticed most of the time is spent compiling sassc (libsass really).

For an older app, we were spending ~8 mins on sassc in our Docker installs. It was painful because any Gemfile change invalidated the Docker layer for the bundle install

Since this gem feels unlikely to get a new release, we took the lowest lift approach here and are doing a RUN gem install sassc:2.4.0 before our RUN bundle install line.

This means the sassc install is cached in its own layer and the bundle install uses the sassc gem on disk. While the flag changes suggested here save real time, having the install cached means future builds spend zero seconds on sassc.

I wrote about this in more detail here.

Thanks this is a really great hint! ❤️

FWIW, here are numbers from today on my current Linux desktop on CRuby 3.1.3:

$ echo $MAKEFLAGS                  
-j8
$ ruby -v && time gem i sassc:2.4.0
ruby 3.1.3p185 (2022-11-24 revision 1a6b16756e) [x86_64-linux]
gem i sassc:2.4.0  41.21s user 4.66s system 595% cpu 7.707 total

$ unset MAKEFLAGS
$ ruby -v && time gem i sassc:2.4.0
ruby 3.1.3p185 (2022-11-24 revision 1a6b16756e) [x86_64-linux]
gem i sassc:2.4.0  36.93s user 4.44s system 98% cpu 42.044 total

So setting MAKEFLAGS to the CPU count helps a lot there.

@Pablushka @dancingmonkey @aamejia @h0jeZvgoxFepBQ2C

*** ATTENTION ***

LibSass is deprecated. SASSC-RUBY depends on LibSass. Ruby on Rails has moved away from using this gem. You should not be using this gem.

*** WHAT TO DO ***

Most people have experienced this issue during an upgrade. Most gems and apps that previously required or depended on this library are now using a new library. Consider updating any gems or apps that depend on this library to a newer version and it will likely no longer require this gem.

Updating your various required gems or Rails version is often enough to fix this issue as the new versions shouldn’t be requiring or referencing this gem.

Sometimes just commenting out the “sassc-ruby” or “sassc” gem requirements in your Gemfile may be enough, although this may cause other errors to then trace and resolve.

Dart Sass is a new implementation of Sass if you want to look into it. https://github.com/rails/dartsass-rails

Note: This advice is provided without any warranties or represenations of any kind.

I think the damage this issue is doing to the adoption of RoR and Ruby and contributing to the downfall of these tools is underestimated. Unfortunately I don’t have enough knowledge to collaborate on a solution. It’s pitiful…

For those dealing with this issue in their Rails app(s), I was able to replace this gem with https://github.com/rails/cssbundling-rails by following this helpful article: https://dev.to/kolide/how-to-migrate-a-rails-6-app-from-sass-rails-to-cssbundling-rails-4l41

I’m not sure if this is any use, but the wkhtmltopdf-binary gem includes precompiled binaries for a numbers of platforms, and will just pick the most appropriate one at runtime.

This of course trades disk space for cpu cycles, but it could be a nice option to offer? I know I’d take it.

If anyone finds this helpful, here is where it actually takes 2 minutes (I installed ffi separately because it’s a dependency and for comparison w/time):

gns@gns-mac1 ~ % docker run -it ruby:latest /bin/bash root@4f4bf2280063:/# time gem install ffi Building native extensions. This could take a while… Successfully installed ffi-1.13.1 1 gem installed

real 0m7.137s user 0m5.407s sys 0m1.055s root@4f4bf2280063:/# time gem install sassc --verbose …

This is where it took ~2 minutes.

… real 2m21.017s user 2m11.993s sys 0m8.384s

For me it took longer, but it worked perfectly.

This is still an ongoing issue on new installs for me as well.

I guess that’s not a guarantee though and might not always work?

It’s definitely not a guarantee enough, see my comment over here.

From experience maintaining a mini_racer fork over a couple of years just for the purpose of adding more platforms, it’s immeasurably better to just consider -linux to be equal to -linux-glibc and -linux-musl (or -linux-uclibc) to be entirely distinct.

We have another binary gem, called libsqreen. That C++ one we control entirely and build with, link against, and package together with LLVM C++ libs. It results in a hefty package but that’s the only other solution we found.

Other gems (Nokogiri is one I’ve noticed in particular) seem to get around this somehow, though, using the precompiled version on Debian and RedHat and other glibc systems, while compiling from source on Alpine. I’m not sure why or how

IIRC the reason is that on some Alpine systems, Ruby ends up being set up to pick the non-binary gems only, and so never reaches to the -linux binary one. Indeed, alpine:3.12 ruby has Gem.platforms be only [:ruby], which is not the case for ruby:2.7-alpine, returning ["ruby", #<Gem::Platform:0x000055fc7e52a730 @cpu="x86_64", @os="linux", @version="musl" @cpu="x86_64", @os="linux", @version="musl">]. Note how there even the gem platform is wrong and @version is nil on ruby:2.6-alpine and below, being ["ruby", #<Gem::Platform:0x0000557454d74330 @cpu="x86_64", @os="linux", @version=nil @cpu="x86_64", @os="linux", @version=nil>] (which IIRC has more to do with the bundled rubygems version that ruby’s).

Right. It seems for Nokogiri they just dynamically link to glibc (the default) and apparently in that case it seems binary compatible with musl (I checked with ldd and require-ing+using Nokogiri in both environments). I guess that’s not a guarantee though and might not always work?