class PackageConfig

Constants

IDENTIFIER_RE
SEPARATOR

Attributes

msvc_syntax[RW]
paths[R]

Public Class Methods

clear_configure_args_cache() click to toggle source
# File lib/pkg-config.rb, line 47
def clear_configure_args_cache
  @native_pkg_config = nil
  @native_pkg_config_prefix = nil
  @custom_override_variables = nil
end
custom_override_variables() click to toggle source
# File lib/pkg-config.rb, line 43
def custom_override_variables
  @custom_override_variables ||= with_config("override-variables", "")
end
native_pkg_config() click to toggle source
# File lib/pkg-config.rb, line 33
def native_pkg_config
  @native_pkg_config ||= guess_native_pkg_config
end
native_pkg_config_prefix() click to toggle source
# File lib/pkg-config.rb, line 38
def native_pkg_config_prefix
  @native_pkg_config_prefix ||= compute_native_pkg_config_prefix
end
new(name, options={}) click to toggle source
# File lib/pkg-config.rb, line 139
def initialize(name, options={})
  @name = name
  @options = options
  path = @options[:path] || ENV["PKG_CONFIG_PATH"]
  @paths = [path, guess_default_path].compact.join(SEPARATOR).split(SEPARATOR)
  @paths.unshift(*(@options[:paths] || []))
  @paths = normalize_paths(@paths)
  @msvc_syntax = @options[:msvc_syntax]
  @variables = @declarations = nil
  override_variables = self.class.custom_override_variables
  @override_variables = parse_override_variables(override_variables)
  default_override_variables = @options[:override_variables] || {}
  @override_variables = default_override_variables.merge(@override_variables)
end

Private Class Methods

compute_native_pkg_config_prefix() click to toggle source
# File lib/pkg-config.rb, line 122
def compute_native_pkg_config_prefix
  pkg_config = native_pkg_config
  return nil unless pkg_config.absolute?

  pkg_config_prefix = pkg_config.parent.parent
  if File::ALT_SEPARATOR
    normalized_pkg_config_prefix =
      pkg_config_prefix.to_s.split(File::ALT_SEPARATOR).join(File::SEPARATOR)
    Pathname(normalized_pkg_config_prefix)
  else
    pkg_config_prefix
  end
end
guess_native_pkg_config() click to toggle source
# File lib/pkg-config.rb, line 62
def guess_native_pkg_config
  exeext = RbConfig::CONFIG["EXEEXT"]
  default_pkg_config = ENV["PKG_CONFIG"] || "pkg-config#{exeext}"
  pkg_config = with_config("pkg-config", default_pkg_config)
  pkg_config = Pathname.new(pkg_config)
  unless pkg_config.absolute?
    found_pkg_config = search_executable_from_path(pkg_config)
    pkg_config = found_pkg_config if found_pkg_config
  end
  unless pkg_config.absolute?
    found_pkg_config = search_pkg_config_by_dln_find_exe(pkg_config)
    pkg_config = found_pkg_config if found_pkg_config
  end
  pkg_config
end
search_executable_from_path(name) click to toggle source
# File lib/pkg-config.rb, line 78
def search_executable_from_path(name)
  (ENV["PATH"] || "").split(SEPARATOR).each do |path|
    try_name = Pathname(path) + name
    return try_name if try_name.executable?
  end
  nil
end
search_pkg_config_by_dln_find_exe(pkg_config) click to toggle source
# File lib/pkg-config.rb, line 86
def search_pkg_config_by_dln_find_exe(pkg_config)
  begin
    require "dl/import"
  rescue LoadError
    return nil
  end
  dln = Module.new
  dln.module_eval do
    if DL.const_defined?(:Importer)
      extend DL::Importer
    else
      extend DL::Importable
    end
    begin
      dlload RbConfig::CONFIG["LIBRUBY"]
    rescue RuntimeError
      return nil if $!.message == "unknown error"
      return nil if /: image not found\z/ =~ $!.message
      raise
    rescue DL::DLError
      return nil
    end
    begin
      extern "const char *dln_find_exe(const char *, const char *)"
    rescue DL::DLError
      return nil
    end
  end
  path = dln.dln_find_exe(pkg_config.to_s, nil)
  if path.nil? or path.size.zero?
    nil
  else
    Pathname(path.to_s)
  end
