Applying a patch

To apply a patch to just one file, use

patch -ipatch
To apply a file to a source tree, use
patch -ipatch -p n
where n is however many path components in the patch file that should be ignored. For example, if the patch file specifiles dir1/file.c, and all components should be used, then specify -p 0.

Compiling threaded code

Compiling threaded code usually requires special flags, defines, or libraries. Most compilers provide some flag that automatically sets everything.

gcc

Use -pthread.

Forte (Sun)

Use -mt, and add -lpthread to get strict POSIX behavior.

MIPSpro

VisualAge (IBM)

Compiling threaded code is enabled when using the *_r form of the compiler. Among other things, this will add the option -qthreaded. This option can be set separately, but setting this option does not enable all the settings that you get when you use *_r.

Creating a patch

It seems that it's easiest to create patches using the GNU tools, so the below assumes you are using those.

First create two adjacent directories, one old and one new. Then run

diff -Naur old new

The names old and new should not contain any slashes. The -N option specifies that the patch should add and delete any new files. The -a option specifies that the patch should include binary files. The -u generates time stamps and context. The -r option specifies a recursive diff.

C++ and dlopen()

Generally speaking, this seems to work okay.

g++/Linux

Later versions (something like 3.x) versions of g++ use the address of type objects for equalilty comparison. This can create a problem if the DSO has its own symbol for a type. To make the DSO use the symbol in the executable, it's necessary to use -rdynamic, which actually passes -export-dynamic to the linker. (Strangely, the ld manpage lists this as --export-dynamic (with two hyphens). I'm not sure why there is this discrepancy.) This is discussed more in the GCC FAQ entry.

C++ Templates and Libraries

This note looks at the template issues encountered when deploying reusable objects. These reusable objects are binary entities, and must be self-contained. Any templates used internally cannot be instantiated at the time the executable is actually created, because the source is not available at that time. (In this section, I will use the word object in the linker sense, not the OOP sense.)

There are three kinds of reusable objects that one might wish to create: archives, shared objects, and relocatable objects. Each presents slightly different problems, but the goal is to include all necessary templates without also creating multiply-defined symbols, which can sometimes be tricky.

Archives and shared objects are commonly deployed as reusable objects, but one can imagine also deploying static objects. This would allow the user to link the functionality of the object statically into the executable, and thus not have to deal with dynamic loading issues. Deploying as an archive could achieve this same goal in some cases, but not in the case of "plug-in"-like components, because there may be no initial reference to anything in the archive. (This could be worked-around by specifying that each such plug-in must define a unique symbol. On the link line, we could then specify that symbol as initially undefined, thus forcing the linker to include the object. This is somewhat awkward, however, and prone to error if the user forgets to undefine the special symbol.)

Linux g++ 3.0

g++ (by default) uses compile-time instantiation. All templates are instantiated into the relocatable object in a special section. At link time, the linker eliminates duplicate instantiations.

This should work fine for all reusable objects, since any duplicates are removed by the linker automatically.

SGI MIPSpro 7.3

The MIPSpro compilers use link-time instantiation. During compilation, the compiler records what templates a translation unit is capable of compiling. During linking, any missing templates are assigned to a translation unit, and that translation unit is recompiled with a directive to instantiate that template. So no additional object files for the templates are created.

It appears that all implicit template instantiations are defined as weak symbols. This means that archives should work fine, since the linker will allow multiply defined weak symbols, and also prefer any specializations over weak symbols.

Shared objects should also work fine. All instantiations will be put into one shared object, and the linker will select one of the weak instantiations.

Relocatable objects should also work fine. If the same template is in two relocatable objects, they will be weak, and therefore okay.

Sun Forte 6

The Forte compiler instantiates templates at compile-time into a template repository. The compiler just aggregates everything together when asked to create an archive or shared object.

For archives, this seems to work okay. Each template symbol is instantiated into its own object file. So duplicates are fine, because the linker will use the first symbol it finds. If the symbol is already present in a .o file, it will simply ignore the symbol in the archive (assuming it is in a separate object).

