mirror of
https://github.com/chromebrew/chromebrew.git
synced 2026-01-08 23:18:10 -05:00
* rebuild uutils_coreutils, add 32-bit core binaries for armv7l Signed-off-by: Satadru Pramanik <satadru@gmail.com> * More shebang adjustments. Signed-off-by: Satadru Pramanik <satadru@gmail.com> --------- Signed-off-by: Satadru Pramanik <satadru@gmail.com> Co-authored-by: Satadru Pramanik <satadru@gmail.com>
210 lines
9.3 KiB
Ruby
Executable File
210 lines
9.3 KiB
Ruby
Executable File
#!/usr/local/bin/ruby
|
|
# getrealdeps version 1.7 (for Chromebrew)
|
|
# Author: Satadru Pramanik (satmandu) satadru at gmail dot com
|
|
require 'fileutils'
|
|
|
|
crew_local_repo_root = `git rev-parse --show-toplevel 2> /dev/null`.chomp
|
|
# When invoked from crew, pwd is CREW_DEST_DIR, so crew_local_repo_root
|
|
# is empty.
|
|
if crew_local_repo_root.to_s.empty?
|
|
require_relative '../lib/const'
|
|
else
|
|
require File.join(crew_local_repo_root, 'lib/const')
|
|
end
|
|
|
|
if ARGV.include?('--use-crew-dest-dir')
|
|
ARGV.delete('--use-crew-dest-dir')
|
|
@opt_use_crew_dest_dir = true
|
|
end
|
|
|
|
# Exit quickly if an invalid package name is given.
|
|
if ARGV[0].nil? || ARGV[0].empty? || ARGV[0].include?('#')
|
|
puts 'Getrealdeps checks for the runtime dependencies of a package.'
|
|
puts 'The runtime dependencies are added if the package file is missing them.'
|
|
puts 'Usage: getrealdeps.rb [--use_crew_dest_dir] <packagename>'
|
|
exit 1
|
|
end
|
|
|
|
# Search for which packages have a needed library in CREW_LIB_PREFIX.
|
|
# This is a subset of what crew whatprovides gives.
|
|
def whatprovidesfxn(pkgdepslcl, pkg)
|
|
filelcl = if pkgdepslcl.include?(CREW_LIB_PREFIX)
|
|
`#{@grep} --exclude #{pkg}.filelist --exclude #{pkgfilelist} --exclude={"#{CREW_PREFIX}/etc/crew/meta/*_build.filelist"} "#{pkgdepslcl}$" "#{CREW_PREFIX}"/etc/crew/meta/*.filelist`
|
|
else
|
|
`#{@grep} --exclude #{pkg}.filelist --exclude #{pkgfilelist} --exclude={"#{CREW_PREFIX}/etc/crew/meta/*_build.filelist"} "^#{CREW_LIB_PREFIX}.*#{pkgdepslcl}$" "#{CREW_PREFIX}"/etc/crew/meta/*.filelist`
|
|
end
|
|
filelcl.gsub(/.filelist.*/, '').gsub(%r{.*/}, '').split("\n").uniq.join("\n").gsub(':', '')
|
|
end
|
|
|
|
def main(pkg)
|
|
puts "Checking for the runtime dependencies of #{pkg}..."
|
|
|
|
if @opt_use_crew_dest_dir
|
|
define_singleton_method('pkgfilelist') { File.join(CREW_DEST_DIR, 'filelist') }
|
|
abort('Pkg was not built.') unless File.exist?(pkgfilelist)
|
|
else
|
|
define_singleton_method('pkgfilelist') { "#{CREW_PREFIX}/etc/crew/meta/#{pkg}.filelist" }
|
|
# Package needs to be installed for package filelist to be populated.
|
|
unless File.exist?(pkgfilelist)
|
|
puts "Installing #{pkg} because it is not installed."
|
|
system("yes | crew install #{pkg}")
|
|
end
|
|
abort("Package #{pkg} either does not exist or does not contain any libraries.") unless File.exist?(pkgfilelist)
|
|
end
|
|
|
|
# Speed up grep.
|
|
ENV['LC_ALL'] = 'C'
|
|
|
|
# Install grep if a functional local copy does not exist.
|
|
if system('grep --version > /dev/null 2>&1')
|
|
@grep = 'grep'
|
|
else
|
|
system('crew install grep')
|
|
@grep = "#{CREW_PREFIX}/bin/grep"
|
|
end
|
|
|
|
# Gawk is needed for adding dependencies.
|
|
unless system('gawk -W version > /dev/null 2>&1')
|
|
puts "\nThe inplace replacement functionality of gawk is used to add missing dependencies to package files."
|
|
system('crew install gawk')
|
|
end
|
|
|
|
# upx is needed to expand compressed binaries to check for dependencies.
|
|
unless system('upx --version > /dev/null 2>&1')
|
|
puts "\nUpx is needed to expand compressed binaries."
|
|
system('crew install upx')
|
|
end
|
|
|
|
# What files does the package provide.
|
|
pkgfiles = File.read(pkgfilelist).split("\n").uniq
|
|
|
|
# Look at files in CREW_DEST_DIR instead of assuming the package is
|
|
# normally installed, which lets us avoid installing the package if it
|
|
# was just built.
|
|
pkgfiles.map! { |item| item.prepend(CREW_DEST_DIR) } if @opt_use_crew_dest_dir
|
|
|
|
FileUtils.rm_rf("/tmp/deps/#{pkg}")
|
|
# Remove files we don't care about, such as man files and non-binaries.
|
|
pkgfiles = pkgfiles.reject { |i| !File.file?(i.chomp) || File.read(i.chomp, 4) != "\x7FELF" || i.include?('.zst') }
|
|
|
|
# Use readelf to determine library dependencies, as
|
|
# this doesn't almost run a program like using ldd would.
|
|
pkgdepsfiles = pkgfiles.map do |i|
|
|
system("upx -d #{i} > /dev/null 2>&1")
|
|
FileUtils.mkdir_p("/tmp/deps/#{pkg}/")
|
|
`readelf -d "#{i}" 2>/dev/null | #{@grep} NEEDED | awk '{print $5}' | sed 's/\\[//g' | sed 's/\\]//g' | awk '!x[$0]++' | tee /tmp/deps/#{pkg}/#{File.basename(i)}`
|
|
end
|
|
pkgdepsfiles = pkgdepsfiles.map do |filedeps|
|
|
filedeps.split("\n")
|
|
end.flatten.compact.uniq
|
|
|
|
# Figure out which Chromebrew packages provide the relevant deps.
|
|
pkgdeps = pkgdepsfiles.map { |file| whatprovidesfxn(file, pkg) }.sort.reject { |i| i.include?(pkg) }.map { |i| i.split("\n") }.flatten.uniq
|
|
|
|
# Massage the glibc entries in the dependency list.
|
|
pkgdeps = pkgdeps.map { |i| i.gsub(/glibc_build.*/, 'glibc') }.uniq
|
|
pkgdeps = pkgdeps.map { |i| i.gsub(/glibc_lib.*/, 'glibc_lib') }.uniq.map(&:strip).reject(&:empty?)
|
|
|
|
# Massage the gcc entries in the dependency list.
|
|
pkgdeps = pkgdeps.map { |i| i.gsub('gcc_build', 'gcc_lib') }.uniq
|
|
|
|
# Massage the llvm entries in the dependency list.
|
|
pkgdeps = pkgdeps.map { |i| i.gsub('llvm_build', 'llvm_lib') }.uniq
|
|
|
|
# Leave early if we didn't find any dependencies.
|
|
return if pkgdeps.empty?
|
|
|
|
# Look for missing runtime dependencies.
|
|
missingpkgdeps = pkgdeps.reject { |i| File.read("#{CREW_PREFIX}/lib/crew/packages/#{pkg}.rb").include?("depends_on '#{i}'") unless File.read("#{CREW_PREFIX}/lib/crew/packages/#{pkg}.rb").include?("depends_on '#{i}' => :build") }
|
|
|
|
# Do not add llvm*_{dev,lib} runtime deps if this is a llvm*_build
|
|
# package as those packages are created from the llvm build package
|
|
# after it is built.
|
|
if /llvm.*_build/.match(pkg)
|
|
missingpkgdeps.delete_if { |d| /llvm.*_*/.match(d) }
|
|
pkgdeps.delete_if { |d| /llvm.*_*/.match(d) }
|
|
end
|
|
|
|
# Do not add llvm_build runtime deps if this is a llvm*_{dev,lib}
|
|
# package, as the llvm build package should only be a build dep for
|
|
# these packages.
|
|
if /llvm.*_lib/.match(pkg) || /llvm.*_dev/.match(pkg) || /libclc/.match(pkg) || /openmp/.match(pkg)
|
|
missingpkgdeps.delete_if { |d| /llvm.*_build/.match(d) }
|
|
pkgdeps.delete_if { |d| /llvm.*_build/.match(d) }
|
|
end
|
|
if /llvm.*_lib/.match(pkg)
|
|
missingpkgdeps.delete_if { |d| /llvm_lib/.match(d) }
|
|
pkgdeps.delete_if { |d| /llvm_lib/.match(d) }
|
|
end
|
|
|
|
# Do not add gcc_{dev,lib} runtime deps if this is a gcc_build
|
|
# package as those packages are created from the gcc_build package
|
|
# after it is built.
|
|
if /gcc_build/.match(pkg)
|
|
missingpkgdeps.delete_if { |d| /gcc.*_*/.match(d) }
|
|
pkgdeps.delete_if { |d| /gcc.*_*/.match(d) }
|
|
end
|
|
|
|
# Do not add gcc_build runtime deps if this is a gcc_{dev,lib}
|
|
# package, as the gcc_build package should only be a build dep for
|
|
# these packages.
|
|
if /gcc_lib/.match(pkg) || /gcc_dev/.match(pkg) || /libssp/.match(pkg)
|
|
missingpkgdeps.delete_if { |d| /gcc_build/.match(d) }
|
|
pkgdeps.delete_if { |d| /gcc_build/.match(d) }
|
|
end
|
|
if /gcc_lib/.match(pkg)
|
|
missingpkgdeps.delete_if { |d| /gcc_lib/.match(d) }
|
|
pkgdeps.delete_if { |d| /gcc_lib/.match(d) }
|
|
end
|
|
|
|
puts "\nPackage #{pkg} has runtime library dependencies on these packages:"
|
|
pkgdeps.each do |i|
|
|
puts " depends_on '#{i}' # R"
|
|
end
|
|
|
|
# Leave if we didn't find any missing dependencies.
|
|
return if missingpkgdeps.empty?
|
|
puts "\nPackage file #{pkg}.rb is missing these runtime library dependencies:"
|
|
puts " depends_on '#{missingpkgdeps.join("' # R\n depends_on '")}' # R"
|
|
|
|
missingpkgdeps.each do |adddep|
|
|
puts " depends_on '#{adddep}' # R"
|
|
|
|
# Add missing dependencies to the package.
|
|
puts "\n Adding deps: #{adddep}"
|
|
gawk_cmd = if File.foreach("#{CREW_PREFIX}/lib/crew/packages/#{pkg}.rb").grep(/depends_on/).any?
|
|
# This files contains dependencies already, so add new deps after existing dependencies.
|
|
"gawk -i inplace -v dep=\" depends_on '#{adddep}' # R\" 'FNR==NR{ if (/depends_on/) p=NR; next} 1; FNR==p{ print dep }' #{CREW_PREFIX}/lib/crew/packages/#{pkg}.rb #{CREW_PREFIX}/lib/crew/packages/#{pkg}.rb"
|
|
else
|
|
# This files doesn't contain deps, so just add new deps.
|
|
"gawk -i inplace -v dep=\" depends_on '#{adddep}' # R\" 'FNR==NR{ if (/})/) p=NR; next} 1; FNR==p{ print \"\\n\" dep }' #{CREW_PREFIX}/lib/crew/packages/#{pkg}.rb #{CREW_PREFIX}/lib/crew/packages/#{pkg}.rb"
|
|
end
|
|
system(gawk_cmd)
|
|
end
|
|
|
|
# Check for and delete old runtime dependencies.
|
|
# Its unsafe to do this with other dependencies, because the packager might know something we don't.
|
|
lines_to_delete = {}
|
|
File.readlines("#{CREW_PREFIX}/lib/crew/packages/#{pkg}.rb").each_with_index do |line, line_number|
|
|
# Find all the explicitly marked runtime dependencies.
|
|
dep = line.match(/ depends_on '(.*)' # R/)
|
|
# Basically just a nil check, but this way we avoid matching twice.
|
|
next unless dep
|
|
# Skip unless the runtime dependency in the package does not match the runtime dependencies we've found.
|
|
next unless pkgdeps.none?(dep[1])
|
|
# Skip if we're dealing with a glibc, glibc_lib or gcc_lib dependency-- these are architecture dependent sometimes?
|
|
next if %w[glibc glibc_lib gcc_lib].include?(dep[1])
|
|
# Record the line content as the key and the line number (incremented by one because the index starts at 0) as the value.
|
|
lines_to_delete[line] = line_number + 1
|
|
end
|
|
# Leave if there aren't any old runtime dependencies.
|
|
return if lines_to_delete.empty?
|
|
puts "\nPackage file #{pkg}.rb has these outdated runtime library dependencies:"
|
|
puts lines_to_delete.keys
|
|
system("gawk -i inplace 'NR != #{lines_to_delete.values.join(' && NR != ')}' #{CREW_PREFIX}/lib/crew/packages/#{pkg}.rb")
|
|
end
|
|
|
|
ARGV.each do |package|
|
|
main(package.chomp('rb'))
|
|
end
|