|
|||||||||||||||||||||||||||||||||||||||||||||||||
|
Compiling source codeAlan Pae Last Revised: March 15, 2003 Compiling source code on Unix systems used to be a time consuming, trial and error ordeal. The reason that compiling software in the old days was so difficult is because there was no universal way to create a Makefile for different machines and operating systems. IntroductionA C compiler uses the Makefile as a kind of blueprint that tells the compiler the steps to take to compile the source code into a usable binary file. Binary files are the programs you're trying to run. They're also called executables. In the old days, when a developer was writing his/her code, they were writing it to run on their machine and may or may not have been trying to make it run on another platform or two, but generally not all Unices. Thus, software written to run on one system, under their structure, would not necessarily compile on another vendors Unix variant under their structure. If you wanted to run someone else's code from another architecture on yours, it was up to you to figure out how to make it compile and work on your machine. Writing software on Unix has essentially gone through three different stages. First was the Makefile stage. This was all you got. It was up to you to figure out which system libraries and which header files on your system were needed to make the program compile. Each system has its own header files. These are files that end in .h These files define how C programs can access your system. They provide system definitions that programmers can use to write their code. If your machine didn't have a "dependent" application or library, you had to go out and redo the process all over again for those dependencies. Although this is still true today, the biggest change is that there is now a system in place to help you create the Makefile, whereas in the old days, there was not. The second era that software went through was the Imake stage. This stage was used mainly for X Windows applications. Since X Windows is pretty standard across all machines, a system was developed to take advantage of this situation. An Imakefile was created. This was essentially a template that your system would use to help in the creation of a Makefile. In addition to the applications Imakefile, your system had variables that that it would supply to Imake that would then create the Makefile for you. The biggest disadvantage to this system is that not all software was written with X Windows in mind, and so it wasn't always applicable. There are other pluses and minuses to the Imake system that you can explore on your own if you desire. The GNU autoconf manual has a section towards the end that addresses the differences between Imake and Autoconf. The third stage of software development is the one we're in right now. This era of software development has tools that are designed to generate a Makefile regardless of your hardware or Operating Environment. This stage uses the autoconf utilities to generate a Makefile for your machine. The autoconf utility creates a script called "configure" which creates a Makefile custom tailored for your hardware/operating system. The autoconf utility tries to ease the process of having to write a different Makefile for each vendors hardware/operating system. The autoconf utility uses a variety of techniques and other programs to ascertain what Unix system your running on, runs some checks to see what your system has and doesn't have, checks for dependencies, and then creates a Makefile for your system. This allows a developer to work on the source code and not worry so much about how to get it to compile on your machine. This frees up the developer to work on features and bug fixes (also called features). The web pages that follow will assist you in getting your machine ready to compile software, and then will attempt to walk you through the process for compiling software for each of the situations mentioned above. The first scenario I'll present you with is the autoconf method since its in heavy use today. The first two compilation scenarios will be shown for completeness. Sometimes, you will have to resort to the old ways as well. In addition there will be other topics covered such as how to create a package as well as a short dialog on static versus dynamic libraries. Preparing your systemFor compiling software you will need a few things. You'll need the source code for the program that you're trying to compile. You'll need a compiler, and lastly, if you need it, have the e-mail address of the author or company available. If that fails, turn to your favorite search engine, newsgroup, e-mail list, or wherever else you go to get help. On Solaris systems there are two different compilers you can use. These are: Sun's C Compiler - cc is short for C compiler Gnu's C Compiler - GCC is short for Gnu's Compiler Collection. There are a few differences in these compilers. The first is money. Sun's compilers will cost you a few bucks while Gnu's is free. The reason for this is Sun's compilers come with a lot of goodies built in that Gnu's doesn't. You can supplement Gnu's with other Gnu software to achieve some of the same functionality, but you have to assemble all the pieces yourself. In addition, Solaris is written with Sun's compilers in mind and not Gnu's. What does that mean to you. It means that some Solaris utilities will not work when using Gnu's compiler and you may have to find Gnu equivalents in order to get some software programs to compile correctly. Solaris commands such as tr or gettext, would not work when compiling early version of Gnome for instance. The fix was to download and install a GNU version of tr or gettext and place that version first in your path statement. Another reason that Sun's compiler is considered superior to Gnu's is that Sun's compilers are tightly coupled to the hardware and can take advantage of Sun's hardware in a way that Gnu's doesn't. GNU's compilers are designed to run a range of UNIX variants not just Solaris. Although there are some optimizations that you can enable in Gnu's compiler for Sun hardware, Sun's compiler will probably always produce faster code than Gnu's will. This is because the Sun compiler knows about Sun's hardware and will optimize the code to take advantage of the CPU and hardware architecture in ways that GNU's currently does not. Solaris itself DOES NOT COME BUNDLED with a compiler. In order to compile software on Solaris you WILL NEED TO INSTALL either Gnu's C Compiler or Sun's C Compiler. When you install the Developer Cluster or greater of Solaris, what you're actually installing is all the utility software, libraries, and header files that the compilers use to produce binary programs. Installing the Developer Cluster will put you in a position so that all you will need to do is to install a compiler, adjust the path, set an environment variable, and your ready to go. However, you don't need to install the Developer Cluster or greater to be able to compile software. According to Casper Dik's Solaris 2.x faq, the packages you will need to insure that are installed on your system to compile software are:
These packages are all on the Solaris 2.x CDs, except that some packages may only exist in some releases and not in others. Some packages may be on separate CDs, such as the "Desktop/CDE" CD, but all are part of the Solaris "bundle". Some of the above packages do not exist in all Solaris releases. As the FAQ says, don't use Gnu's as or ld commands, make sure these are Sun's and not Gnu's. All the binaries live in /usr/ccs/bin. Make sure that this is present in your path before you attempt to compile software. The first thing you should do if you're going to use Gnu's compiler, is to compile your own compiler. Not an easy task since you don't get one to start with. If you're going to use Sun's compiler, read through the included docs, and you're on your way. Using Sun's compilers will not be covered here. We are going to go through the steps to compile GCC on your computer. The steps to compile any other program will pretty much be the same. It's important to remember that you don't need to install a compiler on all your computers. If you have several Sun 4U architecture machines, than one machine can compile source code for all your Sun 4U machines. After you compile the code, you can use pkgadd, ftp, or whatever means are available to push the code out to other machines. You also need to be aware of versions of Solaris. If your compiler sits on a machine running Solaris version 8, you probably won't be able to run this code on an earlier version of Solaris. However, your compiled code should run on later revisions of Solaris code. This is because Sun is constantly adding things to the OS and what exists later on, may or may not be available on an earlier revision of Solaris. Ok, so how do you go about compiling your own Gnu compiler since you start out with nothing? Not as hard as it sounds. First, on the machine that you're going to use to compile software, insure that the packages listed above are installed. Second, modify your path to include /usr/ccs/bin. Now you have one of two or more options. Sun is now shipping a "Companion" CD that does include a copy of GCC. In addition you could easily ftp a copy from http://www.sunfreeware.com. If that doesn't work, you can have someone you know burn it on CD, setup an ftp server, NFS mount a share with it, etc.... If you use the first two methods, you should have a package file that will make it super easy to install the software. You simply use the pkgadd command to install the software. Usually its something like pkgadd -d . Include the period in the command. This assumes that you're currently in the directory that contains the GCC package and your using a user account that will allow you to install software onto the current machine. After typing pkgadd -d . the package add command will list all of the packages it finds in the current directory. Simply select the number corresponding to the package that you want to install, and barring any problems, Solaris will take care of the rest. Be sure to note which directory that the files are being created in. You'll need to add this to you're path statement as well, preferable before /usr/ccs/bin. You'll also need to set LD_LIBRARY_PATH to the lib directory for the package you just installed. Typically, this is LD_LIBRARY_PATH=/usr/local/lib; export LD_LIBRARY_PATH if your using the GCC package available from Sunfreeware. After you've installed the package, modified your path, and set the LD_LIBRARY_PATH environment variable, the command, gcc --version, should return the version of gcc that you've just installed on your system. You are now ready to compile your own compiler. You'll need to ftp the current version of gcc from ftp://ftp.gnu.org/gnu/gcc. Before you compile GCC, you should take the time to setup some other environment variables. Environment variablesThere are a handful of environment variables that you can set that will have an effect on your ability to compile software. These are:
Export CC CFLAGS CXX CPPFLAGS TMPDIR LDFLAGS LD_LIBRARY_PATH. You don't have to set environment variables for GCC to use them. You could simply add them to the configure command line as shown below: ./configure CC=gcc CFLAGS=-O3 LDFLAGS="-L/usr/local/lib -R/usr/local/lib" TMPDIR=/tmp LIBS=-lposix Let's take a look at what each of these do:
Those are the main environment variables that you need to be concerned with. For CFLAGS you can set: For SPARC Hardware:
For Intel Hardware:
These '-m' switches are supported in addition to the above on AMD x86-64 processors in 64-bit environments.
Running configureYou can tell when a program uses configure because it will contain at least one file with the filename of Makefile.in. The quick and dirty method to compile software using configure is: ./configure make make install Believe it or not, once you've got a compiler installed, got the path adjusted, and have the environment variables set, this pretty much is the quick and dirty method to compile software. Just because you can doesn't mean you should though. There are a few things that you need to know about configure to use it to its full potential. Running this single file will create a Makefile that will enable a compiler to produce code on just about any system that can run the script. Before you do anything, you should read the README and INSTALL docs that came with the source code. They feature comments by the programmer on the program, how to compile it, things to watch out for and more. It goes without saying that you should read these files. These should be ASCII text files that any program should be able to display. After you've finished reading README and INSTALL type: ./configure --help |more After you press enter configure will run and will send to your screen, all the options that are available to you to use. Almost any configure --help screen should include the option: --enable-shared. In almost all cases, you should set this option. When you compile GCC on your system, I strongly encourage you to use this switch. I've had software fail to compile because my GCC was built with static libraries and not dynamic libraries. After you've noted which configure options your going to use, run configure again with your list of options. When you run configure --options, the shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile` in each directory of the package. It may also create one or more `.h` files containing system-dependent definitions. Finally, it creates a shell script config.status that you can run in the future to recreate the current configuration, and a file config.log containing compiler output (useful mainly for debugging `configure`). You can copy the config.status file to another machine. Any options that you chose when you ran configure are saved to this file. Instead of running configure --options again, you can simply run config.status and it will recreate the environment automatically for you. If configure fails for any reason, check the log file. I've sent my config.log file to developers before to get help when they had a major version change of their software. This is a great way for them to see what's happening on the system your using, especially if you're running a different flavor of Unix then they are. Remember configure attempts to automate the process of creating the all-important Makefile. It can also use an optional file (typically called config.cache and enabled with --cache-file=config.cache or simply -C) saves the results of its tests to speed up reconfiguring. (Caching is disabled by default to prevent problems with accidental use of stale cache files.) If you have a config.cache file, running configure --options again will NOT do you any good until you remove the cache file. Configure will look for the cache file before looking for an options list. It uses config.cache before it looks for your switches. After configure finishes, you simply type make, and then when that finishes, `make install`. Make install, installs the software onto your system. You're now finished with compiling software. There are a couple of more things you need to be aware of though. If for any reason the software fails to compile, run make clean before attempting to compile the program again. Most software can be uninstalled by recompiling the software and instead of running make install, you run make uninstall. We'll discuss some other things you can do to help troubleshoot compilation failures in another section. Compiling GCCBy now, hopefully you have a good idea already of how to compile GCC. Let's refresh so we're all on the same page.
./configure -help | more will list all the configure options that you can enable to build GCC. After you have selected your options, run configure again, and specify these options. ./configure --exec-prefix=/usr/local \ --bindir=/usr/local/bin \ --libdir=/usr/local/lib \ --infodir=/usr/local/info \ --mandir=/usr/local/man \ --with-local-prefix=/usr/local/include \ --enable-shared \ --enable-threads=solaris \ LDFLAGS="-L/usr/local/lib -R/usr/local/lib" Press enter and let configure do its work. When it finished it will create the config.status script so you don't have to type everything in all over again. Just save the config.status file someplace safe. Now that GCC is configured, you are ready to build the compiler and runtime libraries. It is normal to have compiler warnings when compiling certain files. Unless you are a developer, you can generally ignore these warnings unless they cause compilation to fail. Normally, you'd now just type make, and let it run until its finished. However, according to the install docs you need to add a couple of switches to the make command. So the make command should look like: make CFLAGS='-O' LIBCFLAGS='-g -O2' \ LIBCXXFLAGS='-g -O2 -fno-implicit-templates' \ Bootstrap Press enter and wait. At the end of the build process, you should be sitting at a command prompt with no errors on the screen. You're now ready to install your new compiler. To do this, first remove the old one. pkgrm package_name will take care of this. Next, we need to remove the LD_LIBRARY_PATH setting since we shouldn't need it anymore. unset LD_LIBRARY_PATH takes care of that. Now we're finally ready to install the compiler. make install will take care of that. You should now type gcc --version again to verify that gcc still works. Now you're ready to compile other software programs. You're next one should be the GNU version of make, some people refer to this as gmake. Build problemsOK, you should have a working compiler now and you're off to the races to compile everything in site. But what do you do when something goes wrong. There are several things you can do, but punching your neighbor in the nose is not one of them. There are a few utilities that you can use to help track down what went wrong. During compilation, due to some unforeseen error, make may abort. Contact the developer when that happens. As is often the case, there may be more than one compile time error. `make -k` will tell make to keep going even if it encounters an error that would normally end the make session. The benefit to the developer if they ask you to run this, is they might be able to fix all the problems at once instead of going through the process of fixing them one at a time. I've been asked to do this before, and it's a great time saver. If you encounter an error such as "symbol missing", use the nm command to list out which symbols are present in the library in question. Usually all you'll need to do is update the library and off you go. If a program crashes after its compiled, a developer may ask you to run gdb against it. You'll need to ftp and install the GNU Debugger before you can do this. I'm not a developer so I had to ask them for some quick steps on what commands they wanted me to type, and they sent me a list. It's not that complicated. They were able to quickly fix the problem thanks to the debugger. And if you want to see the internals of application as it runs, using the Solaris commands truss or apptrace will give you a lot of data to look at. If you have problems with an application that doesn't work once its compiled and running, you may need to crash it intentionally. Contact the developer and see if they want a core file from the application. There are tools such as Solaris Modular Debugger, or as mentioned previously, the GNU Debugger, that may help them to determine what went wrong with the code. imake instructionsYou can tell when a program uses imake because it will contain at least one file with the filename of Imakefile. In order to compile software using the Imake system, you'll first need to modify some Solaris files so they work with GCC. First of all, copy the files from /usr/openwin/lib/X11/config/ into an empty directory, like your home directory. This should be something like /home/usr/X11/config. Next, make the following changes to the following files: Changes to site.def
Changes to sun.cf
Now you'll need to run:
xmkmf -a -DuseInstalled -I/home/usr/X11/config make install, will place the resultant binaries in /usr/openwin/bin. This should already be in your path, so just typing the binary filename should execute the program. All I got is a Makefile instructionsIf there is just a Makefile, try executing make all, make, and make progname in that order. Otherwise, you'll have to invoke gcc manually: if the source is in foo.c, try
gcc -c foo.c -o foo.o to produce an executable called foo. If you can't find anything, it is likely that you are supposed to run the compiler 'bare' on the source files. This is all the more likely if there's just a single *.c file. To do this: gcc -o new_name file.c If you need to define extra include or library directories, or libraries, you have to do so by providing them as command line options to 'gcc' directly, e.g. gcc -o new_name file.c -L/path/dir -llib -I/path/dir Library directories are denoted by -L. Header file directories, are denoted by -I. How to make a packageFor instruction on how to create Solaris packages reffer the followig pages:Static libraries versus dynamic librariesYou should try to used Dynamic libraries, those ending in .so whenever possible. You can think of static libraries as driving to work in your automobile by yourself. To illustrate dynamic libraries think of it as being driven to work on a train. This is essentially what happens when you use static libraries versus dynamic libraries. The major drawback to static libraries is if you want to upgrade the library, you then have to recompile the application to take advantage of the new library. With dynamic libraries, you can just add a soft link if needed, and off you go. Statically linked libraries are linked into the final executable by the linker. The size of the final code increases by the amount of code the linker needs to insert from the libraries. Dynamically linked libraries are not linked into the executable at link time, although references are resolved; instead at run time the libraries are linked in (by a run time linker). Dynamically linked libraries are significantly better than static libraries and should be used whenever possible for the following reasons:
There may be some drawbacks to dynamic libraries as well such as:
Author's bioCopyright © 2003 by Alan Pae. All rights reserved.
Thanks to Alan Pae for permission to re-publish the article. |
||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||