Archive

Compile From Source


Introduction

Most of the information contained herein has been lifted from an email sent to the list. I hope it will be of use to some of you when you consider compiling an application from source. I’ve expanded it.

Prerequisites

I assume that you have the necessary base tools for compiling programs. Although:

debian: apt-get install build-essential patchrpm-based: rpm -i glibc-devel gcc g++

are the most likely packages you’ll need as a base. But this doesn’t include any of the source packages (such as other libs) that the application you’re going to compile relies on — so you’ll obviously have to get those, too.

You might also want to see /NonRootBuildEnvironment, if you are in a multi-user environment.

General Ramblings

Having unpacked the source, one of the first things you should do is check what documentation came with the source. Typically, these will be in one of two files (or both):

./README ./INSTALL

These will usually detail any specific instructions that you need to do to install the package. Typically (although not always) many source packages are compiled via GNU-buildtools — a set of programs that aids compilation and installation. So the canonical answer to compiling a program (that uses GNU-buildtools) would be to execute the following:

cd source_code-version ./configure make su -c 'make install'

It is the job of the script ./configure to generate the Makefile based on whatever options you might supply along with it. There are a number of common situations when you might want to supply arguments to ./configure. One of those includes using Stow (/KeepingTrack). Another would be when using checkinstall.

One thing to be aware of, when compiling an application which relies on any libraries is to either install them beforehand, or compile them yourself. The libraries are needed for the application to be compiled because without it, it Won’t Work ™. If you install any libraries to /usr/local/lib, it is important to remember that the system has to be made aware that they exist. Currently, there is no way of getting the system to automatically detect the presence of shared-libraries. This has to be done manually. This involves (as “root”):

echo "/usr/local/lib" >> /etc/ld.so.conf ldconfig

Note that if “/usr/local/lib” is already listed in /etc/ld.so.conf, you needn’t add it again. Just ensure you run ldconfig as user root.

Without any arguments, ./configure will assume an installation path under /usr/local/*. Now, there’s nothing wrong with that, but there are a few things to be aware of. The first issue, more than anything is maintainability. Once you have installed an application to /usr/local/* — how the hell do you uninstall it to make way for another version? There are a few ways. The canonical way is using the same Makefile from above, generate a script that, rather than installing the software, removes it.

cd source_code-version make -n install > ./somefile (edit ./somefile, replacing instances of "cp" and/or "install" lines with "rm -fr") sh ./somefile

Now, imagine if that were a big application — the number of lines in it would be quite a lot. Yes, you could automate the output from makeĀ -nĀ install so it does it automatically for you, but why bother? It’s still a lot of work — there are “better” methods to use. The other aspect to take note of are any libraries that depend on the compiled program. If there are, they’ll probably only be there (in /usr/local/lib) because they depended on that application. So you can remove those as well, if they too have to be upgraded.

So having done all of that. Recompile the new app, and install it as per before. Genius. It worked. But gosh, that’s long-winded, isn’t it? Well, help is at hand. Stow (/KeepingTrack) can be used to install to a base directory so that the only entries that appear in /usr/local/* are symlinks to a basedir (typically /usr/local/stow/foo). This makes an excellent candidate for maintainability.

The final thing to be aware of is coexistence. It is perfectly feasible to have more than one copy of a program installed (a typical scenario might be: compiled versus packaged-program). But how do you ensure that the compiled program is the one that’s executed, and not the other version? For that, you should ensure that $PATH is set correctly. You must ensure that /usr/local/bin exists before /usr/bin. Hence:

export PATH=/usr/local/bin:$PATH

Typically, you’d put this in ~/.bash_profile, so that it was available next time you logged in. If you wanted an instant effect, you could also type it in directly.

I mentioned earlier that GNU-buildtools might not always be used. This is true of much older source-code. You might well see “Imakefile” — this is not parsable by GNU-make. So to get them to work, you have to do:

xmkfm -a make && su -c 'make install'

Of course, this shoots the whole concept of maintaining /usr/local/* in the foot. But I’d be surprised if you encountered any source packages still using this method of working. Although some makefiles, allow one to pass parameters to it. So for instance, sometimes one can use:

make PREFIX=/usr/local

Note what’s happening here — the variable ‘PREFIX’ is being sent to the make command. I’ve seen people try to do it this way:

PREFIX=/usr/local make

Which is fine, but most makefiles have an order of preference such that they assign internally, and don’t always check the environment. By using the former construct, this usually ensures it to work.

As a Debian-specific note, if you’re compiling a program to avoid using the packaged one, and you are wondering how to stop the packaged one from being installed, you’d have to install the equivs package, and get that to install dummy packages. But perhaps I’ll leave that topic for some other time.

If you wanted to know what’s happening ‘under the hood’ with all of this — then see the /CompilationBasics page.

That should be just about it. Happy compiling!

Leave a Reply