Class: Emf2svg::Recipe

Inherits:
MiniPortileCMake
  • Object
show all
Defined in:
lib/emf2svg/recipe.rb

Constant Summary collapse

VCPKG_REF =

Pinned vcpkg commit. Matches the SHA claricle/libemf2svg CI uses; bump deliberately to refresh the ports tree.

"4f95fba7a7d1101bb8acdeb51e4609686449701e".freeze
VCPKG_URL =
"https://github.com/microsoft/vcpkg.git".freeze
ROOT =
Pathname.new(File.expand_path("../..", __dir__))

Instance Method Summary collapse

Constructor Details

#initializeRecipe

Returns a new instance of Recipe.



16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/emf2svg/recipe.rb', line 16

def initialize
  super("libemf2svg", LIBEMF2SVG_VERSION)

  @files << {
    # rubocop:disable Layout/LineLength
    url: "https://github.com/claricle/libemf2svg/releases/download/v#{LIBEMF2SVG_VERSION}/libemf2svg.tar.gz",
    sha256: "3782453987b477f2d8657c727e30f1e7a509188edfe6de2f7423443635aefd6d",
    # rubocop:enable Layout/LineLength
  }

  @target = ROOT.join(@target).to_s
  @printed = {}
end

Instance Method Details

#bootstrap_cmdObject



87
88
89
90
91
92
93
# File 'lib/emf2svg/recipe.rb', line 87

def bootstrap_cmd
  if MiniPortile.windows?
    "bootstrap-vcpkg.bat -disableMetrics"
  else
    "./bootstrap-vcpkg.sh -disableMetrics"
  end
end

#bootstrap_vcpkgObject



70
71
72
73
74
75
76
77
78
79
80
# File 'lib/emf2svg/recipe.rb', line 70

def bootstrap_vcpkg
  vcpkg_root = File.join(work_path, "vcpkg")
  return if vcpkg_bootstrapped?(vcpkg_root)

  message("Bootstrapping vcpkg@#{VCPKG_REF} into #{vcpkg_root}\n")
  FileUtils.rm_rf(vcpkg_root)
  execute("clone-vcpkg", "git clone --quiet #{VCPKG_URL} #{vcpkg_root}")
  execute("checkout-vcpkg",
          "git checkout --quiet #{VCPKG_REF}", cd: vcpkg_root)
  execute("bootstrap-vcpkg", bootstrap_cmd, cd: vcpkg_root)
end

#checkpointObject



108
109
110
# File 'lib/emf2svg/recipe.rb', line 108

def checkpoint
  File.join(@target, "#{name}-#{version}-#{target_platform}.installed")
end

#compileObject



137
138
139
# File 'lib/emf2svg/recipe.rb', line 137

def compile
  execute("compile", "#{make_cmd} --target emf2svg")
end

#configureObject

Since libemf2svg v1.8.2 the source tarball no longer bundles the vcpkg tool (it moved too fast to ship as a snapshot). We bootstrap vcpkg into the work path before CMake configure runs -- unless we're targeting musl, in which case vcpkg has no public binary cache for arm64-linux-musl / x64-linux-musl and would compile every dependency from source (hours). For musl we use the distribution's own -dev packages (freetype, fontconfig, etc.) via pkg-config instead.



47
48
49
50
51
# File 'lib/emf2svg/recipe.rb', line 47

def configure
  bootstrap_vcpkg unless use_system_libs?
  export_toolchain_to_env
  super
end

#configure_defaultsObject



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/emf2svg/recipe.rb', line 112

def configure_defaults
  opts = []

  opts << "-DCMAKE_BUILD_TYPE=Release"
  opts << "-DLONLY=ON"

  unless use_system_libs?
    unless target_triplet.nil? || drop_target_triplet?
      opts << "-DVCPKG_TARGET_TRIPLET=#{target_triplet}"
    end
    opts << "-DCMAKE_TOOLCHAIN_FILE=vcpkg/scripts/buildsystems/vcpkg.cmake"
  end

  opts
end

#cookObject



34
35
36
37
# File 'lib/emf2svg/recipe.rb', line 34

def cook
  super
  FileUtils.touch(checkpoint)
end

#cook_if_notObject



30
31
32
# File 'lib/emf2svg/recipe.rb', line 30

def cook_if_not
  cook unless File.exist?(checkpoint)
end

#drop_target_triplet?Boolean

Returns:

  • (Boolean)


99
100
101
102
103
104
105
106
# File 'lib/emf2svg/recipe.rb', line 99

