rubycc 1.0.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 (159) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +56 -0
  3. data/LICENSE.txt +21 -0
  4. data/NOTICE +52 -0
  5. data/README.md +208 -0
  6. data/data/README.md +117 -0
  7. data/data/r10_corpus_scan.json +4082 -0
  8. data/data/r10_manual_classification.json +5342 -0
  9. data/data/r10_verification_m4a.json +1531 -0
  10. data/data/r10_verification_m4b.json +1818 -0
  11. data/data/r10_verification_m4c.json +1489 -0
  12. data/data/r10_verification_m4d.json +318 -0
  13. data/data/r10_verification_rbs.json +192 -0
  14. data/data/verified_gems.json +397 -0
  15. data/exe/rmake +16 -0
  16. data/exe/rubycc +9 -0
  17. data/exe/rubycc-ar +114 -0
  18. data/exe/rubycc-doctor +14 -0
  19. data/exe/rubycc-pkgconf +8 -0
  20. data/include/float.h +87 -0
  21. data/include/iso646.h +18 -0
  22. data/include/libc/alloca.h +18 -0
  23. data/include/libc/arpa/inet.h +61 -0
  24. data/include/libc/assert.h +43 -0
  25. data/include/libc/dirent.h +72 -0
  26. data/include/libc/dlfcn.h +58 -0
  27. data/include/libc/features.h +205 -0
  28. data/include/libc/glibc/aarch64/ctype.h +108 -0
  29. data/include/libc/glibc/aarch64/endian.h +54 -0
  30. data/include/libc/glibc/aarch64/errno.h +154 -0
  31. data/include/libc/glibc/aarch64/fcntl.h +144 -0
  32. data/include/libc/glibc/aarch64/inttypes.h +182 -0
  33. data/include/libc/glibc/aarch64/limits.h +63 -0
  34. data/include/libc/glibc/aarch64/pthread.h +131 -0
  35. data/include/libc/glibc/aarch64/setjmp.h +84 -0
  36. data/include/libc/glibc/aarch64/stdint.h +174 -0
  37. data/include/libc/glibc/aarch64/sys/epoll.h +88 -0
  38. data/include/libc/glibc/aarch64/sys/fcntl.h +19 -0
  39. data/include/libc/glibc/aarch64/sys/select.h +75 -0
  40. data/include/libc/glibc/aarch64/sys/stat.h +136 -0
  41. data/include/libc/glibc/aarch64/sys/syscall.h +167 -0
  42. data/include/libc/glibc/aarch64/sys/time.h +74 -0
  43. data/include/libc/glibc/aarch64/sys/types.h +127 -0
  44. data/include/libc/glibc/aarch64/time.h +113 -0
  45. data/include/libc/glibc/x86_64/ctype.h +108 -0
  46. data/include/libc/glibc/x86_64/endian.h +54 -0
  47. data/include/libc/glibc/x86_64/errno.h +154 -0
  48. data/include/libc/glibc/x86_64/fcntl.h +134 -0
  49. data/include/libc/glibc/x86_64/inttypes.h +182 -0
  50. data/include/libc/glibc/x86_64/limits.h +61 -0
  51. data/include/libc/glibc/x86_64/pthread.h +111 -0
  52. data/include/libc/glibc/x86_64/setjmp.h +82 -0
  53. data/include/libc/glibc/x86_64/stdint.h +163 -0
  54. data/include/libc/glibc/x86_64/sys/epoll.h +91 -0
  55. data/include/libc/glibc/x86_64/sys/fcntl.h +19 -0
  56. data/include/libc/glibc/x86_64/sys/select.h +75 -0
  57. data/include/libc/glibc/x86_64/sys/stat.h +130 -0
  58. data/include/libc/glibc/x86_64/sys/syscall.h +188 -0
  59. data/include/libc/glibc/x86_64/sys/time.h +74 -0
  60. data/include/libc/glibc/x86_64/sys/types.h +123 -0
  61. data/include/libc/glibc/x86_64/time.h +113 -0
  62. data/include/libc/grp.h +50 -0
  63. data/include/libc/langinfo.h +126 -0
  64. data/include/libc/link.h +18 -0
  65. data/include/libc/locale.h +83 -0
  66. data/include/libc/math.h +191 -0
  67. data/include/libc/netinet/in.h +126 -0
  68. data/include/libc/netinet/tcp.h +44 -0
  69. data/include/libc/poll.h +46 -0
  70. data/include/libc/pwd.h +58 -0
  71. data/include/libc/regex.h +53 -0
  72. data/include/libc/sched.h +35 -0
  73. data/include/libc/signal.h +204 -0
  74. data/include/libc/stdio.h +157 -0
  75. data/include/libc/stdlib.h +92 -0
  76. data/include/libc/string.h +74 -0
  77. data/include/libc/strings.h +25 -0
  78. data/include/libc/sys/cdefs.h +126 -0
  79. data/include/libc/sys/inotify.h +111 -0
  80. data/include/libc/sys/ioctl.h +36 -0
  81. data/include/libc/sys/mman.h +65 -0
  82. data/include/libc/sys/param.h +41 -0
  83. data/include/libc/sys/resource.h +109 -0
  84. data/include/libc/sys/socket.h +167 -0
  85. data/include/libc/sys/statfs.h +82 -0
  86. data/include/libc/sys/timerfd.h +55 -0
  87. data/include/libc/sys/uio.h +40 -0
  88. data/include/libc/sys/un.h +25 -0
  89. data/include/libc/sys/utsname.h +35 -0
  90. data/include/libc/sys/wait.h +135 -0
  91. data/include/libc/termios.h +179 -0
  92. data/include/libc/unistd.h +194 -0
  93. data/include/stdalign.h +16 -0
  94. data/include/stdarg.h +31 -0
  95. data/include/stdatomic.h +158 -0
  96. data/include/stdbool.h +15 -0
  97. data/include/stdckdint.h +28 -0
  98. data/include/stddef.h +60 -0
  99. data/include/stdnoreturn.h +18 -0
  100. data/include/x86intrin.h +16 -0
  101. data/lib/rubycc/backend/aarch64.rb +1724 -0
  102. data/lib/rubycc/backend/x86_64.rb +1369 -0
  103. data/lib/rubycc/compile_error.rb +36 -0
  104. data/lib/rubycc/compiler.rb +305 -0
  105. data/lib/rubycc/doctor/builder.rb +151 -0
  106. data/lib/rubycc/doctor/cli.rb +190 -0
  107. data/lib/rubycc/doctor/fetcher.rb +84 -0
  108. data/lib/rubycc/doctor/gemfile.rb +115 -0
  109. data/lib/rubycc/doctor/verified_gems.rb +114 -0
  110. data/lib/rubycc/doctor.rb +16 -0
  111. data/lib/rubycc/driver.rb +463 -0
  112. data/lib/rubycc/front/ast.rb +528 -0
  113. data/lib/rubycc/front/constant_evaluator.rb +631 -0
  114. data/lib/rubycc/front/initializer_resolver.rb +592 -0
  115. data/lib/rubycc/front/lexeme_reader.rb +460 -0
  116. data/lib/rubycc/front/lexer.rb +232 -0
  117. data/lib/rubycc/front/parser.rb +4122 -0
  118. data/lib/rubycc/front/token.rb +49 -0
  119. data/lib/rubycc/ir/call_convention.rb +486 -0
  120. data/lib/rubycc/ir/generator.rb +6036 -0
  121. data/lib/rubycc/ir/ir.rb +417 -0
  122. data/lib/rubycc/link/compat_runtime.rb +89 -0
  123. data/lib/rubycc/link/errors.rb +13 -0
  124. data/lib/rubycc/link/executable_linker.rb +405 -0
  125. data/lib/rubycc/link/library_resolver.rb +437 -0
  126. data/lib/rubycc/link/partial_linker.rb +546 -0
  127. data/lib/rubycc/link/shared_linker.rb +1732 -0
  128. data/lib/rubycc/mkmf_shim.rb +83 -0
  129. data/lib/rubycc/objfile/ar_archive.rb +437 -0
  130. data/lib/rubycc/objfile/elf_reader.rb +646 -0
  131. data/lib/rubycc/objfile/elf_writer.rb +891 -0
  132. data/lib/rubycc/objfile/relocatable_writer.rb +376 -0
  133. data/lib/rubycc/pkgconf/cli.rb +139 -0
  134. data/lib/rubycc/pkgconf/errors.rb +39 -0
  135. data/lib/rubycc/pkgconf/model.rb +28 -0
  136. data/lib/rubycc/pkgconf/parser.rb +109 -0
  137. data/lib/rubycc/pkgconf/pkgconf.rb +15 -0
  138. data/lib/rubycc/pkgconf/resolver.rb +70 -0
  139. data/lib/rubycc/pkgconf/search_path.rb +38 -0
  140. data/lib/rubycc/pkgconf/system_path_filter.rb +131 -0
  141. data/lib/rubycc/preprocess/constant_expression.rb +219 -0
  142. data/lib/rubycc/preprocess/glibc_version.rb +124 -0
  143. data/lib/rubycc/preprocess/pp_token.rb +62 -0
  144. data/lib/rubycc/preprocess/preprocessor.rb +2020 -0
  145. data/lib/rubycc/preprocess/scanner.rb +290 -0
  146. data/lib/rubycc/preprocess/token_converter.rb +157 -0
  147. data/lib/rubycc/rmake/cli.rb +143 -0
  148. data/lib/rubycc/rmake/errors.rb +71 -0
  149. data/lib/rubycc/rmake/executor.rb +818 -0
  150. data/lib/rubycc/rmake/expander.rb +251 -0
  151. data/lib/rubycc/rmake/makefile.rb +352 -0
  152. data/lib/rubycc/rmake/model.rb +137 -0
  153. data/lib/rubycc/rmake/parser.rb +226 -0
  154. data/lib/rubycc/rmake/rmake.rb +15 -0
  155. data/lib/rubycc/type.rb +1236 -0
  156. data/lib/rubycc/version.rb +5 -0
  157. data/lib/rubycc.rb +36 -0
  158. data/lib/rubygems_plugin.rb +102 -0
  159. metadata +219 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: aa70e92444211a2d9e68b297a9338d4d517f4c4ad746b95c3a3842e3347cb47f
