Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: MiniPortile#mkmf_config which supports pkg-config files to configure compiler and linker flags #131

Merged
merged 4 commits into from
Sep 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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