def drop_target_triplet?
  # Windows ARM64 builds against MSVC with static linking. vcpkg's
  # auto-detection would pick arm64-windows (dynamic) instead of
  # arm64-windows-static, so always pass the triplet explicitly.
  return false if target_platform == "aarch64-mingw-ucrt"

  windows_native? || host_platform.eql?(target_platform)
end

#execute(action, command, command_opts = {}) ⇒ Object



180
181
182
# File 'lib/emf2svg/recipe.rb', line 180

def execute(action, command, command_opts = {})
  super(action, command, command_opts.merge(debug: false))
end

#export_toolchain_to_envObject

Downstream consumers (e.g. metanorma) sometimes patch RbConfig at runtime to point Ruby's toolchain at a known-good compiler, but those overrides live in the Ruby process and don't reach the raw cmake subprocess that mini_portile2 spawns. The result is "CMAKE_C_COMPILER not set" when the deploy environment has a stripped PATH. Mirror the resolved RbConfig toolchain into ENV so the subprocess sees the same compiler the running Ruby was built with.



61
62
63
64
65
66
67
68
# File 'lib/emf2svg/recipe.rb', line 61

def export_toolchain_to_env
  %w[CC CXX LDFLAGS].each do |var|
    val = RbConfig::CONFIG[var]
    next if val.nil? || val.empty?

    ENV[var] = val
  end
end

#installObject



168
169
170
171
172
173
174
175
176
177
178
# File 'lib/emf2svg/recipe.rb', line 168

def install
  libs = if MiniPortile.windows?
           Dir.glob(File.join(work_path, "Release", "*.dll"))
         else
           Dir.glob(File.join(work_path, "libemf2svg.{so,dylib}"))
             .grep(/\/(?:lib)?[a-zA-Z0-9-]+\.(?:so|dylib)$/)
         end
  FileUtils.cp_r(libs, ROOT.join("lib", "emf2svg"), verbose: true)

  verify_libs unless target_format.eql?("skip")
end

#lb_to_verifyObject



145
146
147
148
149
150
151
152
# File 'lib/emf2svg/recipe.rb', line 145

def lb_to_verify
  pt = if MiniPortile.windows?
         "emf2svg.dll"
       else
         "libemf2svg.{so,dylib}"
       end
  @lb_to_verify ||= Dir.glob(ROOT.join("lib", "emf2svg", pt))
end

#make_cmdObject



141
142
143
# File 'lib/emf2svg/recipe.rb', line 141

def make_cmd
  "cmake --build #{File.expand_path(work_path)} --config Release"
end

#message(text) ⇒ Object



184
185
186
187
188
189
190
191
192
193
# File 'lib/emf2svg/recipe.rb', line 184

def message(text)
  return super unless text.start_with?("\rDownloading")

  match = text.match(/(\rDownloading .*)\(\s*\d+%\)/)
  pattern = match ? match[1] : text
  return if @printed[pattern]

  @printed[pattern] = true
  super
end

#use_system_libs?Boolean

Musl builds link against the distro's own -dev packages (freetype, fontconfig, libxml2, libpng) via pkg-config. This sidesteps vcpkg's lack of a public binary cache for musl triplets, which otherwise forces from-source compiles that exceed CI timeouts.

Returns:

  • (Boolean)


133
134
135
# File 'lib/emf2svg/recipe.rb', line 133

def use_system_libs?
  target_platform.end_with?("-linux-musl")
end

#vcpkg_bootstrapped?(vcpkg_root) ⇒ Boolean

Returns:

  • (Boolean)


82
83
84
85
# File 'lib/emf2svg/recipe.rb', line 82

def vcpkg_bootstrapped?(vcpkg_root)
  exe = MiniPortile.windows? ? "vcpkg.exe" : "vcpkg"
  File.executable?(File.join(vcpkg_root, exe))
end

#verify_libsObject



154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/emf2svg/recipe.rb', line 154

def verify_libs
  lb_to_verify.each do |l|
    out, st = Open3.capture2("file #{l}")
    raise "Failed to query file #{l}: #{out}" unless st.exitstatus.zero?

    if target_format.match?(out)
      message("Verifying #{l} ... OK\n")
    else
      fmt = target_format.source
      raise "Invalid file format '#{out}', /#{fmt}/ expected"
    end
  end
end

#windows_native?Boolean

Returns:

  • (Boolean)


95
96
97
# File 'lib/emf2svg/recipe.rb', line 95

def windows_native?
  MiniPortile.windows? && target_triplet.eql?("x64-mingw-static")
end