How can I use Gitlab CI to work with tcl/tk dependency?

Context

I’m building for some weeks a GUI project in ruby where I chose to use Tcl/tk gem.

Now that I start having something a bit functionnal, I invested some time into my CI. I wanted to use gitlab CI but only specifying the gem in my Gemfile doesn’t work. (full build output at the end)

I’ve checked online and in this forum but can’t find someone that tried the same haha
I’ve tried to download activestate on the fly, complile it in the before_script, but could not manage to make it work.

I know the configuration is quite unique (Tk + ruby on gitlab) but i’m sure there must be a way to make everything work.

Some info on the way :

  • To make it work locally i had to install it from Download & Install Tcl | ActiveState
  • I don’t really need it to run the CI as i test everything around tk without launching anything, maybe we can find a way to skip this install ?

Configuration

  • I’m working on a mac pro with ruby 2.6
  • I’m using gitlab.com (not self hosted)

My current gitlab-ci.yml :

# This file is a template, and might need editing before it works on your project.
# Official language image. Look for the different tagged releases at:
# https://hub.docker.com/r/library/ruby/tags/
image: "ruby:2.6"

# Cache gems in between builds
cache:
  paths:
    - vendor/ruby

# This is a basic example for a gem or script which doesn't use
# services such as redis or postgres
before_script:
  - ruby -v  # Print out ruby version for debugging
  - wget https://platform.activestate.com/dl/cli/install.sh
  - chmod +x ./install.sh
  - ./install.sh -n -t /usr/local/bin
  - bundle install -j $(nproc) --path vendor  # Install dependencies into ./vendor/ruby

# Optional - Delete if not using `rubocop`
rubocop:
  script:
    - rubocop

rspec:
  script:
    - rspec spec

pages:
  script:
    - mkdir public/ || true
    - make doc
  artifacts:
    paths:
      - public
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

(all three jobs fail)

I’m really open to suggestion and ready to try lots of things !
And if you really need it, here is the repo i’m trying to build \o/

EDIT

I’ve found that it might be really easy, just running apt install tk8.6-dev ruby2.7 ruby2.7-dev

but the jobs fail with messages:

$ apt install tk8.6-dev ruby2.7 ruby2.7-dev
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Reading package lists...
Building dependency tree...
Reading state information...
E: Unable to locate package tk8.6-dev
E: Couldn't find any package by glob 'tk8.6-dev'
E: Couldn't find any package by regex 'tk8.6-dev'
E: Unable to locate package ruby2.7
E: Couldn't find any package by glob 'ruby2.7'
E: Couldn't find any package by regex 'ruby2.7'
E: Unable to locate package ruby2.7-dev
E: Couldn't find any package by glob 'ruby2.7-dev'
E: Couldn't find any package by regex 'ruby2.7-dev'

Full output of bundle install :

