]> git.ipfire.org Git - pakfire.git/commitdiff
packager: Add automatic provides/requires to packages
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 2 Jun 2021 11:11:33 +0000 (11:11 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 2 Jun 2021 11:11:33 +0000 (11:11 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/build.c
src/libpakfire/execute.c
src/libpakfire/filelist.c
src/libpakfire/include/pakfire/execute.h
src/libpakfire/include/pakfire/filelist.h
src/scripts/find-provides
src/scripts/find-requires

index 0fab7bedf849d8c1701adf34a33129674d4713f0..c837d7856cf8e203ec2f8c14d7fcb6d9df491698 100644 (file)
@@ -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;
index bc021825feb9b468da10cb36ff6fce58aea36e48..240e5dc5aafc8a70ea36930bf56aadd1cb28f61d 100644 (file)
@@ -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;
index 77b8a7a5bccebcaec8e1f282f6fabb314abb10b7..09d03fbaf622b749af4b191a1a61991cde02f8a3 100644 (file)
@@ -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;
+}
index 335fe0bbdd7b644ec2be2eabf9e374afbc198f4d..c1e6b1d5a2598167287a18182c3105a724f1680e 100644 (file)
@@ -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
index ac124c5c1b1bf1303e4e8eb7c5cd842f9665bf0e..c48796df13ae3c6d7c297328f14aa67e6fd427dc 100644 (file)
@@ -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
 
index 06b3c4797bc390bc150506909deb720fa0fbfda2..3badd03fc9e0ff9245c60887dacd381954f98436 100644 (file)
 #!/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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
 
-# 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 $?
index 1f49dabea905302b04c934460c75ef2976ba9c4d..e8b443685881d5a15b4080574ac8345a4b7a0269 100644 (file)
 #!/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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+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 $?