Home / Documents / Guides / Compile
 
 
 
 
 
 
 
 
 
 
 
 
 DOCUMENTS 
 GUIDES 

Compiling source code

Alan 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.

Introduction

A 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 system

For 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:

tools: sccs, lex, yacc, make, nm, truss, ld, as SUNWbtool, SUNWsprot, SUNWtoo, SUNWcpp
libraries and headers SUNWhea, SUNWarc, SUNWlibm, SUNWlibms SUNWdfbh, SUNWcg6h, SUNWxwinc, SUNWolinc, SUNWxglh, SUNWlibC, SUNWzlib, SUNWscpu
bit development SUNWarcx, SUNWbtoox, SUNWdplx, SUNWscpux, SUNWsprox, SUNWtoox, SUNWlmsx, SUNWlmx, SUNWlibCx, SUNWzlibx
ucb compatibility SUNWsra, SUNWsrh

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 variables

There are a handful of environment variables that you can set that will have an effect on your ability to compile software. These are:

CC , CFLAGS compiling C code
CXX, CPPFLAGS compiling C++ code
LDFLAGS the linking stage
TMPDIR compiling any code
LD_LIBRARY_PATH after the code is compiled

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:

CC=gcc
tells configure that your C Compiler (CC) is gcc.
CFLAGS=-03
tells configure that you want the compiler to use the following optimization flags. By using optimization flags you can adjust how the code is compiled. For instance, -03 tells the compiler to optimize the code for speed. There are other switches you can use and some of them are listed at the end of this page. You should check the GCC manual for all the different flags that you can set to see if there are any of those you think you should use. If you are currently running SPARC hardware it is strongly suggested that you set at least -mv8, so GCC can use some hardware registers that otherwise would not be available for it to use. In addition to compiler optimizations, you can also add include directories here. The terms include and header files are used interchangeable. If the compiler cannot find a filename.h file, you can tell it to look in the directories listed here to help the compiler find the files it needs to compile the program.

An example would be:

CFLAGS=-I/usr/local/include

CXX=g++
tells configure that your C++ compiler is named g++, the GNU equivalent of c++.
CPPFLAGS=-I/usr/local/include
same as CFLAGS listed above, except for use with C++.
LDFLAGS="-L/usr/local/lib -R/usr/local/lib"
Linking is the final stage of compiling. One of the things that you need to be concerned with is where do the programs libraries go. Libraries can be thought of as binaries as the system does not know where they are unless you specifically tell it. When you go to run a program you will sometimes run into a situation where you need to set LD_LIBRARY_PATH. On Solaris 8 and greater you can get around this by using the crle command instead. Or, you can fix the issue right here so you don't have to do either. The LD_LIBRARY_PATH variable is to libraries what PATH is to executables. When you run a program that is dynamically linked, it will search LD_LIBRARY_PATH directories to find the libraries that it needs to run. If the program cannot find all its libraries, it won't run. Just like PATH, LD_LIBRARY_PATH is a colon-delimited list of directories.

There are two parts to LDFLAGS. The first part is used for compiling, that's the -L part. The other part is used at runtime, that's the -R part. When your telling GCC to look into this directory to find the libraries that you need to find to compile the program, you set the -L half of LDFLAGS. When your telling GCC to include the path to the library so the executable will know where to find them when you go to run the program, you use the -R part. Properly setting -R should remove the need to use LD_LIBRARY_PATH or crle. When you type the name of the executable, it already knows the path to the library files.

There are two types of library files. Static libraries files end in .a Dynamic or shared library files end in .so To see which libraries an executable program uses, use the ldd command.

ldd binary_program_name

this command will send an output to your screen with all the library files that the program needs to run. If it can find the library, it will display the full path to and the name of the library. If it cannot find the library file, it will report, "(not found)". Unless the program can find all the library files, it will not run. There will be a discussion on static versus dynamic libraries later on.

TMPDIR=/tmp
If TMPDIR is set, it specifies the directory to use for temporary files. GCC uses temporary files to hold the output of one stage of compilation, which is to be used as input to the next stage: for example, the output of the pre-processor, which is the input to the compiler proper.

Those are the main environment variables that you need to be concerned with.

For CFLAGS you can set:

For SPARC Hardware:

-0
-01
Optimize. Optimizing compilation takes somewhat more time, and a lot more memory for a large function. Without '-0' the compiler's goal is to reduce the cost of compilation and to make debugging produce the expected results. Statements are independent: if you stop the program with a breakpoint between statements, you can then assign a new value to any variable or change the program counter to any other statement in the function and get exactly the results you would expect from the source code. With '-0' the compiler tries to reduce the code size and execution time, without performing any optimizations that take a great deal of compilation time.
-02
Optimize even more. GCC performs nearly all supported optimizations that do not involve a space-speed trade-off. The compiler does not perform loop unrolling or function in lining when you specify '-02'. As compared to '-0', this option increases both compilation time and performance of the generated code. '-02' turns on all optional optimizations except for loop unrolling, function inlining and register renaming. It also turns on the '-fforce-mem' option on all machines and frame pointer elimination on machines where doing so does not interfere with debugging. Please note the warning under '-fgcse' about invoking '-02' on programs that use computed gotos.
-03
Optimize yet more. '-03' turns on all optimizations specified by '-02' and also turns on the 'finline-functions' and '-frename-registers' options.
-I dir
Add the directory dir to the list of directories to be searched for header files. Directories named by '-I' are searched before the standard system include directories. The terms header files and include are used interchangeably.
-llibrary
-l library
Search the library named library when linking (The second alternative with the library as a separate argument is only for POSIX compliance and is not recommended.) If you're going to be compiling software that uses sockets (any program that uses a network connection), you may need to tell the program about the Solaris socket libraries. These are socket and nsl. To set them, use -lsocket -lnsl.
-mv8
-msparclite
These two options select variations on the SPARC architecture. By default (unless specifically configured for the Fujitsu SPARClite), GCC generates code for the v7 variant of the SPARC architecture. '-mv8' will give you SPARC v8 code. The only difference from v7 code is that the compiler emits the integer multiply and integer divide instructions which exist in SPARC v8 but not in SPARC v7.
-mcpu=cpu_type
Set the instruction set, register set, and instruction scheduling parameters for machine type cpu_type. Supported values for cpu_type are 'v7', 'cypress', 'v8', 'supersparc', 'sparclite', 'hypersparc', 'sparclite86x', 'f930', 'f934', 'sparclet', 'tsc701', 'v9', and 'ultrasparc'. Default instruction scheduling parameters are used for values that select an architecture and not an implementation. These are 'v7', 'v8', 'sparclite', 'sparclet', 'v9'. Here is a list of each supported architecture and their supported implementations.
   v7:            cypress
   v8:            supersparc, hypersparc
   sparclite:     f930,f934,sparclite86x
   sparclet:      tsc701
   v9:            ultrasparc
   
-mtune=cpu_type
Set the instruction scheduling parameters for machine type cpu_type, but do not set the instruction set or register set that the option '-mcpu=cpu_type' would. The same values for '-mcpu=cpu_type' can be used for '-mtune=cpu_type', but the only useful values are those that select a particular cpu implementation. Those are 'cypress', 'supersparc', 'hypersparc', 'f930', 'f934', 'sparclite86x', 'tsc701', and 'ultrasparc'.
-32
-64
Generate code for a 32-bit or 64-bit environment. The 32-bit environment sets int, long and pointer to 32 bits. The 64-bit environment sets int to 32 bits and long and pointer to 64 bits.

For Intel Hardware:

-mcpu=cpu_type
Tune to cpu_type everything applicable about the generated code, except for the ABI and the set of available instructions. The choices for cpu_type are 'i386', 'i486', 'i586', 'i686', 'pentium', 'pentium-mmx', 'pentiumpro', 'pentium2', 'pentium3', 'pentium4', 'k6', 'k6-2', 'k6-3', 'athlon', 'athlon-tbird', 'athlon-4', 'athlon-xp' and 'athlon-mp'.

While picking a specific cpu_type will schedule things appropriately for that particular chip, the compiler will not generate any code that does not run on the i386 without the '-march=cpu_type' option being used. 'i586' is equivalent to 'pentium' and 'i686' is equivalent to 'pentiumpro'. 'k6' and 'athlon' are the AMD chips as opposed to the Intel ones.

-march=cpu_type
Generates instructions for the machine type cpu_type. The choices for cpu_type are the same as for '-mcpu'. Moreover, specifying 'march=cpu_type' implies 'mcpu=cpu_type'. -386 -486 -mpentium -mpentiumpro These options are synonyms for '-mcpu=i386', '-mcpu=i486', '-mcpu=pentium', and '-mcpu=pentiumpro' respectively. These synonyms are deprecated.
-mfpmath=unit
Generate floating-point arithmetic's for selected unit, unit. The choices for unit are:

'387'

Use the standard 387 floating point coprocessor present majority of chips and emulated otherwise. Code compiled with this option will run almost everywhere. The temporary results are computed in 80bit precision instead of precision specified by the type resulting in slightly different results compared to most of other chips. See '-ffloat-store' for more detailed description. This is the default choice for i386 compiler.

'sse'

Use scalar floating point instructions present in the SSE instruction set. This instruction set is supported by Pentium3 and newer chips, in the AMD line by the Athlon-4, Athlon-xp and Athlon-mp chips. The earlier version of SSE instruction set supports only single precision arithmetic's, thus the double and extended precision arithmetics is still done using 387. Later version, present only in Pentium4 and the future AMD x86-64 chips supports double precision arithmetic's too. For i387 you need to use '-march=cpu_type', '-msse' or '-msse2' switches to enable SSE extensions and make this option effective. For x86-64 compiler, these extensions are enabled by default.