$ bundle install -j $(nproc) --path vendor
Warning: the running version of Bundler (1.17.2) is older than the version that created the lockfile (1.17.3). We suggest you upgrade to the latest version of Bundler by running `gem install bundler`.
Fetching gem metadata from https://rubygems.org/.......
Fetching gem metadata from https://rubygems.org/.......
Fetching gem metadata from https://rubygems.org/.
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies...
Fetching rake 10.5.0
Installing rake 10.5.0
Using bundler 1.17.2
Fetching byebug 11.1.3
Installing byebug 11.1.3 with native extensions
Fetching childprocess 3.0.0
Installing childprocess 3.0.0
Fetching diff-lcs 1.4.4
Installing diff-lcs 1.4.4
Fetching iniparse 1.5.0
Installing iniparse 1.5.0
Fetching overcommit 0.53.0
Installing overcommit 0.53.0
Fetching tk 0.3.0
Installing tk 0.3.0 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
current directory:
/builds/esilvert/red/vendor/ruby/2.6.0/gems/tk-0.3.0/ext/tk
/usr/local/bin/ruby -I /usr/local/lib/ruby/2.6.0 -r
./siteconf20210206-11-2d7222.rb extconf.rb
check functions.checking for ruby_native_thread_p() in ruby.h... yes
checking for rb_errinfo() in ruby.h... yes
checking for rb_hash_lookup() in ruby.h... yes
checking for rb_proc_new() in ruby.h... yes
checking for rb_sourcefile() in ruby.h... yes
checking for rb_thread_alive_p() in ruby.h... no
checking for rb_thread_check_trap_pending() in ruby.h... yes
checking for ruby_enc_find_basename() in ruby.h... yes
check libraries.checking for t_open() in -lnsl... no
checking for socket() in -lsocket... no
checking for dlopen() in -ldl... yes
checking for log() in -lm... yes
Use ActiveTcl libraries (if available).
Search tclConfig.sh and tkConfig.sh.
Fail to find [tclConfig.sh, tkConfig.sh]
Use X11 libraries (or use TK_XINCLUDES/TK_XLIBSW information on tkConfig.sh).
checking for XOpenDisplay() in -lX11... yes
Search tcl.h
checking for tcl.h... no
Search tk.h
checking for tk.h... no
Search Tcl library..........*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.
Provided configuration options:
	--with-opt-dir
	--without-opt-dir
	--with-opt-include
	--without-opt-include=${opt-dir}/include
	--with-opt-lib
	--without-opt-lib=${opt-dir}/lib
	--with-make-prog
	--without-make-prog
	--srcdir=.
	--curdir
	--ruby=/usr/local/bin/$(RUBY_BASE_NAME)
	--enable-shared
	--with-tk-old-extconf
	--without-tk-old-extconf
	--with-tk-old-extconf
	--without-tk-old-extconf
	--with-ActiveTcl
	--without-ActiveTcl
	--with-tk-shlib-search-path
	--without-tk-shlib-search-path
	--with-tcltkversion
	--without-tcltkversion
	--with-tcl-build-dir
	--without-tcl-build-dir
	--with-tk-build-dir
	--without-tk-build-dir
	--with-tcl-config
	--without-tcl-config
	--with-tk-config
	--without-tk-config
	--with-tclConfig-dir
	--without-tclConfig-dir
	--with-tkConfig-dir
	--without-tkConfig-dir
	--with-tclConfig-file
	--without-tclConfig-file
	--with-tkConfig-file
	--without-tkConfig-file
	--with-tcllib
	--without-tcllib
	--with-tklib
	--without-tklib
	--with-tcl-dir
	--without-tcl-dir
	--with-tk-dir
	--without-tk-dir
	--with-tcl-include
	--without-tcl-include
	--with-tk-include
	--without-tk-include
	--with-tcl-lib
	--without-tcl-lib
	--with-tk-lib
	--without-tk-lib
	--with-tcltk-framework
	--without-tcltk-framework
	--with-tcl-framework-dir
	--without-tcl-framework-dir
	--with-tk-framework-dir
	--without-tk-framework-dir
	--with-tcl-framework-header
	--without-tcl-framework-header
	--with-tk-framework-header
	--without-tk-framework-header
	--with-X11
	--without-X11
	--with-X11-dir
	--without-X11-dir
	--with-X11-include
	--without-X11-include
	--with-X11-lib
	--without-X11-lib
	--enable-tcltk-stubs
	--disable-tcltk-stubs
	--enable-tcl-h-ver-check
	--disable-tcl-h-ver-check
	--enable-tk-h-ver-check
	--disable-tk-h-ver-check
	--enable-mac-tcltk-framework
	--disable-mac-tcltk-framework
	--enable-tcltk-framework
	--disable-tcltk-framework
	--enable-pthread
	--disable-pthread
	--enable-tcl-thread
	--disable-tcl-thread
	--enable-space-on-tk-libpath
	--disable-space-on-tk-libpath
	--with-nsllib
	--without-nsllib
	--with-socketlib
	--without-socketlib
	--with-dllib
	--without-dllib
	--with-mlib
	--without-mlib
	--with-tcl-build-dir
	--without-tcl-build-dir
	--with-tk-build-dir
	--without-tk-build-dir
	--with-tcltkversion
	--without-tcltkversion
	--with-ActiveTcl
	--without-ActiveTcl
	--enable-space-on-tk-libpath
	--disable-space-on-tk-libpath
	--enable-tcltk-stubs
	--disable-tcltk-stubs
	--with-tcltk-stubs
	--without-tcltk-stubs
	--with-tcl-dir
	--without-tcl-dir
	--with-tcl-include
	--without-tcl-include=${tcl-dir}/include
	--with-tcl-lib
	--without-tcl-lib=${tcl-dir}/lib
	--with-tk-dir
	--without-tk-dir
	--with-tk-include
	--without-tk-include=${tk-dir}/include
	--with-tk-lib
	--without-tk-lib=${tk-dir}/lib
	--with-tclConfig-file
	--without-tclConfig-file
	--with-tkConfig-file
	--without-tkConfig-file
	--with-tclConfig-dir
	--without-tclConfig-dir
	--with-tkConfig-dir
	--without-tkConfig-dir
	--with-tcl-framework-header
	--without-tcl-framework-header
	--with-tk-framework-header
	--without-tk-framework-header
	--with-tcl-framework-dir
	--without-tcl-framework-dir
	--with-tk-framework-dir
	--without-tk-framework-dir
	--with-tcltk-framework
	--without-tcltk-framework
	--enable-tcltk-framework
	--disable-tcltk-framework
	--with-tcltk-framework
	--without-tcltk-framework
	--enable-tcltk-framework
	--disable-tcltk-framework
	--enable-mac-tcltk-framework
	--disable-mac-tcltk-framework
	--with-tk-shlib-search-path
	--without-tk-shlib-search-path
	--with-tklib
	--without-tklib
	--with-tcllib
	--without-tcllib
	--with-X11
	--without-X11
	--with-X11-dir
	--without-X11-dir
	--with-X11-include
	--without-X11-include=${X11-dir}/include
	--with-X11-lib
	--without-X11-lib=${X11-dir}/lib
	--with-X11-lib
	--without-X11-lib
	--with-X11lib
	--without-X11lib
	--enable-tcl-h-ver-check
	--disable-tcl-h-ver-check
	--enable-tk-h-ver-check
	--disable-tk-h-ver-check
