Module: Tebako::Packager

Defined in:
lib/tebako/packager.rb,
lib/tebako/packager/patch.rb,
lib/tebako/packager/patch_main.rb,
lib/tebako/packager/pass1_patch.rb,
lib/tebako/packager/pass2_patch.rb,
lib/tebako/packager/pass1a_patch.rb,
lib/tebako/packager/patch_helpers.rb,
lib/tebako/packager/patch_literals.rb,
lib/tebako/packager/rubygems_patch.rb,
lib/tebako/packager/pass2_patch_crt.rb,
lib/tebako/packager/pass2msys_patch.rb,
lib/tebako/packager/patch_libraries.rb,
lib/tebako/packager/patch_buildsystem.rb

Overview

Packager module

Defined Under Namespace

Modules: PatchBuildsystem, PatchHelpers, PatchLibraries, PatchLiterals, PatchMain Classes: Pass1APatch, Pass1DarwinPatch, Pass1MSysPatch, Pass1Patch, Pass2MSysPatch, Pass2NonMSysPatch, Pass2Patch, Patch, RubygemsPatch, RubygemsUpdatePatch

Constant Summary collapse

FILES_TO_RESTORE =
%w[
  common.mk
  configure
  config.status
  dir.c
  dln.c
  file.c
  gem_prelude.rb
  io.c
  main.c
  Makefile
  ruby.c
  thread_pthread.c
  util.c
  ext/bigdecimal/bigdecimal.h
  ext/Setup
  cygwin/GNUmakefile.in
  include/ruby/onigmo.h
  lib/rubygems/openssl.rb
  lib/rubygems/path_support.rb
  template/Makefile.in
  tool/mkconfig.rb
  win32/winmain.c
  win32/file.c
].freeze
GNUMAKEFILE_IN_DLLTOOL_SUBST =

Substitutions for cygwin/Gnumakefile.in shared across Pass1 and Pass2

<<~SUBST
  $(Q) dlltool --output-lib=$(LIBRUBY) --output-def=tebako.def --export-all $(LIBRUBY_A) --output-exp=$(RUBY_EXP)   # tebako patched
SUBST
GNUMAKEFILE_IN_WINMAIN_SUBST =

This MSYS specific thing ensure compilation of winmain.c Did try to understand why it did not work out of the box

<<~SUBST
  RUBYDEF = $(DLL_BASE_NAME).def

  # Start of tebako patch
  WINMAINOBJ    = win32/winmain.$(OBJEXT)
  $(WINMAINOBJ): win32/winmain.c
  # End of tebako patch
SUBST
IO_C_MSYS_BASE_PATCH =
{
  "#define open	rb_w32_uopen" => "#define open(p, f, m) tebako_open(3, (p), (f), (m))"
}.freeze
IO_C_MSYS_PATCH_PRE_32 =
{
  "(rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), Qnil))" =>
      "((is_tebako_file_descriptor((fptr)->fd) || rb_w32_io_cancelable_p((fptr)->fd)) ? \\\n" \
      "Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), Qnil))"
}.freeze
IO_C_MSYS_PATCH =
{
  "(rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, " \
  "RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))" =>
      "((is_tebako_file_descriptor((fptr)->fd) || rb_w32_io_cancelable_p((fptr)->fd)) ? \\\n" \
      "Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))"
}.freeze
RUBY_C_MSYS_PATH_SUBST =
<<~SUBST
  /* -- Start of tebako patch -- */
          VALUE path = within_tebako_memfs(paths) ?
                          rb_str_new_cstr(paths) :
                          RUBY_RELATIVE(paths, len);
          /* -- End of tebako patch -- */
SUBST
RUBY_C_MSYS_PATCHES =
{
  "#ifndef MAXPATHLEN" => "#{PatchLiterals::C_FILE_SUBST_LESS}\n#ifndef MAXPATHLEN",
  "VALUE path = RUBY_RELATIVE(paths, len);" => RUBY_C_MSYS_PATH_SUBST
}.freeze
WIN32_FILE_C_MSYS_SUBST =
<<~SUBST
  /* -- Start of tebako patch -- */
    if (tebako_file_load_ok(path)) return ret;
      /* -- End of tebako patch -- */
  wpath = mbstr_to_wstr(CP_UTF8, path, -1, &len);