The resulting code should be considerably faster in majority of cases and avoid the numerical instability problems of 387 code, but may break some existing code that expects temporaries to be 80 bit. This is the default choice for x86-64 compiler.

'sse,387'

Attempt to utilize both instruction sets at once. This effectively double the amount of available registers and on chips with separate execution units for 387 and SSE the execution resources too. Use this option with care, as it is still experimental, because GCC register allocator does not model separate functional units well resulting in instable performance.

These '-m' switches are supported in addition to the above on AMD x86-64 processors in 64-bit environments.

-m32
-m64
Generate code for a 32-bit or 64-bit environment. The 32-bit environment sets int, long and pointer to 32 bits and generates code that runs on any i386 system. The 64-bit environment sets int to 32 bits and long and pointer to 64 bits and generates code for AMD's x86-64 architecture.

Running configure

You 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 GCC

By now, hopefully you have a good idea already of how to compile GCC. Let's refresh so we're all on the same page.
  1. You've ftp'd GCC from http://www.sunfreeware.com or installed it from the companion CD or whatever and this step is complete.
  2. You've added the bin directory for GCC to your path statement.
  3. You've add /usr/ccs/bin to your path statement after the directory for gcc
  4. You've verified that all the packages mentioned in Casper Dik's FAQ are installed on your system.
  5. You've set the environment variable LD_LIBRARY_PATH so that it points to GCC's lib directory. Typically this is /usr/local/lib.
  6. If you type gcc --version from any directory, it reports your currently installed version of GCC
  7. If you type `make` from any directory, it runs the program.
  8. You've read through the GCC Manual and setup all the optimization flags you think should be set for your system. If you're in doubt here, ask for help, or simply skip this step. Your programs will still compile.
  9. You've ftp'd the current version of GCC from ftp://ftp.gnu.org/gnu/gcc
Ok we're now ready to compile the compiler. The first step as you already know is to unzip and then untar the gcc code onto the system. After you've unzipped and untarred the tar ball, read through the "Install" directory. You can also peruse the gcc/doc directory if you desire. Be sure to check the `host/target specific installation notes`. After your done reading the documents, your ready to run configure.

./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 problems

OK, 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 instructions

You 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

  • uncomment HasGcc2 section
  • uncomment HasCplusplus section
  • C uses the convention of /* */ to denote a comment. Simply remove the lines above and below the HasGcc2 and HasCplusplus sections.
  • Next look for the following line:
    /* #define PreIncDir /usr/local/lib/gcc-lib/sparc-sun-sunos4.1.3/2.5.8/include */
    

    Uncomment this line by removing the first two, and the last two characters, and then adjust the path so that it points to your include directory. Use the one that is now uncommented as a guide.

Changes to sun.cf

  • The fourth line of the file is:
      #define HasSunC YES 
    

    Change YES to NO

  • Further down in the file look for the following line:
      #define OptimizedCDebugFlags -O2 -msupersparc
    

    You can adjust this line to set the optimizations that you would like GCC to use.

Changes to svr4.cf
  • Check the path and binary names of the programs listed, adjust if you need to.

Now you'll need to run:

xmkmf -a -DuseInstalled -I/home/usr/X11/config
make all
make install

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 instructions

If 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
gcc foo.o -o foo

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

-o option if the directory contains more than one *.c (*.C, *.cc, *.cxx) file. In this case, the resulting binary will get the standard name 'a.out', you then might want to rename it to something sensible.

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 package

For instruction on how to create Solaris packages reffer the followig pages:

Static libraries versus dynamic libraries

You 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:

  • Programs share dynamically linked libraries but cannot share statically linked libraries. Since many of the common libraries are probably already loaded on the system, and since many different programs are likely to use common libraries, this will significantly cut down on the memory used (wasted) by a running system.

  • Since the library is not linked into the executable located in the file system, the executable is much smaller. This saves file space and makes the executable faster to load.

  • Statically compiled programs are appropriate only if there is a security concern about changes to libraries or for executables that need to be runnable even in the event of system problems that prevent libraries from loading. Root's shell is usually statically linked for this reason. Static binaries are often located in directory /sbin.

There may be some drawbacks to dynamic libraries as well such as:

  • Additional processor time is needed to load and link-edit the library routines during runtime. Also, the library's position-independent coding might execute more slowly than the relocatable coding in a static library.
  • Another issue with dynamic libraries is what happens if your executable and your libraries are on different partitions. If the partition that your libraries are on is unavailable, so is your application.

Author's bio

Copyright © 2003 by Alan Pae. All rights reserved.


Thanks to Alan Pae for permission to re-publish the article.
Original text: http://www.geocities.com/paedalbu/compile

Logo
Top
Last modified: 2003-03-15