end
with_config(config, default=nil) click to toggle source
Calls superclass method
# File lib/pkg-config.rb, line 54
def with_config(config, default=nil)
  if defined?(super)
    super
  else
    default
  end
end

Public Instance Methods

cflags() click to toggle source
# File lib/pkg-config.rb, line 166
def cflags
  path_flags, other_flags = collect_cflags
  (other_flags + path_flags).join(" ")
end
cflags_only_I() click to toggle source
# File lib/pkg-config.rb, line 171
def cflags_only_I
  collect_cflags[0].join(" ")
end
cflags_only_other() click to toggle source
# File lib/pkg-config.rb, line 175
def cflags_only_other
  collect_cflags[1].join(" ")
end
declaration(name) click to toggle source
# File lib/pkg-config.rb, line 217
def declaration(name)
  parse_pc if @declarations.nil?
  expand_value(@declarations[name])
end
description() click to toggle source
# File lib/pkg-config.rb, line 208
def description
  declaration("Description")
end
exist?() click to toggle source
# File lib/pkg-config.rb, line 154
def exist?
  not pc_path.nil?
end
libs() click to toggle source
# File lib/pkg-config.rb, line 179
def libs
  path_flags, other_flags = collect_libs
  (path_flags + other_flags).join(" ")
end
libs_only_L() click to toggle source
# File lib/pkg-config.rb, line 194
def libs_only_L
  collect_libs[0].find_all do |arg|
    if @msvc_syntax
      /\A\/libpath:/ =~ arg
    else
      /\A-L/ =~ arg
    end
  end.join(" ")
end
libs_only_l() click to toggle source
# File lib/pkg-config.rb, line 184
def libs_only_l
  collect_libs[1].find_all do |arg|
    if @msvc_syntax
      /\.lib\z/ =~ arg
    else
      /\A-l/ =~ arg
    end
  end.join(" ")
end
pc_path() click to toggle source
# File lib/pkg-config.rb, line 222
def pc_path
  @paths.each do |path|
    _pc_path = File.join(path, "#{@name}.pc")
    return _pc_path if File.exist?(_pc_path)
  end
  nil
end
requires() click to toggle source
# File lib/pkg-config.rb, line 158
def requires
  parse_requires(declaration("Requires"))
end
requires_private() click to toggle source
# File lib/pkg-config.rb, line 162
def requires_private
  parse_requires(declaration("Requires.private"))
end
variable(name) click to toggle source
# File lib/pkg-config.rb, line 212
def variable(name)
  parse_pc if @variables.nil?
  expand_value(@override_variables[name] || @variables[name])
end
version() click to toggle source
# File lib/pkg-config.rb, line 204
def version
  declaration("Version")
end

Private Instance Methods

all_required_packages() click to toggle source
# File lib/pkg-config.rb, line 457
def all_required_packages
  (requires_private + requires.reverse).reject do |package|
    @name == package
  end.uniq
end
collect_cflags() click to toggle source
# File lib/pkg-config.rb, line 231
def collect_cflags
  cflags_set = [declaration("Cflags")]
  cflags_set += private_required_packages.collect do |package|
    self.class.new(package, @options).cflags
  end
  cflags_set += required_packages.collect do |package|
    self.class.new(package, @options).cflags
  end
  all_cflags = normalize_cflags(Shellwords.split(cflags_set.join(" ")))
  path_flags, other_flags = all_cflags.partition {|flag| /\A-I/ =~ flag}
  path_flags = normalize_path_flags(path_flags, "-I")
  path_flags = remove_duplicated_include_paths(path_flags)
  path_flags = path_flags.reject do |flag|
    flag == "-I/usr/include"
  end
  if @msvc_syntax
    path_flags = path_flags.collect do |flag|
      flag.gsub(/\A-I/, "/I")
    end
  end
  [path_flags, other_flags]
