sassc-ruby
sassc-ruby copied to clipboard
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 withg++ 8.3.1
!time gem install sassc -- --disable-lto
takes113.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
For comparison, nokogiri 1.10.9 takes 30 seconds to compile:
$ time gem install nokogiri
Building native extensions. This could take a while...
Successfully installed nokogiri-1.10.9
1 gem installed
gem install nokogiri 24.42s user 7.26s system 102% cpu 30.846 total
libxml2 is a much larger library than libsass (200k C SLOC vs 22k C++ SLOC), but probably part of why it compiles faster is it's C instead of C++.
@bolandrm @glebm Thoughts on this? Which approaches do you think we should use to speed up the installation of this gem?
@eregon Enable parallel compilation or do a unity bulid
See https://github.com/sparklemotion/nokogiri/issues/1983#issuecomment-605657240 regarding what nokogiri does. I'm not sure what they do to deal with alpine but the binary gem seems to work with alpine/musl.
@glebm Could you clarify the main issue(s) with having precompiled gems for linux/macos for sassc?
@eregon The main issue is libc. RubyGems does not allow targeting different versions of libc. This is a deficiency in RubyGems. A libc cannot be linked statically for this project, one of the reasons being that plugins are loaded using dlopen.
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?
This is undefined behaviour, and won't work with ucLibc or even older glibc.
There is an open PR in the Nokogiri repo that removes the use of sprintf
because sprintf
segfaults on musl with the precompiled gem (see 1571).
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.
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
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.
same case here, it takes more than 9 minutes to install causing the cancelation of the bundle install :/
Similar story here, our build time is clocking in at 13mins at the moment which is mostly spent compiling sassc (with native extensions)
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.
Regarding precompiled binaries, see https://github.com/sass/sassc-ruby/issues/189#issuecomment-605687236 and before.
In short, it seems musl does not guarantee to be binary compatible with glibc. Nokogiri seems to be lucky enough to only use libc functions which are compatible (except sprintf
which was worked around), but I guess that's much less feasible for a C++ codebase like libsass.
A good way forward would be to consider the libc in RubyGems when checking for precompiled gems. That would be useful beyond just sassc. It seems there is already some support for it actually, see https://github.com/rubygems/rubygems/pull/2922 but seems there is some issue: https://github.com/rubygems/rubygems/issues/3174.
Anyone interested to fix that? Essentially, we'd need a way that alpine users would not download the glibc-precompiled gems, because that's generally not going to work. Ideally it'd be possible to upload alpine-precompiled gems to RubyGems too.
A workaround until then could be to use separate release versions for "precompiled" and "not", like libv8 does.
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).
Hi there, we had this issue and found some others already mentioned by @lloeki. We avoid rebuilding binary gems altogether by hosting our own gem repo with geminabox and gem-compiler, but due to https://github.com/rubygems/rubygems/issues/3174 the repo can only host binary gems built for musl (and a single musl version at that).
This is still an ongoing issue on new installs for me as well.
Are there plans to address this, specifically shipping pre-compiled binaries for Debian or other popular distros?
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.
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.
Holy cow...this took over 13 mins to install
:(
This helped:
gem 'sassc', '~> 2.1.0'
I can confirm that this is an issue for me too. Wow.
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
This is still an issue, it takes about 20 minutes on my docker machine.
Still an issue