Compilation

Now that the software is correctly configured, all that remains is for it to be compiled. This stage is usually easy, and does not pose serious problems.

Make

The favorite tool of the free software community to compile sources is make. It has two advantages:

  • The developer saves time, because it allows him to efficiently manage the compilation of his project.

  • The end-user can compile and install the software in a few command lines, even if he has no preliminary knowledge of development.

Actions that must be executed to obtain a compiled version of the sources are stored in a file often named Makefile or GNUMakefile. Actually, when make is called, it reads this file – if it exists – in the current directory. If not, the file may be specified by using make's -f option.

Rules

make operates in accordance with a system of dependencies, so compiling a binary file (“ target ”) requires going through several stages (“dependencies”). For instance, to create the (imaginary) glloq binary file, the main.o and init.o object files (intermediate files of the compilation) must be compiled and then linked. These object files are also targets, whose dependencies are their corresponding source files.

This text is only a minimal introduction to survive in the merciless world of make. For an exhaustive documentation, refer to Managing Projects with Make, 2nd edition, O'Reilly, by Andrew Oram and Steve Talbott.

Go, go, go!

Usually, the use of make follows several conventions. For instance:

  • make without argument just executes the compilation of the program, without installation.

  • make install compiles the program (but not always), and then installs the required files at the right place in the file system. Some files are not always correctly installed (man, info), they might have to be copied by the user himself. Sometimes, make install has to be executed again in sub-directories. Usually, this happens with modules developed by third parties.

  • make clean clears all the temporary files created by the compilation, and also the executable file in most cases.

The first stage is to compile the program, and therefore to type (imaginary example):

    $ make
    gcc -c glloq.c -o glloq.o
    gcc -c init.c -o init.o
    gcc -c main.c -o main.o
    gcc -lgtk -lgdk -lglib -lXext -lX11 -lm glloq.o init.o main.o -o glloq
   

Excellent, the binary file is correctly compiled. We are ready to go to the next stage, which is the installation of the files of the distribution (binary files, data files, etc). See the section called “Installation”.

Explanations

If you are curious enough to look in the Makefile file, you will find known commands (rm, mv, cp, etc), but also strange strings, looking like $(CFLAGS).

They are variables which are strings that are usually set at the beginning of the Makefile file, and then replaced by the value they are associated with. It is quite useful when you want to use the same compilation options several times in a row.

For instance, to print the string “foo” on the screen using make all:

    TEST = foo
    all:
        echo $(TEST)
   

Most of the time, the following variables are set:

  1. CC: This is the compiler. Usually, it is cc, which is in most of free systems synonymous with gcc. When in doubt, put gcc here.

  2. LD: This is the program used to ensure the final compilation stage (see section the section called “The four steps of compilation”). By default, this is ld.

  3. CFLAGS: These are the additional arguments that are given to the compiler during the first compilation stages. Among them:

    • -I<path>: Specifies to the compiler where to search for some additional headers (eg: -I/usr/X11R6/include allows inclusion of the header files that are in directory /usr/X11R6/include).

    • -D<symbol>: Defines an additional symbol, useful for programs whose compilation depends on the defined symbols (ex: use the string.h file if HAVE_STRING_H is defined).

    There are often compilation lines like:

          $(CC) $(CFLAGS) -c foo.c -o foo.o
         
  4. LDFLAGS (or LFLAGS): These are arguments used during the final compilation stage. Among them:

    • -L<path>: Specifies an additional path to search for libraries (eg: -L/usr/X11R6/lib).

    • -l<library>: Specifies an additional library to use during the final compilation stage.

What if... it does not work?