4
+ data.tar.gz: f7139ecd66b6a7e3808da0f67f63edaaa8115620d92757bf6992656c1668bc49
5
+ SHA512:
6
+ metadata.gz: a14a2b3a760995c8dbece07b44d6d5b6c779da09372c5a1a2aa7eb32e673a7bfa02f4c47559c66ee4485fc1a384c47179c307ed5df056b9479e87233d900a494
7
+ data.tar.gz: 5c5d8960ee72abf7cd8a64904b9063ae4a86d04d2a57a36b9a365ebf4078b0b53214818ab2b2826db8553aa7e7f4acc0d1a8ab7eaf9d7281a472f9ee0f6d2bff
data/CHANGELOG.md ADDED
@@ -0,0 +1,56 @@
1
+ # Changelog
2
+
3
+ Notable changes per release. The per-step design record — why each decision was made,
4
+ and what was measured to justify it — is in [docs/development/STEPS.md](docs/development/STEPS.md); this file is
5
+ the summary a consumer of the gem needs.
6
+
7
+ Versioning follows semver with one project-specific rule: **a regression in the corpus
8
+ pass rate is a breaking change**, whatever the code change looked like. See the
9
+ Versioning section of the README.
10
+
11
+ ## 1.0.0 (2026-08-12)
12
+
13
+ First release. rubycc builds Ruby C extensions with no gcc, no binutils, no make and no
14
+ shell — it is a C compiler, assembler-free ELF writer, linker, `ar`, `make`, `pkg-config`
15
+ shim and preprocessor, written in Ruby.
16
+
17
+ ### What works
18
+
19
+ - **31 gems verified**: bigdecimal, bootsnap, date, digest, erb, etc, fiddle,
20
+ google-protobuf, http_parser.rb, io-console, io-nonblock, io-wait, json, msgpack,
21
+ mysql2, nio4r, nkf, pg, prism, psych, puma, racc, redcarpet, sqlite3, stackprof,
22
+ stringio, strscan, syslog, websocket-driver, yajl-ruby, zlib. "Verified" means the
23
+ gem's own test suite passed against the `.so` that a `RUBYCC=1 gem install` produced
24
+ — the record is `data/verified_gems.json`, written only by
25
+ `tools/verify_gem_tests.rb`, never by hand. That is 31 of the 34 gems in the corpus
26
+ denominator (**91.2%**), meeting the 90% the design sets as its acceptance criterion.
27
+ - **Two machines**: x86-64 and aarch64, each with its own backend and ABI.
28
+ - **Two C libraries**: glibc and musl. The bundled headers carry both where they differ,
29
+ and every difference was measured against that environment's own gcc rather than
30
+ copied from a libc's sources.
31
+ - **Bundled libc headers** so a distroless image with no libc development package still
32
+ compiles `ruby.h`.
33
+ - `rubycc-doctor` reports whether a project's gems are known to build.
34
+
35
+ ### Known limitations
36
+
37
+ Listed in full, with measurements, in the README. The ones most likely to matter:
38
+
39
+ - Compile throughput is 69% of the 20,000 lines/sec target.
40
+ - Generated code is unoptimized; up to 7.65x slower than `gcc -O2` on tight loops.
41
+ - C11 atomics are partial: `_Atomic` compiles to the unqualified type's layout and ABI
42
+ for scalars of 1, 2, 4 and 8 bytes, and the bundled `<stdatomic.h>` carries the fences
43
+ and the generic macros; `atomic_fetch_or`/`_and`/`_xor`, `atomic_flag` and the implicit
44
+ sequential consistency of a plain access are missing.
45
+ - `long double` is compiled as `double` (8 bytes, not the ABI's 80-bit x87 in 16), so it
46
+ loses precision and a value passed to `printf("%Lg", …)` reads back wrong.
47
+ - Shared objects bind their own global symbols directly (`ld -Bsymbolic` semantics),
48
+ with no switch to turn it off.
49
+ - 128-bit integers: passing, returning and shifting work; division, remainder, bitwise
50
+ operators and variadic passing do not.
51
+
52
+ ### Not in scope
53
+
54
+ C++ (grpc), gems that run `configure` through mini_portile (nokogiri's vendored build —
55
+ `--use-system-libraries` is fine), and gems that ship assembly (ffi). The full list with
56
+ reasons is [docs/reference/OUT-OF-SCOPE-GEMS.md](docs/reference/OUT-OF-SCOPE-GEMS.md).
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DATE Ken
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/NOTICE ADDED
@@ -0,0 +1,52 @@
1
+ rubycc
2
+ ======
3
+
4
+ This product bundles a set of C library compatibility headers under
5
+ `include/libc/` so that hosted translation units can be compiled without the
6
+ target system's own libc development headers (the "distroless" use case).
7
+
8
+ Portions of the bundled libc headers are derived from musl libc
9
+ (https://musl.libc.org/), used as the starting point for the standard
10
+ declarations, and then modified so their type widths, structure layouts and
11
+ macro values match the glibc x86-64 ABI (measured from the reference platform,
12
+ not copied from glibc). Each derived header carries a one-line provenance note
13
+ in its opening comment; headers whose entire mechanism is glibc/arch specific
14
+ (for example the <ctype.h> classification table accessors) or whose values come
15
+ from the Linux kernel UAPI (<errno.h>, <sys/stat.h>) are written clean room
16
+ against the published ABI rather than derived from musl.
17
+
18
+ musl's COPYRIGHT grants permission for its public header files to omit the
19
+ copyright and permission notices the MIT license would otherwise require, so
20
+ retaining the musl notice below is not an obligation for the derived headers;
21
+ rubycc keeps it as an acknowledgement of provenance. The full per-file
22
+ provenance ledger and the licensing analysis are in docs/reference/HEADER-LICENSING.md.
23
+
24
+ No source was copied from glibc (which is LGPL) or from the Linux kernel UAPI
25
+ headers (which are GPL); only observable ABI facts (sizeof/_Alignof, offsetof,
26
+ struct layouts, and macro values, printed by the reference compiler) were
27
+ measured and reproduced. ABI facts are not copyrightable expression.
28
+
29
+ musl libc
30
+ ---------
31
+
32
+ Copyright (C) 2005-2020 Rich Felker, et al.
33
+
34
+ musl is licensed under the MIT license:
35
+
36
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
37
+ this software and associated documentation files (the "Software"), to deal in
38
+ the Software without restriction, including without limitation the rights to
39
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
40
+ of the Software, and to permit persons to whom the Software is furnished to do
41
+ so, subject to the following conditions:
42
+
43
+ The above copyright notice and this permission notice shall be included in all
44
+ copies or substantial portions of the Software.
45
+
46
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
47
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
49
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
50
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
51
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
52
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,208 @@
1
+ # rubycc
2
+
3
+ **Almost Pure Ruby C toolchain** — build Ruby native extensions without gcc, binutils, or a shell.
4
+
5
+ rubycc is a C compiler, linker, archiver and `make` written entirely in Ruby. It compiles
6
+ C to ELF64 machine code directly (no assembly text, no external assembler) and links
7
+ shared objects itself, so a `gem install` that needs a C extension can run on a machine
8
+ that has no toolchain installed.
9
+
10
+ ```
11
+ $ RUBYCC=1 gem install msgpack
12
+ Building native extensions. This could take a while...
13
+ Successfully installed msgpack-1.8.3
14
+ ```
15
+
16
+ ## Status
17
+
18
+ Working. The toolchain compiles and links real gems, and the gems' own test suites pass
19
+ against the resulting binaries. **31 gems are verified this way**, each by running the
20
+ gem's own suite against the `.so` a `RUBYCC=1 gem install` produced — never by inspection:
21
+
22
+ bigdecimal bootsnap date digest erb etc fiddle google-protobuf http_parser.rb
23
+ io-console io-nonblock io-wait json msgpack mysql2 nio4r nkf pg prism psych
24
+ puma racc redcarpet sqlite3 stackprof strscan stringio syslog websocket-driver
25
+ yajl-ruby zlib
26
+
27
+ The verified environments are:
28
+
29
+ | environment | verified gems |
30
+ |---|---|
31
+ | glibc x86-64 | 31 |
32
+ | musl x86-64 (Alpine) | 3 |
33
+ | glibc aarch64 | 6 |
34
+
35
+ The bundled headers match the ABI of the supported environments on both architectures
36
+ and both C libraries.
37
+
38
+ The current corpus census has 39 candidates, 34 gems in the R10 machine-gate denominator,
39
+ and 31 verified gems: **91.2%**, which meets the 90% the design requires. `pg` and
40
+ `sqlite3` are in that denominator through explicit DESIGN-compatible profiles (pg's
41
+ native-source path, sqlite3 with `--enable-system-libraries`), so the rate is measured
42
+ against a larger corpus than the 90.6% reported before those two were added. See
43
+ [`test/corpus/include-census.md`](test/corpus/include-census.md) for the generated report.
44
+
45
+ It also compiles the SQLite amalgamation — a single 261,463-line translation unit — in
46
+ 8.1 s using 467 MB of memory.
47
+
48
+ ## What's in the box
49
+
50
+ | command | stands in for |
51
+ |---|---|
52
+ | `rubycc` | `cc` — preprocessor, compiler, linker driver (`-c`, `-o`, `-E`, `-shared`, `-fPIC`, `-I`, `-D`, `-L`, `-l`) |
53
+ | `rmake` | `make` — parses Makefiles, runs recipes without a shell, parallel by default |
54
+ | `rubycc-ar` | `ar` — deterministic archives |
55
+ | `rubycc-pkgconf` | `pkg-config` |
56
+ | `rubycc-doctor` | diagnostics: check an environment or a gem for compatibility |
57
+
58
+ Targets **x86-64** and **aarch64** Linux (ELF64). The repository currently carries 81
59
+ physical bundled header files, representing 64 normalized angle-bracket spellings in the
60
+ census. They cover the C11 freestanding set plus the POSIX surface real gems use, so no
61
+ libc development package is needed for the headers.
62
+
63
+ ## Requirements
64
+
65
+ - **Ruby 3.3 or newer.** The suite is run on 3.3, 3.4 and 4.0; see *Known limitations*.
66
+ - **Ruby's own headers** (`ruby.h` and friends) and `rbconfig`. Official ruby images have
67
+ them; on a distro Ruby you need the `-dev`/`-devel` package.
68
+ - **Shared libraries you link against** must be present as binaries (`libc.so`, `libz.so`,
69
+ …). Their *headers* are not needed — the linker reads `.dynsym` and emits `DT_NEEDED`.
70
+ - A Ruby built with `--enable-shared` is recommended, because mkmf's `try_link` conftests
71
+ link an executable.
72
+
73
+ ## Usage
74
+
75
+ Set `RUBYCC=1` and install as usual:
76
+
77
+ ```sh
78
+ RUBYCC=1 gem install <gem>
79
+ ```
80
+
81
+ For a complete build-stage/runtime-stage example aimed at shell-less images,
82
+ see [examples/distroless](examples/distroless/README.md).
83
+
84
+ `RUBYCC=0` forces it off. With neither set, rubycc activates itself only when `cc` and
85
+ `make` are absent from `PATH`, so it stays out of the way on a normal development machine.
86
+
87
+ Direct use works too:
88
+
89
+ ```sh
90
+ rubycc -c foo.c -o foo.o
91
+ rubycc -shared -fPIC -o foo.so foo.o
92
+ rubycc -E foo.c # preprocess only
93
+ rubycc --target=aarch64 -c foo.c -o foo.o
94
+ ```
95
+
96
+ ## Known limitations
97
+
98
+ - **Compile speed is 69% of the target.** 13,854 preprocessed lines/sec (Ruby 4.0 + YJIT,
99
+ median over real gem sources) against a 20,000 goal. A typical gem still builds in
100
+ seconds.
101
+ - **Generated code is unoptimized.** No register allocation: every value is spilled to the
102
+ stack. Against `gcc -O2` the slowdown reaches 7.65x on tight loops (1.2x–2.6x on
103
+ branch- and call-bound code); against `gcc -O0` it is 1.1x–2.9x.
104
+ - **C11 atomics are partial.** `_Atomic` is accepted in both spellings (`_Atomic int`,
105
+ `_Atomic(int)`) and compiles to the unqualified type's layout and ABI — measured
106
+ against gcc — for integer, floating and pointer types of 1, 2, 4 or 8 bytes; an
107
+ aggregate, a 16-byte scalar, an array or a function under `_Atomic` is a compile
108
+ error rather than a silently non-atomic object. The bundled `<stdatomic.h>` provides
109
+ the memory-order constants, `atomic_thread_fence`/`atomic_signal_fence`,
110
+ `atomic_init`, and the load/store/exchange/compare-exchange/fetch-add/fetch-sub
111
+ generic macros, all lowered to locked machine sequences at 4 and 8 bytes.
112
+ What is missing: `atomic_fetch_or`/`_and`/`_xor`, `atomic_flag`,
113
+ `atomic_is_lock_free`, and the implicit sequential consistency C11 gives a plain
114
+ read or write of an `_Atomic` object (such an access compiles to an ordinary,
115
+ still-indivisible, instruction — use the macros where the ordering matters).
116
+ See `docs/reference/C11-COVERAGE.md`.
117
+ - **C23 checked arithmetic is partial.** The bundled `<stdckdint.h>` maps `ckd_add`,
118
+ `ckd_sub`, and `ckd_mul` to rubycc's overflow builtins; the rest of C23 is not implemented.
119
+ - **`<regex.h>` is a minimal ABI header.** It provides the glibc-compatible `regex_t`/
120
+ `regmatch_t` layout needed by C extensions, but the full POSIX regex implementation is
121
+ not part of rubycc.
122
+ - **`__GNUC__` is deliberately not defined.** Headers take their non-GNU fallback path.
123
+ - **128-bit integers**: passing, returning and shifting work; division, remainder, bitwise
124
+ `& | ^` and variadic passing do not.
125
+ - **`long double` is 8 bytes** — it is compiled as `double`, where the x86-64 psABI gives
126
+ it 80-bit x87 extended precision in 16 bytes (and AArch64 gives it IEEE binary128).
127
+ Arithmetic therefore carries double's 53-bit significand, `sizeof(long double)` is 8,
128
+ and a `long double` handed to a variadic function does not match what the C library
129
+ reads back: `printf("%Lg", x)` prints a wrong number, because glibc's `printf` reads
130
+ 16 bytes where rubycc pushed 8. This is measured, not theoretical — it is the one
131
+ difference between rubycc and the reference compiler in the `oj` gem's suite, whose
132
+ `usual.c` formats a `long double` that way. Code that only stores and computes with
133
+ `long double` gets double's range and precision; code that passes it across the libc
134
+ boundary gets wrong values. Full support needs x87 (and binary128) arithmetic and is
135
+ not in this release.
136
+ - **Out of scope**: C++ input is rejected with a diagnostic (the compiler accepts C only),
137
+ so gems needing a C++ compiler (grpc) are out of scope. Gems that run `configure` through
138
+ mini_portile (nokogiri's vendored build; `--use-system-libraries` is fine), or that ship
139
+ assembly (ffi), are also out of scope.
140
+ - **Shared objects bind their own global symbols directly.** A symbol a shared object
141
+ both defines and references resolves to that object's own definition, not to an
142
+ earlier one in the process — the behaviour `ld -Bsymbolic` gives, which many
143
+ distributions enable on purpose because it skips the PLT/GOT indirection. rubycc
144
+ always does it and offers no switch. Calls, struct passing, varargs and alignment
145
+ are unaffected; what changes is `LD_PRELOAD` interposition of such a symbol, and
146
+ the case where the same symbol is already defined elsewhere in the process (two
147
+ live copies instead of one).
148
+
149
+ ## No gem-side changes required
150
+
151
+ Compatibility is rubycc's job, not the gem's. A gem must build **unmodified**: rubycc never
152
+ asks for source changes, `extconf.rb` or gemspec edits, install-time patches, or
153
+ rubycc-specific code such as `#ifdef __RUBYCC__`. If a gem does not build, that is a rubycc
154
+ bug.
155
+
156
+ Two things are *not* considered gem-side changes: turning rubycc on (`RUBYCC=1`), and
157
+ choosing an install option the gem itself offers — for example
158
+ `gem install nokogiri -- --use-system-libraries`, which is a supported flag of that gem,
159
+ not a rubycc workaround.
160
+
161
+ ## Versioning
162
+
163
+ Semantic versioning, with one project-specific rule:
164
+
165
+ - **A regression in the corpus pass rate is a breaking change.** The corpus
166
+ (`test/corpus/gems.rb`, 39 candidates and currently 34 R10 machine-gate targets) is the
167
+ contract. The selected profile and exact extconf arguments are part of each target's
168
+ identity; they do not by themselves count as an upstream-suite verification.
169
+ If a release stops building a gem that the previous release built, that is major-version
170
+ territory, not a patch — regardless of how small the code change was.
171
+ - **Minor** releases add language or header coverage, new targets, or new gems that build.
172
+ - **Patch** releases fix bugs and improve performance without changing what builds.
173
+ - The generated code's *speed* is not part of the compatibility contract, but throughput
174
+ and runtime performance are tracked (`rake bench:throughput`, `benchmark/run.rb`) and
175
+ regressions are treated as bugs.
176
+
177
+ The full picture is in [docs/reference/C11-COVERAGE.md](docs/reference/C11-COVERAGE.md) (clause-by-clause C11
178
+ conformance) and [docs/development/ROADMAP.md](docs/development/ROADMAP.md) §3 (known limitations).
179
+
180
+ ## How it works
181
+
182
+ Source → preprocessor (translation phases 1–4) → parser → typed AST → IR → machine code →
183
+ ELF writer. The linker resolves symbols, merges sections and emits `.so`/executables. No
184
+ stage shells out; no stage writes assembly text.
185
+
186
+ - [docs/development/DESIGN.md](docs/development/DESIGN.md) — requirements, architecture decisions, scope
187
+ - [docs/internals/IR.md](docs/internals/IR.md) — the intermediate representation
188
+ - [docs/development/RELEASE-CHECKLIST.md](docs/development/RELEASE-CHECKLIST.md) — non-functional requirement status
189
+ - [docs/reference/HEADER-LICENSING.md](docs/reference/HEADER-LICENSING.md) — provenance of every bundled header
190
+
191
+ ## Development
192
+
193
+ ```sh
194
+ rake test # full suite
195
+ rake bench:throughput # compile-speed benchmark (network: fetches gems)
196
+ rake corpus:census # which headers do real gems need? (network)
197
+ R10_CORPUS_CACHE=... rake corpus:r10_scan # provenance + variadic candidates (no network)
198
+ ruby benchmark/run.rb # generated-code speed vs gcc
199
+ ```
200
+
201
+ The suite compares rubycc against gcc on every layer it can: preprocessed token streams,
202
+ exit codes and stdout of compiled programs, cross-architecture ABI probes, and the
203
+ c-testsuite. gcc is a development-time dependency only — it is never required at runtime.
204
+
205
+ ## License
206
+
207
+ MIT. See [LICENSE.txt](LICENSE.txt) and [NOTICE](NOTICE) — the bundled headers' provenance
208
+ is documented in [docs/reference/HEADER-LICENSING.md](docs/reference/HEADER-LICENSING.md).
data/data/README.md ADDED
@@ -0,0 +1,117 @@
1
+ # data/ — repository-attached reference data
2
+
3
+ ## verified_gems.json
4
+
5
+ The build-verified gem database `rubycc doctor` consults as its **primary
6
+ reference** before attempting any on-the-fly build. JSON carries no comments, so
7
+ the schema is documented here.
8
+
9
+ Top level は **gem 名**をキーとするオブジェクト。1 gem = 1 エントリで、値は次のオブジェクト:
10
+
11
+ | key | type | meaning |
12
+ |-----------------|----------------------------|---------|
13
+ | `verifications` | array of verification 記録 | その gem を確認した**環境ごとの記録**。挿入順(古い順)。空にはしない |
14
+ | `notes` | string | 既知の但し書き(必要だったフラグ、手で補った手順など)。無ければ空文字 |
15
+
16
+ `verifications` の各要素:
17
+
18
+ | key | type | meaning |
19
+ |---------------|---------------------|---------|
20
+ | `versions` | array of string | この環境で検証したバージョン文字列(例 `"2.21.1"`)またはバージョン範囲(例 `">= 1.8, < 2"`)。ここに合致する gem は**ビルドせずに verified** と報告される |
21
+ | `environment` | string | その検証が成り立った環境。例 `"glibc x86_64 / ruby 3.4.5"` |
22
+ | `verified_at` | string `YYYY-MM-DD` | その環境での検証を記録した日付 |
23
+ | `evidence` | string | どう確認したか — どの rubycc ステップ/テストが証明したか(その gem 自身のテストスイートの合格など) |
24
+
25
+ `versions` が**トップレベルではなく各記録の内側にある**のは、環境ごとに実際に検証した
26
+ バージョンが違いうるからである。トップレベルに 1 本置くと、ある環境でしか測っていない
27
+ バージョンまで全環境で検証済みだと主張することになる。
28
+
29
+ 同じ理由で、**ある環境で未検証であることは「その環境の記録が無いこと」で表す**。
30
+ 散文で書かない(下記「更新は…」節を参照)。
31
+
32
+ ### Version matching
33
+
34
+ `versions` の各要素は、gem の解決済みバージョンに対して RubyGems の要求文法
35
+ (`Gem::Requirement`)で照合される。`"2.21.1"` のような完全一致はそのバージョンだけに、
36
+ `">= 1.8, < 2"` のような範囲はその内側の全バージョンに一致する。**どれか 1 つの記録の
37
+ どれか 1 つの要素**を満たせばその gem は verified、つまり**どれか 1 つの環境で検証
38
+ されていれば verified** である。`rubycc doctor` の note 欄には、実際に合致した記録の
39
+ 環境名が並ぶ。
40
+
41
+ ### What may be added here
42
+
43
+ Only versions that were **actually built and exercised in this repository** — the
44
+ initial data is `json 2.21.1` and `msgpack 1.8.3`, both of which built with
45
+ rubycc and passed their own upstream test suites (Step 54, re-confirmed via the
46
+ in-process rmake build in Step 61 and the hermetic gem install in Step 64). The
47
+ intended long-term flow is to generate/extend this file from the corpus CI
48
+ results (ROADMAP H3) rather than hand-editing it.
49
+
50
+ ### 更新は `tools/verify_gem_tests.rb` 経由で行う(手編集ではなく)
51
+
52
+ 上記の「手編集ではなくコーパス CI の結果から生成/拡張したい」という意図は
53
+ **`tools/verify_gem_tests.rb` として実現済み**である。このツールは
54
+
55
+ 1. scratch GEM_HOME に本チェックアウトの rubycc を入れ、
56
+ 2. `RUBYCC=1 gem install <gem>` でその gem の C 拡張を rubycc でビルドし、
57
+ 3. 本当に rubycc が使われたことを RubyGems が残す痕跡
58
+ (`gem_make.out` の `$(MAKE)` = rubycc の `exe/rmake`、生成 Makefile の
59
+ `CC = <...>/exe/rubycc`)で確認し、
60
+ 4. 上流タグの tarball を取得して、そこへビルド済み `.so` を差し込み、
61
+ 5. **その gem 自身のテストスイート**を実走してサマリ行を実測パースする。
62
+
63
+ **書き込み経路はこのツールの `--update --step N` だけ**である。PASS した gem
64
+ だけが記録され、失敗した gem・サマリ行を読み取れなかった gem は決して書かれない。
65
+ `evidence` / `environment` / `verified_at` はすべて**その実行の実測値**から生成
66
+ される。書式(インデント 2、`versions` は 1 行のインライン配列)も既存に合わせて
67
+ 出力されるため、意図した行以外に差分は出ない。
68
+
69
+ 記録先の選び方は、その実行が**どの環境で走ったか**で決まる:
70
+
71
+ - そのエントリに `environment` が一致する記録がある → **その記録だけ**を更新する
72
+ (`versions` は和集合、`verified_at` は当日、`evidence` は追記)。他の環境の記録は触らない
73
+ - エントリはあるが、その環境の記録が無い → `verifications` の**末尾に新しい記録を足す**。
74
+ `evidence` はこのとき新規形から始める(他環境で測った証拠を引き継ぐと、
75
+ そこで測っていない事実をその環境で測ったことにしてしまう)
76
+ - エントリ自体が無い → 記録 1 本と `notes` を持つ新エントリを作る
77
+
78
+ ```
79
+ tools/verify_gem_tests.rb --all # 実走して報告するだけ
80
+ tools/verify_gem_tests.rb --update --step 143 redcarpet # 合格した gem を記録する
81
+ ```
82
+
83
+ このツールを使ううえでの決まりごと:
84
+
85
+ - **レシピには `sanity` 式が必須**。gem によっては C 拡張がロードされず純 Ruby の
86
+ フォールバック(racc)や処理系同梱の別コピー(date・bigdecimal・json)が使われても
87
+ テストスイートは合格しうる。実測例: racc の `cparse.so` を壊したままスイートを走らせると
88
+ **71 tests / 0 failures / 100% passed** になる(純 Ruby ランタイムに落ちている)。
89
+ sanity 式が無ければ、この状態が「rubycc で検証済み」として記録されてしまう。
90
+ そのためツールは `sanity` を持たないレシピの実行を拒否する。
91
+ - **`notes` は人間の責務**であり、**このファイルで唯一、手で書き換えてよい欄**。
92
+ エントリ階層にあり、環境をまたいだ但し書きを書く。新規エントリで `--notes` を省略すると
93
+ 空文字が入り、警告が出る。
94
+ 「機械が観測できない但し書き」(racc の `lib/racc/parser-text.rb` を手で補った、など)は
95
+ 必ず手で書き加えること。既存エントリを更新するとき、ツールは `notes` を**保持**する
96
+ (実測できる skip / pending / omission の件数だけは事実として追記する)。
97
+ ツールが上書きしないのは「機械が人間の但し書きを消さない」ためであって、
98
+ **人間が古くなった但し書きを直すのは正しい操作**である
99
+ (実例: stackprof の「`dlclose` 後始末は保証されない」は Step 156 で解消したので
100
+ 手で書き換えた)。`versions` / `environment` / `verified_at` / `evidence` は
101
+ verification 記録の側にあり、実測から生成される欄なので、**手では触らない**こと。
102
+ - **`notes` に「X ではまだ未検証」と書いてはならない**。ある環境で未検証であることは
103
+ **その環境の verification 記録が無いこと**で既に表現されている。散文にも書くと
104
+ 同じ事実の管理箇所が 2 つになり、片方(必ず散文の側)が古くなる。実際、
105
+ 全エントリが持っていた "musl and aarch64 not yet verified." がこれで、
106
+ スキーマを入れ子にしたときに削除した。
107
+ - **既存の verification 記録の `evidence` は上書きではなく追記**される。`evidence` は
108
+ **その環境で**その gem を確認した全ステップの履歴を溜める欄で(json は Step 54・61・64、
109
+ msgpack は Step 138 で H4 の 1 文が足された)、今日の実走は「今日測った事実」を
110
+ 足すだけであり、過去の確認が無かったことにはならない。上書きすると再実行では
111
+ 復元できない部分が黙って消える。ただし**その環境の記録を新たに作るときは新規形から
112
+ 始める**(他環境の履歴を引き継ぐと、そこで測っていない事実を主張することになる)。
113
+ - **`test/test_doctor.rb` の許可リストは手で更新する**。
114
+ `test_verified_gems_json_holds_only_confirmed_gems` が持つ gem 名の許可リストと
115
+ DB のキー集合が食い違うと、ツールは貼り付け用の `assert_equal` 行を表示して警告する
116
+ だけで、テストファイルは決して自動編集しない(gem の追加を意識的な編集に留める
117
+ ための意図的なゲート)。