LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Debian packaging - how to automate "Depends:" list (https://www.linuxquestions.org/questions/programming-9/debian-packaging-how-to-automate-depends-list-907913/)

kornelix 10-13-2011 04:19 AM

Debian packaging - how to automate "Depends:" list
 
There must be an elegant way to do this but I have not found one.

I cobbled together something that seems to work:

1. $ readelf -d <binary executable>
Get the list of dynamically linked library files

2. $ dpkg-query -S <library file>
Find the debian package containing a library file

3. $ dpkg-query -W <package name>
Find the installed version of a package

4. Use the outputs from (3) and (4) to construct the text
in the debian control file: "Depends: package (>= version), ..."

There must be a better way. True?

thanks
Mike

coralfang 10-13-2011 06:40 AM

Have a look at
Code:

man ldd
Not sure if this is what you're after. You could parse the output using awk for example:
Code:

$ ldd /usr/bin/htop | awk '{ print $1 }'
linux-vdso.so.1
libncursesw.so.5
libm.so.6
libc.so.6
/lib/ld-linux-x86-64.so.2

And if you wanted to strip the numbers off the end (could be useful):
findlibs.sh
Code:

#!/bin/bash
for lib in $(ldd $1 | awk '{ print $1 }'); do
        echo ${lib%.*}
done

Code:

$ ./findlibs.sh /usr/bin/htop
linux-vdso.so
libncursesw.so
libm.so
libc.so
/lib/ld-linux-x86-64.so

Etc.

kornelix 10-13-2011 10:25 AM

Thanks coralfang, that is useful. Still need to add version numbers (a similar approach would work).
Since this is an issue every packager faces, there must be a canned solution.
Mike

kornelix 10-13-2011 10:30 AM

Actually ldd gives too much information: libraries linked from other libraries are included. For packaging dependencies, only the first level is needed and readelf does that (If I understand adequately).

gnashley 10-13-2011 02:52 PM

Here's an alternate 'ldd' which I use:

Code:

#!/bin/bash
# Copyright 2009-2011 Gilbert Ashley <amigo@ibiblio.org>
# re-written from an idea by
# Ricardo Garcia Gonzalez.
# His version needed bash-4, awk, cat, cut, grep and tr -plus objdump
# This only needs bash >=3.0 and objdump :-)
# I added the "not found" report
# version 0.1

if [[ -n $1 ]] ; then
  declare MY_LIBS="$(objdump -p $@ |grep NEEDED)"
  # Library directories.
  LIBDIRS=${LD_LIBRARY_PATH//:/ }"/lib$LIBDIRSUFFIX /usr/lib$LIBDIRSUFFIX"
  if [[ -r /etc/ld.so.conf ]] ; then
        while read LINE ; do
                LIBDIRS=${LIBDIRS}" $LINE"
        done < /etc/ld.so.conf
  fi

  #LIBDIRS=${LIBDIRS}${LD_LIBRARY_PATH//:/ }

  for LINE in $(echo $MY_LIBS) ; do
        HAVE_LIB=0
        if [[ $LINE != "NEEDED" ]] ; then
                for LIBDIR in $LIBDIRS ; do
                        if [[ -e "$LIBDIR/$LINE" ]] ; then
                                # don't use '-x' which requires the lib to be executable
                                HAVE_LIB=1
                                echo "$LIBDIR/$LINE"
                                # for an output more like the real ldd:
                                # echo "$LINE => $LIBDIR/$LINE"
                                break
                        else
                                continue
                        fi
                done
                if [[ $HAVE_LIB != 1 ]] ; then
                        echo "$LINE"" not found"
                        # for an output more like the real ldd:
                        # echo "$LINE => not found"
                fi
        fi
  done
fi

Similar to the OP's use of readelf, it shows only directly-linked dependencies, and only those which are actually needed by the bin/lib being checked.

kornelix 10-14-2011 07:19 AM

I think I likely reinvented the wheel, but I now have a solution.
I wrote a c program that generates the "Depends" text directly.
I put it here in case someone else needs it.

Here is a sample output:

Code:


$: getdeps /usr/bin/mashup

 LIBRARY                        PACKAGE                        VERSION                       
 libgtk-x11-2.0.so.0            libgtk2.0-0                    2.24.6-0ubuntu5               
 libgdk-x11-2.0.so.0            libgtk2.0-0                    2.24.6-0ubuntu5               
 libgdk_pixbuf-2.0.so.0        libgdk-pixbuf2.0-0            2.24.0-1ubuntu1               
 libcairo.so.2                  libcairo2                      1.10.2-6ubuntu3               
 libpango-1.0.so.0              libpango1.0-0                  1.29.3+git20110916-0ubuntu1   
 libgobject-2.0.so.0            libglib2.0-dev                2.30.0-0ubuntu4               
 libglib-2.0.so.0              libglib2.0-0                  2.30.0-0ubuntu4               
 libstdc++.so.6                libstdc++6                    4.6.1-9ubuntu3               
 libm.so.6                      libc6                          2.13-20ubuntu5               
 libgcc_s.so.1                  libgcc1                        1:4.6.1-9ubuntu3             
 libpthread.so.0                libc6                          2.13-20ubuntu5               
 libc.so.6                      libc6                          2.13-20ubuntu5               


 PACKAGE                        VERSION                       
 libgtk2.0-0                    2.24.6                       
 libgdk-pixbuf2.0-0            2.24.0                       
 libcairo2                      1.10.2                       
 libpango1.0-0                  1.29.3+git20110916           
 libglib2.0-dev                2.30.0                       
 libglib2.0-0                  2.30.0                       
 libstdc++6                    4.6.1                         
 libc6                          2.13                         
 libgcc1                        1:4.6.1                       


Depends: libgtk2.0-0 (>= 2.24.6), libgdk-pixbuf2.0-0 (>= 2.24.0),
libcairo2 (>= 1.10.2), libpango1.0-0 (>= 1.29.3+git20110916),
libglib2.0-dev (>= 2.30.0), libglib2.0-0 (>= 2.30.0),
libstdc++6 (>= 4.6.1), libc6 (>= 2.13), libgcc1 (>= 1:4.6.1),

And here is the source code:

Code:

/**************************************************************************
  getdeps.cc  v.01

  find all package dependencies of a binary executable program

  usage:  $ getdeps program
 
  STDOUT:  "Depends packname1 (>= N.N), packname2 ... "
 
  Copyright 2011  Michael Cornelison

  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.

***************************************************************************/

#include <stdio.h>
#include <string.h>


int main(int argc, char *argv[])
{
  int      cc, ii, jj, Npkg = 0;
  char    *program, *pp1, *pp2;
  char    command[100], buff[200];
  char    libname[100][100], package[100][100], version[100][100];
  FILE    *fid;

  if (argc < 2) {
      printf("usage: $ getdeps program \n");
      return 1;
  }
 
  program = argv[1];
 
  snprintf(command,100,"readelf -d %s", program);                        //  get linked dynamic libraries
  fid = popen(command,"r");
  if (! fid) {
      printf("getdeps, %s not found \n",program);
      return 1;
  }

  while ((fgets(buff,200,fid)))                                          //  process readelf outputs, formatted
  {                                                                      //    ... Shared library: [filename]
      pp1 = strstr(buff,"Shared library:");
      if (! pp1) continue;
      pp1 = strstr(pp1,"[");
      if (! pp1) continue;
      pp2 = strstr(pp1,"]");
      if (! pp2) continue;
      cc = pp2 - pp1 - 1;
      if (cc > 99) continue;
      strncpy(libname[Npkg],pp1+1,cc);                                    //  isolate filename
      libname[Npkg][cc] = 0;
      Npkg++;
      if (Npkg > 99) {
        printf("over 100 libraries, stop here \n");
        break;
      }
  }

  pclose(fid);
 
  for (ii = 0; ii < Npkg; ii++)                                          //  find packages containing lib files
  {
      snprintf(command,100,"dpkg-query -S %s",libname[ii]);
      fid = popen(command,"r");
      fgets(buff,200,fid);
      pclose(fid);
      pp1 = strstr(buff,":");                                              //  format is packagename: ...
      if (pp1) {
        *pp1 = 0;
        strncpy(package[ii],buff,100);                                    //  isolate packagename
        buff[99] = 0;
      }
      else strcpy(package[ii],"??");
  }
 
  for (ii = 0; ii < Npkg; ii++)                                          //  get package versions
  {
      snprintf(command,100,"dpkg-query -W %s",package[ii]);
      fid = popen(command,"r");
      fgets(buff,200,fid);
      pclose(fid);
      pp1 = strstr(buff,"\t");                                            //  format is packagename <tab> version
      if (pp1) {
        strncpy(version[ii],pp1+1,100);                                  //  isolate version
        version[ii][99] = 0;
        cc = strlen(version[ii]);
        version[ii][cc-1] = 0;                                            //  get rid of trailing \n
      }
      else strcpy(version[ii],"??");
  }
 
  printf("\n %-30s %-30s %-30s \n","LIBRARY","PACKAGE","VERSION");        //  print libraries and corresp. packages

  for (ii = 0; ii < Npkg; ii++)                               
      printf(" %-30s %-30s %-30s \n",
              libname[ii], package[ii], version[ii]);

  for (ii = 0; ii < Npkg; ii++)                                          //  eliminate duplicates
  {
      for (jj = ii+1; jj < Npkg; jj++)
      {
        if (strcmp(package[jj],package[ii]) == 0 &&
            strcmp(version[jj],version[ii]) == 0) *package[jj] = 0;
      }
  }
 
  for (ii = 0; ii < Npkg; ii++)                                          //  eliminate distro version appendages
  {
      pp1 = strrchr(version[ii],'-');
      if (pp1) *pp1 = 0;
  }
 
  printf("\n\n %-30s %-30s \n","PACKAGE","VERSION");                      //  print packages and versions

  for (ii = 0; ii < Npkg; ii++)
      if (*package[ii])
        printf(" %-30s %-30s \n",package[ii], version[ii]);
 
  printf("\n\nDepends: ");                                                //  print Depends: package (>= version), ...
  for (ii = 0; ii < Npkg; ii++)
      if (*package[ii])
        printf("%s (>= %s), ",package[ii], version[ii]);
  printf("\n\n");
 
  return 0;
}



All times are GMT -5. The time now is 05:18 PM.