Module: Vcdeps::Triplet

Defined in:
lib/vcdeps/triplet.rb

Overview

Derives the vcpkg triplet for the running Ruby and validates user-supplied triplets. The default is the dynamic-CRT, dynamic-library triplet that matches an -MD mswin Ruby (x64 -> "x64-windows"); static-CRT triplets are rejected (the LNK2005/dual-heap hazard, R§4).

No "x64" literal lives in code: the architecture token is derived from RbConfig::CONFIG, so arm64-mswin derives "arm64-windows" for free.

Constant Summary collapse

ARCH_TOKENS =

Known architecture prefixes a triplet may start with — used to detect an arch mismatch against the running Ruby.

%w[x64 x86 arm64 arm].freeze

Class Method Summary collapse

Class Method Details

.arch_token(arch) ⇒ Object

Maps a Ruby arch string to its vcpkg architecture token, or nil if unrecognized. Mirrors Vcvars::Doctor.arch's regexes. "x64-mswin64_140" -> "x64" "arm64-mswin64_140" -> "arm64" "i386-mswin32" -> "x86"



21
22
23
24
25
26
27
# File 'lib/vcdeps/triplet.rb', line 21

def arch_token(arch)
  a = arch.to_s
  return "x64"   if a =~ /\A(?:x64|x86_64|amd64)/i
  return "arm64" if a =~ /arm64|aarch64/i
  return "x86"   if a =~ /\A(?:i[3-6]86|x86)/i
  nil
end

.default(arch = RbConfig::CONFIG["arch"]) ⇒ Object

The default triplet for the given Ruby arch (dynamic CRT, dynamic libs). Raises Vcdeps::TripletError for an unrecognized arch.

Raises:



35
36
37
38
39
40
41
42
# File 'lib/vcdeps/triplet.rb', line 35

def default(arch = RbConfig::CONFIG["arch"])
  token = arch_token(arch)
  raise TripletError, "vcdeps: cannot derive a vcpkg triplet for arch " \
    "#{arch.inspect} (recognized: x64, x86, arm64). Set VCDEPS_TRIPLET or " \
    "pass --with-vcdeps-triplet=<triplet> explicitly." if token.nil?

  "#{token}-windows"
end

.validate!(triplet, arch: RbConfig::CONFIG["arch"]) ⇒ Object

Validate a triplet against §2.6 and return it unchanged, or raise Vcdeps::TripletError. arch is the running Ruby's arch (for the mismatch check); pass it explicitly in tests to exercise the forward-compat path.



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/vcdeps/triplet.rb', line 47

def validate!(triplet, arch: RbConfig::CONFIG["arch"])
  t = triplet.to_s

  unless t =~ /\A[a-z0-9][a-z0-9-]*\z/
    raise TripletError, "vcdeps: invalid triplet #{triplet.inspect} " \
      "(must match /\\A[a-z0-9][a-z0-9-]*\\z/). Run `vcdeps doctor`."
  end

  # Reject a static-CRT triplet (-static suffix). static-md (static libs +
  # dynamic CRT) is fine; plain -static sets VCPKG_CRT_LINKAGE static.
  if t =~ /-static\z/
    raise TripletError, "vcdeps: triplet #{triplet.inspect} uses a STATIC " \
      "CRT, which is ABI-incompatible with this -MD Ruby (LNK2005 / dual " \
      "heap). Use #{t.sub(/-static\z/, '-static-md')} (static libs, dynamic " \
      "CRT — no DLLs to vendor) or the default #{default(arch)}."
  end

  # If the triplet leads with a known arch token that differs from this
  # Ruby's arch, it would LNK1112 at link time.
  lead = t.split("-", 2).first
  ruby_token = arch_token(arch)
  if ARCH_TOKENS.include?(lead) && ruby_token && lead != ruby_token
    raise TripletError, "vcdeps: triplet #{triplet.inspect} targets #{lead} " \
      "but this Ruby is #{ruby_token} (#{arch}); linking would fail with " \
      "LNK1112. Use a #{ruby_token}-* triplet (default #{default(arch)})."
  end

  t
end