Commercial Computing with C/C++

3 Posts tagged with the compiler-option tag
2

This is my first post on our C/C++ Cafe that has been long in coming.

If you are like me, then you are a new zOS programmer. The learning ride has been quite turbulent and there are ways to go yet. If you are a devoted programmer then you feel quiet excitement of your new program almost working, tempered by the chance of another large manual being 'thrown' at you. zOS is one of those products that has too much of a good thing, that is there is a LOT of documentation. This fact very quickly becomes an advantage as one gains more experience.

No matter what design patterns you use, almost as soon as you start writing code, you will need to include other files, be it either your own include files or third party libraries. For efficiency purposes, these files will in all likelihood reside in datasets. To make things more interesting, the documentation might instruct to use directory based (HFS) #include, confusing the new-comers as to where files reside.

I want to discuss two tasks that come up when dealing with include files:

  • Finding the include files
  • Dealing with preprocessor macros

If the compiler already found the include file (i.e. successful
compile) and you are interested where the file is located (i.e. which version of the library you are actually using), both -qlist and
-qsource produce an includes section.

#Will list all included files:
xlc -qsource -c foo.c | sed -n '/I N C L U D E S/,/E N D O F I N C L U D E S/ p'
#Will list the path to NAME_OF_INCLUDE:
xlc -qlist -c foo.c | grep NAME_OF_INCLUDE

The grep command might not return anything because of some zOS specific file translations, hence be careful:

  • if NAME.OF.INCLUDE contains dots, the real file name might be translated to INCLUDE.OF.NAME or just NAME
  • if NAME_OF_INCLUDE contains underscores, it might get translated to NAME@OF@INCLUDE

If you are using V1R11 compiler, there is a new feature, -qmakedep (on USS only) that will produce a list of all included files. It is much easier to remember then the sed command above. For example if you compiled:

# previus invocation: 'xlc -c foo.c'
# Append -qmakedep
xlc -c foo.c -qmakedep
cat foo.u

For previous releases of zOS compiler, have a look at the makedepend utility. It contains some other options that might be useful for include file debugging.

-qshowinc is another particularly useful option, if you already have the include files. It shows the the contents of the included files. It is similar to what PPONLY (-E equivalent) option does, except it outputs to the listing and does not strip preprosessor directives. However, be ready to pipe the output to other programs to filter out the thousands of lines of code produced. Most of the time I use less and its search features. sed and grep sometimes are also be useful.

If you are trying to include a file, and the compiler cannot find it, there is more research involved. In a general case, the include files can be found, top to bottom in these places:

pwd
LSEARCH
DD:USERLIB
SEARCH
DD:SYSLIB


  • System includes can only be found in SEARCH and DD:SYSLIB.
  • DD: statements come from the JCL, hence you might need to know how the compiler was invoked.
  • SEARCH and LSEARCH come from the compiler options hence are easy to modify

SEARCH and LSEARCH both contain a list of directories and partial dataset qualifiers. The topic is discussed in detail in our Compiler User Guide in 'Chapter 7: Using include files'. I personally found the flowcharts in Chapter 7 and the Examples in the LSEARCH option explanation cleared up most of the most dataset questions that I had. It is worth noting for newcomers that terms 'z/OS Unix files' and 'HFS files' are equivalent and refer to directory based files (i.e. similar to organization Linux and Windows file systems) (as opposed to DATASETs that can be sequential or PDS in this discussion)

-qlist, -qsource options and -V and -v c89 and xlc flags provide a quick way to find out what the values of LSEARCH and SEARCH are.

As Visda has discussed before in her blog post, NOSEARCH() and NOLSEARCH() reset the respective option value back to empty.

Last topic I wanted to touch was preprocessor macros and what options are available when dealing with them.

Michael Wong has posted here a way to find compiler predefined macros on AIX using the SHOWMACROS option. zOS unfortunately does not have this option till V1R11. The best equivalent is to use the makedepend utility -Wm,list option and then view depend.lst. It will contain a list of predefined compiler macros. However, makedepend utility is being deprecated since V1R11 in preference to built-in -qmakedep option.

Nevertheless most macros should be mentioned in the zOS manuals related feature sections. Here is a small list from the manual.

If you already have the macro name you wish to use, have a look at the -qEXPMAC option. This option will show you the value of the macro in the source listing. It is most useful when combined with -qshowinc.

I hope this gets you started on the right track.

2 Comments Permalink
0

RENT or NORENT

Posted by Visda Jan 11, 2009

Here we are eleven days into a new year; and I would like to wish all of you a happy belated 2009! May this be a year of making technology less complex, more intuitive, friendlier and greener.

Is it clear why we have RENT|NORENT compiler option? Do you know that C++ always uses constructed re-enterancy? Can you imagine how applications can benefit most from this?

Recently, I developed a greater appreciation for RENT option, that is after I banged my head against the wall to REALLY understand what RENT is all about in order to fix a related bug. :8}

Reentrancy becomes important when a rather large application have multiple users who may access it concurrently, for example Oracle. Oracle applications developed to run on z/OS will access Oracle interface which is a reentrant code.

Per z/OS Language Environment Programming Guide the following routines must be reentrant.

  • Routines to be loaded into the LPA or ELPA
  • Routines to be used with CICS
  • Routines to be preloaded with IMS

Furthermore, a large application with many concurrent users will benefit from reentrancy, ie runs faster, because there is less paging to auxilary storage --variables are placed in writeable static area.

This is done for you, if your application is written in C++ or is a DLL. Compile with "-qlist" and you see RENT in the Compiler Option Listing. A C program, however, can be naturally reenterant, that is the user code doesn't change the static storage.


For example:

extern int x;


int main()


{

return x;

}

is naturally reentrant because the value of x is not changed by main.

A C program can be made reentrant, constructed reenterancy by specifying

a. -qRENT on the command line (in HFS) or RENT in CPARM (in BATCH)
b. #pragma variable(x,RENT) in the source

There you have it. In a nutshell: reentrancy comes for free with C++ and DLL code, for the rest you have ways to make the code reentrant; if your code is big and is called/used by multiple users at the same time you want to take advantage of this feature because it will improve the run time performance of your application.

0 Comments Permalink
5

Compilers, what they might do ...

Posted by Visda Nov 23, 2008

Ever wonder what compiler does to your code? I suppose this is of little importance if binary is generated quickly, it executes fast and yields correct result. I regard compiler as an interactive tool. Given that the destination is the same (the executable), compiler provides many routes for your source code to reach it.

Whether you are invoking the compiler via a JCL, under TSO, or ISPF panel, or you are using c89/xlc commands in z/OS USS environment, you can utilize a variety of compiler options that can affect how the source is treated during the compilation process.

For example, if your source is in C++ and declares/defines a whole bunch of generic types, you may want to use one of the C++ template options, FASTTEMPINC, TEMPINC, TEMPLATERECOMPILE, and etc. Or, if you are planning to debug a run-time problem, you may want to pass DEBUG (Batch/TSO) or –g (z/OS USS) to the compiler. (Have a look at Kendrick’s article to learn more about debugging on z/OS.) Or you want to enable optimization, then you specify OPTIMIZE.

But, let’s say you are in a similar situation as I was this past week, and want to disable optimization at the subprogram level. I wanted the entire compilation unit, CU, to be compiled at O3 except one, non-overloaded function. I used* #pragma option_override* to bump down the optimization level to O2 for that one function.

In summary, compilers may do a lot of things to your code, but at the same time they allow you full control.
:)

5 Comments Permalink
Bottom Banner