Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patch MakeMakefile for extension builds #13328

Merged
merged 2 commits into from
Jan 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/vagrant.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1

require "log4r"

# Add patches to log4r to support trace level
require "vagrant/patches/log4r"
require "vagrant/patches/net-ssh"
require "vagrant/patches/rubygems"

# Set our log levels and include trace
require 'log4r/configurator'
Log4r::Configurator.custom_levels(*(["TRACE"] + Log4r::Log4rConfig::LogLevels))
Expand Down
116 changes: 116 additions & 0 deletions lib/vagrant/patches/builder/mkmf.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1

# This custom mkmf.rb file is used on Windows platforms
# to handle common path related build failures where
# a space is included in the path. The default installation
# location being in Program Files results in most many
# extensions failing to build. These patches will attempt
# to find unquoted paths in flags and quote them prior to
# usage.

# Start with locating the real mkmf.rb file and
# loading it
mkmf_paths = $LOAD_PATH.find_all { |x|
!x.start_with?(__dir__) &&
File.exist?(File.join(x, "mkmf.rb"))
}.uniq

# At this point the path collection should only consist
# of a single entry. If there's more than one, load all
# of them but include a warning message that more than
# one was encountered. If none are found, then something
# bad is going on so just bail.
if mkmf_paths.size > 1
$stderr.puts "WARNING: Multiple mkmf.rb files located: #{mkmf_paths.inspect}"
elsif mkmf_paths.empty?
raise "Failed to locate mkmf.rb file"
end

mkmf_paths.each do |mpath|
require File.join(mpath, "mkmf.rb")
end

# Attempt to detect and quote Windos paths found within
# the given string of flags
#
# @param [String] flags Compiler/linker flags
# @return [String] flags with paths quoted
def flag_cleaner(flags)
parts = flags.split(" -")
parts.map! do |p|
if p !~ %r{[A-Za-z]:(/|\\)}
next p
elsif p =~ %r{"[A-Za-z]:(/|\\).+"$}
next p
end

p.gsub(%r{([A-Za-z]:(/|\\).+)$}, '"\1"')
end

parts.join(" -")
end

# Check values defined for CFLAGS, CPPFLAGS, LDFLAGS,
# and INCFLAGS for unquoted Windows paths and quote
# them.
def clean_flags!
$CFLAGS = flag_cleaner($CFLAGS)
$CPPFLAGS = flag_cleaner($CPPFLAGS)
$LDFLAGS = flag_cleaner($LDFLAGS)
$INCFLAGS = flag_cleaner($INCFLAGS)
end

# Since mkmf loads the MakeMakefile module directly into the
# current scope, apply patches directly in the scope
def vagrant_create_makefile(*args)
clean_flags!

ruby_create_makefile(*args)
end
alias :ruby_create_makefile :create_makefile
alias :create_makefile :vagrant_create_makefile

def vagrant_append_cflags(*args)
result = ruby_append_cflags(*args)
clean_flags!
result
end
alias :ruby_append_cflags :append_cflags
alias :append_cflags :vagrant_append_cflags

def vagrant_append_cppflags(*args)
result = ruby_append_cppflags(*args)
clean_flags!
result
end
alias :ruby_append_cppflags :append_cppflags
alias :append_cppflags :vagrant_append_cppflags

def vagrant_append_ldflags(*args)
result = ruby_append_ldflags(*args)
clean_flags!
result
end
alias :ruby_append_ldflags :append_ldflags
alias :append_ldflags :vagrant_append_ldflags

def vagrant_cc_config(*args)
clean_flags!
ruby_cc_config(*args)
end
alias :ruby_cc_config :cc_config
alias :cc_config :vagrant_cc_config

def vagrant_link_config(*args)
clean_flags!
ruby_link_config(*args)
end
alias :ruby_link_config :link_config
alias :link_config :vagrant_link_config

# Finally, always append the flags that Vagrant has
# defined via the environment
append_cflags(ENV["CFLAGS"]) if ENV["CFLAGS"]
append_cppflags(ENV["CPPFLAGS"]) if ENV["CPPFLAGS"]
append_ldflags(ENV["LDFLAGS"]) if ENV["LDFLAGS"]
23 changes: 23 additions & 0 deletions lib/vagrant/patches/rubygems.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1

# This allows for effective monkey patching of the MakeMakefile
# module when building gem extensions. When gem extensions are
# built, the extconf.rb file is executed as a separate process.
# To support monkey patching the MakeMakefile module, the ruby
# executable path is adjusted to add a custom load path allowing
# a customized mkmf.rb file to load the proper mkmf.rb file, and
# then applying the proper patches.
if Gem.win_platform?
Gem.class_eval do
class << self
def vagrant_ruby
cmd = ruby_ruby
"#{cmd} -I\"#{Vagrant.source_root.join("lib/vagrant/patches/builder")}\""
end

alias_method :ruby_ruby, :ruby
alias_method :ruby, :vagrant_ruby
end
end
end