For shared objects, this also works okay, because symbol resolution for shared objects by default allows multiply-defined symbols.

For static relocatable objects, this does not work, because the object may contain a template that is present elsewhere. For example, the relocatable object may contain instantiations for "list". These instantiations may already be present in the repository, however, because the application source code may be using them.

There seems to be no good way to handle this using the existing Forte mechanisms. There are a number of different instantiation schemes (static, global, etc.), but none of them seem to work.

Static instances places all instantiations into the current compilation unit as a local symbol. This is somewhat similar to the g++ model, but differs in that during link time, the multiple instances are not eliminated. Thus, any code that depends on sharing template instances, like a mutable static data member, will not work.

Global instances also instantiates into the current compilation unit, but as a global symbol rather than as a local symbol. This obviously creates numerous multiply-defined symbols.

Explicit instances instantiates explicitly instantiated templates into the current compilation unit. Implicit instantiations are not instantiated. This doesn't help our problem. A library that uses "list" still doesn't know what to do. If it explicitly instantiates, it runs the risks of multiple definitions. If it doesn't, it just won't get satisfied.

Semi-explicit instances is similar to explicit instances, but will also instantiate implicit templates within an explicit template. The problems are the same.

So it appears that the only real solution for Forte is to write a small ELF utility that will change all globally-defined symbols in the repository to weak symbols.

C++ Static Object Initialization Order

General

The initialization order of static objects within a translation unit is in the order in which their definition appears in the translation unit. There is no ordering guarantee for objects in different translation units other than that given below.

It is unspecified whether or not a static object is initialized before the first statement of main. If it is not, then it is guaranteed to be initialized before the first use of any object or function defined in the same translation unit.

For a library, we want the library to initialized before first use. If a static object might use the library, this could cause a ordering problem.

A number of techniques are possible to workaround this problem. One way is to use a static initializer object that is defined at least once before the definition of any static object whose initialization uses the library.

The constructor for this initializer object increments a counter to keep track of how many times it's called. The first time it's called, it will initialize the library.

Likewise, the destructor will decrement the counter. The last time it is called it can clean-up the library.

A simple way to assure this is to follow the two rules:

  1. Any header file that defines a static object should include the library initialization header file.

    This is to insure that the library initializer object will be initialized before the static object defined by the header file.

  2. Any file with a static object should include the library initialization header file.

    This again is to make sure that the library initializer object will be initialized before the static object defined by the file.

Strictly speaking, we only need to include the library initialization header file when the defined static object has a constructor which depends on the library. This can be hard to determine though, since the dependency may span several objects, and therefore not be obvious from the code for the static object.

So the above rules will define the initializer object more often than necessary, but this normally should not be a problem.

Templates

Templates with static data members can complicate the ordering problem. Sun's Forte compiler instantiates each static data member into a separate .o. But when it instantiates it, it ignores any definitions that might have been in the original .cc or .h. Thus, no initializer object will be present in the translation unit, and the constructor might be called before the the library is initialized.

No good solution, but some possibilities:

  1. The initializations occur in the order of the .o files to the linker. Furthermore, that of templates ocurr before the .o's included on the link line.

    The order of the template .o's is controlled by the compiler driver. It might be possible to munge the CC_state file in SunWS_cache, but it looks hard.

  2. If we can cause one file to be compiled with one of the other instantiation models, the template data members might go into that .o. That .o can also have the initializer object definition. This is actually a pretty good solution, but will involve significant Makefile support.

  3. If we can cause the whole template to be instantiated into one file, then we might be able to declare the initializer object as another static data member ahead of all others. Neither explicit instantiation nor using the -template=wholeclass option forced this to happen, so it may not be possible.

Common HTML Character Entity References