SUBST
WIN32_FILE_C_MSYS_PATCHES =
{
  "#ifndef INVALID_FILE_ATTRIBUTES" => "#{PatchLiterals::C_FILE_SUBST_LESS}\n#ifndef INVALID_FILE_ATTRIBUTES",
  "wpath = mbstr_to_wstr(CP_UTF8, path, -1, &len);" => WIN32_FILE_C_MSYS_SUBST
}.freeze
WIN32_WIN32_C_MSYS_SUBST =
<<~SUBST
  /* -- Start of tebako patch -- */
    if (is_tebako_cwd()) {
      char* tebako_cwd = tebako_getcwd(NULL,0);
      if (tebako_cwd == NULL) {
        errno = ENOMEM;
        return NULL;
      }
      len = strlen(tebako_cwd) + 1;

      if (buffer) {
        if (size < len) {
          free(tebako_cwd);
          errno = ERANGE;
          return NULL;
        }
      }
      else {
        buffer = (*alloc)(len, arg);
        if (!buffer) {
          free(tebako_cwd);
          errno = ENOMEM;
          return NULL;
        }
      }
      translate_char(tebako_cwd, (char)0x5c, '/', CP_UTF8);
      strcpy(buffer, tebako_cwd);
      free(tebako_cwd);
      return buffer;
    }
    /* -- End of tebako patch -- */

    len = GetCurrentDirectoryW(0, NULL);
SUBST
WIN32_WIN32_C_MSYS_PATCHES =
{
  "#if defined _MSC_VER && _MSC_VER <= 1200" =>
    "#{PatchLiterals::C_FILE_SUBST_LESS}\n#if defined _MSC_VER && _MSC_VER <= 1200",
  "len = GetCurrentDirectoryW(0, NULL);" => WIN32_WIN32_C_MSYS_SUBST,
  "clock_gettime(clockid_t clock_id, struct timespec *sp)" =>
    "_dummy_clock_gettime(clockid_t clock_id, struct timespec *sp)",
  "clock_getres(clockid_t clock_id, struct timespec *sp)" =>
    "_dummy_clock_getres(clockid_t clock_id, struct timespec *sp)"
}.freeze

Class Method Summary collapse

Class Method Details

.create_implib(src_dir, package_src_dir, app_name, ruby_ver) ⇒ Object

Create implib



73
74
75
76
77
78
79
80
# File 'lib/tebako/packager.rb', line 73

def create_implib(src_dir, package_src_dir, app_name, ruby_ver)
  a_name = File.basename(app_name, ".*")
  create_def(src_dir, a_name)
  puts "   ... creating Windows import library"
  params = ["dlltool", "-d", def_fname(src_dir, a_name), "-D", out_fname(a_name), "--output-lib",
            lib_fname(package_src_dir, ruby_ver)]
  BuildHelpers.run_with_capture(params)
end

.crt_pass1_patch(ostype, mount_point, ruby_ver) ⇒ Object



38
39
40
41
42
43
44
45
46
47
# File 'lib/tebako/packager/pass1_patch.rb', line 38

def crt_pass1_patch(ostype, mount_point, ruby_ver)
  scmb = ScenarioManagerBase.new(ostype)
  if scmb.macos?
    Pass1DarwinPatch.new(mount_point, ruby_ver)
  elsif scmb.msys?
    Pass1MSysPatch.new(mount_point, ruby_ver)
  else
    Pass1Patch.new(mount_point, ruby_ver)
  end
end

.crt_pass2_patch(ostype, deps_lib_dir, ruby_ver) ⇒ Object



36
37
38
39
40
41
42
43
# File 'lib/tebako/packager/pass2_patch_crt.rb', line 36

def crt_pass2_patch(ostype, deps_lib_dir, ruby_ver)
  scmb = ScenarioManagerBase.new(ostype)
  if scmb.msys?
    Pass2MSysPatch.new(ostype, deps_lib_dir, ruby_ver)
  else
    Pass2NonMSysPatch.new(ostype, deps_lib_dir, ruby_ver)
  end
end

.deploy(target_dir, pre_dir, ruby_ver, fs_root, fs_entrance, cwd) ⇒ Object

Deploy



83
84
85
86
87
88
89
90
# File 'lib/tebako/packager.rb', line 83

def deploy(target_dir, pre_dir, ruby_ver, fs_root, fs_entrance, cwd) # rubocop:disable Metrics/ParameterLists
  puts "-- Running deploy script"

  deploy_helper = Tebako::DeployHelper.new(fs_root, fs_entrance, target_dir, pre_dir)
  deploy_helper.configure(ruby_ver, cwd)
  deploy_helper.deploy
  Tebako::Stripper.strip(deploy_helper, target_dir)
end

.do_patch(patch_map, root) ⇒ Object