end
collect_libs() click to toggle source
# File lib/pkg-config.rb, line 291
def collect_libs
  all_libs = required_packages.collect do |package|
    self.class.new(package, @options).libs
  end
  all_libs = [declaration("Libs")] + all_libs
  all_flags = split_lib_flags(all_libs.join(" "))
  path_flags, other_flags = all_flags.partition {|flag| /\A-L/ =~ flag}
  path_flags = normalize_path_flags(path_flags, "-L")
  path_flags = path_flags.reject do |flag|
    /\A-L\/usr\/lib(?:64|x32)?\z/ =~ flag
  end
  if @msvc_syntax
    path_flags = path_flags.collect do |flag|
      flag.gsub(/\A-L/, "/libpath:")
    end
    other_flags = other_flags.collect do |flag|
      if /\A-l/ =~ flag
        "#{$POSTMATCH}.lib"
      else
        flag
      end
    end
  end
  [path_flags, other_flags]
end
expand_value(value) click to toggle source
# File lib/pkg-config.rb, line 374
def expand_value(value)
  return nil if value.nil?
  value.gsub(/\$\{(#{IDENTIFIER_RE})\}/) do
    variable($1)
  end
end
guess_default_path() click to toggle source
# File lib/pkg-config.rb, line 381
def guess_default_path
  arch_depended_path = Dir.glob("/usr/lib/*/pkgconfig")
  default_paths = [
    "/usr/local/lib64/pkgconfig",
    "/usr/local/libx32/pkgconfig",
    "/usr/local/lib/pkgconfig",
    "/usr/local/libdata/pkgconfig",
    "/usr/local/share/pkgconfig",
    "/opt/local/lib/pkgconfig",
    *arch_depended_path,
    "/usr/lib64/pkgconfig",
    "/usr/libx32/pkgconfig",
    "/usr/lib/pkgconfig",
    "/usr/libdata/pkgconfig",
    "/usr/X11R6/lib/pkgconfig",
    "/usr/X11R6/share/pkgconfig",
    "/usr/X11/lib/pkgconfig",
    "/opt/X11/lib/pkgconfig",
    "/usr/share/pkgconfig",
  ]
  libdir = ENV["PKG_CONFIG_LIBDIR"]
  default_paths.unshift(libdir) if libdir

  paths = []
  pkg_config_prefix = self.class.native_pkg_config_prefix
  if pkg_config_prefix
    pkg_config_arch_depended_paths =
      Dir.glob((pkg_config_prefix + "lib/*/pkgconfig").to_s)
    paths.concat(pkg_config_arch_depended_paths)
    paths << (pkg_config_prefix + "lib64/pkgconfig").to_s
    paths << (pkg_config_prefix + "libx32/pkgconfig").to_s
    paths << (pkg_config_prefix + "lib/pkgconfig").to_s
    paths << (pkg_config_prefix + "libdata/pkgconfig").to_s
  end
  if /-darwin\d[\d\.]*\z/ =~ RUBY_PLATFORM and
      /\A(\d+\.\d+)/ =~ `sw_vers -productVersion`
    mac_os_version = $1
    homebrew_repository_candidates = []
    if pkg_config_prefix
      brew_path = pkg_config_prefix + "bin" + "brew"
      if brew_path.exist?
        escaped_brew_path = Shellwords.escape(brew_path.to_s)
        homebrew_repository = `#{escaped_brew_path} --repository`.chomp
        homebrew_repository_candidates << Pathname.new(homebrew_repository)
      else
        homebrew_repository_candidates << pkg_config_prefix + "Homebrew"
        homebrew_repository_candidates << pkg_config_prefix
      end
    else
      brew = self.class.__send__(:search_executable_from_path, "brew")
      if brew
        homebrew_repository = `brew --repository`.chomp
        homebrew_repository_candidates << Pathname(homebrew_repository)
      end
    end
    homebrew_repository_candidates.each do |candidate|
      path = candidate + "Library/Homebrew/os/mac/pkgconfig/#{mac_os_version}"
      paths << path.to_s if path.exist?
    end
  end
  paths.concat(default_paths)
  paths.join(SEPARATOR)
end
normalize_cflags(cflags) click to toggle source
# File lib/pkg-config.rb, line 270
def normalize_cflags(cflags)
  normalized_cflags = []
  enumerator = cflags.to_enum
  begin
    loop do
      cflag = enumerator.next
      normalized_cflags << cflag
      case cflag
      when "-I"
        normalized_cflags << enumerator.next
      end
    end
  rescue StopIteration
  end
  normalized_cflags
end
normalize_path_flags(path_flags, flag_option) click to toggle source
# File lib/pkg-config.rb, line 254
def normalize_path_flags(path_flags, flag_option)
  return path_flags unless /-mingw32\z/ === RUBY_PLATFORM

  pkg_config_prefix = self.class.native_pkg_config_prefix
  return path_flags unless pkg_config_prefix

  mingw_dir = pkg_config_prefix.basename.to_s
  path_flags.collect do |path_flag|
    path = path_flag.sub(/\A#{Regexp.escape(flag_option)}/, "")
    path = path.sub(/\A\/#{Regexp.escape(mingw_dir)}/i) do
      pkg_config_prefix.to_s
    end
    "#{flag_option}#{path}"
  end
end
normalize_paths(paths) click to toggle source
# File lib/pkg-config.rb, line 463
def normalize_paths(paths)
  paths.reject do |path|
    path.empty? or !File.exist?(path)
  end
end
parse_override_variables(override_variables) click to toggle source
# File lib/pkg-config.rb, line 365
def parse_override_variables(override_variables)
  variables = {}
  override_variables.split(",").each do |variable|
    name, value = variable.split("=", 2)
    variables[name] = value
  end
  variables
end
parse_pc() click to toggle source
# File lib/pkg-config.rb, line 341
def parse_pc
  raise ".pc for #{@name} doesn't exist." unless exist?
  @variables = {}
  @declarations = {}
  File.open(pc_path) do |input|
    input.each_line do |line|
      line = line.gsub(/#.*/, '').strip
      next if line.empty?
      case line
      when /^(#{IDENTIFIER_RE})=/
        @variables[$1] = $POSTMATCH.strip
      when /^(#{IDENTIFIER_RE}):/
        @declarations[$1] = $POSTMATCH.strip
      end
    end
  end
end
parse_requires(requires) click to toggle source
# File lib/pkg-config.rb, line 359
def parse_requires(requires)
  return [] if requires.nil?
  requires_without_version = requires.gsub(/[<>]?=\s*[\d.a-zA-Z_-]+\s*/, '')
  requires_without_version.split(/[,\s]+/)
end
private_required_packages() click to toggle source
# File lib/pkg-config.rb, line 451
def private_required_packages
  requires_private.reject do |package|
    @name == package
  end.uniq
end
remove_duplicated_include_paths(path_flags) click to toggle source
# File lib/pkg-config.rb, line 287
def remove_duplicated_include_paths(path_flags)
  path_flags.uniq
end
required_packages() click to toggle source
# File lib/pkg-config.rb, line 445
def required_packages
  requires.reject do |package|
    @name == package
  end.uniq
end
split_lib_flags(libs_command_line) click to toggle source
# File lib/pkg-config.rb, line 317
def split_lib_flags(libs_command_line)
  all_flags = {}
  flags = []
  in_option = false
  libs_command_line.gsub(/-([Ll]) /, '\1').split.each do |arg|
    if in_option
      flags << arg
      in_option = false
    else
      case arg
      when /-[lL]/
        next if all_flags.key?(arg)
        all_flags[arg] = true
        flags << arg
        in_option = true
      else
        flags << arg
      end
    end
  end
  flags
end