soft hyphen ­ ­ ­
capital sigma Σ Σ Σ
thin space    
en space    
em space    
en dash – –
em dash — —
left single quote ‘ ‘
right single quote ’ ’
left double quote “ “
right double quote ” ”
horizontal ellipsis … …
single prime ′ ′
double prime ″ ″
minus sign − −

Creating a shared library

Creating shared libraries should normally be done with the compiler front-end, and not by running the linker directly. This is especially important for C++, since the templates may not be instantiated into the object files.

The options given below apply equally to C and C++.

The soname in the examples below is hard-coded into the library, and is used for resolving library dependencies. From Sun's Linker and Libraries Guide:

The recording of a dependency in a dynamic executable or shared object will, by default, be the filename of the associated shared object as it is referenced by the link-editor. For example, the following dynamic executables, built against the same shared object libfoo.so, result in different interpretations of the same dependency:

$ cc -o ../tmp/libfoo.so -G foo.o
$ cc -o prog main.o -L../tmp -lfoo
$ dump -Lv prog | grep NEEDED
[1]     NEEDED   libfoo.so
$ cc -o prog main.o ../tmp/libfoo.so
$ dump -Lv prog | grep NEEDED
[1]     NEEDED   ../tmp/libfoo.so
$ cc -o prog main.o /usr/tmp/libfoo.so
$ dump -Lv prog | grep NEEDED
[1]     NEEDED   /usr/tmp/libfoo.so

As these examples show, this mechanism of recording dependencies can result in inconsistencies due to different compilation techniques. Also, the location of a shared object as referenced during the link-edit might differ from the eventual location of the shared object on an installed system. To provide a more consistent means of specifying dependencies, shared objects can record within themselves the filename by which they should be referenced at runtime.

IRIX

-shared -soname soname -o output_path

Linux

-shared -Wl,-soname,soname -o output_path

Sun Workshop

-G -ztext -h soname -o output_path

The -ztext option verifies that all symbols are resolved. If creating a shared object which will be dynamically loaded into an executable, omit the -ztext option, since some of the symbols will be resolved by the executable itself.

Creating a C or Fortran static library (archive)

A static library is just an archive of object files (.o files). Archives (files created with the ar command), contain a symbol index to assist the linker in locating the appropriate object files. The ranlib command used to be used to generate this index, but most ar implementations these days automatically generate the index.

Traditionally, the ordering of object files within an archive was significant. An archive in which the files were topologically sorted based on an ordering determined from the dependencies could be processed faster. The tools for this are lorder, which extracts the dependencies, and tsort, which performed the sort. These tools seem to be rarely used these days, presumably because computers are faster.

AIX

AIX has two different formats, the Big Archive Format and the Small Archive Format. The latter only supports 32-bit object files. The Big Archive Format is the default, and seems to be the reasonable choice.

rm -f archive
ar -qoc archive file1 file2 ...

The q option means to quickly append files to the archive. The o option requests ar to order the files for maximum efficiency. The c option suppresses the normal warning when creating an archive. You should remove the archive first, otherwise the files will be appended to the existing archive.

The symbol index is generated automatically.

IRIX

rm -f archive
ar -qc archive file1 file2 ...

The q option means to quickly append files to the archive. The c option suppresses the normal warning when creating an archive. You should remove the archive first, otherwise the files will be appended to the existing archive.

The symbol index is generated automatically.

Linux

rm -f archive
ar -rsc archive file1 file2 ...

The GNU version of ar treats the q option as a synonym for r, so we just use r. The s option is necessary because otherwise it will not create a symbol index. The c option suppresses the normal warning when creating an archive. You should remove the archive first, otherwise the files will be appended to the existing archive.

Sun Workshop

rm -f archive
ar -qc archive `lorder file1 file2 ... | tsort`

The q option means to quickly append files to the archive. The c option suppresses the normal warning when creating an archive. You should remove the archive first, otherwise the files will be appended to the existing archive.

The symbol index is generated automatically.

The use of lorder and tsort is not really necessary, but might speed up linking a bit.