Do not panic, it can happen to anyone. Among the most common causes:

  1. glloq.c:16: decl.h: No such file or directory

    The compiler did not manage to find the corresponding header. Yet, the software configuration step should have anticipated this error. Here is how to solve this problem:

    • Check that the header really exists on the disk in one of the following directories: /usr/include, /usr/local/include, /usr/X11R6/include or one of their sub-directories. If not, look for it on the whole disk (with find or locate), and if you still do not find it, check that you have installed the library corresponding to this header. You can find examples of the find and locate commands in their respective manual pages.

    • Check that the header is really readable (type less <path>/<file>.h to test this)

    • If it is in a directory like /usr/local/include or /usr/X11R6/include, you sometimes have to add a new argument to the compiler. Open the corresponding Makefile (be careful to open the right file, those in the directory where the compilation fails [32]) with your favorite text editor (Emacs, Vi, etc). Look for the faulty line, and add the string -I<path> – where <path> is the path where the header in question can be found – just after the call of the compiler (gcc, or sometimes $(CC)). If you do not know where to add this option, add it at the beginning of the file, after CFLAGS=<something> or after CC=<something>.

    • Launch make again, and if it still does not work, check that this option (see the previous point) is added during compilation on the faulty line.

    • If it still does not work, call for help from your local guru or call for help from the free software community to solve your problem (see section the section called “Technical support”).

  2. glloq.c:28: `struct foo' undeclared (first use this function)

    The structures are special data types that all programs use. A lot of them are defined by the system in headers. That means the problem is certainly caused by a missing or misused header. The correct procedure for solving the problem is:

    • try to check whether the structure in question is defined by the program or by the system. A solution is to use the command grep in order to see whether the structure is defined in one of the headers.

      For instance, when you are in the root of the distribution:

      	$ find . -name '*.h'| xargs grep 'struct foo' | less
             

      Many lines may appear on the screen (each time that a function using this type of structure is defined for instance). If it exists, pick out the line where the structure is defined by looking at the header file obtained by the use of grep.

      The definition of a structure is:

      	struct foo {
      	    <contents of the structure>
      	};
             

      Check if it corresponds with what you have. If so, this means that the header is not included in the faulty .c file. There are two solutions:

      • add the line #include "<filename>.h" at the beginning of the faulty .c file.

      • or copy-paste the definition of the structure at the beginning of this file (it is not really neat, but at least it usually works).

    • If not, do the same thing with the system header files (which are usually in directories /usr/include, /usr/X11R6/include, or /usr/local/include). But this time, use the line #include <<filename>.h>.

    • If this structure still does not exist, try to find out which library (i.e. set of functions put together in a single package) it should be defined in (look in the INSTALL or README file to see which libraries are used by the program and their required versions). If the version that the program needs is not the one installed on your system, you will need to update this library.

    • If it still does not work, check that the program properly works with your architecture (some programs have not been ported yet on all the UNIX systems). Check also that you have correctly configured the program (when configure ran, for instance) for your architecture.

  3. parse error

    This is a problem that is quite complicated to solve, because it often is an error that appears at a certain line, but after the compiler has met it. Sometimes, it is simply a data type that is not defined. If you meet an error message like:

          main.c:1: parse error before `glloq_t
          main.c:1: warning: data definition has no type or storage class
         

    then the problem is that the glloq_t type is not defined. The solution to solve the problem is more or less the same as that in the previous problem.

    Note

    there may be a parse error in the old curses libraries if my memory serves me right.

  4. no space left on device

    This problem is easy to solve: there is not enough space on the disk to generate a binary file from the source file. The solution consists of making free space on the partition that contains the install directory (delete temporary files or sources, uninstall any programs you do not use). If you decompressed it in /tmp, rather than in /usr/local/src, which avoids needlessly saturating the /tmp partition. Check whether there are core files[33] on your disk. If so, delete them or make them get deleted if they belong to another user.

  5. /usr/bin/ld: cannot open -lglloq: No such file or directory

    That clearly means that the ld program (used by gcc during the last compilation stage) does not manage to find a library. To include a library, ld searches for a file whose name is in the arguments of type -l<library>. This file is lib<library>.so. If ld does not manage to find it, it produces an error message. To solve the problem, follow the steps below:

    1. Check that the file exists on the hard disk by using the locate command. Usually, the graphic libraries can be found in /usr/X11R6/lib. For instance:

      	$ locate libglloq
             

      If the search is unrewarding, you can make a search with the find command (eg: find /usr -name "libglloq.so*"). If you still cannot find the library, you will have to install it.

    2. Once the library is located, check that it is accessible by ld: the /etc/ld.so.conf file specifies where to find these libraries. Add the incriminate directory at the end (you may have to reboot your computer for this to be taken into account). You also can add this directory by changing the contents of the environment variable LD_LIBRARY_PATH. For instance, if the directory to add is /usr/X11R6/lib, type:

      	export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/X11R6/lib
             

      (if your shell is bash).

    3. If it still does not work, check that the library format is an executable file (or ELF) with the file command. If it is a symbolic link, check that the link is good and does not point at an non-existent file (for instance, with nm libglloq.so). The permissions may be wrong (if you use an account other than root and if the library is protected against reading, for example).

  6. glloq.c(.text+0x34): undefined reference to `glloq_init'

    It is a problem of a symbol that was not solved during the last compilation stage. Usually, it is a library problem. There may be several causes:

    • the first thing to do is to find out whether the symbol is supposed to be in a library. For instance, if it is a symbol beginning by gtk, it belongs to the gtk library. If the name of the library is easily identifiable (frobnicate_foobar), you may list the symbols of a library with the nm command. For example,

      	$ nm libglloq.so
      	0000000000109df0 d glloq_message_func
      	000000000010a984 b glloq_msg
      	0000000000008a58 t glloq_nearest_pow
      	0000000000109dd8 d glloq_free_list
      	0000000000109cf8 d glloq_mem_chunk
             

      Adding the -o option to nm allows you to print the library name on each line, which makes the search easier. Let's imagine that we are searching for the symbol bulgroz_max, a crude solution is to make a search like:

      	$ nm /usr/lib/lib*.so | grep bulgroz_max
      	$ nm /usr/X11R6/lib/lib*.so | grep bulgroz_max
      	$ nm /usr/local/lib/lib*.so | grep bulgroz_max
      	/usr/local/lib/libfrobnicate.so:000000000004d848 T bulgroz_max
             

      Wonderful! The symbol bulgroz_max is defined in the frobnicate library (the capital letter T is before its name). Then, you only have to add the string -lfrobnicate in the compilation line by editing the Makefile file: add it at the end of the line where LDFLAGS or LFGLAGS (or CC at worst) are defined, or on the line corresponding to the creation of the final binary file.

    • the compilation is being made with a version of the library which is not the one allowed for by the software. Read the README or INSTALL files of the distribution to see which version must be used.

    • not all the object files of the distribution are correctly linked. The file where this function is defined is lacking. Type nm -o *.o to know which one it is and add the corresponding .o file on the compilation line if it is missing.

    • the problem function or variable may be non-existent. Try to delete it: edit the problem source file (its name is specified at the beginning of the error message). It is a desperate solution whose consequence will certainly be a chaotic execution of the program with a (segfault at startup, etc).

  7. Segmentation fault (core dumped)

    Sometimes, the compiler hangs immediately and produces this error message. I have no advise except suggesting that you install a more recent version of your compiler.

  8. no space on /tmp

    Compilation needs temporary workspace during the different stages; if it does not have space, it fails. So, you may have to clean the partition, but be careful some programs being executed (X server, pipes, etc) can hang if some files are deleted. You must know what you are doing! If /tmp is part of a partition that does not only contain it (for example the root), search and delete some possible core files.

  9. make/configure in infinite recursion

    It is often a problem of time in your system. Indeed, make needs to know the date in the computer and the date of the files it checks. It compares the dates and uses the result to know whether the target is more recent than the dependence.

    Some date problems may cause make to endlessly build itself (or to build and build again a sub-tree in infinite recursion). In such a case, the use of touch (whose use here is to set the files in question to the current time) usually solves the problem.

    For instance:

          $ touch *
         

    Or also (cruder, but efficient):

          $ find . | xargs touch
         


[32] Analyze the error message returned by make. Normally, the last lines should contain a directory (a message like make[1]: Leaving directory `/home/queen/Project/foo'). Pick out the one with the highest number. To check that it is the good one, go to that directory and execute make again to obtain the same error.

[33] File generated by the system when a process tries to access a memory location that it is not allowed to. These files are used to analyze the reason of such a behavior to correct the problem.