Linkers create executable files from object files and libraries, by binding external references of calling programs with the entry points of the called routines. The external references and entry points should be identical symbols for the link to succeed.
Object files are put into an executable file and are linked to any references made to any objects already linked. Library archives (libxxx.a) are collections of objects where the object is extracted from the library and put into the executable. Shared libraries (libxxx.so) are only partially linked in the linker, and at runtime the shared library present will be read and the routine extracted and run. This allows users to link with one library in the linker, and link the actual routine on the platform at runtime.
The most common linker problems are:
Libraries or object files linked in the wrong order. The linkers extract objects from libraries based on whether they are referenced earlier in the linker line. If object x.o references something in liba.a and the routine extracted from liba.a references something in libb.a the proper link order is
pgfortran x.o -la -lb
If the object extracted from libb.a makes a refernce to another routine in liba.a, the proper link order is
pgfortran x.o -la -lb -la
Linking objects compiled with ‑mcmodel=medium with objects that are not compiled that way. This will fail, unless the object linked is part of a shared library.
pgfortran x.f90 -Munix
The link is successful but the executable file fails when run. A common problem is compiling using modfiles from various routines, but not linking the objects associated with the modfiles into the final executable. If the source file associated with the module that created the modfile initializes data or defines a contained subroutine or function, the objects must be linked to work properly in the executable (data gets initialized, subroutines get found and executed). There is no penalty for linking the foo.o file associated with foo.mod, so always linking the objects is a good practice.
pgcpp -c y.C pgfortran x.f90 y.o -pgcpplibs pgf77 -c w.f pgcc v.c w.o -pgf77libs pgfortran -c t.f90 pgcpp s.C t.o -pgf90libs
This is a common error when linking g77 compiled programs with the PGI compiler-driver.
> Linking: > /usr/local/mpich/build/LINUX/ch_p4/lib/libmpich.a(farg.o): In function > `mpir_iargc__': > farg.o(.text+0x8): undefined reference to `f__xargc'
Both xargc and xargv are g77 global variables which represent the Fortran equivalents of the C variables argc and argv. The file, farg.f, contains references to the functions iargc() and getarg(). When g77 is used to compile farg.f, these variables are used by g77-generated code for the iargc() and getarg() functions. These variables are defined when there is a g77-compiled main program. pgf77 also has global variables for the same purpose and are named __argc_save an __argv_save.
There are a couple of work-arounds:
Add a C function which defines and assigns xargc and xargv and add a call to the C function from the Fortran main program. For example:
zarg.c:
int xargc;
char **xargv;
extern int __argc_save;
extern char **__argv_save;
void zarg_() { /* call zarg() from Fortran */
xargc = __argc_save;
xargv = __argv_save;
} Recompile the file farg.f with pgf77 -c and add the object to the link before ‑lmpich. If the second underscore is needed for global names, remember to include the second underscore option. The source for farg.f is:
integer function mpir_iargc()
mpir_iargc = iargc()
return
end
subroutine mpir_getarg( i, s )
integer i
character*(*) s
call getarg(i,s)
return
end
There are two common underscore problems:
gcc produces a second underscore. Try compiling with ‑Msecond_underscore
Calling C routines from Fortran. This is discussed in Chapter 10 of the PGI User's Guide. If you do not want to create a wrapper function, you can use the directive
!$PRAGMA C (rout1, rout2, etc)
to direct the Fortran compilers to not underscore the symbols for rout1 and rout2 and so on.
PGI uses the linker that is part of the development tools installed on your system (e.g. GCC, Visual Studio, Xcode, etc.). On Linux, this is usually ld. The ld option ‑noinhibit-exec will usually produce an executable file even if there are linking errors. To pass switches to the linker, use the ‑Wl, switch along with the linker switch. For example:
%cat x.c
main() {
while (0)
{
foo();
}
}
pgcc -o x x.c -Wl,-noinhibit-exec
The Intel Math Kernel Library is a library of math functions highly optimized for Intel's line of microprocessors. With release 10.0 and later of the MKL, Intel adopted a layered architecture. This modular approach separates the MKL into four distinct functional layers:
All compiler-specific run-time library references are now isolated in the threading layer. In Release 10.1 and above of the MKL, Intel included threading libraries for PGI compilers. Following are the steps required to use the MKL with multi-threaded OpenMP programs compiled with PGI.
Using MKL with PGI Workstation and PGI Server
For PGI Workstation and PGI Server class products on Linux, Mac OS X and Windows, add one of the MKL supplied libraries for each of the first three layers (interface, threading, computation) to your linker command line. Use the ‑mp option on the linker command line as well to ensure the multi-threaded PGI runtime library is used. Also, check that you are linking in the appropriate PGI threading library (either static or dynamic) from the MKL.
Here is an example of compiling an OpenMP multi-threaded version of a simple matmul program (pgi_mm.F) with PGI Fortran (pgfortran) on Linux, and linking in the MKL.
Compile with OpenMP directive processing enabled (‑mp)
> pgfortran -mp -Minfo -fast -c ../pgi_mm.F
Link the three MKL supplied libraries with the compiled object file. The ‑mp option will link in the PGI multi-threaded runtime library.
% pgf90 -mp -Minfo -o mm_mp pgi_mm.o ../dclock_64.o -R/opt/mkl/lib/em64t -L/opt/mkl/lib/em64t -lmkl_intel_lp64 -lmkl_pgi_thread -lmkl_core
Note: dclock_64 is a clock function used in the matmul program that returns elapsed time in seconds.
Here is the same souce code example compiled using the sequential non-threaded version of the MKL threading library.
Compile serially (no ‑mp option)
% pgf90 -Minfo -fast -c ../pgi_mm.F
Link the three MKL supplied libraries with the compiled object file. No ‑mp option links in the PGI serial runtime library.
% pgf90 -Minfo -o mm pgi_mm.o ../dclock_64.o -R/opt/mkl/lib/em64t -L/opt/mkl/lib/em64t -lmkl_intel_lp64 -lmkl_sequential -lmkl_core
Determining which library to use for optimum performance involves a number of factors including array sizes, the choice of single or double precision arithmetic and the number of processors and/or cores available. Experimentation is the only sure way to know what's best for your situation.
Using MKL with PGI Visual Fortran
To use MKL with PGI Visual FortranĀ®, follow the directions for configuring MKL for Intel Visual Fortran in Section 4 of the MKL for Windows User's Guide. Substitute the appropriate mkl_pgi_thread* for the mkl_intel_thread* library as an Additional Dependency in the Configuration Properties > Linker > Input section of your project's Property Pages window. Enable the Process OpenMP Directives option through the Configuration Properties > Fortran > Language section as well to ensure the multi-treaded runtime layer is included.
See the Intel MKL documentation page for more information.
The environment variable LIBRARY_PATH is used by some gcc drivers to add directories to the library search paths. This can be done with a few lines in the siterc file in the PGI installation directory.
Create a siterc file with the following lines, or add the following lines to your existing siterc file; an alternative is to add these lines to a .mypgccrc, .mypgfortranrc, .mypgf77rc or .mypgCCrc files in your home directory.
# get the value of the environment variable LIBRARY_PATH variable LIBRARY_PATH is environment(LD_LIBRARY_PATH); # split this value at colons, separate by -L, prepend 1st one by -L variable library_path is default($if($LIBRARY_PATH,-L$replace($LIBRARY_PATH,":", -L))); # add the -L arguments to the link line append LDLIBARGS=$library_path;
This happens when the compiler can't find where gcc has been installed (the Linux system libraries are found in the gcc area).
This is usually the result of
The usual remedy is to reinstall the compilers, making sure that the gcc environment is set up properly (try compiling and executing hello.c with gcc). This will ensure that the PGI drivers point to the proper areas for locating the system libraries.
To make sure things are correct, try compiling hello.c with both gcc and pgcc.
gcc -v hello.c pgcc -v hello.c
Analyze the dialogue created and determine if the gcc libs being brought in are identical.
Memory maps are produced by your system's linker. PGI compilers can pass switches directly to linkers by using the ‑Wl, switch on the Linux command line. Linkers for most operating systems have a similar option.
For example, if ‑Map mapfilename creates a memory map in the file called mapfilename using the Linux ld linker, then the compilers can create the same map file using
pgfortran -o x x.f -Wl,-Map,mapfilename