92
93
94
# File 'lib/tebako/packager.rb', line 92

def do_patch(patch_map, root)
  patch_map.each { |fname, mapping| PatchHelpers.patch_file("#{root}/#{fname}", mapping) }
end

.finalize(src_dir, app_name, ruby_ver, patchelf, output_type) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/tebako/packager.rb', line 96

def finalize(src_dir, app_name, ruby_ver, patchelf, output_type)
  puts "-- Running finalize script"

  RubyBuilder.new(ruby_ver, src_dir).target_build(output_type)
  exe_suffix = ScenarioManagerBase.new.exe_suffix
  src_name = File.join(src_dir, "ruby#{exe_suffix}")
  patchelf(src_name, patchelf)
  package_name = "#{app_name}#{exe_suffix}"
  # strip_or_copy(os_type, src_name, package_name)
  Tebako::Stripper.strip_file(src_name, package_name)
  puts "Created tebako #{output_type} at \"#{package_name}\""
end

.init(stash_dir, src_dir, pre_dir, bin_dir) ⇒ Object

Init



110
111
112
113
114
115
116
# File 'lib/tebako/packager.rb', line 110

def init(stash_dir, src_dir, pre_dir, bin_dir)
  puts "-- Running init script"

  puts "   ... creating packaging environment at #{src_dir}"
  PatchHelpers.recreate([src_dir, pre_dir, bin_dir])
  FileUtils.cp_r "#{stash_dir}/.", src_dir
end

.mkdwarfs(deps_bin_dir, data_bin_file, data_src_dir, descriptor = nil) ⇒ Object



118
119
120
121
122
123
124
# File 'lib/tebako/packager.rb', line 118

def mkdwarfs(deps_bin_dir, data_bin_file, data_src_dir, descriptor = nil)
  puts "-- Running mkdwarfs script"
  FileUtils.chmod("a+x", Dir.glob(File.join(deps_bin_dir, "mkdwarfs*")))
  params = [File.join(deps_bin_dir, "mkdwarfs"), "-o", data_bin_file, "-i", data_src_dir, "--no-progress"]
  params << "--header" << descriptor if descriptor
  BuildHelpers.run_with_capture_v(params)
end

.pass1(ostype, ruby_source_dir, mount_point, src_dir, ruby_ver) ⇒ Object

Pass1 Executed before Ruby build, patching ensures that Ruby itself is linked statically



128
129
130
131
132
133
134
135
136
137
138
# File 'lib/tebako/packager.rb', line 128

def pass1(ostype, ruby_source_dir, mount_point, src_dir, ruby_ver)
  puts "-- Running pass1 script"
  PatchHelpers.recreate(src_dir)

  # Roll all known patches
  # Just in case we are recovering after some error
  PatchHelpers.restore_and_save_files(FILES_TO_RESTORE, ruby_source_dir, strict: false)

  patch = crt_pass1_patch(ostype, mount_point, ruby_ver)
  do_patch(patch.patch_map, ruby_source_dir)
end

.pass1a(ruby_source_dir) ⇒ Object

Pass1A Patch gem_prelude.rb



142
143
144
145
146
# File 'lib/tebako/packager.rb', line 142

def pass1a(ruby_source_dir)
  puts "-- Running pass1a script"
  patch = Pass1APatch.new
  do_patch(patch.patch_map, ruby_source_dir)
end

.pass2(ostype, ruby_source_dir, deps_lib_dir, ruby_ver) ⇒ Object

Pass2 Creates packaging environment, patching ensures that tebako package is linked statically



150
151
152
153
154
155
# File 'lib/tebako/packager.rb', line 150

def pass2(ostype, ruby_source_dir, deps_lib_dir, ruby_ver)
  puts "-- Running pass2 script"

  patch = crt_pass2_patch(ostype, deps_lib_dir, ruby_ver)
  do_patch(patch.patch_map, ruby_source_dir)
end

.stash(src_dir, stash_dir, ruby_source_dir, ruby_ver) ⇒ Object

Stash Created and saves pristine Ruby environment that is used to deploy applications for packaging



159
160
161
162
163
164
165
166
# File 'lib/tebako/packager.rb', line 159

def stash(src_dir, stash_dir, ruby_source_dir, ruby_ver)
  puts "-- Running stash script"
  RubyBuilder.new(ruby_ver, ruby_source_dir).toolchain_build

  puts "   ... saving pristine Ruby environment to #{stash_dir}"
  PatchHelpers.recreate(stash_dir)
  FileUtils.cp_r "#{src_dir}/.", stash_dir
end