Warning:: cannot find Tcl library. tcltklib will not be compiled (tcltklib is
disabled on your Ruby. That is, Ruby/Tk will not work). Please check configure
options.
Can't find proper Tcl/Tk libraries. So, can't make tcltklib.so which is required
by Ruby/Tk.
If you have Tcl/Tk libraries on your environment, you may be able to use them
with configure options (see ext/tk/README.tcltklib).
At present, Tcl/Tk8.6 is not supported. Although you can try to use Tcl/Tk8.6
with configure options, it will not work correctly. I recommend you to use
Tcl/Tk8.5 or 8.4.
To see why this extension failed to compile, please check the mkmf.log which can
be found here:
/builds/esilvert/red/vendor/ruby/2.6.0/extensions/x86_64-linux/2.6.0/tk-0.3.0/mkmf.log
extconf failed, exit code 1
Gem files will remain installed in
/builds/esilvert/red/vendor/ruby/2.6.0/gems/tk-0.3.0 for inspection.
Results logged to
/builds/esilvert/red/vendor/ruby/2.6.0/extensions/x86_64-linux/2.6.0/tk-0.3.0/gem_make.out
An error occurred while installing tk (0.3.0), and Bundler cannot continue.
Make sure that gem install tk -v '0.3.0' --source 'https://rubygems.org/'
succeeds before bundling.
In Gemfile:
  red was resolved to 0.1.0, which depends on
    tk
```

Okay i’ve managed to bundle. I needed to install tcl/tk on the docker system, i’ve managed to do it so with this before_sript :

before_script:
  - ruby -v  # Print out ruby version for debugging
  - cd build
  - tar -xf ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d.tar.gz
  - cd ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d
  - echo -e "\nA\n" | ./install.sh
  - export PATH="/opt/ActiveTcl-8.6/bin:$PATH"
  - cd ../../
  - apt-get update && apt-get install -y tcl tk tcl-dev tk-dev
  - bundle update --bundler
  - bundle install

(The tar.gz comes from the activestate website)

But unfortunately I hurt myself in a harder wall : The tk framework won’t initialize once running the ruby scripts (here i try to run the test suite) :

$ rspec spec

[1591](https://gitlab.com/esilvert/red/-/jobs/1016069659#L1591)#<Thread:0x000055f4c173c9c0 /usr/local/bundle/gems/tk-0.3.0/lib/tk.rb:1226 run> terminated with exception (report_on_exception is true):

[1592](https://gitlab.com/esilvert/red/-/jobs/1016069659#L1592)/usr/local/bundle/gems/tk-0.3.0/lib/tk.rb:32:in `initialize': tcltklib: fail to Tk_Init(). (RuntimeError)

[1593](https://gitlab.com/esilvert/red/-/jobs/1016069659#L1593) from /usr/local/bundle/gems/tk-0.3.0/lib/tk.rb:32:in `initialize'

[1594](https://gitlab.com/esilvert/red/-/jobs/1016069659#L1594) from /usr/local/bundle/gems/tk-0.3.0/lib/tk.rb:1229:in `new'

[1595](https://gitlab.com/esilvert/red/-/jobs/1016069659#L1595) from /usr/local/bundle/gems/tk-0.3.0/lib/tk.rb:1229:in `block in <module:TkCore>'

[1596](https://gitlab.com/esilvert/red/-/jobs/1016069659#L1596)RuntimeError

[1597](https://gitlab.com/esilvert/red/-/jobs/1016069659#L1597)"tcltklib: fail to Tk_Init(). "

[1598](https://gitlab.com/esilvert/red/-/jobs/1016069659#L1598)An error occurred while loading spec_helper.

[1599](https://gitlab.com/esilvert/red/-/jobs/1016069659#L1599)Failure/Error: ENV['RED_ENV'] ||= Red::Env::TEST

[1600](https://gitlab.com/esilvert/red/-/jobs/1016069659#L1600)NameError:

[1601](https://gitlab.com/esilvert/red/-/jobs/1016069659#L1601) uninitialized constant Red::Env

[1602](https://gitlab.com/esilvert/red/-/jobs/1016069659#L1602) Did you mean? ENV

[1603](https://gitlab.com/esilvert/red/-/jobs/1016069659#L1603)# ./spec/spec_helper.rb:22:in `block in <top (required)>'

[1604](https://gitlab.com/esilvert/red/-/jobs/1016069659#L1604)# ./spec/spec_helper.rb:11:in `<top (required)>'

There is nothing online about such an error. I suspect an issue with version compatibility but can’t really find where it is; as i’ve tried many many many things.

Any idea about how tk won’t initialize on a machine ?

I’ve managed to run my code on anoter PC running fedora with this actuall before_script instructions.