rbe-tebako 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/.clang-format +4 -0
  3. data/Brewfile +23 -0
  4. data/CMakeLists.txt +464 -0
  5. data/CODE_OF_CONDUCT.adoc +128 -0
  6. data/CONTRIBUTING.adoc +294 -0
  7. data/Gemfile +31 -0
  8. data/INSTALLATION.adoc +233 -0
  9. data/LICENSE.md +33 -0
  10. data/README.adoc +1363 -0
  11. data/Rakefile +35 -0
  12. data/bin/console +15 -0
  13. data/bin/setup +8 -0
  14. data/cmake/copy_dir.cmake +29 -0
  15. data/common.env +5 -0
  16. data/exe/rbe-tebako +32 -0
  17. data/exe/rbe-tebako-packager +77 -0
  18. data/include/tebako/tebako-fs.h +43 -0
  19. data/include/tebako/tebako-main.h +42 -0
  20. data/include/tebako/tebako-prism.h +51 -0
  21. data/lib/rbe-tebako.rb +6 -0
  22. data/lib/tebako/build_helpers.rb +77 -0
  23. data/lib/tebako/cache_manager.rb +112 -0
  24. data/lib/tebako/cli.rb +220 -0
  25. data/lib/tebako/cli_helpers.rb +165 -0
  26. data/lib/tebako/codegen.rb +252 -0
  27. data/lib/tebako/deploy_helper.rb +258 -0
  28. data/lib/tebako/error.rb +70 -0
  29. data/lib/tebako/options_manager.rb +338 -0
  30. data/lib/tebako/package_descriptor.rb +143 -0
  31. data/lib/tebako/packager/pass1_patch.rb +266 -0
  32. data/lib/tebako/packager/pass1a_patch.rb +55 -0
  33. data/lib/tebako/packager/pass2_patch.rb +140 -0
  34. data/lib/tebako/packager/pass2_patch_crt.rb +46 -0
  35. data/lib/tebako/packager/pass2msys_patch.rb +190 -0
  36. data/lib/tebako/packager/patch.rb +54 -0
  37. data/lib/tebako/packager/patch_buildsystem.rb +124 -0
  38. data/lib/tebako/packager/patch_helpers.rb +109 -0
  39. data/lib/tebako/packager/patch_libraries.rb +188 -0
  40. data/lib/tebako/packager/patch_literals.rb +275 -0
  41. data/lib/tebako/packager/patch_main.rb +93 -0
  42. data/lib/tebako/packager/rubygems_patch.rb +83 -0
  43. data/lib/tebako/packager.rb +210 -0
  44. data/lib/tebako/packager_lite.rb +78 -0
  45. data/lib/tebako/ruby_builder.rb +71 -0
  46. data/lib/tebako/ruby_version.rb +206 -0
  47. data/lib/tebako/scenario_manager.rb +251 -0
  48. data/lib/tebako/stripper.rb +135 -0
  49. data/lib/tebako/version.rb +30 -0
  50. data/lib/tebako.rb +34 -0
  51. data/src/tebako-main.cpp +168 -0
  52. data/tools/.gitattributes +4 -0
  53. data/tools/.github/workflows/build-containers.yml +190 -0
  54. data/tools/.github/workflows/lint.yml +41 -0
  55. data/tools/.github/workflows/test.yml +331 -0
  56. data/tools/.gitignore +1 -0
  57. data/tools/README.md +49 -0
  58. data/tools/ci-scripts/arm-brew-install.sh +43 -0
  59. data/tools/ci-scripts/arm-brew-setup.sh +33 -0
  60. data/tools/ci-scripts/level-up.sh +35 -0
  61. data/tools/ci-scripts/patch-fbthrift.sh +94 -0
  62. data/tools/ci-scripts/patch-folly.sh +551 -0
  63. data/tools/ci-scripts/patch-glog.sh +57 -0
  64. data/tools/ci-scripts/patch-zstd.sh +57 -0
  65. data/tools/ci-scripts/tools.sh +63 -0
  66. data/tools/ci-scripts/x86-brew-install.sh +43 -0
  67. data/tools/ci-scripts/x86-brew-setup.sh +33 -0
  68. data/tools/cmake-scripts/def-external-project.cmake +96 -0
  69. data/tools/cmake-scripts/macos-environment.cmake +91 -0
  70. data/tools/cmake-scripts/msys-environment.cmake +78 -0
  71. data/tools/cmake-scripts/setup-libarchive.cmake +93 -0
  72. data/tools/cmake-scripts/setup-libfmt.cmake +61 -0
  73. data/tools/cmake-scripts/setup-libhowardhinnerdate.cmake +55 -0
  74. data/tools/cmake-scripts/setup-libutfcpp.cmake +56 -0
  75. data/tools/cmake-scripts/version.cmake +162 -0
  76. data/tools/docker/alpine-3.17-dev.Dockerfile +49 -0
  77. data/tools/docker/tools/tools.sh +66 -0
  78. data/tools/docker/ubuntu-20.04-dev.Dockerfile +51 -0
  79. data/tools/dwarfs-test-helper/CMakeLists.txt +34 -0
  80. data/tools/include/pro-statvfs.h +57 -0
  81. data/tools/tests/cmake/CMakeLists.txt +81 -0
  82. data/tools/tests/setup-libfmt/CMakeLists.txt +35 -0
  83. data/tools/tests/setup-libhowardhinnerdate/CMakeLists.txt +35 -0
  84. data/tools/tests/setup-librachive/CMakeLists.txt +35 -0
  85. data/tools/tests/setup-libutfcpp/CMakeLists.txt +36 -0
  86. data/tools/tests/setup-openssl/CMakeLists.txt +36 -0
  87. metadata +312 -0
