This reworks the implmentation of libprovides for the following benefits: - Moves functionality from write_pkginfo() to find_libprovides() - Only calculates the version for libraries specifically requested and not all libraries. This has the disadvantage of running find over the $pkgdir for as many libraries as needed, but is unlikely to be an issue due to caching. - The order of the provides array in the PKGBUILD is kept in the package - There are more warning messages when things fail and those that were there are no longer errors (as I do not think failure of libprovides should result in complete packaging failure) - It is now modular so can be easy extended to other library types other than ELF *.so.
Signed-off-by: Allan McRae allan@archlinux.org --- scripts/makepkg.sh.in | 85 +++++++++++++++++++++++++++---------------------- 1 files changed, 47 insertions(+), 38 deletions(-)
diff --git a/scripts/makepkg.sh.in b/scripts/makepkg.sh.in index 64b33c6..08c4384 100644 --- a/scripts/makepkg.sh.in +++ b/scripts/makepkg.sh.in @@ -1076,30 +1076,51 @@ find_libdepends() { }
find_libprovides() { - local libprovides - find "$pkgdir" -type f -name *.so* | while read filename - do - # check if we really have a shared object - if LC_ALL=C readelf -h "$filename" 2>/dev/null | grep -q '.*Type:.*DYN (Shared object file).*'; then - # 64 - soarch=$(LC_ALL=C readelf -h "$filename" | sed -n 's/.*Class.*ELF(32|64)/\1/p') - # get the string binaries link to: libfoo.so.1.2 -> libfoo.so.1 - sofile=$(LC_ALL=C readelf -d "$filename" 2>/dev/null | sed -n 's/.*Library soname: [(.*)].*/\1/p') - [ -z "$sofile" ] && sofile="${filename##*/}" + local libprovides missing + for p in ${provides[@]}; do + missing=0 + case "$p" in + *.so) + local filename=$(find "$pkgdir" -type f -name $p*) + # packages may provide multiple versions of the same library + for fn in ${filename[@]}; do + # check if we really have a shared object + if LC_ALL=C readelf -h "$fn" 2>/dev/null | grep -q '.*Type:.*DYN (Shared object file).*'; then + # get the string binaries link to (e.g. libfoo.so.1.2 -> libfoo.so.1) + local sofile=$(LC_ALL=C readelf -d "$fn" 2>/dev/null | sed -n 's/.*Library soname: [(.*)].*/\1/p') + if [[ -z "$sofile" ]]; then + warning "$(gettext "Library listed in %s is not versioned: %s")" "'provides'" "$p" + libprovides=(${libprovides[@]} "$p") + continue + fi
- # extract the library name: libfoo.so - soname="${sofile%%.so.*}.so" - # extract the major version: 1 - soversion="${sofile##*.so.}" - if in_array "${soname}" ${provides[@]}; then - if ! in_array "${soname}=${soversion}-${soarch}" ${libprovides[@]}; then - # libfoo.so=1-64 - echo "${soname}=${soversion}-${soarch}" - libprovides=(${libprovides[@]} "${soname}=${soversion}-${soarch}") + # get the library architecture (32 or 64 bit) + local soarch=$(LC_ALL=C readelf -h "$fn" | sed -n 's/.*Class.*ELF(32|64)/\1/p') + + # extract the library major version + local soversion="${sofile##*.so.}" + + libprovides=(${libprovides[@]} "${p}=${soversion}-${soarch}") + else + warning "$(gettext "Library listed in %s is not a shared object: %s")" "'provides'" "$p" + libprovides=(${libprovides[@]} "$p") + fi + else + libprovides=(${libprovides[@]} "$p") + missing=1 fi - fi - fi + ;; + *) + libprovides=(${libprovides[@]} "$p") + ;; + esac + + if (( missing )); then + warning "$(gettext "Can not find library listed in %s: %s")" "'provides'" "$p" + fi done + + echo ${libprovides[@]} }
write_pkginfo() { @@ -1133,13 +1154,15 @@ write_pkginfo() { [[ $groups ]] && printf "group = %s\n" "${groups[@]}" [[ $optdepends ]] && printf "optdepend = %s\n" "${optdepends[@]//+([[:space:]])/ }" [[ $conflicts ]] && printf "conflict = %s\n" "${conflicts[@]}" + + provides=("$(find_libprovides)") + [[ $provides ]] && printf "provides = %s\n" "${provides[@]}" + [[ $backup ]] && printf "backup = %s\n" "${backup[@]}"
- local it
- libprovides=$(find_libprovides) + local it libdepends=$(find_libdepends) - provides=("${provides[@]}" ${libprovides}) depends=("${depends[@]}" ${libdepends})
for it in "${depends[@]}"; do @@ -1155,20 +1178,6 @@ write_pkginfo() { fi done
- for it in "${provides[@]}"; do - # ignore versionless entires (those come from the PKGBUILD) - if [[ $it = *.so ]]; then - # check if the entry has been found by find_libprovides - # if not, it's unneeded; tell the user so he can remove it - if [[ ! $libprovides =~ (^|\s)${it}=.* ]]; then - error "$(gettext "Cannot find library listed in %s: %s")" "'provides'" "$it" - return 1 - fi - else - echo "provides = $it" - fi - done - for it in "${packaging_options[@]}"; do local ret="$(check_option $it)" if [[ $ret != "?" ]]; then
First off, this patch creates a syntax error.
On 25.12.2011 07:52, Allan McRae wrote:
- Only calculates the version for libraries specifically requested and not all libraries. This has the disadvantage of running find over the $pkgdir for as many libraries as needed, but is unlikely to be an issue due to caching.
Maybe you could create a search string like the following? This won't preserve the order, but it will traverse the file system only once and according to the find manpage it's POSIX compliant.
find /usr/lib -type f ( -name libx264.so* -o -name libc.so* -o -name libarchive.so* )
- The order of the provides array in the PKGBUILD is kept in the package
- There are more warning messages when things fail and those that were there are no longer errors (as I do not think failure of libprovides should result in complete packaging failure)
I think it should because libraries hardly move between packages or change their names and the packager might not see the message and push a package with incorrect provides.
It might be a good idea not to abort right away though. You could check all entries and abort later, but I think you shouldn't create a package since the packager will have to fix the incorrect entry and rebuild/repackage anyway.
- It is now modular so can be easy extended to other library types other than ELF *.so.
Signed-off-by: Allan McRae allan@archlinux.org
scripts/makepkg.sh.in | 85 +++++++++++++++++++++++++++---------------------- 1 files changed, 47 insertions(+), 38 deletions(-)
diff --git a/scripts/makepkg.sh.in b/scripts/makepkg.sh.in index 64b33c6..08c4384 100644 --- a/scripts/makepkg.sh.in +++ b/scripts/makepkg.sh.in @@ -1076,30 +1076,51 @@ find_libdepends() { }
find_libprovides() {
- local libprovides
- find "$pkgdir" -type f -name *.so* | while read filename
- do
# check if we really have a shared object
if LC_ALL=C readelf -h "$filename" 2>/dev/null | grep -q '.*Type:.*DYN (Shared object file).*'; then
# 64
soarch=$(LC_ALL=C readelf -h "$filename" | sed -n 's/.*Class.*ELF\(32\|64\)/\1/p')
# get the string binaries link to: libfoo.so.1.2 -> libfoo.so.1
sofile=$(LC_ALL=C readelf -d "$filename" 2>/dev/null | sed -n 's/.*Library soname: \[\(.*\)\].*/\1/p')
[ -z "$sofile" ] && sofile="${filename##*/}"
- local libprovides missing
- for p in ${provides[@]}; do
missing=0
case "$p" in
*.so)
local filename=$(find "$pkgdir" -type f -name $p\*)
# packages may provide multiple versions of the same library
for fn in ${filename[@]}; do
# check if we really have a shared object
if LC_ALL=C readelf -h "$fn" 2>/dev/null | grep -q '.*Type:.*DYN (Shared object file).*'; then
# get the string binaries link to (e.g. libfoo.so.1.2 -> libfoo.so.1)
local sofile=$(LC_ALL=C readelf -d "$fn" 2>/dev/null | sed -n 's/.*Library soname: \[\(.*\)\].*/\1/p')
if [[ -z "$sofile" ]]; then
warning "$(gettext "Library listed in %s is not versioned: %s")" "'provides'" "$p"
libprovides=(${libprovides[@]} "$p")
continue
fi
# extract the library name: libfoo.so
soname="${sofile%%\.so\.*}.so"
# extract the major version: 1
soversion="${sofile##*\.so\.}"
if in_array "${soname}" ${provides[@]}; then
if ! in_array "${soname}=${soversion}-${soarch}" ${libprovides[@]}; then
# libfoo.so=1-64
echo "${soname}=${soversion}-${soarch}"
libprovides=(${libprovides[@]} "${soname}=${soversion}-${soarch}")
# get the library architecture (32 or 64 bit)
local soarch=$(LC_ALL=C readelf -h "$fn" | sed -n 's/.*Class.*ELF\(32\|64\)/\1/p')
# extract the library major version
local soversion="${sofile##*\.so\.}"
libprovides=(${libprovides[@]} "${p}=${soversion}-${soarch}")
else
warning "$(gettext "Library listed in %s is not a shared object: %s")" "'provides'" "$p"
libprovides=(${libprovides[@]} "$p")
fi
else
libprovides=(${libprovides[@]} "$p")
missing=1 fi
This else block doesn't have any matching if statement. The one with "Library listed in %s is not a shared object" already closes 'if LC_ALL=C readelf -h "$fn" 2>/dev/null | grep -q '.*Type:.*DYN (Shared object file).*'; then'
On 25/12/11 20:06, Florian Pritz wrote:
First off, this patch creates a syntax error.
That is fixed on my working branch - I will resend.
On 25.12.2011 07:52, Allan McRae wrote:
- Only calculates the version for libraries specifically requested and not all libraries. This has the disadvantage of running find over the $pkgdir for as many libraries as needed, but is unlikely to be an issue due to caching.
Maybe you could create a search string like the following? This won't preserve the order, but it will traverse the file system only once and according to the find manpage it's POSIX compliant.
find /usr/lib -type f ( -name libx264.so* -o -name libc.so* -o -name libarchive.so* )
I do not see that being worth the effort of creating the find command. Even for the largest of packages the find will take a fraction of a second with the files being cached.
- The order of the provides array in the PKGBUILD is kept in the package
- There are more warning messages when things fail and those that were there are no longer errors (as I do not think failure of libprovides should result in complete packaging failure)
I think it should because libraries hardly move between packages or change their names and the packager might not see the message and push a package with incorrect provides.
If the package does not see a warning in the last few lines of the build output, then they need to stop packaging...
It might be a good idea not to abort right away though. You could check all entries and abort later, but I think you shouldn't create a package since the packager will have to fix the incorrect entry and rebuild/repackage anyway.
There are two cases where this occurs: 1) the library has no soname information 2) the listed provide is not a shared object
If we make these errors and someone wants to add a provide that hits one of these conditions, then there is nothing they can do. This could be especially possible with #1...
Allan
pacman-dev@lists.archlinux.org