Skip to content

Commit

Permalink
Merge pull request #131 from flavorjones/118-fedora-pkgconf
Browse files Browse the repository at this point in the history
feat: `MiniPortile#mkmf_config` which supports pkg-config files to configure compiler and linker flags
  • Loading branch information
flavorjones authored Sep 13, 2023
2 parents 3255d3f + b17522b commit 6ae2e70
Show file tree
Hide file tree
Showing 9 changed files with 446 additions and 16 deletions.
19 changes: 18 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,22 @@ jobs:
- uses: actions/cache@v3
with:
path: examples/ports/archives
key: ${{ matrix.platform }}-examples-${{ hashFiles('examples/Rakefile') }}
key: examples-${{ hashFiles('examples/Rakefile') }}
- run: bundle exec rake test:examples

fedora: # see https://github.com/flavorjones/mini_portile/issues/118
runs-on: ubuntu-latest
container:
image: fedora:35
steps:
- run: |
dnf group install -y "C Development Tools and Libraries"
dnf install -y ruby ruby-devel libyaml-devel git-all patch cmake xz
- uses: actions/checkout@v3
- uses: actions/cache@v3
with:
path: examples/ports/archives
key: examples-${{ hashFiles('examples/Rakefile') }}
- run: bundle install
- run: bundle exec rake test:unit
- run: bundle exec rake test:examples
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ Gemfile.lock
pkg
ports
tmp
mkmf.log
35 changes: 33 additions & 2 deletions examples/Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ $: << File.expand_path(File.join(File.dirname(__FILE__), "../lib"))
require "mini_portile2"

recipes = []
recipe_hooks = {}