@@ -0,0 +1,190 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2021-2025 [Ribose Inc](https://www.ribose.com).
4
+ # All rights reserved.
5
+ # This file is a part of the Tebako project.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions
9
+ # are met:
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ # 2. Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ #
16
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+ # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18
+ # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
20
+ # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
+ # POSSIBILITY OF SUCH DAMAGE.
27
+
28
+ require_relative "pass2_patch"
29
+ require_relative "patch_helpers"
30
+ require_relative "patch_literals"
31
+
32
+ # Tebako - an executable packager
33
+ module Tebako
34
+ # Packager module
35
+ module Packager
36
+ IO_C_MSYS_BASE_PATCH = {
37
+ "#define open rb_w32_uopen" => "#define open(p, f, m) tebako_open(3, (p), (f), (m))"
38
+ }.freeze
39
+
40
+ IO_C_MSYS_PATCH_PRE_32 = {
41
+ "(rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), Qnil))" =>
42
+ "((is_tebako_file_descriptor((fptr)->fd) || rb_w32_io_cancelable_p((fptr)->fd)) ? \\\n" \
43
+ "Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), Qnil))"
44
+ }.freeze
45
+
46
+ IO_C_MSYS_PATCH = {
47
+ "(rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, " \
48
+ "RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))" =>
49
+ "((is_tebako_file_descriptor((fptr)->fd) || rb_w32_io_cancelable_p((fptr)->fd)) ? \\\n" \
50
+ "Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))"
51
+ }.freeze
52
+
53
+ RUBY_C_MSYS_PATH_SUBST = <<~SUBST
54
+ /* -- Start of tebako patch -- */
55
+ VALUE path = within_tebako_memfs(paths) ?
56
+ rb_str_new_cstr(paths) :
57
+ RUBY_RELATIVE(paths, len);
58
+ /* -- End of tebako patch -- */
59
+ SUBST
60
+
61
+ RUBY_C_MSYS_PATCHES = {
62
+ "#ifndef MAXPATHLEN" => "#{PatchLiterals::C_FILE_SUBST_LESS}\n#ifndef MAXPATHLEN",
63
+ "VALUE path = RUBY_RELATIVE(paths, len);" => RUBY_C_MSYS_PATH_SUBST
64
+ }.freeze
65
+
66
+ WIN32_FILE_C_MSYS_SUBST = <<~SUBST
67
+ /* -- Start of tebako patch -- */
68
+ if (tebako_file_load_ok(path)) return ret;
69
+ /* -- End of tebako patch -- */
70
+ wpath = mbstr_to_wstr(CP_UTF8, path, -1, &len);
71
+ SUBST
72
+
73
+ WIN32_FILE_C_MSYS_PATCHES = {
74
+ "#ifndef INVALID_FILE_ATTRIBUTES" => "#{PatchLiterals::C_FILE_SUBST_LESS}\n#ifndef INVALID_FILE_ATTRIBUTES",
75
+ "wpath = mbstr_to_wstr(CP_UTF8, path, -1, &len);" => WIN32_FILE_C_MSYS_SUBST
76
+ }.freeze
77
+
78
+ WIN32_WIN32_C_MSYS_SUBST = <<~SUBST
79
+ /* -- Start of tebako patch -- */
80
+ if (is_tebako_cwd()) {
81
+ char* tebako_cwd = tebako_getcwd(NULL,0);
82
+ if (tebako_cwd == NULL) {
83
+ errno = ENOMEM;
84
+ return NULL;
85
+ }
86
+ len = strlen(tebako_cwd) + 1;
87
+
88
+ if (buffer) {
89
+ if (size < len) {
90
+ free(tebako_cwd);
91
+ errno = ERANGE;
92
+ return NULL;
93
+ }
94
+ }
95
+ else {
96
+ buffer = (*alloc)(len, arg);
97
+ if (!buffer) {
98
+ free(tebako_cwd);
99
+ errno = ENOMEM;
100
+ return NULL;
101
+ }
102
+ }
103
+ translate_char(tebako_cwd, (char)0x5c, '/', CP_UTF8);
104
+ strcpy(buffer, tebako_cwd);
105
+ free(tebako_cwd);
106
+ return buffer;
107
+ }
108
+ /* -- End of tebako patch -- */
109
+
110
+ len = GetCurrentDirectoryW(0, NULL);
111
+ SUBST
112
+
113
+ WIN32_WIN32_C_MSYS_PATCHES = {
114
+ "#if defined _MSC_VER && _MSC_VER <= 1200" =>
115
+ "#{PatchLiterals::C_FILE_SUBST_LESS}\n#if defined _MSC_VER && _MSC_VER <= 1200",
116
+ "len = GetCurrentDirectoryW(0, NULL);" => WIN32_WIN32_C_MSYS_SUBST,
117
+ "clock_gettime(clockid_t clock_id, struct timespec *sp)" =>
118
+ "_dummy_clock_gettime(clockid_t clock_id, struct timespec *sp)",
119
+ "clock_getres(clockid_t clock_id, struct timespec *sp)" =>
120
+ "_dummy_clock_getres(clockid_t clock_id, struct timespec *sp)"
121
+ }.freeze
122
+
123
+ # Msys Pass2 patches
124
+ class Pass2MSysPatch < Pass2Patch
125
+ def patch_map
126
+ pm = super
127
+ pm.merge!(msys_patches)
128
+ pm.store("config.status", get_config_status_patch(@ostype, @deps_lib_dir, @ruby_ver))
129
+ pm
130
+ end
131
+
132
+ private
133
+
134
+ # Other MSYS (GNUMakefile) specific patches
135
+ # - The same issue with libraries as for Makefile above
136
+ # - 'Kill' ruby.exp regeneration on pass2
137
+ # since we want to use output from pass1 for implib generation
138
+ # [VERY UGLY HACK]
139
+ # - Introduce LIBRUBY dependency on static extensions
140
+ # This is an addition to COMMON_MK_PATCH specified above
141
+ def gnumakefile_in_patch_p2 # rubocop:disable Metrics/MethodLength
142
+ objext = @ruby_ver.ruby32? ? "$(OBJEXT)" : "@OBJEXT@"
143
+
144
+ {
145
+ "$(Q) $(DLLWRAP) \\" => GNUMAKEFILE_IN_DLLTOOL_SUBST,
146
+
147
+ "--output-exp=$(RUBY_EXP) \\" => "# tebako patched --output-exp=$(RUBY_EXP) \\",
148
+
149
+ "--export-all $(LIBRUBY_A) $(LIBS) -o $(PROGRAM)" =>
150
+ "# tebako patched --export-all $(LIBRUBY_A) $(LIBS) -o $(PROGRAM)",
151
+
152
+ "@rm -f $(PROGRAM)" => "# tebako patched @rm -f $(PROGRAM)",
153
+
154
+ " $(Q) $(LDSHARED) $(DLDFLAGS) $(OBJS) dmyext.o $(SOLIBS) -o $(PROGRAM)" =>
155
+ "# tebako patched $(Q) $(LDSHARED) $(DLDFLAGS) $(OBJS) dmyext.o $(SOLIBS) -o $(PROGRAM)",
156
+
157
+ "$(WPROGRAM): $(RUBYW_INSTALL_NAME).res.#{objext}" =>
158
+ "$(WPROGRAM): $(RUBYW_INSTALL_NAME).res.#{objext} $(WINMAINOBJ) # tebako patched",
159
+
160
+ "RUBYDEF = $(DLL_BASE_NAME).def" => GNUMAKEFILE_IN_WINMAIN_SUBST,
161
+
162
+ "$(MAINOBJ) $(EXTOBJS) $(LIBRUBYARG) $(LIBS) -o $@" =>
163
+ "$(WINMAINOBJ) $(EXTOBJS) $(LIBRUBYARG) $(MAINLIBS) -o $@ # tebako patched",
164
+
165
+ "$(RUBY_EXP): $(LIBRUBY_A)" => "dummy.exp: $(LIBRUBY_A) # tebako patched",
166
+
167
+ "$(PROGRAM): $(RUBY_INSTALL_NAME).res.#{objext}" =>
168
+ "$(PROGRAM): $(RUBY_INSTALL_NAME).res.#{objext} $(LIBRUBY_A) # tebako patched\n" \
169
+ "$(LIBRUBY_A): $(LIBRUBY_A_OBJS) $(INITOBJS) # tebako patched\n"
170
+ }
171
+ end
172
+
173
+ def io_c_patch
174
+ patch = super
175
+ patch.merge!(@ruby_ver.ruby32? ? IO_C_MSYS_PATCH : IO_C_MSYS_PATCH_PRE_32)
176
+ patch.merge!(IO_C_MSYS_BASE_PATCH)
177
+ patch
178
+ end
179
+
180
+ def msys_patches
181
+ {
182
+ "cygwin/GNUmakefile.in" => gnumakefile_in_patch_p2,
183
+ "ruby.c" => RUBY_C_MSYS_PATCHES,
184
+ "win32/file.c" => WIN32_FILE_C_MSYS_PATCHES,
185
+ "win32/win32.c" => WIN32_WIN32_C_MSYS_PATCHES
186
+ }
187
+ end
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2025 [Ribose Inc](https://www.ribose.com).
4
+ # All rights reserved.
5
+ # This file is a part of the Tebako project.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions
9
+ # are met:
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ # 2. Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ #
16
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+ # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18
+ # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
20
+ # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
+ # POSSIBILITY OF SUCH DAMAGE.
27
+
28
+ # Tebako - an executable packager
29
+ module Tebako
30
+ module Packager
31
+ # Substitutions for cygwin/Gnumakefile.in shared across Pass1 and Pass2
32
+ GNUMAKEFILE_IN_DLLTOOL_SUBST = <<~SUBST
33
+ $(Q) dlltool --output-lib=$(LIBRUBY) --output-def=tebako.def --export-all $(LIBRUBY_A) --output-exp=$(RUBY_EXP) # tebako patched
34
+ SUBST
35
+
36
+ # This MSYS specific thing ensure compilation of winmain.c
37
+ # Did try to understand why it did not work out of the box
38
+ GNUMAKEFILE_IN_WINMAIN_SUBST = <<~SUBST
39
+ RUBYDEF = $(DLL_BASE_NAME).def
40
+
41
+ # Start of tebako patch
42
+ WINMAINOBJ = win32/winmain.$(OBJEXT)
43
+ $(WINMAINOBJ): win32/winmain.c
44
+ # End of tebako patch
45
+ SUBST
46
+
47
+ # Ruby patching definitions (common base)
48
+ class Patch
49
+ def patch_map
50
+ {}.freeze
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2023-2025 [Ribose Inc](https://www.ribose.com).
4
+ # All rights reserved.
5
+ # This file is a part of the Tebako project.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions
9
+ # are met:
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ # 2. Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ #
16
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+ # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18
+ # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
20
+ # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
+ # POSSIBILITY OF SUCH DAMAGE.
27
+
28
+ require_relative "patch_helpers"
29
+
30
+ # Tebako - an executable packager
31
+ module Tebako
32
+ module Packager
33
+ # Ruby buildsystem patches (pass2)
34
+ module PatchBuildsystem
35
+ # This patch forces rebuild of extinit.c when exts.mk changes
36
+ # exts.mk changes when we rebuild extensions to make them statically linked
37
+ # [TODO] it is possible that we can build extensions statically on pass1 and it will
38
+ # eliminate the need for this patch
39
+ COMMON_MK_PATCH = {
40
+ "ext/extinit.c: $(srcdir)/template/extinit.c.tmpl $(PREP)" =>
41
+ "ext/extinit.c: $(srcdir)/template/extinit.c.tmpl $(PREP) $(EXTS_MK)"
42
+ }.freeze
43
+
44
+ # This patch changes libraries that are used for Ruby linking
45
+ # MAINLIBS is patched elsewhere (not with literal but dynamically)
46
+ # to haold the list of sattic libraries and related options
47
+ # Also we have to put LIBRUBYARG_STATIC instead of LIBRUBYARG to link with static libruby,
48
+ # configure's --disable-shared option does not do it
49
+ # Several variants depending on os and version
50
+ TEMPLATE_MAKEFILE_IN_BASE_PATTERN_PRE_3_1 =
51
+ "\t\t$(Q) $(PURIFY) $(CC) $(LDFLAGS) $(XLDFLAGS) $(MAINOBJ) " \
52
+ "$(EXTOBJS) $(LIBRUBYARG) $(MAINLIBS) $(LIBS) $(EXTLIBS) $(OUTFLAG)$@"
53
+
54
+ TEMPLATE_MAKEFILE_IN_BASE_PATCH_PRE_3_1 =
55
+ "# -- Start of tebako patch --\n" \
56
+ "\t\t$(Q) $(PURIFY) $(CC) $(LDFLAGS) $(MAINOBJ) " \
57
+ "$(EXTOBJS) $(LIBRUBYARG_STATIC) $(OUTFLAG)$@\n" \
58
+ "# -- End of tebako patch --"
59
+
60
+ TEMPLATE_MAKEFILE_IN_BASE_PATTERN_PRE_3_3 =
61
+ "\t\t$(Q) $(PURIFY) $(CC) $(EXE_LDFLAGS) $(XLDFLAGS) $(MAINOBJ) $(EXTOBJS) " \
62
+ "$(LIBRUBYARG) $(MAINLIBS) $(LIBS) $(EXTLIBS) $(OUTFLAG)$@"
63
+
64
+ TEMPLATE_MAKEFILE_IN_BASE_PATTERN =
65
+ "\t\t$(Q) $(PURIFY) $(CC) $(EXE_LDFLAGS) $(XLDFLAGS) $(MAINOBJ) $(EXTOBJS) " \
66
+ "$(LIBRUBYARG) $(MAINLIBS) $(EXTLIBS) $(OUTFLAG)$@"
67
+
68
+ TEMPLATE_MAKEFILE_IN_BASE_PATCH =
69
+ "# -- Start of tebako patch --\n" \
70
+ "\t\t$(Q) $(PURIFY) $(CC) $(EXE_LDFLAGS) $(MAINOBJ) " \
71
+ "$(EXTOBJS) $(LIBRUBYARG_STATIC) $(OUTFLAG)$@\n" \
72
+ "# -- End of tebako patch --"
73
+
74
+ TEMPLATE_MAKEFILE_IN_BASE_PATCH_MSYS =
75
+ "# -- Start of tebako patch --\n" \
76
+ "\t\t$(Q) $(PURIFY) $(CC) $(EXE_LDFLAGS) $(RUBY_EXP) $(MAINOBJ) " \
77
+ "$(EXTOBJS) $(LIBRUBYARG_STATIC) $(OUTFLAG)$@\n" \
78
+ "# -- End of tebako patch --"
79
+
80
+ def template_makefile_in_subst(ruby_ver)
81
+ if ScenarioManagerBase.new.msys?
82
+ TEMPLATE_MAKEFILE_IN_BASE_PATCH_MSYS
83
+ elsif !ruby_ver.ruby31?
84
+ TEMPLATE_MAKEFILE_IN_BASE_PATCH_PRE_3_1
85
+ else
86
+ TEMPLATE_MAKEFILE_IN_BASE_PATCH
87
+ end
88
+ end
89
+
90
+ def template_makefile_in_patch_two(ruby_ver)
91
+ if !ruby_ver.ruby31?
92
+ { TEMPLATE_MAKEFILE_IN_BASE_PATTERN_PRE_3_1 => template_makefile_in_subst(ruby_ver) }
93
+ elsif !ruby_ver.ruby33?
94
+ { TEMPLATE_MAKEFILE_IN_BASE_PATTERN_PRE_3_3 => template_makefile_in_subst(ruby_ver) }
95
+ else
96
+ { TEMPLATE_MAKEFILE_IN_BASE_PATTERN => template_makefile_in_subst(ruby_ver) }
97
+ end
98
+ end
99
+
100
+ def get_config_status_pattern(ostype)
101
+ scmb = ScenarioManagerBase.new(ostype)
102
+ if scmb.macos?
103
+ "S[\"MAINLIBS\"]=\"-ldl -lobjc -lpthread \""
104
+ elsif scmb.msys?
105
+ "S[\"MAINLIBS\"]=\"-lshell32 -lws2_32 -liphlpapi -limagehlp -lshlwapi -lbcrypt \""
106
+ else
107
+ "S[\"MAINLIBS\"]=\"-lz -lrt -lrt -ldl -lcrypt -lm -lpthread \""
108
+ end
109
+ end
110
+
111
+ def get_config_status_patch(ostype, deps_lib_dir, ruby_ver)
112
+ # with_compression: true so rbconfig's MAINLIBS (used by mkmf have_func() conftest links
113
+ # during extension builds) force_loads the DwarFS (de)compressor libs. Since the v0.15
114
+ # split, libdwarfs_reader.a references dwarfs::block_decompressor (defined in
115
+ # libdwarfs_decompressor.a); omitting it made EVERY conftest fail to link, so every bundled
116
+ # gem fell back to its `static` compat shim and failed to compile under the real headers.
117
+ {
118
+ get_config_status_pattern(ostype) =>
119
+ "S[\"MAINLIBS\"]=\"#{PatchLibraries.mlibs(ostype, deps_lib_dir, ruby_ver, true)}\""
120
+ }
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2023-2025 [Ribose Inc](https://www.ribose.com).
4
+ # All rights reserved.
5
+ # This file is a part of the Tebako project.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions
9
+ # are met:
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ # 2. Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ #
16
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+ # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18
+ # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
20
+ # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
+ # POSSIBILITY OF SUCH DAMAGE.
27
+
28
+ require "open3"
29
+ require_relative "patch_literals"
30
+
31
+ # Tebako - an executable packager
32
+ module Tebako
33
+ module Packager
34
+ # Ruby patching helpers (pass2)
35
+ module PatchHelpers
36
+ class << self
37
+ def patch_file(fname, mapping)
38
+ raise Tebako::Error, "Could not patch #{fname} because it does not exist." unless File.exist?(fname)
39
+
40
+ puts " ... patching #{fname}"
41
+ restore_and_save(fname)
42
+ contents = File.read(fname)
43
+
44
+ mapping.each { |pattern, subst| contents.sub!(pattern, subst) }
45
+ File.open(fname, "w") { |file| file << contents }
46
+ end
47
+
48
+ def get_prefix_macos(package)
49
+ out, st = Open3.capture2("brew --prefix #{package}")
50
+ raise Tebako::Error, "brew --prefix #{package} failed with code #{st.exitstatus}" unless st.exitstatus.zero?
51
+
52
+ out
53
+ end
54
+
55
+ def get_prefix_linux(package)
56
+ out, st = Open3.capture2("pkg-config --variable=libdir #{package}")
57
+ unless st.exitstatus.zero?
58
+ raise Tebako::Error,
59
+ "pkg-config --variable=libdir #{package} failed with code #{st.exitstatus}"
60
+ end
61
+
62
+ out
63
+ end
64
+
65
+ def patch_c_file_pre(pattern)
66
+ {
67
+ pattern => "#{PatchLiterals::C_FILE_SUBST}\n#{pattern}"
68
+ }
69
+ end
70
+
71
+ def patch_c_file_post(pattern)
72
+ {
73
+ pattern => "#{pattern}\n\n#{PatchLiterals::C_FILE_SUBST}"
74
+ }
75
+ end
76
+
77
+ def recreate(dirname)
78
+ FileUtils.rm_rf(dirname, noop: nil, verbose: nil, secure: true)
79
+ FileUtils.mkdir(dirname)
80
+ end
81
+
82
+ def restore_and_save(fname, strict: true)
83
+ unless File.exist?(fname)
84
+ return unless strict
85
+
86
+ raise Tebako::Error, "Could not save #{fname} because it does not exist."
87
+ end
88
+
89
+ old_fname = "#{fname}.old"
90
+ if File.exist?(old_fname)
91
+ FileUtils.rm_f(fname)
92
+ File.rename(old_fname, fname)
93
+ end
94
+ FileUtils.cp(fname, old_fname)
95
+ end
96
+
97
+ def restore_and_save_files(files, ruby_source_dir, strict: true)
98
+ files.each do |fname|
99
+ restore_and_save("#{ruby_source_dir}/#{fname}", strict: strict)
100
+ end
101
+ end
102
+
103
+ def yaml_reference(ruby_ver)
104
+ ruby_ver.ruby32? ? "-l:libyaml.a" : ""
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,188 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2021-2025 [Ribose Inc](https://www.ribose.com).
4
+ # All rights reserved.
5
+ # This file is a part of the Tebako project.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions
9
+ # are met:
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ # 2. Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ #
16
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+ # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18
+ # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
20
+ # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
+ # POSSIBILITY OF SUCH DAMAGE.
27
+
28
+ require_relative "patch_helpers"
29
+
30
+ # Tebako - an executable packager
31
+ module Tebako
32
+ module Packager
33
+ # Ruby patching definitions (pass2)
34
+ module PatchLibraries
35
+ class << self
36
+ # rubocop:disable Style/WordArray
37
+ DARWIN_BREW_LIBS = [
38
+ ["zlib", "z"], ["gdbm", "gdbm"], ["readline", "readline"], ["libffi", "ffi"],
39
+ ["ncurses", "ncurses"], ["lz4", "lz4"], ["xz", "lzma"], ["libyaml", "yaml"],
40
+ ["boost", "boost_chrono"], ["double-conversion", "double-conversion"],
41
+ # DwarFS v0.15 compression/hash deps (were staged into deps_lib_dir under the bridge)
42
+ ["xxhash", "xxhash"], ["zstd", "zstd"],
43
+ ["brotli", "brotlienc"], ["brotli", "brotlidec"], ["brotli", "brotlicommon"],
44
+ # DwarFS reader link deps
45
+ ["boost", "boost_filesystem"], ["boost", "boost_atomic"],
46
+ ["boost", "boost_iostreams"], ["boost", "boost_program_options"],
47
+ ["boost", "boost_context"], ["boost", "boost_regex"],
48
+ ["boost", "boost_thread"],
49
+ ["flac", "FLAC"], ["flac", "FLAC++"],
50
+ ["libogg", "ogg"]
51
+ ].freeze
52
+
53
+ DARWIN_BREW_LIBS_PRE_31 = [["openssl@1.1", "ssl"], ["openssl@1.1", "crypto"]].freeze
54
+
55
+ DARWIN_BREW_LIBS_31 = [["openssl@3", "ssl"], ["openssl@3", "crypto"]].freeze
56
+
57
+ # DwarFS v0.15 split static libs (installed to deps_lib_dir by libdwarfs). folly/fbthrift
58
+ # are gone; the thrift/fsst/frozen libs are now real .a files. glog/gflags/fmt are no
59
+ # longer linked (fmt is header-only / baked into the DwarFS libs).
60
+ DARWIN_DEP_LIBS_1 = [
61
+ "dwarfs_reader", "dwarfs_common",
62
+ "dwarfs_fsst", "dwarfs_frozen", "dwarfs_thrift_lite_v2",
63
+ "dwarfs_metadata_thrift", "dwarfs_compression_thrift",
64
+ "dwarfs_history_thrift", "dwarfs_features_thrift"
65
+ ].freeze
66
+ # rubocop:enable Style/WordArray
67
+
68
+ LIBTEBAKOFS = "-Wl,--push-state,--whole-archive -l:libtebako-fs.a -Wl,--pop-state"
69
+
70
+ COMMON_LINUX_LIBRARIES = [
71
+ LIBTEBAKOFS, "-l:libdwarfs-wr.a", "-l:libdwarfs.a", "LIBCOMPRESSION",
72
+ "-l:libfolly.a", "-l:libfsst.a", "-l:libmetadata_thrift.a", "-l:libthrift_light.a",
73
+ "-l:libxxhash.a", "-l:libfmt.a", "-l:libdouble-conversion.a", "-l:libglog.a",
74
+ "-l:libgflags.a", "-l:libevent.a"
75
+ ].freeze
76
+
77
+ COMMON_ARCHIEVE_LIBRARIES = [
78
+ "-l:libarchive.a", "-l:liblz4.a", "-l:libz.a", "-l:libzstd.a",
79
+ "-l:libbrotlienc.a", "-l:libbrotlidec.a", "-l:libbrotlicommon.a", "-l:liblzma.a"
80
+ ].freeze
81
+
82
+ LINUX_GNU_LIBRARIES = [
83
+ "-l:libiberty.a", "-l:libacl.a", "-l:libssl.a", "-l:libcrypto.a",
84
+ "-l:libgdbm.a", "-l:libreadline.a", "-l:libtinfo.a", "-l:libffi.a",
85
+ "-l:libncurses.a", "-l:libjemalloc.a", "-l:libcrypt.a", "-l:libanl.a",
86
+ "LIBYAML", "-l:libboost_system.a", "-l:libboost_chrono.a", "-l:libutil.a",
87
+ "-l:libstdc++.a", "-lgcc_eh", "-l:libunwind.a", "-l:liblzma.a",
88
+ "-l:librt.a", "-ldl", "-lpthread", "-lm"
89
+ ].freeze
90
+
91
+ LINUX_MUSL_LIBRARIES = [
92
+ "-l:libiberty.a", "-l:libacl.a", "-l:libssl.a", "-l:libcrypto.a",
93
+ "-l:libreadline.a", "-l:libgdbm.a", "-l:libffi.a", "-l:libncurses.a",
94
+ "-l:libjemalloc.a", "-l:libcrypt.a", "LIBYAML", "-l:libboost_system.a",
95
+ "-l:libboost_chrono.a", "-l:librt.a", "-l:libstdc++.a", "-lgcc_eh",
96
+ " -l:libunwind.a", "-l:liblzma.a", "-ldl", "-lpthread"
97
+ ].freeze
98
+
99
+ MSYS_LIBRARIES = [
100
+ "-l:liblz4.a", "-l:libz.a", "-l:libzstd.a", "-l:liblzma.a",
101
+ "-l:libncurses.a", "-l:liblzma.a", "-l:libiberty.a", "LIBYAML",
102
+ "-l:libffi.a", "-l:libboost_chrono-mt.a", "-l:libstdc++.a", "-l:libdl.a",
103
+ "-static-libgcc", "-static-libstdc++", "-l:libssl.a", "-l:libcrypto.a",
104
+ "-l:libz.a", "-l:libwinpthread.a", "-lcrypt32", "-lshlwapi",
105
+ "-lwsock32", "-liphlpapi", "-limagehlp", "-lbcrypt",
106
+ "-lole32", "-loleaut32", "-luuid", "-lws2_32"
107
+ ].freeze
108
+
109
+ def linux_gnu_libraries(ruby_ver, with_compression)
110
+ libraries = COMMON_LINUX_LIBRARIES + COMMON_ARCHIEVE_LIBRARIES + LINUX_GNU_LIBRARIES
111
+ linux_libraries(libraries, ruby_ver, with_compression)
112
+ end
113
+
114
+ def linux_musl_libraries(ruby_ver, with_compression)
115
+ libraries = COMMON_LINUX_LIBRARIES + COMMON_ARCHIEVE_LIBRARIES + LINUX_MUSL_LIBRARIES
116
+ linux_libraries(libraries, ruby_ver, with_compression)
117
+ end
118
+
119
+ def linux_libraries(libraries, ruby_ver, with_compression)
120
+ libraries.map! do |lib|
121
+ if lib == "LIBYAML"
122
+ PatchHelpers.yaml_reference(ruby_ver)
123
+ elsif lib == "LIBCOMPRESSION"
124
+ with_compression ? "-Wl,--push-state,--whole-archive -l:libdwarfs_compression.a -Wl,--pop-state" : ""
125
+ else
126
+ lib
127
+ end
128
+ end
129
+ libraries.join(" ")
130
+ end
131
+
132
+ def msys_libraries(ruby_ver, with_compression)
133
+ libraries = with_compression ? ["-Wl,-Bstatic"] : []
134
+ libraries = libraries + COMMON_LINUX_LIBRARIES + MSYS_LIBRARIES
135
+ linux_libraries(libraries, ruby_ver, with_compression)
136
+ end
137
+
138
+ def process_brew_libs!(libs, brew_libs)
139
+ brew_libs.each { |lib| libs << "#{PatchHelpers.get_prefix_macos(lib[0]).chop}/lib/lib#{lib[1]}.a " }
140
+ end
141
+
142
+ def darwin_libraries(deps_lib_dir, ruby_ver, with_compression)
143
+ libs = String.new
144
+
145
+ DARWIN_DEP_LIBS_1.each { |lib| libs << "#{deps_lib_dir}/lib#{lib}.a " }
146
+ process_brew_libs!(libs, ruby_ver.ruby31? ? DARWIN_BREW_LIBS_31 : DARWIN_BREW_LIBS_PRE_31)
147
+ process_brew_libs!(libs, DARWIN_BREW_LIBS)
148
+
149
+ # DwarFS compression codecs self-register via static initializers, so force_load the
150
+ # (de)compressor libs to keep them (the reader would otherwise drop the unreferenced ones).
151
+ compression_lib =
152
+ if with_compression
153
+ "-force_load #{deps_lib_dir}/libdwarfs_decompressor.a " \
154
+ "-force_load #{deps_lib_dir}/libdwarfs_compressor.a"
155
+ else
156
+ ""
157
+ end
158
+ "-ltebako-fs -ldwarfs-wr #{compression_lib} #{libs} #{deps_lib_dir}/libjemalloc.a -lc++ -lc++abi"
159
+ end
160
+
161
+ # .....................................................
162
+ # Notes re linux libraries
163
+ # 1) This order is important: -lgcc_eh -l:libunwind.a -l:liblzma.a lzma is used to process debug sections.
164
+ # gcc_eh shall be linked before unwind to avoid duplicate symbols.
165
+ # 2) -lgcc_eh assumes -static-libgcc (applied in CMakeLists.ext, RUBY_C_FLAGS)
166
+ # 3) -static-libstdc++ did not work, not sure why [TODO ?]
167
+ # 4) When clang is used linker links libraries specified in exensions in such way that they are linked shared
168
+ # (libz, libffi, libreadline, libncurses, libtinfo, ... )
169
+ # Using stuff like -l:libz.a does not help; there is a reference to libz.so anyway.
170
+ # This is fixed by ext/extmk.rb patch [TODO ?]
171
+ # .....................................................
172
+
173
+ def mlibs(ostype, deps_lib_dir, ruby_ver, with_compression)
174
+ scmb = ScenarioManagerBase.new(ostype)
175
+ if scmb.msys?
176
+ msys_libraries(ruby_ver, with_compression)
177
+ elsif scmb.macos?
178
+ darwin_libraries(deps_lib_dir, ruby_ver, with_compression)
179
+ elsif scmb.musl?
180
+ linux_musl_libraries(ruby_ver, with_compression)
181
+ else
182
+ linux_gnu_libraries(ruby_ver, with_compression)
183
+ end
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end