pkg-config 1.5.6 → 1.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/pkg-config.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright 2008-2023 Sutou Kouhei <kou@cozmixng.org>
1
+ # Copyright (C) 2008-2025 Sutou Kouhei <kou@cozmixng.org>
2
2
  #
3
3
  # This library is free software; you can redistribute it and/or
4
4
  # modify it under the terms of the GNU Lesser General Public
@@ -14,16 +14,127 @@
14
14
  # License along with this library; if not, write to the Free Software
15
15
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
- begin
18
- require_relative "pkg-config/version"
19
- rescue LoadError
20
- end
21
-
22
- require "English"
23
17
  require "pathname"
24
18
  require "rbconfig"
25
19
  require "shellwords"
26
20
 
21
+ module PKGConfig
22
+ VERSION = "1.6.2"
23
+
24
+ @@paths = []
25
+ @@override_variables = {}
26
+
27
+ module_function
28
+ def add_path(path)
29
+ @@paths << path
30
+ end
31
+
32
+ def set_override_variable(key, value)
33
+ @@override_variables[key] = value
34
+ end
35
+
36
+ def msvc?
37
+ /mswin/.match(RUBY_PLATFORM) and /^cl\b/.match(RbConfig::CONFIG["CC"])
38
+ end
39
+
40
+ def package_config(package)
41
+ PackageConfig.new(package,
42
+ :msvc_syntax => msvc?,
43
+ :override_variables => @@override_variables,
44
+ :paths => @@paths)
45
+ end
46
+
47
+ def exist?(pkg)
48
+ package_config(pkg).exist?
49
+ end
50
+
51
+ def libs(pkg)
52
+ package_config(pkg).libs
53
+ end
54
+
55
+ def libs_only_l(pkg)
56
+ package_config(pkg).libs_only_l
57
+ end
58
+
59
+ def libs_only_L(pkg)
60
+ package_config(pkg).libs_only_L
61
+ end
62
+
63
+ def cflags(pkg)
64
+ package_config(pkg).cflags
65
+ end
66
+
67
+ def cflags_only_I(pkg)
68
+ package_config(pkg).cflags_only_I
69
+ end
70
+
71
+ def cflags_only_other(pkg)
72
+ package_config(pkg).cflags_only_other
73
+ end
74
+
75
+ def modversion(pkg)
76
+ package_config(pkg).version
77
+ end
78
+
79
+ def description(pkg)
80
+ package_config(pkg).description
81
+ end
82
+
83
+ def variable(pkg, name)
84
+ package_config(pkg).variable(name)
85
+ end
86
+
87
+ def check_version?(pkg, major=0, minor=0, micro=0)
88
+ return false unless exist?(pkg)
89
+ ver = modversion(pkg).split(".").collect {|item| item.to_i}
90
+ (0..2).each {|i| ver[i] = 0 unless ver[i]}
91
+
92
+ (ver[0] > major ||
93
+ (ver[0] == major && ver[1] > minor) ||
94
+ (ver[0] == major && ver[1] == minor &&
95
+ ver[2] >= micro))
96
+ end
97
+
98
+ def have_package(pkg, major=nil, minor=0, micro=0)
99
+ message = "#{pkg}"
100
+ unless major.nil?
101
+ message << " version (>= #{major}.#{minor}.#{micro})"
102
+ end
103
+ major ||= 0
104
+ result = checking_for(checking_message(message), "%s") do
105
+ if check_version?(pkg, major, minor, micro)
106
+ "yes (#{modversion(pkg)})"
107
+ else
108
+ if exist?(pkg)
109
+ "no (#{modversion(pkg)})"
110
+ else
111
+ "no (nonexistent)"
112
+ end
113
+ end
114
+ end
115
+ enough_version = result.start_with?("yes")
116
+ if enough_version
117
+ libraries = libs_only_l(pkg)
118
+ dldflags = libs(pkg)
119
+ dldflags = (Shellwords.shellwords(dldflags) -
120
+ Shellwords.shellwords(libraries))
121
+ dldflags = dldflags.map {|s| /\s/ =~ s ? "\"#{s}\"" : s }.join(" ")
122
+ $libs += " " + libraries
123
+ if /mswin/ =~ RUBY_PLATFORM
124
+ $DLDFLAGS += " " + dldflags
125
+ else
126
+ $LDFLAGS += " " + dldflags
127
+ end
128
+ $CFLAGS += " " + cflags_only_other(pkg)
129
+ if defined?($CXXFLAGS)
130
+ $CXXFLAGS += " " + cflags_only_other(pkg)
131
+ end
132
+ $INCFLAGS += " " + cflags_only_I(pkg)
133
+ end
134
+ enough_version
135
+ end
136
+ end
137
+
27
138
  class PackageConfig