Creating C++ static libraries (archives)

When creating an archive (.a file) from C++-generated object files, the object code for any templates must also be included.

IRIX

-ar -o archive obj1 obj2 ...

Linux

If using g++ in default mode, all templates referenced in a source file will be instantiated into the object file. This means ar can be used normally.

Solaris Workshop

-xar -o archive obj1 obj2 ...

Creating an executable with a run path

A dynamically-linked executable needs to locate its dynamically-linked libraries at run time. If these libraries are not in the standard locations, the run-time linker needs to be informed of their locations. One mechanism is through the use of the LD_LIBRARY_PATH environment variable. Another mechanism is to store the locations directly in the executable itself through the use of a run path. Setting the run path does not preclude the use of LD_LIBRARY_PATH.

In the options shown below, dirs should be a colon-separated list of directories.

IRIX

-rpath dirs

Linux

-Wl,-rpath=dirs

Solaris Workshop

-R dirs

Dependence of debug-enabled executable on original object

An executable compiled with debugging enabled may refer back to the original .o or source files from which it was built. These files therefore need to be preserved. Some debuggers provide a mapping mechanism to map the original path prefixes to new ones, thus allowing the original files to be moved. This may also be necessary for situations where the source is on a file system that is under control of an automounter. The path needed to trigger the automounter might not be the actual path of the file.

IRIX MIPSpro

Appears to require only the .o file.

Linux gdb

Appears to require only the .o file.

Solaris Workshop

Requires both the .o file and the original source, unless the -xs option is used, which instructs the compiler to place debugging information into the executable.

Determining the compiler version

gcc

--version

IRIX MIPSpro

-version

Solaris Workshop

-verbose=version
-V

The first form doesn't work with Workshop 5.x.

Determining the architecture and platform from defined macros

AIX

_AIX
_AIX32
_AIX41
_AIX43

The different numbers indicate the version of the OS.

GCC

__GNUC__

This is set to the major version number, it seems.

IRIX

__sgi

IRIX MIPSpro

__MIPS_SZLONG

This is the size of a long in bits. Since IRIX uses the LP64 model, it is also the size of pointers.

Linux

__linux

Solaris

__sun
_LP64

Indicates that longs and pointers are 64-bits.

Sun Workshop

__SUNPRO_CC

Set to version.

Disabling compiler warnings

In the text below, n represents the warning number.

AIX

-qsuppress=n

IRIX

-woff n

Linux

Gcc appears to have no way to turn off warnings by number.

Solaris

The Forte compilers appear to have no way to turn off warnings by number.

Displaying the runpath of a shared object

AIX

IRIX

dump -Lv object | grep RPATH

Linux

readelf --dynamic object

Solaris

dump -Lv object

Execution of init sections when loading dyamic objects

All platforms execute these sections. If the loading of an object is done during init processing of the executable itself, IRIX will delay execution of the init sections till the init processing of the executable itself is done. Linux and Solaris do not.

Extracting the whole archive during link

GNU ld

--whole-archive
--no-whole-archive

If this is to be used from gcc or g++, it needs to given as -Wl,-whole-archive and -Wl,-no-whole-archive.

IRIX MIPSpro

-all
-notall

Solaris 8

-z allextract
-z defaultextract

Forcing no undefined symbols when generating shared objects

gcc

-Wl,--no_undefined

At least with C++ objects, this does not work very well. It appears that there are symbols that are present during the actual runtime linking that are not present during the ld phase.

IRIX MIPSpro

-no_unresolved

Seems to work well with C++ objects.

Solaris

-z defs

At least with C++ objects, this does not work well. The -G option does not link with the actual libraries that it links with when linking an executable.

Generating PIC code

gcc

-fpic

Some machines limit the size of the global offset table with this option. For these machines, use -fPIC.

-fPIC

For machines with limitations on the size of the global offset table, this option will allow the maximum possible size. Currently, this only makes a difference on m68k, m88k, and SPARC.

