11.1. Creating shared objects from C++ source codes

The C++ language, although similar in some respects to the C language, offers many additional facilities. One of these is known as function overloading, which makes it possible to have multiple functions with the same name but different parameter lists. This feature means it is not possible to use the function name alone as a unique identifier in the symbol table of an object file. For this reason, function names in C++ are mangled to produce the symbol name. The mangling uses a code to indicate the number, type, and ordering of parameters to the function.

The term mangle has a specific meaning in compiler products, especially in the C++ compilers, because the language standard allows you to have multiple instances of the same name function, but each function will be used with specified parameter variable types. For example, the following two function definitions can be mangled (this is a pseudo-mangling example):

int add(int, int)
double add(double, double)

to the following function names during the compilation process:

add_Fii(int, int)
add_Fdd(double, double)

Please note that the mangled names are referred to as symbols only after the compilation; therefore, you do not have to understand what mangled names will be produced after the compilation process (see 6.3.4, “The c++filt utility” on page 243 for further information about the mangling process).

It is the name mangling feature of C++ that means the process of creating a shared object, which includes object code created by the C++ compiler, is slightly more complicated than when using code produced by the C compiler.

Although it would be possible to create import and export files manually, the process is time consuming, since a unique symbol name is required for each instance of an overloaded function.

11.1.1. Creating a C++ shared object

VisualAge C++ for AIX provides the makeC++SharedLib command, which performs most of the dirty work behind the scenes. It is included in the vacpp.cmd.tools fileset and installed automatically when the product is installed, as shown in the following example:

# lslpp -w /usr/vacpp/bin/makeC++SharedLib
  File                                         Fileset               Type
  -----------------------------------------------------------------------------
  /usr/vacpp/bin/makeC++SharedLib              vacpp.cmp.tools       File

The process of creating a shared object from C++ source codes is very similar to the process of creating a shared object from C source codes. See 2.8, “Creating shared objects” on page 92 how to create shared objects from C program source codes.

To create a shared object from C++ source codes, do the following:

1.
Compile the C++ source code from which you wish to create to a shared object. For example, the following example will produce two object modules, cppsrc1.o and cppsrc2.o, in the current directory:

$ xlc -c cppsrc1.C cppsrc2.C

2.
Run the makeC++SharedLib command[1] to create the shared object with the object file names. The following example shows how to create a shared object, shr_cpp_12.o, from the object modules created in the previous step:

[1] If you add the directory path, /usr/vacpp/bin, into the PATH environment value, you do not have to invoke the makeC++SharedLib command with the full pathname.

$ /usr/vacpp/bin/makeC++SharedLib -o shr_cpp_12.o cppsrcl.o cppsrc2.o

Use the -G option when you want to create a shared object enabled for use with run-time linking, or one that uses the libname.so format. For example:

$ /usr/vac/bin/makeC++SharedLib -G -o shr_cpp_12.so cppsrc1.o cppsrc2.o

If the makeC++SharedLib command is used to build the C++ shared libraries and export symbols, make sure that any system libraries required by the shared object are always specified with the -l option (for example, -IX11) and not by name (for example, /usr/lib/libX11.a) on the command line. This allows the system libraries to be simply referenced by the shared object being created and not go through the special C++ related processing.

11.1.2. Generating an export file