28
139
  class Error < StandardError
29
140
  end
@@ -72,18 +183,25 @@ class PackageConfig
72
183
 
73
184
  def guess_native_pkg_config
74
185
  exeext = RbConfig::CONFIG["EXEEXT"]
75
- default_pkg_config = ENV["PKG_CONFIG"] || "pkg-config#{exeext}"
76
- pkg_config = with_config("pkg-config", default_pkg_config)
77
- pkg_config = Pathname.new(pkg_config)
78
- unless pkg_config.absolute?
79
- found_pkg_config = search_executable_from_path(pkg_config)
80
- pkg_config = found_pkg_config if found_pkg_config
81
- end
82
- unless pkg_config.absolute?
83
- found_pkg_config = search_pkg_config_by_dln_find_exe(pkg_config)
84
- pkg_config = found_pkg_config if found_pkg_config
186
+ candidates = [
187
+ with_config("pkg-config"),
188
+ ENV["PKG_CONFIG"],
189
+ "pkgconf#{exeext}",
190
+ "pkg-config#{exeext}",
191
+ ].compact
192
+ candidates.each do |pkg_config|
193
+ pkg_config = Pathname.new(pkg_config)
194
+ return pkg_config if pkg_config.absolute? and pkg_config.exist?
195
+ unless pkg_config.absolute?
196
+ found_pkg_config = search_executable_from_path(pkg_config)
197
+ return found_pkg_config if found_pkg_config
198
+ end
199
+ unless pkg_config.absolute?
200
+ found_pkg_config = search_pkg_config_by_dln_find_exe(pkg_config)
201
+ return found_pkg_config if found_pkg_config
202
+ end
85
203
  end
86
- pkg_config
204
+ Pathname.new(candidates[0])
87
205
  end
88
206
 
89
207
  def search_executable_from_path(name)
@@ -173,6 +291,7 @@ class PackageConfig
173
291
  conda_prefix = ENV["CONDA_PREFIX"]
174
292
  if conda_prefix
175
293
  default_paths << File.join(conda_prefix, "lib", "pkgconfig")
294
+ default_paths << File.join(conda_prefix, "share", "pkgconfig")
176
295
  end
177
296
  default_paths << "/usr/local/lib64/pkgconfig"
178
297
  default_paths << "/usr/local/libx32/pkgconfig"
@@ -221,21 +340,29 @@ class PackageConfig
221
340
  if brew
222
341
  homebrew_repository = run_command("brew", "--repository")
223
342
  if homebrew_repository
224
- homebrew_repository_candidates <<
225
- Pathname(homebrew_repository.to_s)
343
+ homebrew_repository_candidates <<
344
+ Pathname(homebrew_repository.strip)
226
345
  end
227
346
  end
228
347
  homebrew_repository_candidates.uniq.each do |candidate|
229
- pkgconfig_base_path = candidate + "Library/Homebrew/os/mac/pkgconfig"
230
- path = pkgconfig_base_path + mac_os_version
231
- unless path.exist?
232
- path = pkgconfig_base_path + mac_os_version.gsub(/\.\d+\z/, "")
348
+ mac_pkgconfig_base_path =
349
+ candidate + "Library/Homebrew/os/mac/pkgconfig"
350
+ mac_pkgconfig_path = mac_pkgconfig_base_path + mac_os_version
351
+ unless mac_pkgconfig_path.exist?
352
+ mac_pkgconfig_path =
353
+ mac_pkgconfig_base_path + mac_os_version.gsub(/\.\d+\z/, "")
233
354
  end
234
- paths << path.to_s if path.exist?
355
+ paths << mac_pkgconfig_path.to_s if mac_pkgconfig_path.exist?
356
+
357
+ pkgconfig_path = candidate + "lib/pkgconfig"
358
+ paths << pkgconfig_path.to_s if pkgconfig_path.exist?
235
359
  end
236
360
  end
237
361
  paths.concat(default_paths)
238
- paths.join(SEPARATOR)
362
+ [
363
+ with_config("pkg-config-path") || ENV["PKG_CONFIG_PATH"],
364
+ *paths,
365
+ ].compact.join(SEPARATOR)
239
366
  end
240
367
 
