ruby-llvm/ruby-llvm

View on GitHub
ext/ruby-llvm-support/Rakefile

Summary

Maintainability
Test Coverage
# frozen_string_literal: true

require 'rubygems'
require 'rake/clean'
require 'ffi'

require File.expand_path('../../lib/llvm/version', File.dirname(__FILE__))
include LLVM

def check_for(what, variants, env_var)
  variants = [ ENV[env_var], *variants ] if ENV.include?(env_var)

  $stdout.print("checking for #{what}... ")
  $stdout.flush

  result = variants.find do |variant|
    if yield(variant)
      $stdout.puts(variant)
      true
    end
  end

  if result
    result
  else
    raise "Cannot find #{what}: tried #{variants}"
  end
end

def find_llvm_config
  check_for('llvm-config',
            %W(llvm-config-#{LLVM_VERSION} llvm-config),
            'LLVM_CONFIG') do |llvm_config|

    begin
      actual_version = `#{llvm_config} --version`.strip
      actual_maj, actual_min, _ = actual_version.split('.')

      required_maj, required_min = LLVM_REQUIRED_VERSION.split('.')

      actual_maj == required_maj && actual_min == required_min
    rescue Errno::ENOENT
      false
    end
  end
end

def find_cxx
  check_for('C++ compiler', %W(clang++-#{LLVM_VERSION} clang++ g++), 'CXX') do |cxx|
    system(cxx, "--version", out: File::NULL, err: File::NULL)
    $?.success?
  end
end

LLVM_CONFIG = find_llvm_config
CXX         = find_cxx

def invoke_llvm_config(options)
  `#{LLVM_CONFIG} #{options}`.tr("\n", " ").strip
end

def llvm_lib_name
  lib_dir = invoke_llvm_config('--libdir').strip
  lib_name = 'LLVM'
  versioned_lib_name = "#{lib_name}-#{LLVM_VERSION}"
  versioned_lib_pattern = "lib#{versioned_lib_name}.*"
  versioned_lib_found = Dir.glob(File.join(lib_dir, versioned_lib_pattern)) != []
  versioned_lib_found ? versioned_lib_name : lib_name
end

SUPPORT_LIB = FFI.map_library_name("RubyLLVMSupport-#{LLVM_VERSION}")
CONFIG_MOD  = File.expand_path('../../lib/llvm/config.rb', File.dirname(__FILE__))

CLEAN.include(SUPPORT_LIB, CONFIG_MOD)

desc "Build the shared library and config module"
task :default => [SUPPORT_LIB, CONFIG_MOD]

file SUPPORT_LIB => %w(support.cpp) do |task|
  sh "#{CXX} -O3 -shared #{task.prerequisites.join(' ')} -l#{llvm_lib_name} " \
     "#{invoke_llvm_config('--cxxflags --ldflags')} -fPIC -o #{SUPPORT_LIB}"
end

LLVM_CONFIG_OPTS = [
  ['VERSION',      :string, '--version'],
  ['COMPONENTS',    :array,  '--components'],
  ['TARGETS_BUILT', :array,  '--targets-built'],
  ['HOST_TARGET',   :string, '--host-target'],
  ['BUILD_MODE',    :string, '--build-mode'],
  ['CFLAGS',        :string, '--cflags'],
  ['CXXFLAGS',      :string, '--cxxflags'],
  ['LDFLAGS',      :string, '--ldflags'],
].freeze

file CONFIG_MOD do
  open(CONFIG_MOD, 'w') do |f|
    f.puts '# Generated by ruby-llvm. Please do not change this file by hand.'
    f.puts 'module LLVM'
    f.puts '  module CONFIG'

    LLVM_CONFIG_OPTS.each do |(const, fmt, flag)|
      case fmt
      when :string
        value = invoke_llvm_config(flag)
      when :array
        value = invoke_llvm_config(flag).split
      end

      f.puts "    #{const} = #{value.inspect}"
    end

    f.puts '  end'
    f.puts 'end'
  end
end