vcdeps 0.1.0 → 0.1.1
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.
- checksums.yaml +4 -4
- data/README.md +11 -258
- data/lib/vcdeps.rb +4 -180
- metadata +13 -87
- data/CHANGELOG.md +0 -43
- data/exe/vcdeps +0 -6
- data/lib/vcdeps/bootstrap.rb +0 -163
- data/lib/vcdeps/cli.rb +0 -206
- data/lib/vcdeps/doctor.rb +0 -263
- data/lib/vcdeps/installed.rb +0 -139
- data/lib/vcdeps/manifest.rb +0 -100
- data/lib/vcdeps/mkmf.rb +0 -125
- data/lib/vcdeps/runner.rb +0 -145
- data/lib/vcdeps/tool.rb +0 -146
- data/lib/vcdeps/triplet.rb +0 -77
- data/lib/vcdeps/vendor.rb +0 -160
- data/lib/vcdeps/version.rb +0 -5
data/lib/vcdeps/triplet.rb
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "rbconfig"
|
|
4
|
-
|
|
5
|
-
module Vcdeps
|
|
6
|
-
# Derives the vcpkg triplet for the running Ruby and validates user-supplied
|
|
7
|
-
# triplets. The default is the dynamic-CRT, dynamic-library triplet that
|
|
8
|
-
# matches an `-MD` mswin Ruby (x64 -> "x64-windows"); static-CRT triplets are
|
|
9
|
-
# rejected (the LNK2005/dual-heap hazard, R§4).
|
|
10
|
-
#
|
|
11
|
-
# No "x64" literal lives in code: the architecture token is derived from
|
|
12
|
-
# RbConfig::CONFIG["arch"], so arm64-mswin derives "arm64-windows" for free.
|
|
13
|
-
module Triplet
|
|
14
|
-
module_function
|
|
15
|
-
|
|
16
|
-
# Maps a Ruby arch string to its vcpkg architecture token, or nil if
|
|
17
|
-
# unrecognized. Mirrors Vcvars::Doctor.arch's regexes.
|
|
18
|
-
# "x64-mswin64_140" -> "x64"
|
|
19
|
-
# "arm64-mswin64_140" -> "arm64"
|
|
20
|
-
# "i386-mswin32" -> "x86"
|
|
21
|
-
def arch_token(arch)
|
|
22
|
-
a = arch.to_s
|
|
23
|
-
return "x64" if a =~ /\A(?:x64|x86_64|amd64)/i
|
|
24
|
-
return "arm64" if a =~ /arm64|aarch64/i
|
|
25
|
-
return "x86" if a =~ /\A(?:i[3-6]86|x86)/i
|
|
26
|
-
nil
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# Known architecture prefixes a triplet may start with — used to detect an
|
|
30
|
-
# arch mismatch against the running Ruby.
|
|
31
|
-
ARCH_TOKENS = %w[x64 x86 arm64 arm].freeze
|
|
32
|
-
|
|
33
|
-
# The default triplet for the given Ruby arch (dynamic CRT, dynamic libs).
|
|
34
|
-
# Raises Vcdeps::TripletError for an unrecognized arch.
|
|
35
|
-
def default(arch = RbConfig::CONFIG["arch"])
|
|
36
|
-
token = arch_token(arch)
|
|
37
|
-
raise TripletError, "vcdeps: cannot derive a vcpkg triplet for arch " \
|
|
38
|
-
"#{arch.inspect} (recognized: x64, x86, arm64). Set VCDEPS_TRIPLET or " \
|
|
39
|
-
"pass --with-vcdeps-triplet=<triplet> explicitly." if token.nil?
|
|
40
|
-
|
|
41
|
-
"#{token}-windows"
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# Validate a triplet against §2.6 and return it unchanged, or raise
|
|
45
|
-
# Vcdeps::TripletError. `arch` is the running Ruby's arch (for the mismatch
|
|
46
|
-
# check); pass it explicitly in tests to exercise the forward-compat path.
|
|
47
|
-
def validate!(triplet, arch: RbConfig::CONFIG["arch"])
|
|
48
|
-
t = triplet.to_s
|
|
49
|
-
|
|
50
|
-
unless t =~ /\A[a-z0-9][a-z0-9-]*\z/
|
|
51
|
-
raise TripletError, "vcdeps: invalid triplet #{triplet.inspect} " \
|
|
52
|
-
"(must match /\\A[a-z0-9][a-z0-9-]*\\z/). Run `vcdeps doctor`."
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Reject a static-CRT triplet (-static suffix). static-md (static libs +
|
|
56
|
-
# dynamic CRT) is fine; plain -static sets VCPKG_CRT_LINKAGE static.
|
|
57
|
-
if t =~ /-static\z/
|
|
58
|
-
raise TripletError, "vcdeps: triplet #{triplet.inspect} uses a STATIC " \
|
|
59
|
-
"CRT, which is ABI-incompatible with this -MD Ruby (LNK2005 / dual " \
|
|
60
|
-
"heap). Use #{t.sub(/-static\z/, '-static-md')} (static libs, dynamic " \
|
|
61
|
-
"CRT — no DLLs to vendor) or the default #{default(arch)}."
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
# If the triplet leads with a known arch token that differs from this
|
|
65
|
-
# Ruby's arch, it would LNK1112 at link time.
|
|
66
|
-
lead = t.split("-", 2).first
|
|
67
|
-
ruby_token = arch_token(arch)
|
|
68
|
-
if ARCH_TOKENS.include?(lead) && ruby_token && lead != ruby_token
|
|
69
|
-
raise TripletError, "vcdeps: triplet #{triplet.inspect} targets #{lead} " \
|
|
70
|
-
"but this Ruby is #{ruby_token} (#{arch}); linking would fail with " \
|
|
71
|
-
"LNK1112. Use a #{ruby_token}-* triplet (default #{default(arch)})."
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
t
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
data/lib/vcdeps/vendor.rb
DELETED
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "fileutils"
|
|
4
|
-
require "rbconfig"
|
|
5
|
-
require "vcdeps/version"
|
|
6
|
-
|
|
7
|
-
module Vcdeps
|
|
8
|
-
# Syncs an Installed's runtime DLLs, per-port copyright files, and a standalone
|
|
9
|
-
# Fiddle-preload shim into a vendor directory (§2.2/§2.7). This is a SYNC, not
|
|
10
|
-
# a copy: vendor! OWNS <into>\*.dll, <into>\licenses\* and <into>\preload.rb —
|
|
11
|
-
# it overwrites the computed write list and DELETES any owned file no longer on
|
|
12
|
-
# it (so a port removed from vcpkg.json leaves no stale DLL the shim would
|
|
13
|
-
# preload and the precompiled-gem glob would ship). Nothing else under `into`
|
|
14
|
-
# is touched, so authors may keep unrelated assets there.
|
|
15
|
-
module Vendor
|
|
16
|
-
module_function
|
|
17
|
-
|
|
18
|
-
SHIM_NAME = "preload.rb"
|
|
19
|
-
LICENSES_DIR = "licenses"
|
|
20
|
-
|
|
21
|
-
# Returns the list of files written (absolute, backslashed). See §2.2 for the
|
|
22
|
-
# four-case table; stale owned files are deleted whenever `into` exists.
|
|
23
|
-
def sync!(installed, into:, licenses: true, shim: true, out: $stderr)
|
|
24
|
-
dlls = installed.dlls
|
|
25
|
-
copyrights = licenses ? installed.copyright_files : {}
|
|
26
|
-
|
|
27
|
-
# The write plan: a DLL is vendored only when there is something to vendor;
|
|
28
|
-
# the shim is written only when DLLs exist; licenses ship whenever copyright
|
|
29
|
-
# files exist (including static-md, where there are no DLLs).
|
|
30
|
-
write_dlls = dlls
|
|
31
|
-
write_shim = shim && !dlls.empty?
|
|
32
|
-
write_copies = copyrights
|
|
33
|
-
|
|
34
|
-
# Nothing to write AND nothing to clean (into absent) -> [] without
|
|
35
|
-
# creating `into` (§2.2 last case).
|
|
36
|
-
if write_dlls.empty? && write_copies.empty? && !write_shim &&
|
|
37
|
-
!File.directory?(into)
|
|
38
|
-
return []
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
written = []
|
|
42
|
-
FileUtils.mkdir_p(into)
|
|
43
|
-
|
|
44
|
-
# Owned DLLs we intend to keep (base names), for the stale sweep.
|
|
45
|
-
kept_dll_names = []
|
|
46
|
-
write_dlls.each do |src|
|
|
47
|
-
base = File.basename(src)
|
|
48
|
-
dest = File.join(into, base)
|
|
49
|
-
FileUtils.cp(src, dest)
|
|
50
|
-
kept_dll_names << base.downcase
|
|
51
|
-
written << win(dest)
|
|
52
|
-
warn_on_ruby_bin_collision(base, out)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Licenses.
|
|
56
|
-
kept_license_names = []
|
|
57
|
-
unless write_copies.empty?
|
|
58
|
-
ldir = File.join(into, LICENSES_DIR)
|
|
59
|
-
FileUtils.mkdir_p(ldir)
|
|
60
|
-
write_copies.each do |port, src|
|
|
61
|
-
dest = File.join(ldir, "#{port}-copyright.txt")
|
|
62
|
-
FileUtils.cp(src, dest)
|
|
63
|
-
kept_license_names << File.basename(dest).downcase
|
|
64
|
-
written << win(dest)
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
# Shim.
|
|
69
|
-
shim_path = File.join(into, SHIM_NAME)
|
|
70
|
-
if write_shim
|
|
71
|
-
File.write(shim_path, shim_source)
|
|
72
|
-
written << win(shim_path)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
# Stale sweep of OWNED files only.
|
|
76
|
-
sweep_stale!(into, kept_dll_names, kept_license_names, write_shim)
|
|
77
|
-
|
|
78
|
-
written
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
# The generated preload shim (exact §2.7 template). Standalone: stdlib only,
|
|
82
|
-
# no vcdeps require, safe to require twice, safe with zero DLLs present.
|
|
83
|
-
def shim_source
|
|
84
|
-
<<~SHIM
|
|
85
|
-
# frozen_string_literal: true
|
|
86
|
-
#
|
|
87
|
-
# Generated by vcdeps #{Vcdeps::VERSION}. Do not edit; regenerate with `vcdeps vendor`.
|
|
88
|
-
#
|
|
89
|
-
# Preloads the vendored vcpkg runtime DLLs by ABSOLUTE path before the C
|
|
90
|
-
# extension loads. Windows resolves an extension's dependent DLLs via the
|
|
91
|
-
# standard search order, which checks the loaded-module list (step 4) long
|
|
92
|
-
# before PATH (step 12) and NEVER checks the .so's own directory — so loading
|
|
93
|
-
# each DLL here, by full path, is what makes `require "<gem>/<gem>"` work.
|
|
94
|
-
#
|
|
95
|
-
# The dlopen handles are intentionally leaked for process lifetime: the DLLs
|
|
96
|
-
# must stay loaded as long as the extension is loaded.
|
|
97
|
-
require "fiddle"
|
|
98
|
-
|
|
99
|
-
pending = Dir[File.join(__dir__, "*.dll")].sort
|
|
100
|
-
until pending.empty?
|
|
101
|
-
progressed = false
|
|
102
|
-
pending.delete_if do |dll|
|
|
103
|
-
Fiddle.dlopen(dll)
|
|
104
|
-
progressed = true
|
|
105
|
-
true
|
|
106
|
-
rescue Fiddle::DLError
|
|
107
|
-
false # depends on a sibling not yet loaded — retry next pass
|
|
108
|
-
end
|
|
109
|
-
break unless progressed # truly unloadable; let the require raise its own LoadError
|
|
110
|
-
end
|
|
111
|
-
SHIM
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
# --- internals -----------------------------------------------------------
|
|
115
|
-
|
|
116
|
-
# Delete any *.dll directly in `into` not on the kept list, any licenses\*
|
|
117
|
-
# file not kept, and a stale shim when no shim is being written.
|
|
118
|
-
def sweep_stale!(into, kept_dll_names, kept_license_names, write_shim)
|
|
119
|
-
Dir[File.join(into.tr("\\", "/"), "*.dll")].each do |dll|
|
|
120
|
-
File.delete(dll) unless kept_dll_names.include?(File.basename(dll).downcase)
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
ldir = File.join(into.tr("\\", "/"), LICENSES_DIR)
|
|
124
|
-
if File.directory?(ldir)
|
|
125
|
-
Dir[File.join(ldir, "*")].each do |f|
|
|
126
|
-
next unless File.file?(f)
|
|
127
|
-
|
|
128
|
-
File.delete(f) unless kept_license_names.include?(File.basename(f).downcase)
|
|
129
|
-
end
|
|
130
|
-
# Remove an empty licenses dir we no longer populate.
|
|
131
|
-
begin
|
|
132
|
-
Dir.rmdir(ldir) if Dir.empty?(ldir)
|
|
133
|
-
rescue SystemCallError
|
|
134
|
-
nil
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
shim = File.join(into.tr("\\", "/"), SHIM_NAME)
|
|
139
|
-
File.delete(shim) if !write_shim && File.exist?(shim)
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
# Warn when a vendored DLL base name also exists in Ruby's bindir
|
|
143
|
-
# (zlib1.dll/ffi-8.dll/yaml.dll shadowing, R§9.2) — first-loaded wins.
|
|
144
|
-
def warn_on_ruby_bin_collision(base, out)
|
|
145
|
-
bindir = RbConfig::CONFIG["bindir"].to_s
|
|
146
|
-
return if bindir.empty?
|
|
147
|
-
|
|
148
|
-
ruby_copy = File.join(bindir, base)
|
|
149
|
-
return unless File.exist?(ruby_copy)
|
|
150
|
-
|
|
151
|
-
out&.puts("[vcdeps] WARNING: #{base} also ships in #{bindir.tr('/', '\\')} " \
|
|
152
|
-
"— the copy loaded first wins process-wide; preload.rb runs " \
|
|
153
|
-
"first under normal require order.")
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
def win(path)
|
|
157
|
-
path.nil? ? path : path.tr("/", "\\")
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
end
|