241
368
  def run_command(*command_line)
@@ -269,8 +396,10 @@ class PackageConfig
269
396
  @name = name
270
397
  end
271
398
  @options = options
272
- path = @options[:path] || ENV["PKG_CONFIG_PATH"]
273
- @paths = [path, self.class.default_path].compact.join(SEPARATOR).split(SEPARATOR)
399
+ @paths = [
400
+ @options[:path],
401
+ self.class.default_path,
402
+ ].compact.join(SEPARATOR).split(SEPARATOR)
274
403
  @paths.unshift(*(@options[:paths] || []))
275
404
  @paths = normalize_paths(@paths)
276
405
  @msvc_syntax = @options[:msvc_syntax]
@@ -281,6 +410,14 @@ class PackageConfig
281
410
  @override_variables = default_override_variables.merge(@override_variables)
282
411
  end
283
412
 
413
+ def eql?(other)
414
+ other.is_a?(self.class) and @name == other.name
415
+ end
416
+
417
+ def hash
418
+ @name.hash
419
+ end
420
+
284
421
  def exist?
285
422
  not pc_path.nil?
286
423
  end
@@ -295,7 +432,7 @@ class PackageConfig
295
432
 
296
433
  def cflags
297
434
  path_flags, other_flags = collect_cflags
298
- (other_flags + path_flags).join(" ")
435
+ (path_flags + other_flags).join(" ")
299
436
  end
300
437
 
301
438
  def cflags_only_I
@@ -307,26 +444,25 @@ class PackageConfig
307
444
  end
308
445
 
309
446
  def libs
310
- path_flags, other_flags = collect_libs
311
- (path_flags + other_flags).join(" ")
447
+ collect_libs.join(" ")
312
448
  end
313
449
 
314
450
  def libs_only_l
315
- collect_libs[1].find_all do |arg|
451
+ collect_libs.find_all do |arg|
316
452
  if @msvc_syntax
317
- /\.lib\z/ =~ arg
453
+ arg.end_with?(".lib")
318
454
  else
319
- /\A-l/ =~ arg
455
+ arg.start_with?("-l")
320
456
  end
321
457
  end.join(" ")
322
458
  end
323
459
 
324
460
  def libs_only_L
325
- collect_libs[0].find_all do |arg|
461
+ collect_libs.find_all do |arg|
326
462
  if @msvc_syntax
327
- /\A\/libpath:/ =~ arg
463
+ arg.start_with?("/libpath:")
328
464
  else
329
- /\A-L/ =~ arg
465
+ arg.start_with?("-L")
330
466
  end
331
467
  end.join(" ")
332
468
  end
@@ -369,40 +505,32 @@ class PackageConfig
369
505
  @path_position
370
506
  end
371
507
 
372
- def collect_requires(processed_packages={}, &block)
373
- packages = []
374
- targets = yield(self)
375
- targets.each do |name|
376
- next if processed_packages.key?(name)
377
- package = self.class.new(name, @options)
378
- processed_packages[name] = package
379
- packages << package
380
- packages.concat(package.collect_requires(processed_packages, &block))
381
- end
382
- packages_without_self = packages.reject do |package|
383
- package.name == @name
384
- end
385
- packages_without_self.uniq do |package|
386
- package.name
508
+ def collect_requires(&block)
509
+ dependencies = {}
510
+ pending_packages = yield(self).collect {|name| self.class.new(name, @options)}
511
+ until pending_packages.empty?
512
+ package = pending_packages.shift
513
+ next if dependencies.key?(package)
514
+ dependencies[package] = true
515
+ targets = yield(package)
516
+ targets.each do |name|
517
+ require_package = self.class.new(name, @options)
518
+ pending_packages.push(require_package)
519
+ end
387
520
  end
521
+ dependencies.keys
388
522
  end
389
523
 
390
524
  private
391
- def sort_packages(packages)
392
- packages.sort_by.with_index do |package, i|
393
- [package.path_position, i]
394
- end
395
- end
396
-
397
525
  def collect_cflags
398
- target_packages = sort_packages([self, *all_required_packages])
526
+ target_packages = [self, *all_required_packages]
399
527
  cflags_set = []
400
528
  target_packages.each do |package|
401
529
  cflags_set << package.declaration("Cflags")
402
530
  end
403
531
  all_cflags = normalize_cflags(Shellwords.split(cflags_set.join(" ")))
404
532
  path_flags, other_flags = all_cflags.partition {|flag| /\A-I/ =~ flag}
