Skip to content

Commit 8add1db

Browse files
committed
cleaner: rewrite pkg-config file Cellar paths and keg-only
1 parent 8389f50 commit 8add1db

File tree

2 files changed

+87
-0
lines changed

2 files changed

+87
-0
lines changed

Library/Homebrew/cleaner.rb

+43
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ def clean
5959
observe_file_removal info_dir_file
6060
end
6161

62+
rewrite_pkgconfig
6263
rewrite_shebangs
6364
clean_python_metadata
6465

@@ -153,6 +154,48 @@ def clean_dir(directory)
153154
end
154155
end
155156

157+
sig { void }
158+
def rewrite_pkgconfig
159+
basepath = @formula.prefix.realpath
160+
pc_files = %w[lib share].flat_map do |subdir|
161+
pc_dir = basepath/subdir/"pkgconfig"
162+
next [] if !pc_dir.exist? || @formula.skip_clean?(basepath/subdir) || @formula.skip_clean?(pc_dir)
163+
164+
pc_dir.glob("*.pc").reject { |pc_file| @formula.skip_clean?(pc_file) }
165+
end
166+
return if pc_files.empty?
167+
168+
# TODO: Add support for `brew unlink`-ed formulae and check on recursive dependencies
169+
deps_pc_files = @formula.deps
170+
.filter_map { |dep| dep.to_formula if !dep.build? && !dep.test? }
171+
.select(&:keg_only?)
172+
.flat_map { |f| f.opt_prefix.glob("{lib,share}/pkgconfig/*.pc") }
173+
.to_h { |pc_file| [pc_file.basename(".pc").to_s.downcase, pc_file.to_s] }
174+
deps_pc_modules_pattern = deps_pc_files.keys.map { |mod| Regexp.escape(mod) }.join("|")
175+
176+
pc_files.each do |pc_file|
177+
modified_lines = pc_file.each_line.map do |line|
178+
rewrote_prefix = line.gsub!(@formula.prefix.realpath.to_s, @formula.opt_prefix.to_s).present?
179+
next [line, rewrote_prefix] if deps_pc_files.empty? || !line.start_with?(/Requires(?:\.private)?:/)
180+
181+
# pkgconf's pc.5 man page defines dependency list ABNF syntax as:
182+
#
183+
# > package-list = *WSP *( package-spec *( package-sep ) )
184+
# > package-sep = WSP / ","
185+
# > package-spec = package-key [ ver-op package-version ]
186+
# > ver-op = "<" / "<=" / "=" / "!=" / ">=" / ">"
187+
#
188+
# A simplified regular expression is used to lookahead/lookbehind for common
189+
# separator characters to extract the modules used in Requires/Requires.private
190+
rewrote_module = line.gsub!(/(?<=[:,\s])(#{deps_pc_modules_pattern})(?=[<=>!,\s])/io, deps_pc_files).present?
191+
[line, rewrote_prefix || rewrote_module]
192+
end
193+
next if modified_lines.none?(&:second)
194+
195+
pc_file.atomic_write(modified_lines.map(&:first).join)
196+
end
197+
end
198+
156199
sig { void }
157200
def rewrite_shebangs
158201
require "language/node"

Library/Homebrew/test/cleaner_spec.rb

+44
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,50 @@
201201

202202
expect(file.read).to eq "brew\n"
203203
end
204+
205+
it "modifies Cellar prefix in pkg-config files" do
206+
file = f.lib/"pkgconfig/test.pc"
207+
file.dirname.mkpath
208+
file.write <<~EOS
209+
prefix=#{f.prefix}
210+
includedir=#{f.include}
211+
libdir=#{f.lib}
212+
Name: test
213+
Description: test module
214+
Version: 1.2.3
215+
Cflags: -I${includedir}
216+
EOS
217+
218+
cleaner.clean
219+
220+
expect(file.read).to eq <<~EOS
221+
prefix=#{f.opt_prefix}
222+
includedir=#{f.opt_include}
223+
libdir=#{f.opt_lib}
224+
Name: test
225+
Description: test module
226+
Version: 1.2.3
227+
Cflags: -I${includedir}
228+
EOS
229+
end
230+
231+
it "does not modify pkg-config files with no rewrites" do
232+
file = f.lib/"pkgconfig/test.pc"
233+
file.dirname.mkpath
234+
file.write <<~EOS
235+
prefix=#{f.opt_prefix}
236+
includedir=${prefix}/include
237+
Name: test
238+
Description: test module
239+
Version: 1.2.3
240+
Cflags: -I${includedir}
241+
EOS
242+
start_mtime = file.mtime
243+
244+
cleaner.clean
245+
246+
expect(file.mtime).to eq start_mtime
247+
end
204248
end
205249

206250
describe "::skip_clean" do

0 commit comments

Comments
 (0)