IRIX MIPSpro

-KPIC

This is the default. To generate non-PIC code, specify -non_shared.

-non_shared

Generate non-PIC code.

Solaris Workshop

-Kpic

Generate position-independent code for use in shared libraries (small model). Permits references to at most 2**11 unique external symbols on 32-bit architectures, 2**10 on 64-bit.

-KPIC

Generate position-independent code for use in shared libraries (large model). Permits references to at most 2**30 unique external symbols on 32-bit architectures, 2**29 on 64-bit.

Linking shared object against archive that executable also links against

A shared object may be created as a plug-in to be loaded into an executable. The executable and the shared object may be statically linked against an library archive. This creates two copies of some symbols. Using a shared library instead of an archive will solve the problem, but for management reasons, it may be preferrable to use a static archive.

On Solaris and Linux, there doesn't seem to be a problem. Two copies appear to exist, but only one symbol seems to be used for all resolutions. This seems to give the desired behavior, even for situations where a static variable is defined in a translation unit. That static variable must be accessed indirectly via global symbol (unless in an .init section), like a global function that uses the static variable, and for that global function, only one definition will be used for all references.

On IRIX, there does seem to be a problem.

It seems like the best solution is to simply not link the shared object against the archive. This means that the executable must be sure to include everything in the archive, even if it is not used by the executable.

MIPS ISAs

SGI computers are based on a number of MIPS chips. Each chip uses a version of the instruction set architecture (ISA) and compiling on one may mean that the executable will not run on a different SGI machine. Here are the known ISAs for different machines.

Chip ISA Width
R4000 MIPS-3 32
R4400 MIPS-3 32
R5000 MIPS-4 32
R8000 MIPS-4 64
R10000 MIPS-4 64

Miscellaneous useful compiler options

VisualAge (IBM)

Use -qtmplparse=error to make it parse template definitions.

Passing options to different compilation phases

Compilation generally occurs in different phases. Most front-ends do not accept all possible options for all possible phases. Special syntax is necessary to pass an option to a different phase.

gcc

gcc uses syntax of the form
-Wp,opt
p can be a for the assembler and l for the linker. opt can contain commas, in which case it is split into multiple options.

IRIX MIPSpro

MIPSpro uses syntax of the form
-W p,opt
p can be p for preprocessor, a for the assembler, and l for the linker, among others.

opt can contain commas, in which case it is split into multiple options.

Sun Workshop C

The Sun Workshop C compiler (cc) uses syntax of the form
-Wp,opt
p can be a for the assembler and l for the linker. opt can contain commas, in which case it is split into multiple options.

Sun Workshop C++

-Qoption p opt
p can be ld for the linker, among others. opt can contain commas, in which case it is split into multiple options.

Reliably dumping core on Linux

Threaded Linux programs do not reliably dump core. One way is to catch SIGSEGV, fork, and then have the child process, in which only the faulting thread exists, call abort. Another way was posted by:
From: Kaz Kylheku (kaz@accton.shaw.ca)
Subject: Re: abort() function doesn't produce a core dump, somebody help! 
Newsgroups: comp.programming.threads
Date: 2002-02-13 15:41:44 PST 

In article <3C6AF3BC.85BB39AC@webmaster.com>, David Schwartz wrote:
>> And did somebody found a workaround to dump the core in multithread
>> programming under linux?
>
>       Yes. Call 'fork' to create a process in which only the relevant thread
>exists, then call 'abort' in the child.

Another solution is to patch your kernel to get a direct coredump.

There are some changes to  core dump handling in kernel 2.4 I have not
looked at.

Under kernel 2.2 and older, I used to make a patch in fs/binfmt_elf.c
to allow each thread to dump core when a LinuxThreads process dies.

What happens is that each thread *wants* to core dump, because the thread
manager has given it the same fatal signal which was delivered to the
offending thread, but cannot due to the reference count on the memory
map indicating that it's shared, and because they would clash to the
same name.

