From: Michael Tremer Date: Wed, 2 Jun 2021 11:11:33 +0000 (+0000) Subject: packager: Add automatic provides/requires to packages X-Git-Tag: 0.9.28~1285^2~49 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5b0b3dc224dfc7d33c0d1af8372cbfb323c1c87d;p=pakfire.git packager: Add automatic provides/requires to packages Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/build.c b/src/libpakfire/build.c index 0fab7bedf..c837d7856 100644 --- a/src/libpakfire/build.c +++ b/src/libpakfire/build.c @@ -89,6 +89,109 @@ ERROR: return r; } +static int find_dependency(char** haystack, const char* needle) { + if (!needle) { + errno = EINVAL; + return -1; + } + + if (!haystack) + return 0; + + for (char** element = haystack; *element; element++) { + if (strcmp(needle, *element) == 0) + return 1; + } + + return 0; +} + +static int pakfire_build_find_dependencies(Pakfire pakfire, + PakfirePackage pkg, PakfireFilelist filelist, const char* buildroot) { + char** provides = NULL; + char** requires = NULL; + char path[PATH_MAX]; + + // Allocate path to write the filelist to + int r = pakfire_make_path(pakfire, path, "tmp/.pakfire-filelist.XXXXXX"); + if (r < 0) + return 1; + + // Create a temporary file + FILE* f = pakfire_mktemp(path); + if (!f) + goto ERROR; + + // Write filelist to the temporary file + r = pakfire_filelist_export(filelist, f); + fclose(f); + if (r) { + ERROR(pakfire, "Could not export filelist: %s\n", strerror(errno)); + goto ERROR; + } + + const char* root = pakfire_get_path(pakfire); + + // Pass buildroot and the filelist as arguments + const char* args[] = { + buildroot, pakfire_path_relpath(root, path), NULL + }; + + // Find all provides + r = pakfire_build_run_script(pakfire, "find-provides", args, + pakfire_execute_capture_stdout_to_array, &provides); + if (r) { + ERROR(pakfire, "find-provides returned with error %d\n", r); + goto ERROR; + } + + // Find all requires + r = pakfire_build_run_script(pakfire, "find-requires", args, + pakfire_execute_capture_stdout_to_array, &requires); + if (r) { + ERROR(pakfire, "find-requires returned with error %d\n", r); + goto ERROR; + } + + // Add all provides to the package + if (provides) { + for (char** element = provides; *element; element++) { + DEBUG(pakfire, "Adding provides: %s\n", *element); + pakfire_package_add_provides(pkg, *element); + } + } + + // Add all requires to the package + if (requires) { + for (char** element = requires; *element; element++) { + // Skip adding this requirement if also provided by this package + if (find_dependency(provides, *element)) + continue; + + DEBUG(pakfire, "Adding requires: %s\n", *element); + pakfire_package_add_requires(pkg, *element); + } + } + + // Success + r = 0; + +ERROR: + if (provides) { + for (char** element = provides; *element; element++) + free(*element); + free(provides); + } + if (requires) { + for (char** element = requires; *element; element++) + free(*element); + free(requires); + } + unlink(path); + + return r; +} + static int append_to_array(const char*** array, const char* s) { unsigned int length = 0; @@ -111,7 +214,8 @@ static int append_to_array(const char*** array, const char* s) { } static int pakfire_build_package_add_files(Pakfire pakfire, PakfireParser makefile, - const char* namespace, struct pakfire_packager* packager) { + const char* buildroot, const char* namespace, PakfirePackage pkg, + struct pakfire_packager* packager) { PakfireFilelist filelist = NULL; char path[PATH_MAX]; int r = 1; @@ -127,11 +231,6 @@ static int pakfire_build_package_add_files(Pakfire pakfire, PakfireParser makefi if (!files) return 0; - // Fetch buildroot - char* buildroot = pakfire_parser_get(makefile, NULL, "BUILDROOT"); - if (!buildroot) - goto ERROR; - // Convert to absolute path pakfire_make_path(pakfire, path, buildroot); @@ -158,6 +257,13 @@ static int pakfire_build_package_add_files(Pakfire pakfire, PakfireParser makefi const size_t length = pakfire_filelist_size(filelist); DEBUG(pakfire, "%zu file(s) found\n", length); + // Find dependencies + r = pakfire_build_find_dependencies(pakfire, pkg, filelist, buildroot); + if (r) { + ERROR(pakfire, "Finding dependencies failed: %s\n", strerror(errno)); + goto ERROR; + } + // Add all files to the package for (unsigned int i = 0; i < length; i++) { PakfireFile file = pakfire_filelist_get(filelist, i); @@ -188,14 +294,12 @@ ERROR: free(includes); if (excludes) free(excludes); - if (buildroot) - free(buildroot); return r; } static int pakfire_build_package(Pakfire pakfire, PakfireParser makefile, - const char* namespace, const char* target) { + const char* buildroot, const char* namespace, const char* target) { PakfireRepo repo = NULL; PakfirePackage pkg = NULL; struct pakfire_packager* packager = NULL; @@ -234,7 +338,8 @@ static int pakfire_build_package(Pakfire pakfire, PakfireParser makefile, goto ERROR; // Add files - r = pakfire_build_package_add_files(pakfire, makefile, namespace, packager); + r = pakfire_build_package_add_files(pakfire, makefile, buildroot, namespace, + pkg, packager); if (r) goto ERROR; @@ -269,7 +374,8 @@ ERROR: return r; } -static int pakfire_build_packages(Pakfire pakfire, PakfireParser makefile, const char* target) { +static int pakfire_build_packages(Pakfire pakfire, PakfireParser makefile, + const char* buildroot, const char* target) { DEBUG(pakfire, "Creating packages..."); int r = 1; @@ -290,7 +396,7 @@ static int pakfire_build_packages(Pakfire pakfire, PakfireParser makefile, const // Build packages in reverse order for (int i = num_packages - 1; i >= 0; i--) { - r = pakfire_build_package(pakfire, makefile, packages[i], target); + r = pakfire_build_package(pakfire, makefile, buildroot, packages[i], target); if (r) goto ERROR; } @@ -444,7 +550,7 @@ PAKFIRE_EXPORT int pakfire_build(Pakfire pakfire, const char* path, goto ERROR; // Create the packages - r = pakfire_build_packages(pakfire, makefile, target); + r = pakfire_build_packages(pakfire, makefile, buildroot_rel, target); if (r) { ERROR(pakfire, "Could not create packages: %s\n", strerror(errno)); goto ERROR; diff --git a/src/libpakfire/execute.c b/src/libpakfire/execute.c index bc021825f..240e5dc5a 100644 --- a/src/libpakfire/execute.c +++ b/src/libpakfire/execute.c @@ -268,6 +268,51 @@ static int default_logging_callback(Pakfire pakfire, void* data, int priority, return 0; } +int pakfire_execute_capture_stdout(Pakfire pakfire, void* data, int priority, + const char* line, size_t length) { + char** output = (char**)data; + + // Append everything from stdout to a buffer + if (priority == LOG_INFO) { + int r = asprintf(output, "%s%s", (output && *output) ? *output : "", line); + if (r) + return 1; + } + + // Send everything else to the default logger + return default_logging_callback(pakfire, NULL, priority, line, length); +} + +int pakfire_execute_capture_stdout_to_array(Pakfire pakfire, void* data, int priority, + const char* line, size_t length) { + char*** array = (char***)data; + + // Append everything from stdout to an array + if (priority == LOG_INFO) { + unsigned int length = 0; + + // Determine the length of the existing array + if (*array) { + for (char** element = *array; *element; element++) + length++; + } + + // Allocate space + *array = reallocarray(*array, length + 2, sizeof(**array)); + if (!*array) + return 1; + + // Append line and terminate the array + (*array)[length] = strdup(line); + (*array)[length + 1] = NULL; + + return 0; + } + + // Send everything else to the default logger + return default_logging_callback(pakfire, NULL, priority, line, length); +} + static int find_environ(struct pakfire_execute* env, const char* key) { if (!key) { errno = EINVAL; diff --git a/src/libpakfire/filelist.c b/src/libpakfire/filelist.c index 77b8a7a5b..09d03fbaf 100644 --- a/src/libpakfire/filelist.c +++ b/src/libpakfire/filelist.c @@ -482,3 +482,19 @@ int pakfire_filelist_contains(PakfireFilelist list, const char* pattern) { return 0; } + +int pakfire_filelist_export(PakfireFilelist list, FILE* f) { + for (unsigned int i = 0; i < list->size; i++) { + PakfireFile file = list->elements[i]; + + const char* path = pakfire_file_get_path(file); + if (!path) + return 1; + + int r = fprintf(f, "%s\n", path); + if (r < 0) + return r; + } + + return 0; +} diff --git a/src/libpakfire/include/pakfire/execute.h b/src/libpakfire/include/pakfire/execute.h index 335fe0bbd..c1e6b1d5a 100644 --- a/src/libpakfire/include/pakfire/execute.h +++ b/src/libpakfire/include/pakfire/execute.h @@ -41,6 +41,10 @@ enum { #ifdef PAKFIRE_PRIVATE +int pakfire_execute_capture_stdout(Pakfire pakfire, void* data, int priority, + const char* line, size_t length); +int pakfire_execute_capture_stdout_to_array(Pakfire pakfire, void* data, int priority, + const char* line, size_t length); int pakfire_execute_ldconfig(Pakfire pakfire); #endif diff --git a/src/libpakfire/include/pakfire/filelist.h b/src/libpakfire/include/pakfire/filelist.h index ac124c5c1..c48796df1 100644 --- a/src/libpakfire/include/pakfire/filelist.h +++ b/src/libpakfire/include/pakfire/filelist.h @@ -46,6 +46,7 @@ int pakfire_filelist_scan(PakfireFilelist list, const char* root, const char** includes, const char** excludes); int pakfire_filelist_contains(PakfireFilelist list, const char* pattern); +int pakfire_filelist_export(PakfireFilelist list, FILE* f); #endif diff --git a/src/scripts/find-provides b/src/scripts/find-provides index 06b3c4797..3badd03fc 100644 --- a/src/scripts/find-provides +++ b/src/scripts/find-provides @@ -1,96 +1,139 @@ #!/bin/bash +############################################################################### +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2021 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### -# Include functions. -BASEDIR=$(dirname ${0}) -source ${BASEDIR}/find-common - -BUILDROOT=${1} -FILELIST=${2} - -binary_files= -perl_files= -pkgconfig_files= - -# Walk through all file files and see what we have got here. -while read file; do - case "${file}" in - */usr/lib/debug/*|*/usr/src/debug/*) - # Skip all debuginfo files. - continue - ;; - */usr/lib*/python*/*.so*) - # Do not show python shared objects in provides list. - ;; - */usr/lib*/gconv/*) - # Skip gconv files. - continue - ;; - *.so*) - # Skip symlinks for performance reasons. - [ -L "${file}" ] && continue - - file_is_elf ${file} >/dev/null 2>&1 && \ - binary_files="${binary_files} ${file}" - ;; - *.pm) - # This file is a perl module. We check them later. - perl_files="${perl_files} ${file}" - ;; - *.pc) - pkgconfig_files="${pkgconfig_files} ${file}" - ;; - esac -done < ${FILELIST} - -# Search for SONAMEs in all binary files. -for file in ${binary_files}; do - soname=$(file_get_soname ${file}) - - # If the files does not have a SONAME, we will - # simply use the basename. +error() { + echo "${0#/}: $@" >&2 +} + +FILTER_WEAK_PROVIDES='BEGIN { START=0; } + /Version definitions:/ { START=1; } + /^[0-9]/ && (START==1) { print $4; } + /^$/ { START=0; }' + +pkgconfig_provides() { + local file="${1}" + + local n r v + while read -r n r v; do + echo "pkgconfig(${n}) ${r} ${v}" + done < <(pkg-config --print-provides "${file}" 2>/dev/null) + + return 0 +} + +shared_object_provides() { + local file="${1}" + + # Get SONAME + local soname="$(objdump -p "${file}" 2>/dev/null | awk '/SONAME/ { print $2 }')" + + # If the files does not have a SONAME, we will simply use the basename if [ -z "${soname}" ]; then - if [ -L ${file} ]; then - continue - fi - soname=$(basename ${file}) + soname="$(basename "${file}")" fi - if file_is_64bit ${file}; then - is_64=true - echo "${soname}${mark64}" + local suffix + + # Is this a 64 bit file? + if file -L "${file}" 2>/dev/null | grep -q "ELF 64-bit"; then + suffix="(64bit)" + + echo "${soname}()${suffix}" else - is_64=false echo "${soname}" fi - # Find weak symbol provides. - objdump -p ${file} 2>/dev/null | awk ' - BEGIN { START=0 ; } - /Version definitions:/ { START=1; } - /^[0-9]/ && (START==1) { print $4; } - /^$/ { START=0; }' | \ - while read symbol ; do - echo "${soname}(${symbol})$(${is_64} && echo ${mark64} | sed 's/()//')" - done -done - -# Search for perl provides. -if [ -n "${perl_files}" ] && [ -x /usr/bin/perl ]; then - perl ${BASEDIR}/perl.prov ${perl_files} | sort -u -fi - -# pkg-config files. -pkgconfig=$(which pkg-config) - -if [ -n "${pkgconfig}" -a -x "${pkgconfig}" ]; then - for file in ${pkgconfig_files}; do - # Query the dependencies of the package. - ${pkgconfig} --print-provides "${file}" 2> /dev/null | while read n r v ; do - # We have a dependency. Make a note that we need the pkgconfig - # tool for this package. - echo "pkgconfig(${n}) ${r} ${v}" - done - done | sort -u -fi - -exit 0 + # Find weak symbol provides + while read -r symbol; do + echo "${soname}(${symbol})${suffix}" + done < <(objdump -p "${file}" 2>/dev/null | awk "${FILTER_WEAK_PROVIDES}") + + return 0 +} + +main() { + local buildroot="${1}" + local filelist="${2}" + + # Check if BUILDROOT exists + if [ ! -d "${buildroot}" ]; then + error "BUILDROOT does not exist" + return 1 + fi + + # Check if the filelist exists + if [ ! -r "${filelist}" ]; then + error "Cannot read filelist '${filelist}'" + return 1 + fi + + local file + while read -r file; do + # Filter out what we don't need + case "${file}" in + # Debug files + /usr/lib/debug/*|/usr/src/debug/*) + continue + ;; + + # Skip shared objects in Python directories + /usr/lib*/python*/*.so*) + continue + ;; + + # Skip gconv + /usr/lib*/gconv/*) + continue + ;; + esac + + # Make the full path + local path="${buildroot}${file}" + + # Process special files + case "${file}" in + # pkg-config + *.pc) + # Query provides of the package + pkgconfig_provides "${path}" + ;; + + # Perl + *.pm) + # TODO + ;; + + # Shared objects + *.so.*) + # Skip symlinks + if [ -L "${path}" ]; then + continue + fi + + shared_object_provides "${path}" + ;; + esac + done < "${filelist}" | sort -u + + return 0 +} + +main "$@" || exit $? diff --git a/src/scripts/find-requires b/src/scripts/find-requires index 1f49dabea..e8b443685 100644 --- a/src/scripts/find-requires +++ b/src/scripts/find-requires @@ -1,176 +1,241 @@ #!/bin/bash +############################################################################### +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2021 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### + +error() { + echo "${0#/}: $@" >&2 +} + +pkgconfig_requires() { + local file="${1}" + + # Require the pkgconfig package + echo "pkgconfig" + + local n r v + while read -r n r v; do + echo "pkgconfig(${n}) ${r} ${v}" + done < <(pkg-config --print-requires --print-requires-private "${file}" 2>/dev/null) + + return 0 +} + +is_file_on_filelist() { + local file="${1}" + local filelist="${2}" + + local line + while read -r line; do + if [ "${file}" = "${line}" ]; then + return 0 + fi + done < "${filelist}" -# Include functions. -BASEDIR=$(dirname ${0}) -source ${BASEDIR}/find-common - -# BUILDROOT is the first argument. -BUILDROOT=${1} -FILELIST=${2} - -# Determine libdir. -if [ "$(uname -m)" = "x86_64" ]; then - libdir=/usr/lib64 -else - libdir=/usr/lib -fi - -binary_files= -perl_files= -script_files= -pkgconfig_files= - -# Walk through all file files and see what we have got here. -while read file; do - case "${file}" in - */usr/lib/debug/*|*/usr/src/debug/*) - # Skip all debuginfo files. - continue - ;; - */usr/lib*/gconv/*) - # Skip all gconv files. - continue - ;; - *.ko) - # Skip all kernel modules because they do not - # require anything at all. - continue - ;; - *.pc) - # Find all pkg-config files. - pkgconfig_files="${pkgconfig_files} ${file}" - continue - ;; - *.pm) - # Find all perl modules. - if [ -r "${file}" ]; then - perl_files="${perl_files} ${file}" - continue - fi - ;; + # Nothing found + return 1 +} - # Python - */usr/lib*/python*/*) - # Sort out all python files. - # Directories are processed bewlow. - ;; - */usr/lib/python*|*/usr/lib64/python*) - # This will only get the python directory. - file=$(basename ${file}) +find_elf_interpreter() { + local file="${1}" + local filelist="${2}" - # Strip the python version from the string. - python_version="${file#python}" + local interpreter="$(readelf -l "${file}" 2>/dev/null | \ + grep "program interpreter" | tr -d "]" | awk '{ print $NF }')" - if [ -n "${python_version}" ]; then - echo "python-abi = ${python_version}" - fi - continue - ;; - esac + # Only add interpreter if it isn't part of this package + if [ -n "${interpreter}" ] && ! is_file_on_filelist "${interpreter}" "${filelist}"; then + echo "${interpreter}" + fi - # Unresolved symlinks. - if [ -L "${file}" ]; then - # Get destination. - link=$(readlink -m ${file}) + return 0 +} - # If destination does not exist, make - # a dependency for it. - if ! [ -e "${link}" ]; then - echo "${link#${BUILDROOT}}" - fi +find_weak_symbols() { + local file="${1}" - # Don't search for anything else, because - # symlinks do not require anything but the target file. - continue - fi + local suffix - # Search for all binary files. - if file_is_elf ${file}; then - binary_files="${binary_files} ${file}" - continue + # Is this a 64 bit file? + if file -L "${file}" 2>/dev/null | grep -q "ELF 64-bit"; then + suffix="(64bit)" fi - # Search for script files. - if file_is_script ${file}; then - script_files="${script_files} ${file}" + # List all weak symbol versions + objdump -p "${file}" 2>/dev/null | \ + awk \ + 'BEGIN { START=0; LIBNAME=""; } + /^$/ { START=0; } + /^Dynamic Section:$/ { START=1; } + (START==1) && /NEEDED/ { + if ("'${suffix}'" != "") { + sub(/$/, "()'${suffix}'", $2); + } + print $2; + } + (START==2) && /^[A-Za-z]/ { START=3; } + /^Version References:$/ { START=2; } + (START==2) && /required from/ { + sub(/:/, "", $3); + LIBNAME=$3; + } + (START==2) && (LIBNAME!="") && ($4!="") { + print LIBNAME "(" $4 ")'${suffix}'"; + }' + + return 0 +} + +find_script_interpreter() { + local file="${1}" + + local first_line="$(grep -q "^#!" "${file}" && head -n1 "${file}")" + + # Skip files that are not scripts + if [ "${first_line:0:2}" != "#!" ]; then continue fi -done < ${FILELIST} -# Process script files. -interpreters= -for file in ${script_files}; do - [ -r ${file} -a -x ${file} ] || continue + local interpreter="${first_line:2}" - interp=$(file_get_script_interpreter ${file}) - interpreters="${interpreters} ${interp}" - - # Collect all perl files. - case "${interp}" in + case "${interpreter}" in */perl) - perl_files="${perl_files} ${file}" + # XXX process perl files here ;; esac -done - -# Output the list of needed interpreters. -[ -n "${interpreters}" ] && { echo ${interpreters} | tr '[:blank:]' \\n | sort -u ; } - -# Search for binary interpreters. -for file in ${binary_files}; do - # Get the interpreter. - interp=$(file_get_elf_interpreter ${file}) - - # Skip the interpreter if it is provided by this - # package. - [ -e "${BUILDROOT}${interp}" ] && continue - - # Print the interpreter. - echo "${interp}" -done | sort -u - -# Weak symbol versions (from glibc). -[ -n "${mark64}" ] && mark64="(64bit)" -for file in ${binary_files}; do - [ -r ${file} ] || continue - - lib64=$(if file_is_64bit ${file}; then echo "${mark64}"; fi) - objdump -p ${file} 2>/dev/null | awk 'BEGIN { START=0; LIBNAME=""; } - /^$/ { START=0; } - /^Dynamic Section:$/ { START=1; } - (START==1) && /NEEDED/ { - if ("'${lib64}'" != "") { - sub(/$/, "()'${lib64}'", $2); - } - print $2; - } - (START==2) && /^[A-Za-z]/ { START=3; } - /^Version References:$/ { START=2; } - (START==2) && /required from/ { - sub(/:/, "", $3); - LIBNAME=$3; - } - (START==2) && (LIBNAME!="") && ($4!="") { - print LIBNAME "(" $4 ")'${lib64}'"; - }' -done | sort -u - -# Search for perl requires. -if [ -n "${perl_files}" ] && [ -x /usr/bin/perl ]; then - perl ${BASEDIR}/perl.req ${perl_files} | sort -u -fi - -# Search for pkg-config requires. -pkgconfig=$(which pkg-config) -if [ -n "${pkgconfig}" -a -x "${pkgconfig}" ]; then - for file in ${pkgconfig_files}; do - # The dependency for the pkgconfig package itself. - echo "pkgconfig" - - ${pkgconfig} --print-requires --print-requires-private "${file}" 2> /dev/null | while read n r v ; do - echo "pkgconfig(${n})" "${r}" "${v}" - done - done -fi - -exit 0 + + echo "${interpreter}" + return 0 +} + +set -x + +main() { + local buildroot="${1}" + local filelist="${2}" + + # Check if BUILDROOT exists + if [ ! -d "${buildroot}" ]; then + error "BUILDROOT does not exist" + return 1 + fi + + # Check if the filelist exists + if [ ! -r "${filelist}" ]; then + error "Cannot read filelist '${filelist}'" + return 1 + fi + + local file + while read -r file; do + # Filter out what we don't need + case "${file}" in + # Debug files + /usr/lib/debug/*|/usr/src/debug/*) + continue + ;; + + # Skip gconv + /usr/lib*/gconv/*) + continue + ;; + + # Skip all kernel modules + *.ko) + continue + ;; + esac + + # Make the full path + local path="${buildroot}${file}" + + # Process unresolvable symlinks + if [ -L "${path}" ]; then + local link="$(readlink -m "${path}")" + + # Make link relative to buildroot + link="${link#${BUILDROOT}}" + + # If the destination is not in this package, we create a dependency for it + if ! is_file_on_filelist "${link}" "${filelist}"; then + echo "${link}" + fi + + # We do not process symlinks any further + continue + fi + + # Process special files + case "${file}" in + # pkg-config + *.pc) + # Query requires of the package + pkgconfig_requires "${path}" + ;; + + # Perl + *.pm) + # XXX TODO + continue + ;; + + # Python + /usr/lib*/python*/*) + # Fall through for all python files + ;; + + # Catch the module directory + /usr/lib*/python*) + # This will only get the python directory + file="$(basename "${file}")" + + # Strip the python version from the string + python_version="${file#python}" + + if [ -n "${python_version}" ]; then + echo "python-abi = ${python_version}" + fi + ;; + esac + + # Is this an ELF file? + if file -L "${path}" 2>/dev/null | grep -q "ELF"; then + # Find the ELF interpreter + if ! find_elf_interpreter "${path}" "${filelist}"; then + return 1 + fi + + # Find weak symbols + if ! find_weak_symbols "${path}"; then + return 1 + fi + + continue + fi + + # Add script interpreters + if ! find_script_interpreter "${path}"; then + return 1 + fi + done < "${filelist}" | sort -u + + return 0 +} + +main "$@" || exit $?