Project

General

Profile

Actions

Bug #22490

open

`make -n build-ext` deletes `ext/extinit.c` and `ext/extinit.o` in a static-linked-ext build tree

Bug #22490: `make -n build-ext` deletes `ext/extinit.c` and `ext/extinit.o` in a static-linked-ext build tree

Added by graial (al gray) 5 days ago. Updated 5 days ago.

Status:
Open
Assignee:
-
Target version:
-
[ruby-core:127290]

Description

This is a low priority, convenience issue, perhaps you have good reasons for this observed behaviour, but I am bringing it to your attention in any case.

Summary

In a completed build tree configured with --with-static-linked-ext, running
the dry run make -n build-ext deletes ext/extinit.c and ext/extinit.o. A
dry run is expected to change nothing. After it, the tree can no longer relink
ruby correctly without first regenerating ext/extinit.c through exts.mk.

Background

This bug(?) was encountered while developing a custom ruby.wasm runtime for internet computer: https://gitlab.com/phrug/ruby_wasm_builder

I first encountered this on ruby 3.3.3 as that's the latest ruby.wasm version capable of launching rails

I've been developing a fork of ruby.wasm that adds a wasm32-unknown-icp target (proposed upstream as ruby/ruby.wasm#653) and publishes a release-bundle that the downstream builder can use to compile and link CRuby, then pack it into a wasm module.

The prebuilt CRuby is libruby-static.a, ext/extinit.o and other objects the final link needs, together with the exact link command the build ran. With those, downstream projects like the builder can link their own ruby without rebuilding CRuby. That command from make -n build-ext, the only place I've found that prints the build’s own link line.

In a tree with static extensions, running it deletes ext/extinit.o, which is one of the files I need to ship in the release bundle. Then, a later make ruby quietly produces a binary with no extensions. As a workaround, I run the dry run in a copy of the build tree. That works, but it costs a full copy of the tree for every build, plus the time required for the extra build.

Environment

  • Ruby 4.0.9 (originally observed on 3.3.3).
  • GNU make.
  • Observed in a cross build for wasm32-wasi, using wasi-sdk 22.0, driven by
    ruby.wasm with --with-static-linked-ext --with-ext=<list>.

Steps (via attached run-script)

  1. Configure with --with-static-linked-ext and some extensions, and run the
    build to completion. ext/extinit.c exists, with one init(Init_…) line per
    extension, and so does ext/extinit.o.
  2. Run sha256sum ruby ext/extinit.o ext/extinit.c.
  3. Run make -n build-ext.
  4. Run sha256sum ruby ext/extinit.o ext/extinit.c again.

Expected: the same three digests.
Actual: ruby is unchanged, and ext/extinit.o and ext/extinit.c no
longer exist.

Where it comes from

  • template/configure-ext.mk.tmpl
    $(Q)$(MINIRUBY) $(srcdir)/ext/extmk.rb --make='$(MAKE)' ….
  • GNU make runs any recipe line that references $(MAKE) even under -n, -t
    and -q. The GNU make manual documents this under "How the MAKE Variable
    Works". Here, $(MAKE) appears only as an argument to extmk.rb, but that
    is enough for make to treat the whole line as recursive.
  • So during make -n build-ext, extmk.rb really runs. In the -n transcript
    this shows as make -f ext/configure-ext.mk -n … followed by one extmk.rb
    invocation per extension.
  • ext/extmk.rb (line 702 in v3.3.3, 713 in v3.4.1, 715 on master) runs
    FileUtils.rm_f(extinit.to_a) in the branch taken when $extlist is empty.
    That deletes ext/extinit.c and ext/extinit.o.

Why it matters

make -n is a natural way to find out what link a build would perform. Here it
modifies the tree it inspects, and nothing says so. A follow-up make ruby
against the top-level Makefile then regenerates ext/extinit.c from an empty
$(EXTINITS), because EXTINITS is defined only in exts.mk. It writes an
Init_ext that names no extensions and relinks ruby without them, and it
reports success.

Possible directions

These are for the maintainers to judge. I may be missing why the line is
written this way.

  • Pass the make command to extmk.rb without $(MAKE) appearing literally in
    the recipe line, for example through an environment variable set elsewhere,
    so that -n applies to it.
  • Or have extmk.rb skip the rm_f when it is invoked under a dry run, when
    MAKEFLAGS contains n.
  • Or, if this is intended, a note in the build documentation that
    make -n build-ext is not side-effect-free.

Cheers


Files

cruby-make-n-build-ext-runsheet.sh (4.2 KB) cruby-make-n-build-ext-runsheet.sh hopefully you'll only need to set your WORK dir graial (al gray), 11/02/2026 01:03 AM

Updated by graial (al gray) 5 days ago Actions #1

  • ruby -v changed from 3.3.3 to 4.0.9
Actions

Also available in: PDF Atom