views:

75

answers:

2

Hi,

I'm doing cross-platform development and I want to build a nice, self-contained (!) package for Linux. I know that that's not the way it's usually done, but the application requires all data in one place, so I'm installing it into /opt, like many other proprietary software packages do. I will eventually provide deb and rpm packages, but it will only be .tar.gz for now. The user should extract it somewhere and it should work. I'd rather not have an installer.

First my questions, then the details:

  1. How do other people package proprietary software for Linux?
  2. Are there tools for packaging software including shared libraries?

Now for some details: This is my project's (I call it foo for this purpose) layout:

  • foo (binary)
  • config.ini
  • data

Now in the package, there will be two additional elements:

  • libs
  • foo.sh

libs will contain all the shared libraries the project requires, and foo.sh is a script that sets LD_LIBRARY_PATH to include libs. Therefore, the user will execute foo.sh and the program should start.

I have a shell script that packages the software in the following steps:

  1. Create empty directory and copy foo.sh to it
  2. Invoke the build process and make install into the new directory
  3. Copy shared libs from the filesystem
  4. Package everything as .tar.gz

What do you think of this? There are some problems with this approach:

  • I have to hard code all dependencies twice (once in CMake, once in the packaging script)
  • I have to define the version number twice (once in the source code, once in the packaging script)

How do you do it?

Edit: Another question that just came up: How do you determine on which libraries your software depends? I did an ldd foo, but there's an awfull lot. I looked at how WorldOfGoo packages look, and they ship only very few libraries. How can I make assumptions about which library will be present on a user's system and which won't? Just install all targeted distributions into a virtual matine and see what's required?

A: 

Think long and hard (or ask your product development department) which distributions / architectures you need to support.

Make sure that they fully understand the testing implications.

I expect you will come up with a very short list of supported distributions and architectures.

It really depends on which customers are paying for Linux support. Most people use Redhat Enterprise (on servers) or Centos (which is indistinguishable from a technical perspective).

If you only need to support Redhat, you only need to support RPM, job's a good'un.

MarkR
It's consumer software, so Ubuntu is our primarily targeted platform. We will see to it that it works under Fedora, OpenSUSE and Debian as well, only 32-Bit version for now. But what about the packaging?
eomer
+1  A: 

Generic issues

Your way to package your stuff (with dependent libs) to /opt is how proprietary (and even open-source) software is packaged. It's recommended practice of The Linux Foundation (see my answer to the other question for links).

External libs may be either compiled from scratch and embedded into your build process as a separate step (especially if you modify them), or fetched from packages of some distributions. The second approach is easier, but the first one allows more flexibility.

Note that it's not necessary to include some really low-level libraries (such as glibc, Xorg) into your package. They'd be better left to system vendors to tune, and you may just assume they exist. Moreover, there's an Linux Standard Base, that documents the most important libraries; these libraries exist almost everywhere, and can be trusted.

Note also that if you compile under a newer system, most likely, users of older systems won't be able to use it, while the reverse is not true. So, to reach better compatibility, it might be useful to compile package under a system that's two years older than today.

I just outlined some generic stuff, but I believe that Linux Developers Network website contains more information about packaging and portability.

Packaging

Judging by what I saw in the open-source distribution projects, your script does it the same way distribution vendors package software. Their scripts automatically patch sources, mimic installation of software and package the resultant folders into DEBs and RPMs.

Tar.gz, or course, could also work, but creating, for example, an RPM is not complex enough for you to miss such an opportunity to make life of your users so much easier.

Answering your questions,

  • Yes, you have to hard-code dependencies twice.

    The thing is that when you hardocde them in CMake, you specify them in the other terms than when you specify them in a packaging script. CMake refers to shared libraries and header files, while packaging script refers to packages.

    There's no cross-distribution one-to-one relationship between package names and shared libs and headers. It varies through distributions. Therefore, it should be specified twice.

    But the package can be easily re-packed by distribution vendors, especially if you strive to packing all dependent libs into it (so there'll be less external dependencies to port). Also, a tool that can port packages from one distribution to another will appear soon (I'll update my answer when it's released).

  • Yes, you have to specify your version twice.

    But the thing is that you may organize your packaging process in such a way that package and software versions never get out-of-sync. Just make the packaging script check out from your repository (or download from your website) exactly the same version that the script will write to package specifications.

Analyzing Dependencies

To analyze dependencies of your software, you may use our open-source, free Linux Application Checker tool. It will report the list of libraries it depends on, show distributions your software is compatible with, and help your application be more portable across distributions. It turns out that sometimes more cross-distribution compatibility can be achieved by little effort, and you don't have to lock yourself into support of just a few selected distributions.

Pavel Shved
Linux Application Checker looks really cool, thank you! Also thanks for your other comments, makes a lot of sense. I was somehow assuming that there is "one true way" (TM) to package proprietary apps on Linux, but a shell script is pretty neat in fact. I store it in the same VCS project as the source code, so checking the source out via script does not make much sense. I might be able to parse the version that way, parsing --version or something. Is it a bad idea to store packaging/installer stufff along with the code?
eomer
@eomer, if you store it in the same VCS. then you should update *all* version numbers that occur in your repository, both in sources and in packaging scripts. That automatically solves this problem.Keeping all the stuff together is not a bad practice, it's a good practice IMHO. But when you package third-party software (as distribution maintainers do), it's just inevitable.
Pavel Shved
I still have to get this to work. LAC is great, but my current problem is that some of my libraries require a modern version of libc and libstdc++, so it won't work on Debian lenny. If I compile it on Debian lenny though, I have to use older versions of my libraries. What would you suggest here? Using older libraries? Compiling current library versions myself? (not sure how to tell CMake) or is there another way? Also, I'm wondering if putting the package script into VCS is really such a good idea because it is extremely distribution dependent.
eomer
@eomer I suggest compiling modern versions of libraries on your own. Since there are not much of such libraries (?), it would work. (I'd actually suggest compiling *all* of the libraries you use, since you ship them as well, but it may require unnecessary expense). I never used CMake, but I'm sure it's possible to tell it to link against the libs you just compiled (I saw Amarok2 do this, and it uses CMake). As for VCS, in my opinion, storing distribution-dependent script is better than not storing anything.
Pavel Shved
Thanks again! I don't have that much dependencies, a few boost and SDL libs. If I compile the libraries myself, the script will be a lot less distribution dependent (I could even add the shared libs to VCS, or is that a sin?) I might have to use an older distribution for compiling the libs so it won't link against modern versions of libc or libstdc++.
eomer
Thanks again (again), the approach worked great. I compiled the required versions of boost and SDL myself on Debian lenny running in a virtual machine. I used "make install" to install them to /usr/local, and CMake was able to find them without problems. Linux Application Checker showed that my application is now compatible with up to three year old versions of all major distributions!
eomer
@eomer, goot to know that helped :-) I'm sure, in addition to running application checker, you also installed a couple of old distros to Virtual Machines, and tested if there were no undetected issues in your app, didn't you?
Pavel Shved
Not yet, but that's planned :)
eomer