405
- path_flags = normalize_path_flags(path_flags, "-I")
533
+ path_flags = path_flags.collect {|flag| normalize_path_flag(flag, "-I")}
406
534
  path_flags = path_flags.reject do |flag|
407
535
  flag == "-I/usr/include"
408
536
  end
@@ -415,20 +543,18 @@ class PackageConfig
415
543
  [path_flags, other_flags]
416
544
  end
417
545
 
418
- def normalize_path_flags(path_flags, flag_option)
419
- return path_flags unless /-mingw(?:32|-ucrt)\z/ === RUBY_PLATFORM
546
+ def normalize_path_flag(path_flag, flag_option)
547
+ return path_flag unless /-mingw(?:32|-ucrt)\z/ === RUBY_PLATFORM
420
548
 
421
549
  pkg_config_prefix = self.class.native_pkg_config_prefix
422
- return path_flags unless pkg_config_prefix
550
+ return path_flag unless pkg_config_prefix
423
551
 
424
552
  mingw_dir = pkg_config_prefix.basename.to_s
425
- path_flags.collect do |path_flag|
426
- path = path_flag.sub(/\A#{Regexp.escape(flag_option)}/, "")
427
- path = path.sub(/\A\/#{Regexp.escape(mingw_dir)}/i) do
428
- pkg_config_prefix.to_s
429
- end
430
- "#{flag_option}#{path}"
553
+ path = path_flag.sub(/\A#{Regexp.escape(flag_option)}/, "")
554
+ path = path.sub(/\A\/#{Regexp.escape(mingw_dir)}/i) do
555
+ pkg_config_prefix.to_s
431
556
  end
557
+ "#{flag_option}#{path}"
432
558
  end
433
559
 
434
560
  def normalize_cflags(cflags)
@@ -437,10 +563,10 @@ class PackageConfig
437
563
  begin
438
564
  loop do
439
565
  cflag = enumerator.next
440
- normalized_cflags << cflag
566
+ normalized_cflags << cflag.dup
441
567
  case cflag
442
568
  when "-I"
443
- normalized_cflags << enumerator.next
569
+ normalized_cflags.last << enumerator.next
444
570
  end
445
571
  end
446
572
  rescue StopIteration
@@ -449,31 +575,32 @@ class PackageConfig
449
575
  end
450
576
 
451
577
  def collect_libs
452
- target_packages = sort_packages(required_packages + [self])
578
+ target_packages = [*required_packages, self]
453
579
  libs_set = []
454
580
  target_packages.each do |package|
455
581
  libs_set << package.declaration("Libs")
456
582
  end
457
- all_flags = split_lib_flags(libs_set.join(" "))
458
- path_flags, other_flags = all_flags.partition {|flag| /\A-L/ =~ flag}
459
- path_flags = normalize_path_flags(path_flags, "-L")
460
- path_flags = path_flags.reject do |flag|
583
+ flags = split_lib_flags(libs_set.join(" "))
584
+ flags = flags.collect do |flag|
585
+ flag = normalize_path_flag(flag, "-L") if flag.start_with?("-L")
586
+ flag
587
+ end
588
+ flags = flags.reject do |flag|
461
589
  /\A-L\/usr\/lib(?:64|x32)?\z/ =~ flag
462
590
  end
463
- path_flags = path_flags.uniq
591
+ flags = flags.uniq
464
592
  if @msvc_syntax
465
- path_flags = path_flags.collect do |flag|
466
- flag.gsub(/\A-L/, "/libpath:")
467
- end
468
- other_flags = other_flags.collect do |flag|
469
- if /\A-l/ =~ flag
470
- "#{$POSTMATCH}.lib"
593
+ flags = flags.collect do |flag|
594
+ if flag.start_with?("-L")
595
+ flag.gsub(/\A-L/, "/libpath:")
596
+ elsif flag.start_with?("-l")
597
+ "#{flag[2..-1]}.lib"
471
598
  else
472
599
  flag
473
600
  end
474
601
  end
475
602
  end
476
- [path_flags, other_flags]
603
+ flags
477
604
  end
478
605
 
479
606
  def split_lib_flags(libs_command_line)
@@ -506,13 +633,18 @@ class PackageConfig
506
633
  @declarations = {}
507
634
  File.open(pc_path) do |input|
508
635
  input.each_line do |line|
636
+ if line.dup.force_encoding("UTF-8").valid_encoding?
637
+ line.force_encoding("UTF-8")
638
+ end
509
639
  line = line.gsub(/#.*/, "").strip
510
640
  next if line.empty?
511
641
  case line
512
642
  when /^(#{IDENTIFIER_RE})\s*=\s*/
513
- @variables[$1] = $POSTMATCH.strip
643
+ match = Regexp.last_match
644
+ @variables[match[1]] = match.post_match.strip
514
645
  when /^(#{IDENTIFIER_RE})\s*:\s*/
515
- @declarations[$1] = $POSTMATCH.strip
646
+ match = Regexp.last_match
647
+ @declarations[match[1]] = match.post_match.strip
516
648
  end
517
649
  end
518
650
  end
@@ -558,118 +690,3 @@ class PackageConfig
558
690
  end
559
691
  end
560
692
  end
561
-
562
- module PKGConfig
563
- @@paths = []
564
- @@override_variables = {}
565
-
566
- module_function
567
- def add_path(path)
568
- @@paths << path
569
- end
570
-
571
- def set_override_variable(key, value)
572
- @@override_variables[key] = value
573
- end
574
-
575
- def msvc?
576
- /mswin/.match(RUBY_PLATFORM) and /^cl\b/.match(RbConfig::CONFIG["CC"])
577
- end
578
-
579
- def package_config(package)
580
- PackageConfig.new(package,
581
- :msvc_syntax => msvc?,
582
- :override_variables => @@override_variables,
583
- :paths => @@paths)
584
- end
585
-
586
- def exist?(pkg)
587
- package_config(pkg).exist?
588
- end
589
-
590
- def libs(pkg)
591
- package_config(pkg).libs
592
- end
593
-
594
- def libs_only_l(pkg)
595
- package_config(pkg).libs_only_l
596
- end
597
-
598
- def libs_only_L(pkg)
599
- package_config(pkg).libs_only_L
600
- end
601
-
602
- def cflags(pkg)
603
- package_config(pkg).cflags
604
- end
605
-
606
- def cflags_only_I(pkg)
607
- package_config(pkg).cflags_only_I
608
- end
609
-
610
- def cflags_only_other(pkg)
611
- package_config(pkg).cflags_only_other
612
- end
613
-
614
- def modversion(pkg)
615
- package_config(pkg).version
616
- end
617
-
618
- def description(pkg)
619
- package_config(pkg).description
620
- end
621
-
622
- def variable(pkg, name)
623
- package_config(pkg).variable(name)
624
- end
625
-
626
- def check_version?(pkg, major=0, minor=0, micro=0)
627
- return false unless exist?(pkg)
628
- ver = modversion(pkg).split(".").collect {|item| item.to_i}
629
- (0..2).each {|i| ver[i] = 0 unless ver[i]}
630
-
631
- (ver[0] > major ||
632
- (ver[0] == major && ver[1] > minor) ||
633
- (ver[0] == major && ver[1] == minor &&
634
- ver[2] >= micro))
635
- end
636
-
637
- def have_package(pkg, major=nil, minor=0, micro=0)
638
- message = "#{pkg}"
639
- unless major.nil?
640
- message << " version (>= #{major}.#{minor}.#{micro})"
641
- end
642
- major ||= 0
643
- result = checking_for(checking_message(message), "%s") do
644
- if check_version?(pkg, major, minor, micro)
645
- "yes (#{modversion(pkg)})"
646
- else
647
- if exist?(pkg)
648
- "no (#{modversion(pkg)}"
649
- else
650
- "no (nonexistent)"
651
- end
652
- end
653
- end
654
- enough_version = result.start_with?("yes")
655
- if enough_version
656
- libraries = libs_only_l(pkg)
657
- dldflags = libs(pkg)
658
- dldflags = (Shellwords.shellwords(dldflags) -
659
- Shellwords.shellwords(libraries))
660
- dldflags = dldflags.map {|s| /\s/ =~ s ? "\"#{s}\"" : s }.join(" ")
661
- $libs += " " + libraries
662
- if /mswin/ =~ RUBY_PLATFORM
663
- $DLDFLAGS += " " + dldflags
664
- else
665
- $LDFLAGS += " " + dldflags
666
- end
667
- $CFLAGS += " " + cflags_only_other(pkg)
668
- if defined?($CXXFLAGS)
669
- $CXXFLAGS += " " + cflags_only_other(pkg)
670
- end
671
- $INCFLAGS += " " + cflags_only_I(pkg)
672
- end
673
- enough_version
674
- end
675
- end