As threads terminate, the reference count keeps dropping. Whether or not
you get a core dump depends on whether the last thread wants a core dump.
If the last thread to terminate your thread manager, there is no core dump.

Problem one is solved by defeating the refcount check, and problem two
is solved by writing to a file called "core." where  is the
process ID of the thread. So this way you get a core dump for each thread.
You can open up the core files one by one with GDB until you get what
you are looking for.

I don't now what's needed under 2.4, if anything.

Removing white backgrounds from the PostScript output of common applications

Many applications produce PostScript files that fill the background with white, or perhaps some other color. This can cause problems when putting two pages on one, because the background will blank out text if the pages are close together. Also, if the PostScript is to be imported and placed on a page that does not have a white background, such as when making light-on-dark slides, the white background must be removed.

FrameMaker

FrameMaker puts the following function near the beginning.

/FMBEGINPAGE { 
	FrameDict begin 
	/pagesave save def
	3.86 setmiterlimit
	0 0 moveto paperwidth 0 lineto paperwidth paperheight lineto 
	0 paperheight lineto 0 0 lineto 1 setgray fill
	/landscape exch 0 ne def
	landscape { 
		90 rotate 0 exch dup /pwid exch def neg translate pop 
	}{
		pop /pwid exch def
	} ifelse
	edown { [-1 0 0 1 pwid 0] concat } if
	xscale yscale scale
	/orgmatrix matrix def
	gsave 
} def
The line
0 paperheight lineto 0 0 lineto 1 setgray fill
should be commented out.

MATLAB

MATLAB puts a rectfill (abbreviated to rf) at the beginning of each page to clear the whole page. The sg is just a setgray.

1 sg
   0    0 6913 5186 rf

MATLAB also paints the background of the actual drawing area, and sub-drawing areas, such as the legend box.

0 4226 5356 0 0 -4226 899 4615 4 MP
PP
First, it uses the MP procedure to draw the rectangle. The MP procedure is defined as:
/MP {3 1 roll moveto 1 sub {rlineto} repeat} bdef
PP closes the path and fills it with the current color, and is defined as:
/PP {closepath eofill} bdef

eofill stands for "even-odd fill" and fill the outline with the current color obeying the even-odd rule. MATLAB uses sg to set gray-scale colors. For RGB colors, it first defines a standard set from c0 to c7.

92 dict begin %Colortable dictionary
/c0 { 0 0 0 sr} bdef
/c1 { 1 1 1 sr} bdef
/c2 { 1 0 0 sr} bdef
/c3 { 0 1 0 sr} bdef
/c4 { 0 0 1 sr} bdef
/c5 { 1 1 0 sr} bdef
/c6 { 1 0 1 sr} bdef
/c7 { 0 1 1 sr} bdef
If it needs more colors, it defines them on the spot.
/c8 { 1.000000 0.000000 0.000000 sr} bdef
c8
This means that it should be possible to change all uses of a color by just changing the definition of it.

Microsoft Word

Microsoft word puts the following near the beginning of every page.

%%EndPageSetup
0 0 612 792 re
W
n
false setSA
n
9 -11 612 792 re
[/DeviceRGB] cs 1 1 1 sc

f
0 0 0 sc
72 710.916 m
/N5 9.95999 Tf
(Page text begins here.)
The three lines
n
9 -11 612 792 re
[/DeviceRGB] cs 1 1 1 sc
should be commented out. The n operator starts a newpath. The re sets up a rectangle. The sc sets the color of the path to white (1 1 1).

Showing compiler passes

Instruct the compiler front-end to show all options and arguments for each pass.

gcc

-v

IRIX MIPSpro

-show

Solaris Workshop

C

-#
-###

The -### option shows the passes but does not execute them.

C++

-verbose=diags
-v

The first form does not work with C++ 5.0.

VisualAge (IBM)