Another very useful option of the makeC++SharedLib command is the ability to save the export file that is generated behind the scenes and normally discarded after use. If saved, this export file can then be used as an import file when creating another shared object. The -e expfile option is used to save the export file. Note that the export file produced does not have an object file name field (#!) on the first line, so one will have to be manually added, if required.

11.1.3. The -qmkshrobj option

Starting from Version 5, VisualAge C++ for AIX provides a useful compiler option, -qmkshrobj, which is used to instruct the compiler to create a shared object from previously created object files and archive libraries. It provides similar functionality to the makeC++SharedLib command and, in addition, makes it much easier to create shared objects that use template functions. See 11.2, “Shared objects with templates” on page 402 for more detailed information.

For example, to create a shared object shr1.o from the source1.o and source2.o files, use the following command:

$ xlC -qmkshrobj -o shr1.o source1.o source2.o

The -G option can be also used in conjunction with the -qmkshrobj option to create an object that uses the run-time linking shared object, as shown in the following example:

$ xlC -G -qmkshrobj -o libshr1.so source1.o source2.o

To specify the priority of the shared object, which determines the initialization order of the shared objects used in an application, append the priority number to the -qmkshrobj option. For example, to create the shared object shr1.o, which has an initialization priority of -100, use the following command:

xlC -qmkshrobj=-100 -o shr1.o source1.o source2.o

If none of the -bexpall, -bE:, -bexport:, or -bnoexpall options are specified, then using the -qmkshrobj option will force the compiler to generate an exports file that exports all symbols. This file can be saved for use as an import file when creating other shared objects, if desired. This is done using the -qexpfile=filename option. For example:

xlC -qmkshrobj -qexpfile=shr1.exp -o shr1.o source1.o source2.o

11.1.4. Mixing C and C++ object files

In addition to the mangling of symbol names, the C++ language differs from the C language in the way function arguments are passed on the calling stack. The C language pushes arguments onto the stack right to left, which means the left-most argument is top-most on the stack. For various reasons, the C++ language uses right to left instead. This is termed linkage, and a complication unit can have both the C and C++ linkages.

When mixing C and C++ code together, it is necessary to use a linkage block to call a C routine from a C++ routine. This is to prevent the compiler from mangling the name of the C routine, which would result in a symbol name that could not be resolved. For example, to call the C function, foo(), from C++ code, the declaration of foo must be in an external linkage block, as shown in the following code fragment:

extern "C" {
    void foo(void);
}
class1::class1(int a)
{
    foo();
}

If the declaration of foo() was not contained in the extern “C” block, the C++ compiler would mangle the symbol name to foo__Fv.

When mixing C and C++ objects within a single shared object, either the makeC++SharedLib command (which uses the C++ compiler) or the -qmkshrobj option of the C++ compiler should be used to create the shared object. Do not use the C compiler or the linker, since they may not produce the correct result, as they are not aware of C++ constructors, destructors, templates, and other C++ language features.

11.1.5. Order of initialization

There are situations where the order of initialization of data objects within a program is important to the correct operation of the application. A priority can be assigned to an individual object file when it is compiled. This is done using the -qpriority option. For example:

$ xlC -c zoo.C -qpriority=-50

The C++ compiler and the makeC++SharedLib command also support options that can be used to indicate the relative order of initialization of shared objects. There is a slight difference in the way the priority is specified when using each command. When using the C++ compiler, the priority is specified as an additional value with the -qmkshrobj option. For example:

$ xlC -qmkshrobj=-100 -o shr1.o source1.o

When using the makeC++SharedLib command, the priority is specified with the -p option. For example:

$ makeC++SharedLib -p -100 -o shr1.o source1.o

Priority values can also be indicated within C++ code by inserting the priority compiler directive as follows:

#pragma priority(value)
					

These values alter the order of initialization of data objects within the object module.

Priority values

Priority values may be any number from -214782623 to 214783647. A priority value of -214782623 is the highest priority. Data objects with this priority are initialized first. A priority value of 214783647 is the lowest priority. Data objects with this priority are initialized last. Priority values from -214783648 to -214782624 are reserved for system use. If no priority is specified, the default priority of 0 is used.

The explanation of priority values uses the example data objects and files shown in Figure 11-1 on page 399.

Figure 11-1. Illustration of objects in fish.o and animals.o


This example shows how to specify priorities when creating shared objects to guarantee the order of initialization. The user should first of all determine the order in which they want the objects to be initialized, both within each file and between shared objects:

1.
Develop an initialization order for the objects in house.C, farm.C, and zoo.C:

  1. To ensure that the object lion L in zoo.C is initialized before any other objects in either of the other two files in the shared object animals.o, compile zoo.C using a -qpriority=nn option with nn less than zero so that data objects have a priority number less than any other objects in farm.C and house.C:

    $ xlC -c -qpriority=-50 zoo.C
    

  2. Compile the house.C and farm.C files without specifying the -qpriority=nn option. This means the priority will default to zero. This means data objects within the files retain the priority numbers specified by their #pragma priority(nn) directives:

    $ xlC -c house.C farm.C
    

  3. Combine these three files into a shared library. Use the makeC++SharedLib command to construct the shared object animals.o with a priority of 40:

    $ makeC++SharedLib -o animals.o -p 40 house.o farm.o zoo.o
    

2.
Develop an initialization order for the objects in fresh.C and salt.C, and use the #pragma priority(value) directive to implement it:

  1. Compile the fresh.C and salt.C files:

    $ xlC -c fresh.C salt.C
    

  2. To assure that all the objects in fresh.C and salt.C are initialized before any other objects, including those in other shared objects and the main application, use makeC++SharedLib to construct a shared object fish.o with a priority of -100:

    $ makeC++SharedLib -o fish.o -p -100 fresh.o salt.o
    

    Because the shared object fish.o has a lower priority number (-100) than animals.o (40), when the files are placed in an archive file with the ar command, the objects are initialized first.

3.
To create a library that contains the two shared objects, so that the objects are initialized in the order you have specified, use the ar command. To produce an archive file, libprio.a, enter the command:

$ ar rv libprio.a animals.o fish.o

Where libprio.a is the name of the archive file that will contain the shared library files, and animals.o and fish.o are the two shared files created with makeC++SharedLib.

4.
Compile the main program, myprogram.C, that contains the function main to produce an object file, myprogram.o. By not specifying a priority, this file is compiled with a default priority of zero, and the objects in main have a priority of zero:

$ xlC -c myprogram.C

5.
Produce an executable file, animal_time, so that the objects are initialized in the required order, and enter:

$ xlC -o animal_time main.o -lprio -L.

When the animal_time executable is run, the order of initialization of objects is as shown in Table 11-1.

Table 11-1. Order of initialization of objects in prriolib.a
ObjectPriority valueComment
fish.o-100All objects in fish.o are initialized first because they are in a library prepared with makeC++SharedLib -p -100 (lowest priority number; -p -100 specified for any files in this compilation).
shark S-100(-200)Initialized first in fish.o because within file #pragma priority(-200).
trout A-100(-80)#pragma priority(-80).
tuna T-100(10)#pragma priority(10).
bass B-100(500)#pragma priority(500).
myprog.o0File generated with no priority specifications; default is 0.
CAGE0(0)Object generated in main with no priority specifications; default is 0.
animals.o40File generated with makeC++SharedLib with -p 40.
lion L40(-50)Initialized first in file animals.o compiled with -qpriority=-50.
horse H40(0)Follows with priority of 0 (since -qpriority=nn not specified at compilation and no #pragma priority(nn) directive).
dog D40(20)Next priority number (specified by #pragma priority(20)).
zebra N40(50)Next priority number from #pragma priority(50).
cat C40(100)Next priority number from #pragma priority(100).
cow W40(500)Next priority number from #pragma priority(500).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset