class Rake::ExtensionTask
def define_native_tasks(for_platform = nil, ruby_ver = RUBY_VERSION, callback = nil)
def define_native_tasks(for_platform = nil, ruby_ver = RUBY_VERSION, callback = nil) platf = for_platform || platform # tmp_path stage_path = "#{@tmp_dir}/#{platf}/stage" # lib_path lib_path = lib_dir # lib_binary_path lib_binary_path = "#{lib_path}/#{File.basename(binary(platf))}" # Update compiled platform/version combinations @ruby_versions_per_platform[platf] << ruby_ver # create 'native:gem_name' and chain it to 'native' task unless Rake::Task.task_defined?("native:#{@gem_spec.name}:#{platf}") task "native:#{@gem_spec.name}:#{platf}" do |t| # FIXME: workaround Gem::Specification limitation around cache_file: # http://github.com/rubygems/rubygems/issues/78 spec = gem_spec.dup spec.instance_variable_set(:"@cache_file", nil) if spec.respond_to?(:cache_file) # adjust to specified platform spec.platform = Gem::Platform.new(platf) # set ruby version constraints ruby_versions = @ruby_versions_per_platform[platf] sorted_ruby_versions = ruby_versions.sort_by do |ruby_version| ruby_version.split(".").collect(&:to_i) end spec.required_ruby_version = [ ">= #{ruby_api_version(sorted_ruby_versions.first)}", "< #{ruby_api_version(sorted_ruby_versions.last).succ}.dev" ] # clear the extensions defined in the specs spec.extensions.clear # add the binaries that this task depends on ext_files = [] # go through native prerequisites and grab the real extension files from there t.prerequisites.each do |ext| # strip stage path and keep lib/... only ext_files << ext.sub(stage_path+"/", '') end # include the files in the gem specification spec.files += ext_files # expose gem specification for customization callback.call(spec) if callback # Generate a package for this gem pkg = Gem::PackageTask.new(spec) do |p| p.need_zip = false p.need_tar = false # Do not copy any files per PackageTask, because # we need the files from the staging directory p.package_files.clear end # copy other gem files to staging directory if added by the callback define_staging_file_tasks(spec.files, lib_path, stage_path, platf, ruby_ver) # Copy from staging directory to gem package directory. # This is derived from the code of Gem::PackageTask # but uses stage_path as source directory. stage_files = spec.files.map do |gem_file| File.join(stage_path, gem_file) end file pkg.package_dir_path => stage_files do mkdir_p pkg.package_dir rescue nil spec.files.each do |ft| fn = File.join(stage_path, ft) f = File.join(pkg.package_dir_path, ft) fdir = File.dirname(f) mkdir_p(fdir) if !File.exist?(fdir) if File.directory?(fn) mkdir_p(f) else rm_f f safe_ln(fn, f) end end end end end # add binaries to the dependency chain task "native:#{@gem_spec.name}:#{platf}" => ["#{stage_path}/#{lib_binary_path}"] # ensure the extension get copied unless Rake::Task.task_defined?(lib_binary_path) then file lib_binary_path => ["copy:#{@name}:#{platf}:#{ruby_ver}"] end file "#{stage_path}/#{lib_binary_path}" => ["copy:#{@name}:#{platf}:#{ruby_ver}"] # Allow segmented packaging by platform (open door for 'cross compile') task "native:#{platf}" => ["native:#{@gem_spec.name}:#{platf}"] # Only add this extension to the compile chain if current # platform matches the indicated one. if platf == RUBY_PLATFORM then task "native:#{@gem_spec.name}" => ["native:#{@gem_spec.name}:#{platf}"] task "native" => ["native:#{platf}"] end end