Use -V or -v to show passes. -V shows it in the form of executable commands. -v shows it in text that is close to the command form, but not quite. So, for example, -V shows:
rm /tmp/ljljlj.o
while -v shows:
unlink: /tmp/ljljlj.o

Showing the default library search paths

IRIX MIPSpro

Unknown, but probably possible.

Linux

Unknown, but probably possible.

Solaris Workshop

The linker accepts a number of -D "tokens" to specify debugging output.
-D token1,token2
The libs token causes the linker to print out the library search path. Adding the detail token causes the linker to show actual lookup processing.

See Passing options to different compilation phases to see how to pass the -D option to the linker.

Showing defined preprocessor symbols

Instruct the compiler to dump all defined preprocessor symbols after normal processing.

gcc

-dM -E

IRIX MIPSpro

There appears to be no way to do this.

Solaris Workshop

There appears to be no way to do this.

Starting dbx from the command line

To debug a core file:

IRIX MIPSpro

dbx -p pid executable

Linux

gdb executable pid

Solaris

dbx executable pid
dbx - pid

Template dependencies in makefiles

The general principle for makefile dependencies is that file A is dependent on file B if the contents of file A should change when file B changes. This simple principle becomes platform-dependent in the case of templates, however, because different platforms use different instantiation mechanisms.

For example, if the templates are instantiated into the object file that references it, then the object file is dependent on the template definition. If, however, each template is instantiated into a separate .o, then the object file is not dependent on the template definition.

gcc

gcc instantiates all templates into the object file. Thus, the object file is dependent on the template definition.

IRIX MIPSpro

The MIPSpro compiler uses a hybrid instantiation scheme. Each template is instantiated only once for each application, but rather than instantiating each template into a separate object file, only one of the application object files is selected for instantiation.

At link time, the prelinker looks at all the object files, and if any template instantiations are missing, it selects an application object file, and recompiles it with the template definition, thus instantiating it into that object file. The templates that have been assigned to each particular file are recorded in the ii_files directory, and consulted every time the file is compiled.

Thus, in theory only one object file per template needs to be compiled when the template definition changes. Unfortunately, there is no way to determine this without parsing the ii_files directory. So, for makefiles, all object files that use a template need to depend on the template definition.

It would be nice if the MIPSpro compiler automatically checked all the template instantiations for freshness whenever the application was relinked.

Solaris Workshop

Solaris uses separate instantiation, which is handled at link time. The compiler automatically detects when template definition files have changed at link time. So, the program executable needs to depend on the template definition, but the individual object files do not.

Can't share SunWS_cache.

Template instantiation mechanisms

C++ templates are essentially glorified macros. They represent code patterns. Analogously to how regular functions have formal parameters and actual arguments, templates have template parameters and template arguments.

When a template is actually used, a template argument is supplied for each template parameter. The compiler then needs to generate the actual resulting code. This process is known as instantiation. A number of different mechanisms exist.

g++

By default g++ instantiates all templates directly into the object file. This means that each object file will have its own copy of the template code. I believe, but am not sure, that the g++ linker removes duplicates at link time.

g++ also appears to have a repository-like instantiation mechanism, but I don't know the details.

MIPSpro (SGI)

The MIPSpro compiler uses a hybrid instantiation scheme. Each template is instantiated only once for each application, but rather than instantiating each template into a separate object file, only one of the application object files is selected for instantiation.

At link time, the prelinker looks at all the object files, and if any template instantiations are missing, it selects an application object file, and recompiles it with the template definition, thus instantiating it into that object file. The templates that have been assigned to each particular file are recorded in the ii_files directory, and consulted every time the file is compiled.

Note that this means that the compiler needs to loop, since an instantiated template might require more templates.

Forte (Sun)

Forte uses separate instantiation repository, which is handled at compile time. It can also do other kinds.

VisualAge (IBM)

VisualAge has three different instantiation mechanisms.

Repository

The default mechanism is to create one template instantiation object file for every header file. The object file is created in the tempinc directory by default. Bookkeeping is kept in .C files corresponding to each template declaration file. The bookkeeping files are also stored in tempinc.

