module RbSys::Mkmf

def create_rust_makefile(target, &blk)

Other tags:
    Example: Configure a custom build profile -
    Example: Basic -
def create_rust_makefile(target, &blk)
  if target.include?("/")
    target_prefix, target = File.split(target)
    target_prefix[0, 0] = "/"
  else
    target_prefix = ""
  end
  spec = Struct.new(:name, :metadata).new(target, {})
  cargo_builder = CargoBuilder.new(spec)
  builder = Config.new(cargo_builder)
  yield builder if blk
  srcprefix = File.join("$(srcdir)", builder.ext_dir.gsub(/\A\.\/?/, "")).chomp("/")
  RbConfig.expand(srcdir = srcprefix.dup)
  full_cargo_command = cargo_command(srcdir, builder)
  global_rustflags = []
  # Re-enable if this causes issues, but it should be fine and it prevents unnecessary recompilation
  # global_rustflags << "--cfg=rb_sys_gem" unless builder.use_cargo_build
  global_rustflags << "--cfg=rb_sys_use_stable_api_compiled_fallback" if builder.use_stable_api_compiled_fallback?
  make_install = +<<~MAKE
    #{conditional_assign("RB_SYS_BUILD_DIR", File.join(Dir.pwd, ".rb-sys"))}
    #{conditional_assign("CARGO", "cargo")}
    #{conditional_assign("CARGO_BUILD_TARGET", builder.target)}
    #{conditional_assign("SOEXT", builder.so_ext)}
    #{try_load_bundled_libclang(builder)}
    # Determine the prefix Cargo uses for the lib.
    #{if_neq_stmt("$(SOEXT)", "dll")}
    #{conditional_assign("SOEXT_PREFIX", "lib", indent: 1)}
    #{endif_stmt}
    #{set_cargo_profile(builder)}
    #{conditional_assign("RB_SYS_CARGO_FEATURES", builder.features.join(","))}
    #{conditional_assign("RB_SYS_GLOBAL_RUSTFLAGS", global_rustflags.join(" "))}
    #{conditional_assign("RB_SYS_EXTRA_RUSTFLAGS", builder.extra_rustflags.join(" "))}
    #{conditional_assign("RB_SYS_EXTRA_CARGO_ARGS", builder.extra_cargo_args.join(" "))}
    #{conditional_assign("RB_SYS_CARGO_MANIFEST_DIR", builder.manifest_dir)}
    # Set dirname for the profile, since the profiles do not directly map to target dir (i.e. dev -> debug)
    #{if_eq_stmt("$(RB_SYS_CARGO_PROFILE)", "dev")}
    #{conditional_assign("RB_SYS_CARGO_PROFILE_DIR", "debug", indent: 1)}
    #{else_stmt}
    #{conditional_assign("RB_SYS_CARGO_PROFILE_DIR", "$(RB_SYS_CARGO_PROFILE)", indent: 1)}
    #{endif_stmt}
    # Set the build profile (dev, release, etc.).
    #{assign_stmt("RB_SYS_CARGO_PROFILE_FLAG", "--profile $(RB_SYS_CARGO_PROFILE)", indent: 1)}
    # Account for sub-directories when using `--target` argument with Cargo
    #{conditional_assign("RB_SYS_CARGO_TARGET_DIR", "target")}
    #{if_neq_stmt("$(CARGO_BUILD_TARGET)", "")}
    #{assign_stmt("RB_SYS_FULL_TARGET_DIR", "$(RB_SYS_CARGO_TARGET_DIR)/$(CARGO_BUILD_TARGET)", indent: 1)}
    #{else_stmt}
    #{assign_stmt("RB_SYS_FULL_TARGET_DIR", "$(RB_SYS_CARGO_TARGET_DIR)", indent: 1)}
    #{endif_stmt}
    target_prefix = #{target_prefix}
    TARGET_NAME = #{target[/\A\w+/]}
    TARGET_ENTRY = #{RbConfig::CONFIG["EXPORT_PREFIX"]}Init_$(TARGET_NAME)
    RUBYARCHDIR = $(sitearchdir)$(target_prefix)
    TARGET = #{target}
    DLLIB = $(TARGET).#{RbConfig::CONFIG["DLEXT"]}
    RUSTLIBDIR = $(RB_SYS_FULL_TARGET_DIR)/$(RB_SYS_CARGO_PROFILE_DIR)
    RUSTLIB = $(RUSTLIBDIR)/$(SOEXT_PREFIX)$(TARGET_NAME).$(SOEXT)
    TIMESTAMP_DIR = .
    POSTLINK = #{RbConfig::CONFIG["POSTLINK"] || "$(ECHO) skipping postlink"}
    CLEANOBJS = $(RUSTLIBDIR) $(RB_SYS_BUILD_DIR)
    CLEANLIBS = $(DLLIB) $(RUSTLIB)
    RUBYGEMS_CLEAN_DIRS = $(CLEANOBJS) $(CLEANFILES) #{builder.rubygems_clean_dirs.join(" ")}
    #{base_makefile(srcdir)}
    .PHONY: gemclean
    #{if_neq_stmt("$(RB_SYS_VERBOSE)", "")}
    #{assign_stmt("Q", "$(0=@)", indent: 1)}
    #{endif_stmt}
    #{env_vars(builder)}
    #{export_env("RUSTFLAGS", "$(RB_SYS_GLOBAL_RUSTFLAGS) $(RB_SYS_EXTRA_RUSTFLAGS) $(RUSTFLAGS)")}
    FORCE: ;
    #{optional_rust_toolchain(builder)}
    #{timestamp_file("sitearchdir")}:
    \t$(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR)
    \t$(Q) $(TOUCH) $@
    $(RUSTLIB): FORCE
    \t$(ECHO) generating $(@) \\("$(RB_SYS_CARGO_PROFILE)"\\)
    \t#{full_cargo_command}
    $(DLLIB): $(RUSTLIB)
    \t$(Q) $(COPY) "$(RUSTLIB)" $@
    \t$(Q) $(POSTLINK)
    install-so: $(DLLIB) #{timestamp_file("sitearchdir")}
    \t$(ECHO) installing $(DLLIB) to $(RUBYARCHDIR)
    \t#{fixup_libnames}
    \t$(Q) $(MAKEDIRS) $(RUBYARCHDIR)
    \t$(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
    gemclean:
    \t$(ECHO) Cleaning gem artifacts
    \t-$(Q)$(RM_RF) $(RUBYGEMS_CLEAN_DIRS) 2> /dev/null || true
    install: #{builder.clean_after_install ? "install-so gemclean" : "install-so"}
    all: #{$extout ? "install" : "$(DLLIB)"}
  MAKE
  gsub_cargo_command!(make_install, builder: builder)
  File.write("Makefile", make_install)
end