def windows?
RbConfig::CONFIG['target_os'] =~ /mswin|mingw32/
Expand Down Expand Up @@ -119,6 +120,29 @@ zlib.files << {

recipes.push zlib

#
# libyaml, using pkgconf for configuration
#
yaml = MiniPortile.new("yaml", "0.2.5")
yaml.files = [{
url: "https://github.com/yaml/libyaml/releases/download/0.2.5/yaml-0.2.5.tar.gz",
sha256: "c642ae9b75fee120b2d96c712538bd2cf283228d2337df2cf2988e3c02678ef4",
}]
recipes.unshift(yaml)
recipe_hooks["yaml"] = lambda do |recipe|
recipe.mkmf_config(pkg: "yaml-0.1")

expected = "-L" + File.join(recipe.path, "lib")
$LDFLAGS.split.include?(expected) or raise(<<~MSG)
assertion failed: LDFLAGS not updated correctly:
#{$LDFLAGS}
should have included '#{expected}'
MSG

unless have_library("yaml", "yaml_get_version", "yaml.h")
raise("could not find libyaml development environment")
end
end

namespace :ports do
directory "ports"
Expand All @@ -135,7 +159,11 @@ namespace :ports do
desc "Install port #{recipe.name} #{recipe.version}"
task recipe.name => ["ports"] do |t|
recipe.cook
recipe.activate
if hook = recipe_hooks[recipe.name]
hook.call(recipe)
else
recipe.activate
end
end

task :all => recipe.name
Expand All @@ -146,7 +174,10 @@ namespace :ports do
recipes.each do |recipe|
puts "Artifacts of '#{recipe.name}' in '#{recipe.path}'"
end
puts "LDFLAGS: " + ENV['LDFLAGS'].inspect
puts "LIBRARY_PATH: #{ENV['LIBRARY_PATH'].inspect}"
puts "LDFLAGS: #{ENV['LDFLAGS'].inspect}"
puts "$LDFLAGS: #{$LDFLAGS.inspect}"
puts "$CFLAGS: #{$CFLAGS.inspect}"
end
end

Expand Down
96 changes: 83 additions & 13 deletions lib/mini_portile2/mini_portile.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,24 @@ def self.target_cpu
RbConfig::CONFIG['target_cpu']
end

def self.native_path(path)
path = File.expand_path(path)
if File::ALT_SEPARATOR
path.tr(File::SEPARATOR, File::ALT_SEPARATOR)
else
path
end
end

def self.posix_path(path)
path = File.expand_path(path)
if File::ALT_SEPARATOR
"/" + path.tr(File::ALT_SEPARATOR, File::SEPARATOR).tr(":", File::SEPARATOR)
else
path
end
end

def initialize(name, version, **kwargs)
@name = name
@version = version
Expand Down Expand Up @@ -240,7 +258,7 @@ def activate

# rely on LDFLAGS when cross-compiling
if File.exist?(lib_path) && (@host != @original_host)
full_path = File.expand_path(lib_path)
full_path = native_path(lib_path)

old_value = ENV.fetch("LDFLAGS", "")

Expand All @@ -250,6 +268,43 @@ def activate
end
end

def mkmf_config(pkg: nil, dir: nil)
require "mkmf"

if pkg
dir ||= File.join(path, "lib", "pkgconfig")
pcfile = File.join(dir, "#{pkg}.pc")
unless File.exist?(pcfile)
raise ArgumentError, "pkg-config file '#{pcfile}' does not exist"
end

output "Configuring MakeMakefile for #{File.basename(pcfile)} (in #{File.dirname(pcfile)})\n"

# on macos, pkg-config will not return --cflags without this
ENV["PKG_CONFIG_ALLOW_SYSTEM_CFLAGS"] = "t"

# append to PKG_CONFIG_PATH as we go, so later pkg-config files can depend on earlier ones
ENV["PKG_CONFIG_PATH"] = [ENV["PKG_CONFIG_PATH"], dir].compact.join(File::PATH_SEPARATOR)

cflags = minimal_pkg_config(pcfile, "cflags")
ldflags = minimal_pkg_config(pcfile, "libs", "static")
else
output "Configuring MakeMakefile for #{@name} #{@version} (from #{path})\n"

include_path = File.join(path, "include")
lib_path = File.join(path, "lib")

lib_name = name.sub(/\Alib/, "") # TODO: use delete_prefix when we no longer support ruby 2.4

cflags = "-I#{include_path}" if Dir.exist?(include_path)
ldflags = "-L#{lib_path} -l#{lib_name}" if Dir.exist?(lib_path)
end

$CFLAGS << " " << cflags if cflags
$CXXFLAGS << " " << cflags if cflags
$LDFLAGS << " " << ldflags if ldflags
end

def path
File.expand_path(port_path)
end
Expand All @@ -265,21 +320,11 @@ def make_cmd
private

def native_path(path)
path = File.expand_path(path)
if File::ALT_SEPARATOR
path.tr(File::SEPARATOR, File::ALT_SEPARATOR)
else
path
end
MiniPortile.native_path(path)
end

def posix_path(path)
path = File.expand_path(path)
if File::ALT_SEPARATOR
"/" + path.tr(File::ALT_SEPARATOR, File::SEPARATOR).tr(":", File::SEPARATOR)
else
path
end
MiniPortile.posix_path(path)
end

def tmp_path
Expand Down Expand Up @@ -648,4 +693,29 @@ def with_tempfile(filename, full_path)
FileUtils.mkdir_p File.dirname(full_path)
FileUtils.mv temp_file.path, full_path, :force => true
end

#
# this minimal version of pkg_config is based on ruby 29dc9378 (2023-01-09)
#
# specifically with the fix from b90e56e6 to support multiple pkg-config options, and removing
# code paths that aren't helpful for mini-portile's use case of parsing pc files.
#
def minimal_pkg_config(pkg, *pcoptions)
if pcoptions.empty?
raise ArgumentError, "no pkg-config options are given"
end

if ($PKGCONFIG ||=
(pkgconfig = MakeMakefile.with_config("pkg-config") {MakeMakefile.config_string("PKG_CONFIG") || "pkg-config"}) &&
MakeMakefile.find_executable0(pkgconfig) && pkgconfig)
pkgconfig = $PKGCONFIG
else
raise RuntimeError, "pkg-config is not found"
end

pcoptions = Array(pcoptions).map { |o| "--#{o}" }
response = IO.popen([pkgconfig, *pcoptions, pkg], err:[:child, :out], &:read)
raise RuntimeError, response unless $?.success?
response.strip
end
end
13 changes: 13 additions & 0 deletions test/assets/pkgconf/libxml2/libxml-2.0.pc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
prefix=/foo/libxml2/2.11.5
exec_prefix=${prefix}
libdir=/foo/libxml2/2.11.5/lib
includedir=${prefix}/include
modules=1

Name: libXML
Version: 2.11.5
Description: libXML library version2.
Requires:
Libs: -L${libdir} -lxml2
Libs.private: -L/foo/zlib/1.3/lib -lz -lm
Cflags: -I${includedir}/libxml2
13 changes: 13 additions & 0 deletions test/assets/pkgconf/libxslt/libexslt.pc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
prefix=/foo/libxslt/1.1.38
exec_prefix=${prefix}
libdir=/foo/libxslt/1.1.38/lib
includedir=${prefix}/include


Name: libexslt
Version: 0.8.21
Description: EXSLT Extension library
Requires: libxml-2.0, libxslt
Cflags: -I${includedir}
Libs: -L${libdir} -lexslt
Libs.private: -lm
13 changes: 13 additions & 0 deletions test/assets/pkgconf/libxslt/libxslt.pc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
prefix=/foo/libxslt/1.1.38
exec_prefix=${prefix}
libdir=/foo/libxslt/1.1.38/lib
includedir=${prefix}/include


Name: libxslt
Version: 1.1.38
Description: XSLT library version 2.
Requires: libxml-2.0
Cflags: -I${includedir}
Libs: -L${libdir} -lxslt
Libs.private: -lm
Loading

0 comments on commit 6ae2e70

Please sign in to comment.