When using this mechanism, the template definition file must not be included in the template declaration file. The compiler will instantiate any templates into the .o file if it sees any template definitions, which would result in massive duplication and code bloat.

This mechanism requires that a .c file containing template definitions exist for every .h containing template declarations. It appears that there is no way to change the suffix through a command-line option, but it can be done via a pragma:

#pragma implementation ("template_definitions_file")
The pragma can be placed anywhere in the template declarations file.

The macro __TEMPINC__ will have the value 1 if this mechanism is being used.

In-Unit

If -qnotempinc is set, then it uses g++ style instantiation, but the linker definitely won't remove duplicates. When using this style, the template definition must be included in the translation unit. The __TEMPINC__ macro can be checked to decide whether or not to include the template definitions.

Registry

This mechanism is new with version 6.0 of the compiler, and is specified with -qtemplateregistry. It is actually somewhat similar to the MIPSpro mechanism. With this mechanism, the templates are instantiated into the .o files corresponding to non-template translation units. A registry is used to figure out which .o files to use, and to avoid duplicates.

Like the in-unit mechanism, this mechanism requires that the template definitions be included. The __TEMPINC__ macro can be checked to determine if the template definitions should be included.

Understanding ACLs

Solaris ACLs are powerful and flexible, but the man page is difficult to understand. This is not intended to replace the man page, but merely to make it easier to understand.

The ACL of a file consists of a series of entries. Each entry specifies the read-write-execute permissions for a user or group of users.

The ACL starts with no permissions are granted. In the text below, the symbols r, w, and x should be replaced with the corresponding letter to indicate that the permission is granted, or - to indicate that no permission is granted.

Files

user::rwx

This specifies the permissions for the owner of the file. Setting this will also change the usual (non-ACL) permissions.

user:user:rwx

This specifies the permissions granted to user user. If an entry of this form is present, the mask entry must also be present.

group::rwx

This specifies the permissions for any user belonging to the group of the file. Setting this will also change the usual (non-ACL) permissions.

group:group:rwx

This specifies the permissions granted to anyone in group group. If an entry of this form is present, the mask entry must also be present.

other:rwx

This specifies the permissions granted to all users. Setting this will also change the usual (non-ACL) permissions.

mask:rwx

This is ANDed with the final permissions. It's intended to be a convenient way to globally control the permissions on a file without looking at each entry.

Directories

In addition to the entries for files, directories can have default entries. These specify the default ACLs for newly created subdirectories and files. The presence of a default entry causes the umask to be ignored.

default:user::rwx

This specifies the default permissions for the owner of the file.

default:user:user:rwx

This specifies the default permissions granted to user user.

default:group::rwx

This specifies the default permissions for any user belonging to the group of the file.

default:group:group:rwx

This specifies the default permissions granted to anyone in group group.

default:other:rwx

This specifies the default permissions granted to all users.

Warn about missing prototypes

By default, most C compilers do not warn about missing prototypes. These options instruct the compiler to issue warnings or fatal errors when functions are called without prototypes.

gcc

-Wstrict-prototypes -Wimplicit-int -Werror-implicit-function-declaration
The -Wstrict-prototypes option instructs the compiler to issue warnings for declarations of the form:
type f();
The -Wimplicit-int option specifies the compiler to issue warnings for function declarations that do not specify a return type. The -Werror-implicit-function-declaration option instructs the compiler to issue an error for functions that are called with no declared prototype.

IRIX MIPSpro

-diag_error 1196,1116
Diagnostic 1196 concerns functions called without prototypes. Diagnostic 1116 concerns functions that fail to return a value.

Solaris Workshop

-v
Another significant difference between C and C++ that is occasionally surprising is that
int f();
in C does not declare a function that takes no arguments. Instead, it declares a function that takes unspecified arguments. To declare a function that takes no arguments, you must use
int f(void);