Chapter 21. Introduction to C and C

CONTENTS

Chapter 21. Introduction to C and C++

  •  Introduction
  •  C and C++ - The History
  •  C and C++ - Compilers
  •  C and C++ - Make Utility
  •  C and C++ - Debugging
  •  Manual Pages of Some Commands Used in Chapter 21

Introduction

This chapter introduces the closely related programming languages, C and C++. The programs created with these languages need to be compiled before executing. This chapter will review the history of C and C++, and will show how to create executable files from source code.

C and C++ - The History

The C and C++ history starts with the C language. C language was pioneered by Dennis Ritchie at AT&T Bell Laboratories in the early 1970s. The primary reason for creating this language was to enable Bell Labs programmers to write their UNIX operating system for a new DEC (Digital Equipment Corporation) computer. By the late 1970s, C compilers were ready for commercial applications and C language began to grow in popularity.

As its popularity increased, more and more vendors began marketing their own compilers. Unfortunately, due to some ambiguity in the definition of C, vendors were left to interpret some aspects of the language on their own. This resulted in the fragmentation of the language. This meant that programmers creating C programs were not guaranteed that their source files would compile with someone else's version of the C compiler.

In the early 1980s, The American National Standards Institute (ANSI) standardized the definition of the C language. As a result, any programmer who has compiled a C program with an ANSI C compiler is ensured that it will compile without modification on any system that has an ANSI C compiler.

C++ language was developed by Bjarne Stroustrup in AT&T Bell Laboratories. The name C++ was given to the language in 1983 by Rick Mascitti. C++ language is a superset of C language. Because of this, compilers for C++ will correctly compile C programs. This implies it is still possible to program procedurally in C++.

C was chosen as a base language for C++ instead of designing the whole language from scratch. The reason was that designing a new language had problems and so did C language, but C language problems were at least known.

Earlier versions of C++ were known as "C with Classes." Over time it evolved to become the language it is today. The implementation of classes is not the only feature differentiating C++ from C. C++ also has other features such as operator overloading, references, and virtual functions.

In 1989, ANSI became involved with C++ standardization at the initiative of Hewlett-Packard. Today an ANSI C++ standard is widely used.

C and C++ - Compilers

Compilers are nothing more than complex programs designed to convert a language's source code text into computer-readable machine language. A compiler is written for a specific computer language on a specific computer platform. A compiler written for an IBM system is a different program from a compiler written for a Sun system. Check with your computer vendors for compatible compiler software.

graphics/06icon04.gif

A program that is to be compiled is first entered into a file on the computer system. Most programmers use the editors vi, ed, or emacs. A file containing source code is referred to as a source file. A source file for C must end with ".c" and a source file for C++ ends with ".cc" or ".cpp," depending upon the compiler. An example of a valid C source file name is payroll.c, and a valid C++ source file name is payroll.cc or payroll.cpp.

The program entered into the source file is usually referred to as source code or the source program. After the source code has been entered into the source file, it can be compiled. For simplicity, the file extension ".c" will be used but is interchangeable with ".cc" or ".cpp".

Compiling Programs

The compiling is initiated by using a special command. When the command is used, it will include the name of the source file to be compiled.

ANSI C compilers may initiate a compile with an "a" in front of the compile commands, while others will use "CC" to denote a C++ compiler. For simplicity, the cc command will be used in this book. Check with your compiler software for the exact command.

When a programmer invokes the compile command, the system traverses four major components: preprocessor, compiler, assembler, and link editor.

The overall compiler process can be described as consisting of two major processes:

  1. The compile process, consisting of the preprocessor, compiler, and assembler

  2. For more complex programs, the link process, where object files are linked together to form a single executable program

These are shown in Figure 21-1.

Figure 21-1. Single Executable

graphics/21fig01.gif

When compiling, the source program must go through a preprocessor before it can be compiled. This occurs automatically. The preprocessor will prepare the source code for the compiler. For example, there are preprocessor directives that cause information to be included for the compiler. This aspect is explored further when discussing C and C++ programming.

The compiler creates assembly language that corresponds to the programming instructions found in the source file.

The assembler generates machine-readable object code. One object file is created for each source file. Each object file has the same name as the source file, with the exception of the prefix; it is replaced with ".o."

The programmer does not necessarily write every function in a program. Some functions are pre-written and reside in libraries. The compiler vendor supplies some of these libraries for basic functionality, such as reading and writing to a file, math functions, and so on. There are also software companies who provide even more libraries, and a programmer can also create his or her own libraries.

During the final phase, the link editor searches specified libraries for the functions used by the program and combines their object files with the programmer object files to create an executable.

When the C compiler successfully completes all phases of the process for a program, an executable file (executable) is created and the object file is automatically removed. The default name of the executable is a.out.

Type the name of the executable to run the program, in this case the executable file name is a.out.

To compile a program, type:

$ cc payroll.c 

Compiler Options

Compilers can compile one source file, as previously seen. But in some cases, various pieces of a program may be in multiple source files. This arrangement is usually the case for larger programs and programming projects.

To compile multiple source files:

$ cc payroll_1.c payroll_2.c employee.c 

The a.out default name for the executable is not very descriptive. The -o option allows the programmer to specify the name of the executable to be generated. For example, if three source code files contain all the code for a payroll system and I want the executable to be called myPayroll, the following command is used:

$ cc -o myPayroll payroll_1.c payroll_2.c employee.c 

The executable generated by the compile is called myPayroll. To run the payroll program, type:

$ myPayroll 

If the programmer wants to compile but wants to stop before the link process, the -c option can be used. The -c option will not generate an executable, but the user will see the object files. In this case, payroll_1 and payroll_2 source files will have corresponding object files, but no executable will be generated.

$ cc -c payroll_1.c payroll_2.c 

After all the object files for the source code have been generated, the programmer is ready to generate the executable and can do so using the object files instead of the source files in the compile command.

$ cc -o myPayroll payroll_1.o payroll_2.o employee.o 

The compiler recognizes the file extension of .o, and recognizes that the files only need to be linked. You can also include both.c and.o files on a single command line. The compiler will compile and link the.c files whereas the.o files will only be linked. The compiler also accepts assembly language files ending in.s and handles them appropriately, assembling and linking them.

When working with large programs that have many different source files, the ability to compile separately and link them together later can save time. If only one source file is impacted out of many, the compiler will only compile the one, and link the others.

Figuring out which files to compile can also be automated with the make utility.

graphics/21icon01.gif

C and C++ - Make Utility

graphics/21icon01.gif

We saw in the previous section that compiling must go through two primary processes: compile and link. The make utility allows management of this process throughout the development life cycle. This section is an introduction to make; however, the utility varies to a degree among UNIX variants. Consult the UNIX man pages for specifics on your system.

A program consisting of multiple source files will greatly benefit from the make utility. It is a powerful, nonprocedural, template-based method to maintain sets of file interdependencies.

For example, make can be used to manage changes to C, C++, or even HTML source code. The relationship between object and executable files are described via the make utility, and it will update the latter when the former changes. Although make can be invoked directly from a shell or run from the command line, complex build processes are usually captured in a file called a makefile.

Makefiles

A makefile is a text file containing any of four types of lines: target lines, shell command lines, macro lines, and make directive lines. Comments can be included in a makefile and start with a pound sign (#).

To invoke a makefile, the programmer types make. The make command will look for a file named makefile in the current working directory. If makefile does not exist, then make searches for a file named Makefile. The make utility can also look for names other than the defaults, via command options discussed in "Running make from the Command Line" section later in this chapter. If makefile or Makefile is not used as a file name for a file containing make commands, the extension ".mk" is added as a convention.

Targets and Dependencies

Target lines indicate what can be built. They consist of a list of target files, followed by a colon (:), followed by a list of dependencies or prerequisite files.

graphics/21icon01.gif

A target file is a file that depends upon one or more prerequisite files. The prerequisite files are also referred to as dependencies. If a dependency is updated more recently than the target file, make updates the target file based on construction commands that follow the target line. The make utility will stop if an error is encountered during the construction process. A simple makefile will have the following format:

target:dependencies_list         construction_commands 

The construction_commands are regular commands to the shell that construct the target file, usually by compiling and/or linking. The following code shows the target line with construction commands for a file called payroll_form. Its dependencies are form.o and pay_info.o. Acc command constructs the target:payroll_form:form.o payinfo.o

payroll_form:form.o payinfo.o  cc -o payroll_form form.o payinfo.o 

A target list can contain multiple targets, but typically only one target is listed per target line. The target list cannot be empty; however the list of dependencies can be empty. Target line examples are listed below:

target_1: dependency_1 dependency_2               # target with two dependencies  target_2:    # target with no dependencies 

Dependencies are used to ensure that the components are built before the overall executable file. The target must be newer than its dependencies. If any of the dependency is newer than the current target or if the dependency does not exist, the dependencies and then the current target must be made. If the list of dependencies is empty, the target is always made.

It may help to construct a dependency graph. A dependency graph will also show dependencies upon header files.

When several symbolic constant and macro definitions are used in different source files of a program, they can be collected together into a single file called a header file or an include file. By convention, these files end in.h.

Symbolic constants are names that can be used in a source program in place of a constant value. For example, if a payroll program needs to calculate employee reimbursements for automobile mileage, you may want to associate the cost per mile with a symbolic constant, AUTO_MILEAGE.

#define      AUTO_MILEAGE   .33 

Anywhere this cost is needed, the programmer can use AUTO_MILEAGE instead of the actual value of $.33. When the federal government changes the reimbursement per mile charge, the symbolic constant value is changed in one place, most likely in a header file. Anyone, including that header file in the source file and in the makefile as a dependency, and using AUTO_MILEAGE within the program, will see the change.

Macros are similar to short functions and can also be included in header files. For example, if I need a short function throughout my program to ensure that the salary total for an employee does not fall below zero after deductions, I may want to include it as a macro and put it in a header file for multiple source files to use:

# define     isWageValid(n)  ( n >= 0 ) 

In the graph in Figure 21-2, the executable payroll_form depends upon two object files and the object files each depend on their respective source files and a header form.h. In turn, form.h depends upon two other header files.

Figure 21-2. Dependencies

graphics/21fig02.gif

Each of the dependencies can be a target on another dependency. For example, both form.o and payroll_info.o are targets on one line and dependencies for other targets on another line. Nesting dependencies can create a complex hierarchy that specifies relationships among many files.

The following makefile corresponds to the complete dependency graph shown above.

payroll_form:form.o payroll_info.o  cc -o payroll_form form.o payroll_info.o  form.o:size.c form.h  cc -c size.c  payroll_info.o:payroll_info.c form.h  cc -c payroll_info.c  form.h:graph.h format.h  cat graph.h format.h > form.h 

The last line illustrates how shell commands can be put on a construction line, although concatenation of two files to create a third is not common practice.

Library Targets

Libraries consist of multiple functions or classes. Functions or classes are usually logically grouped together and placed in a library with a descriptive name for reuse by multiple programs. If a target or dependency includes parentheses (()), then it is concidered to be a library.

An example of a target line with library targets is as follows:

payroll_lib.a(payroll_tools.o):payroll_tools.c  payroll.h 

Do not use spaces between parentheses, because they result in an error.

Rule Targets

graphics/21icon01.gif

A powerful feature of make is the ability to specify generic targets known as suffix rules, inference rules, or simply rules. Rules are a shorthand method used to tell make only once how to build certain type of targets. Consider the following excerpt from a makefile (the -I compile option tells the compiler where to look for header files):

payroll.o:   payroll.c  cc -c payroll.c -I. -I/user/local/include  screens.o:   screens.c  cc -c screens.c -I. -I/user/local/include  main.o:      main.c  cc -c main.c -I. -I/user/local/include  main:       payroll.o screens.o main.o  cc  payroll.o screens.o main.o 

This has a great deal of redundancy. All the shell command lines are identical, except the file being compiled into an executable. The following rule tells make how to transform a file ending in.c to a file ending in.o:

graphics/21icon01.gif

.c.o:      cc -c $< -I. -I/user/local/include 

This rule has a special macro, $<, which will substitute the current source file in the body of a rule. Using this rule,.c.o, simplifies the previous makefile excerpt to:

.c.o:     cc -c $< -I. -I/user/local/include  main:        payroll.o screens.o main.o     cc payroll.o screens.o main.o 

Macros

Macros can be used to simplify references to commonly used text, increase maintainability by providing a single place where information is defined, and improve readability.

The basic syntax for defining macros with a makefile is:

name = valuelist 

The name may consist of any combination of upper- and lowercase letters, digits (0-9), and underlines or underbars (_). Macro names appear in all uppercase by convention. The make utility allows name to be replaced with an identifying name.

The valuelist may contain zero, one, or more entries. The valuename can be replaced with a list of file names. The valuelist can be quite long, and the backslash (\) newline escape can be used to continue a definition on another line and the backslash is seen as a space.

A macro definition can be used to represent a group of header files frequently used within the makefile.

HEADERS = payroll.h companies.h benefits.h 

The makefile can make use of HEADERS by using:

process.o: $(HEADERS) 

Running make from the Command Line

The make utility has methods of configuration from within a makefile, but it also has command-line options. These options are used when executing the makefile.

graphics/21icon01.gif

A typical sequence of make command-line arguments can appear in any order:

Make [-f makefile] [options] [macro definitions] [targets]

Option items are enclosed in [].

Command-line options are preceded with a (-) followed by the option, for example make -d. The following is a list of some of the more common options used:

Comman Line Options For make

-d

Enables debug mode. Debug mode will produce a large amount of messages and should only be turned on as a last resort when debugging a makefile.

-f

FilenameDenotes the name of the file to be used as a makefile. A space must appear between the option and the file name.

-p

Prints all macro definitions and rules.

-i

Make will ignore nonzero error codes returned by commands. Instead of terminating the build of all targets, it will continue.

-k

Will kill work on the current target if a non-zero error code is returned by a command. Work on other targets will continue. This is the opposite of -s mode.

-s

Puts make into silent mode. Normally commands are executed to standard out.

-t

The files are touched; commands associated with a rule are not issued. See the UNIX touch command.

C and C++ - Debugging

After programs have been successfully debugged from syntactic errors, allowing the compiler to generate an executable, the program must be tested for runtime and logical errors. Debuggers help a programmer find where these errors have occurred.

The C and C++ compilers are liberal about the kinds of constructs they allow in programs. The compiler assumes that you mean what you've entered. This assumption allows for various errors to occur while running the program. A serious error, called a segmentation violation, will stop the program from executing. A message such as Segmentation violation - Core dumped is displayed and creates a core file. A core file contains information about the state of the program and the system when the failure occurred. A stack trace is part of the information put into the core file. The trace indicates the source line where the core dump occurred and the functions that were called to reach that line.

Debuggers such as sdb (symbolic debugger) or dbx use the core file to help programmers find and fix the problem. The debuggers sdb and dbx each have their own look and feel, but they provide similar capabilities. Both allow the programmer to monitor and control the execution of a program. The program can be stepped through line by line, allowing an examination of the state of the execution environment. They also allow the core file to be examined. The debugger can also be told on which line or lines to pause execution via breakpoints. After the execution has been paused, the programmer can check the system and values found in variables and structures. The programmer may choose to watch the execution step by step and the execution can be resumed at any point.

Lint is another useful tool. The lint command examines the source code for possible problems. The code may compile completely and cleanly, but it may execute incorrectly. Lint is stricter than the compiler. It detects and reports on a wide variety of problems and potential problems, including variables that are used before a value has been assigned to it, arguments to functions that are never used, and functions using return values that were never returned.

You are free to ignore Lint's warnings and complete the compile, but a warning typically means that the program has a bug or a non-portable construct, or that you have violated a standard of good programming. Paying attention to Lint's warnings is a good way not only to debug your programs but also to hone your programming skill.

Manual Pages of Some Commands Used in Chapter 21

The following is the HP-UX manual page for make used in this chapter. Commands often differ among UNIX variants, so you may find differences in the options or other areas for some commands; however, the following manual pages serve as an excellent reference.

make

graphics/21icon01.gif

make - Maintain, update, and regenerate groups of files.

make(1)                                                             make(1)  NAME       make - maintain, update, and regenerate groups of programs  SYNOPSIS       make [-f makefile] [-bBdeiknpqrsSt] [macro_name=value] [names]  DESCRIPTION     Makefile Structure       A makefile can contain four different kinds of lines: target lines,       shell command lines, macro definitions, and include lines.       TARGET LINES:       Target lines consist of a blank-separated, non-null list of targets,       followed by a colon (:) or double colon (::), followed by a (possibly       null) list of prerequisite files called dependents. Pattern Matching       Notation (see regexp(5)) is supported for the generation of file names       as dependents.       SHELL COMMAND LINES:       Text following a semicolon (;) on a target line, and all following       lines that begin with a tab are shell commands to be executed to       update the target (see the Environment section below about SHELL).       The first line that does not begin with a tab or # begins a new target       definition, macro definition, or include line. Shell commands can be       continued across lines by using a <backslash><new-line> sequence.       Target lines with their associated command lines are called rules.       MACROS:       Lines of the form string1 = string2 are macro definitions. Macros can       be defined anywhere in the makefile, but are usually grouped together       at the beginning. string1 is the macro name; string2 is the macro       value. string2 is defined as all characters up to a comment character       or an unescaped new-line. Spaces and tabs immediately to the left and       right of the = are ignored. Subsequent appearances of $(string1)       anywhere in the makefile (except in comments) are replaced by string2.       The parentheses are optional if a single character macro name is used       and there is no substitute sequence. An optional substitute sequence,       $(string1 [:subst1=[subst2]]) can be specified, which causes all       nonoverlapping occurrences of subst1 at the end of substrings in the       value of string1 to be replaced by subst2. Substrings in a macro       value are delimited by blanks, tabs, new-line characters, and       beginnings of lines. For example, if            OBJS = file1.o file2.o file3.o       then            $(OBJS:.o=.c)       evaluates to            file1.c file2.c file3.c       Macro values can contain references to other macros (see WARNINGS):            ONE =1            TWELVE = $(ONE)2       The value of $(TWELVE) is set to $(ONE)2 but when it is used in a       target, command, or include line, it is expanded to 12. If the value       of ONE is subsequently changed by another definition further down in       the makefile or on the command line, any references to $(TWELVE)       reflect this change.       Macro definitions can also be specified on the command line and       override any definitions in the makefile.       (XPG4 only. Macros on the command line are added to the MAKEFLAGS       environment variable. Macros defined in the MAKEFLAGS environment       variable, but without any command line macro, adds the macro to the       environment overwriting any existing environment variable of the same       name.)       Certain macros are automatically defined for make (see Built-in       Macros). See the Environment section for a discussion of the order in       which macro definitions are treated.       The value assigned to a macro can be overridden by a conditional macro       definition. A conditional macro definition takes on the form target       := string1 = string2. When the target line associated with target is       being processed, the macro value specified in the conditional macro       definition is in effect. If string1 is previously defined, the new       value of string1 will override the previous definition. The new value       of string1 takes effect when target or any dependents of target are       being processed.       INCLUDE LINES:       If the string include appears as the first seven letters of a line in       a makefile, and is followed by one or more space or tab characters,       the rest of the line is assumed to be a file name and is read and       processed by the current invocation of make as another makefile after       any macros in the filename have been expanded.     General Description       make executes commands previously placed in a makefile to update one       or more target names. Target names are typically names of programs.       If no -f option is specified, the filenames makefile, Makefile,       s.makefile, SCCS/s.makefile, s.Makefile and SCCS/s.Makefile are tried       in that order. If -f - is specified, the standard input is used.       More than one -f option can be specified. The makefile arguments are       processed in the order specified. A space between the -f and the       filename must be present, and multiple makefile names must each have       their own -f option preceding them. The contents of a makefile       override the built-in rules and macros if they are present.       If no target names are specified on the command line, make updates the       first target in the (first) makefile that is not an inference rule. A       target is updated only if it depends on files that are newer than the       target. Missing files are deemed to be out-of-date. All dependents       of a target are recursively updated, if necessary, before the target       is updated. This effects a depth-first update of the dependency tree       for the target.       If a target does not have any dependents specified after the separator       on the target line (explicit dependents), any shell commands       associated with that target are executed if the target is out-of-date.       A target line can have either a single or double colon between the       target name or names and any explicit dependent names. A target name       can appear on more than one target line, but all of those lines must       be of the same (single- or double-colon) type. For the usual single-      colon case, at most one of these target lines can have explicit       commands associated with it. If the target is out-of-date with any of       its dependents on any of the lines, the explicit commands are       executed, if they are specified, or else a default rule can be       executed. For the double-colon case, explicit commands can be       associated with more than one of the target lines containing the       target name; if the target is out-of-date with any of the dependents       on a particular line, the commands for that line are executed. A       built-in rule may also be executed.       Target lines and their associated shell command lines are also       referred to as rules. Hash marks (#) and new-line characters surround       comments anywhere in the makefile except in rules. Comments in the       rules depend on the setting of the SHELL macro.       The following makefile says that pgm depends on two files: a.o and       b.o, and that they in turn depend on their corresponding source files       (a.c and b.c) and a common file incl.h:            OBJS = a.o b.o            pgm: $(OBJS)                cc $(OBJS) -o pgm            a.o: incl.h a.c                cc -c a.c            b.o: incl.h b.c                cc -c b.c       Command lines are executed one at a time, each by its own shell. Each       command line can have one or more of the following prefixes: -, @, or       +. These prefixes are explained below.       Commands returning non-zero status normally terminate make. The -i       option or the presence of the special target .IGNORE in the makefile       cause make to continue executing the makefile regardless of how many       command lines cause errors, although the error messages are still       printed on standard output. If - is present at the beginning of a       command line, any error returned by that line is printed to standard       output but make does not terminate. The prefix - can be used to       selectively ignore errors in a makefile. If the -k option is       specified and a command line returns an error status, work is       abandoned on the current target, but continues on other branches that       do not depend on that target. If the -k option is present in the       MAKEFLAGS environment variable, processing can be returned to the       default by specifying the -S option.       The -n option specifies printing of a command line without execution.       However, if the command line has the string $(MAKE) or ${MAKE} in it       or + as a prefix, the line is always executed (see discussion of the       MAKEFLAGS macro under Environment). The -t (touch) option updates the       modified date of a file without executing any commands.       A command line is normally printed before it is executed, but if the       line has a @ at the beginning, printing is suppressed. The -s option       or the presence of the special target .SILENT: in the makefile       suppresses printing of all command lines. The @ can be used to       selectively turn off printing. Everything printed by make (except the       initial tab) is passed directly to the shell without alteration.       Thus,            echo a\            b       produces            ab       just as the shell would.       The -b option allows old makefiles (those written for the old version       of make) to run without errors. The old version of make assumed that       if a target did not have any explicit commands associated with it, the       user intended the command to be null, and would not execute any       .DEFAULT rule that might have been defined. The current version of       make operates in this mode by default. However, the current version       of make provides a -B option which turns this mode off so that if a       target does not have explicit commands associated with it and a       .DEFAULT rule is defined, the .DEFAULT rule is executed. Note that       the -b and -B options have no effect on the search and possible       location and execution of an appropriate inference rule for the       target. The search for a built-in inference rule other than .DEFAULT       is always performed.       The signals SIGINT, SIGQUIT, SIGHUP, and SIGTERM (see signal(5)) cause       the target to be deleted unless the target depends on the special name       .PRECIOUS.     Options       The following is a brief description of all options and some special       names. Options can occur in any order. They can be specified       separately, or together with one -, except for the -f option.       -b             Compatibility mode for old (Version 7) makefiles. This                      option is turned on by default.       -B             Turn off compatibility mode for old (Version 7)                      makefiles.       -d             Debug mode. Print out detailed information on files                      and times examined. (This is very verbose and is                      intended for debugging the make command itself.)       -e             Environment variables override assignments within                      makefiles .       -f  makefile   Description file name, referred to as the makefile. A                      file name of - denotes the standard input. The                      contents of the makefile override the built-in rules                      and macros if they are present. Note that the space                      between -f and makefile must be present. Multiple                      instances of this option are allowable (except for -f                      -), and are processed in the order specified.       -p             Write to standard output the complete set of macro                      definitions and target descriptions.       -i             Ignore error codes returned by invoked commands. This                      mode is also entered if the special target name .IGNORE                      appears in the makefile.       -k             When a command returns nonzero status, abandon work on                      the current entry, but continue on other branches that                      do not depend on that target. This is the opposite of                      -S. If both -k and -S are specified, the last one                      specified is used.       -n             No execute mode. Print commands, but do not execute                      them. Even lines beginning with an @ are printed.                      However, lines that contain the string $(MAKE) or                      ${MAKE} or that have + as a prefix to the command are                      executed.       -q             Question. The make command returns a zero or non-zero                      status code, depending on whether the target file is or                      is not up-to-date. Targets are not updated with this                      option.       -r             Clear suffix list and do not use the built-in rules.       -s             Silent mode. Command lines are not printed to standard                      output before their execution. This mode is also                      entered if the special target name .SILENT appears in                      the makefile.       -S             Terminate if an error occurs while executing the                      commands to bring a target up-to-date. This is the                      default and the opposite of -k. If both -k and -S are                      specified, the last one given is used. This enables                      overriding the presence of the k flag in the MAKEFLAGS                      environment variable.       -t             Touch the target files (causing them to be up-to-date)                      rather than issue the usual commands.       [macro_name=value]                      Zero or more command line macro definitions can be                      specified. See the Macros section.       [names]        Zero or more target names that appear in the makefile.                      Each target so specified is updated by make. If no                      names are specified, make updates the first target in                      the makefile that is not an inference rule.     Environment       All variables defined in the environment (see environ(5)) are read by       make and are treated and processed as macro definitions, with the       exception of the SHELL environment variable which is always ignored.       make automatically sets SHELL to /usr/bin/sh. Variables with no       definition or empty string definitions are included by make.       There are four possible sources of macro definitions which are read in       the following order: internal (default), current environment, the       makefile(s), and command line. Because of this order of processing,       macro assignments in a makefile override environment variables. The       -e option allows the environment to override the macro assignments in       a makefile. Command-line macro definitions always override any other       definitions.       The MAKEFLAGS environment variable is processed by make on the       assumption that it contains any legal input option (except -f, -p, and       -d) defined for the command line. The MAKEFLAGS variable can also be       specified in the makefile.       (XPG4 only. MAKEFLAGS in the makefile replaces the MAKEFLAGS       environment variable. Command line options have precedence over       MAKEFLAGS environment variable.)       If MAKEFLAGS is not defined in either of these places, make constructs       the variable for itself, puts the options specified on the command       line and any default options into it, and passes it on to invocations       of commands. Thus, MAKEFLAGS always contains the current input       options. This proves very useful for recursive makes. Even when the       -n option is specified, command lines containing the string $(MAKE) or       ${MAKE} are executed; hence, one can perform a make -n recursively on       an entire software system to see what would have been executed. This       is possible because the -n is put into MAKEFLAGS and passed to the       recursive invocations of $(MAKE) or ${MAKE}. This is one way of       debugging all of the makefiles for a software project without actually       executing any of the commands.       Each of the commands in the rules is given to a shell to be executed.       The shell used is the shell command interpreter (see sh(1)), or the       one specified in the makefile by the SHELL macro. To ensure the same       shell is used each time a makefile is executed, the line:            SHELL=/usr/bin/sh       or a suitable equivalent should be put in the macro definition section       of the makefile.     Suffixes       Target and/or dependent names often have suffixes. Knowledge about       certain suffixes is built into make and used to identify appropriate       inference rules to be applied to update a target (see the section on       Inference Rules). The current default list of suffixes is:            .o .c .c~ .C .C~ .cxx .cxx~ .cpp .cpp~ .cc .cc~            .y .y~ .l .l~ .s .s~ .sh .sh~            .h .h~ .H .H~  .p .p~ .f .f~ .r .r~       These suffixes are defined as the dependents of the special built-in       target .SUFFIXES. This is done automatically by make.       Additional suffixes can be specified in a makefile as the dependents       list for .SUFFIXES. These additional values are added to the default       values. Multiple suffix lists accumulate. The order of the suffix       list is significant (see the Inference Rules section). If the user       wishes to change the order of the suffixes, he must first define       .SUFFIXES with a null dependent list, which clears the current value       for .SUFFIXES, and then define .SUFFIXES with the suffixes in the       desired order. The list of suffixes built into make on any machine       can be displayed by:            make -fp - 2>/dev/null </dev/null       The list of built-in suffixes incorporated with the definitions in a       given makefile called mymakefile can be displayed by:            make -fp mymakefile 2>/dev/null </dev/null     Inference Rules       Certain target or dependent names (such as those ending with .o) have       inferable dependents such as .c and .s, etc. If no update commands       for such a name appear in the makefile, and if an inferable dependent       file exists, that dependent file is compiled to update the target. In       this case, make has inference rules that allow building files from       other files by examining the suffixes and determining an appropriate       inference rule to use. There are currently default inference rules       defined for:       Single Suffix Rules                .c .c~                .C .C~ .cxx .cxx~ .cpp .cpp~ .cc .cc~                .sh .sh~                .p .p~                .f .f~                .r .r~       Double Suffix Rules                .c.o .c~.o .c~.c .c.a .c~.a                .C.o .C~.o .C~.C .C.a .C~.a                .cxx.o .cxx~.o .cxx~.cxx .cxx.a .cxx~.a                .cpp.o .cpp~.o .cpp~.cpp .cpp.a .cpp~.a                .cc.o .cc~.o .cc~.cc .cc.a .cc~.a                .s.o .s~.o .s~.a                .p.o .p~.o .p~.p .p.a .p~.a                .f.o .f~.o .f~.f .f.a .f~.a                .r.o .r~.o .r~.r .r.a .r~.a                .y.o .y~.o .y.c .y~.c                .l.o .l~.o .l.c                .h~.h .H~.H .hxx~.hxx .hpp~.hpp                .C.o .C~.o .C.a .C~.a       Double suffix inference rules (.c.o) define how to build x.o from x.c.       Single suffix inference rules (.c) define how to build x from x.c. In       effect, the first suffix is null. Single suffix rules are useful for       building targets from only one source file; e.g., shell procedures and       simple C programs.       A tilde in the above rules refers to an SCCS file (see sccsfile(4)).       Thus, the rule .c~.o would transform an SCCS C source file into an       object file (.o). Since the s. of the SCCS files is a prefix, it is       incompatible with make's suffix point-of-view. Hence, the tilde is a       way of changing any file reference into an SCCS file reference.       A rule to create a file with suffix .o from a file with suffix .c is       specified as an entry with .c.o as the target and no dependents.       Shell commands associated with the target define the rule for making a       .o file from a .c file. Any target name that has no slashes in it and       starts with a dot is identified as an inference (implicit) rule       instead of a target (explicit) rule. Targets with one dot are single       suffix inference rules; targets with two dots are double suffix       inference rules. Users can, in a makefile, define additional       inference rules and either redefine or cancel default inference rules.       The default inference rule for changing a .c file into a .o file might       look like this:           .c.o:               $(CC) $(CFLAGS) -c $<       and the default inference rule for changing a yacc file to a C object       file might look like this:            .y.o:                $(YACC) $(YFLAGS) $<                $(CC) $(CFLAGS) -c y.tab.c                rm y.tab.c            mv y.tab.o $@       Certain macros are used in the default inference rules to permit the       inclusion of optional matter in any resulting commands. For example,       CFLAGS, LDFLAGS, and YFLAGS are used for compiler options to cc(1),       lex(1), and yacc(1), respectively. LDFLAGS is commonly used to       designate linker/loader options. These macros are automatically       defined by make but can be redefined by the user in the makefile.       The macro LIBS is, by convention, used to specify the order of       inclusion of any special libraries during the linking phase of       compilation. To specify a particular order of inclusion for a       particular set of libraries, the existing single suffix rule for a .c       file,            $(CC) $(CFLAGS) $< $(LDFLAGS) -o $ @       can be redefined as            $(CC) $(CFLAGS) $< $(LDFLAGS) -o $ @ $(LIBS)       as well as defining LIBS in the makefile.       There are also some special built-in macros used in the inference       rules (@, <). See the Built-in Macros section.       If a target does not have explicit dependents, or if a dependent does       not also have a target that matches it with associated explicit rules,       make looks for the first inference rule that matches both the target's        dependent's) suffix (which may be null) and a file which matches the       other suffix of the rule. Since it conducts this search by going       through the list of .SUFFIXES values front to back, the order in which       .SUFFIXES is defined is significant.       To print out the rules compiled into the make on any machine, type:            make -fp - 2>/dev/null </dev/null       Since make defines an inference rule .c.o, the example in the General       Description section can be rewritten more simply:            OBJS = a.o b.o                pgm: $(OBJS)                    cc $(OBJS) -o pgm                $(OBJS): incl.h     Libraries       If a target or dependent name contains parentheses, it is assumed to       be an archive library, the string within parentheses referring to a       member within the library. Thus lib(file.o) and $(LIB)(file.o) both       refer to an archive library that contains file.o (this assumes the LIB       macro has been previously defined). The expression $(LIB)(file1.o       file2.o) is not valid. Rules pertaining to archive libraries have the       form .xx.a where xx is the suffix from which the archive member is to       be made. An unfortunate byproduct of the current implementation       requires the xx to be different from the suffix of the archive member.       Thus, one cannot have lib(file.o) depend upon file.o explicitly. The       most common use of the archive interface follows. Here, we assume the       source files are all C type source:            lib: lib(file1.o) lib(file2.o) lib(file3.o)                @echo lib is now up-to-date            .c.a:                $(CC) -c $(CFLAGS) $<                ar rv $@ $*.o                rm -f $*.o       (See the section on Built-in Macros for an explanation of the <, @,       and * symbols.) In fact, the .c.a rule listed above is built into make       and is unnecessary in this example. This rule is applied to each       dependent of lib in turn. The following example accomplishes this       more efficiently:            lib:  lib(file1.o) lib(file2.o) lib(file3.o)                 $(CC) -c $(CFLAGS) $(?:.o=.c)                 ar rv lib $?                 rm $?                 @echo lib is now up-to-date            .c.a:;       Here substitution in the macros is used. The $? list is defined to       be the set of object file names (inside lib) whose C source files are       out-of-date. The substitution sequence translates the .o to .c.       (Unfortunately, one cannot as yet transform to .cZ; however~ this may       become possible in the future.) Note also, the disabling of the .c.a       rule, which would have created and archived each object file, one by       one. This particular construct speeds up archive library maintenance       considerably, but becomes very cumbersome if the archive library       contains a mix of assembly programs and C programs.       Kernel entry points are designated by double parentheses around the       entry point name, lib((entry_name)), but are otherwise handled as       described above.     Built-In Targets       make has knowledge about some special targets. These must be       specified in the makefile to take effect (with the exception of       .SUFFIXES, which is automatically set by make but can be changed by       the user).            .DEFAULT       If a file must be made but there are no explicit                           commands or relevant built-in rules for it, the                           commands associated with the target name .DEFAULT                           are used if .DEFAULT has been defined in the                           makefile. .DEFAULT does not have any explicit                           dependents.            .PRECIOUS      Dependents of this target are not removed when                           QUIT, INTERRUPT, TERMINATE, or HANGUP are                           received.            .SILENT        Same effect as the -s option. No dependents or                           explicit commands need to be specified.            .IGNORE        Same effect as the -i option. No dependents or                           explicit commands need to be specified.            .SUFFIXES      The explicit dependents of .SUFFIXES are added to                           the built-in list of known suffixes and are used                           in conjunction with the inference rules. If                           .SUFFIXES does not have any dependents, the list                           of known suffixes is cleared. There are no                           commands associated with .SUFFIXES.     Built-in Macros       There are five internally maintained macros that are useful for       writing rules for building targets. In order to clearly define the       meaning of these macros, some clarification of the terms target and       dependent is necessary. When make updates a target, it may actually       generate a series of targets to update. Before any rule (either       explicit or implicit) is applied to the target to update it, recursion       takes place on each dependent of the target. The dependent, upon       recursion, becomes a target itself, and may have or generate its own       dependents, which in turn are recursed upon until a target is found       that has no dependents, at which point the recursion stops. Not all       targets processed by make appear as explicit targets in the makefile;       some of them are explicit dependents from the makefile while others       are implicit dependents generated as make recursively updates the       target. For instance, when the following makefile is executed:            pgm: a.o b.o                cc a.o b.o -o pgm       the following series of targets to be made is generated:            --- pgm   with two dependents and an explicit rule to follow            --- a.o   (recursively) with an implicit dependent of a.c which                      matches the implicit rule .c.o            --- a.c   (recursively) with no implicit dependents and no                      implicit rules. This stops the recursion and simply                      returns the last modification time of the file a.c.            --- b.o   (recursively) with an implicit dependent of b.c which                      matches the implicit rule .c.o            --- b.c   (recursively) with no implicit dependents and no                      implicit rules. This stops the recursion and merely                      returns the last modification time of the file b.c.       In the definitions below, the word target refers to a target specified       in the makefile, an explicit dependent specified in the makefile which       becomes the target when make recurses on it, or an implicit dependent       (generated as a result of locating an inference rule and file that       match the suffix of the target) which becomes the target when make       recurses on it. The word dependent refers to an explicit dependent       specified in the makefile for a particular target, or an implicit       dependent generated as a result of locating an appropriate inference       rule and corresponding file that matches the suffix of the target.       It may be helpful to think of target rules as user specified rules for       a particular target name, and inference rules as user or make       specified rules for a particular class of target names. It may also       be helpful to remember that the value of the target name and its       corresponding dependent names change as make recurses on both explicit       and implicit dependents, and that inference rules are only applied to       implicit dependents or to explicit dependents which do not have target       rules defined for them in the makefile.       $@             The $@ macro is the full target name of the current                      target, or the archive filename part of a library                      archive target. It is evaluated for both target and                      inference rules.       $%             The $% macro is only evaluated when the current target                      is an archive library member of the form                      libname(member.o) or libname((entry.o)). In these                      cases, $@ evaluates to libname and $% evaluates to                      member.o or entry.o. $% is evaluated for both target                      and inference rules.       $?             The $? macro is the list of dependents that are out-                     of-date with respect to the current target;                      essentially, those modules that have been rebuilt. It                      is evaluated for both target and inference rules, but                      is usually only used in target rules. $? evaluates to                      one name only in an inference rule, but may evaluate to                      more than one name in a target rule.       $<             In an inference rule, $< evaluates to the source file                      name that corresponds to the implicit rule which                      matches the suffix of the target being made. In other                      words, it is the file that is out-of-date with respect                      to the target. In the .DEFAULT rule, the $< macro                      evaluates to the current target name. $< is evaluated                      only for inference rules. Thus, in the .c.o rule, the                      $< macro would evaluate to the .c file. An example for                      making optimized .o files from .c files is:                           .c.o:                               cc -c -O $*.c                      or:                           .c.o:                               cc -c -O $<       $*             The macro $* is the current target name with the suffix                      deleted. It is evaluated only for inference rules.       These five macros can have alternative forms. When an uppercase D or       F is appended to any of the five macros, the meaning is changed to       ``directory part'' for D and ``file part'' for F. Thus, $(@D) refers       to the directory part of the string $@. If there is no directory       part, ./ is generated. When the $? macro contains more than one       dependent name, the $(?D) expands to a list of directory name parts       and the $(?F) expands to a list of the filename parts.       In addition to the built-in macros listed above, other commonly used       macros are defined by make. These macros are used in the default       inference rules, and can be displayed with the -p option. These       macros can be used in target rules in the makefile. They can also be       redefined in the makefile.            $$@            The $$@ macro has meaning only on dependency                           lines. Macros of this form are called dynamic                           dependencies because they are evaluated at the                           time the dependency is actually processed. $$@                           evaluates to exactly the same thing as $@ does on                           a command line; i.e., the current target name.                           This macro is useful for building large numbers of                           executable files, each of which has only one                           source file. For instance, the following HP-UX                           commands could all be built using the same rule:                                CMDS = cat echo cmp chown                                $(CMDS) : $$@.c                                    $(CC) -O $? -o $@                           If this makefile is invoked with make cat echo cmp                           chown, make builds each target in turn using the                           generic rule, with $$@ evaluating to cat while cat                           is the target, to echo when the target is echo,                           and so forth.                           The dynamic dependency macro can also take the F                           form, $$(@F) which represents the filename part of                           $$@. This is useful if the targets contain                           pathnames. For example:                                INCDIR = /usr/include                                INCLUDES = $(INCDIR)/stdio.h \                                        $(INCDIR)/pwd.h \                                        $(INCDIR)/dir.h \                                        $(INCDIR)/a.out.h                                $(INCLUDES) : $$(@F)                                    cp $? $@                                    chmod 0444 $@     Special Macros       The VPATH macro allows make to search a colon separated list of       directories for dependents. Lines of the form VPATH= path1:path2 ...       causes make to first search the current directory for a dependent and       if the dependent is not found, make searches path1 and continues until       the directories specified in the VPATH macro are exhausted.  EXTERNAL INFLUENCES     Environment Variables       LANG provides a default value for the internationalization variables       that are unset or null. If LANG is unset or null, the default value of       "C" (see lang(5)) is used. If any of the internationalization       variables contains an invalid setting, make will behave as if all       internationalization variables are set to "C". See environ(5).       LC_ALL If set to a non-empty string value, overrides the values of all       the other internationalization variables.       LC_CTYPE determines the interpretation of text as single and/or       multi-byte characters, the classification of characters as printable,       and the characters matched by character class expressions in regular       expressions.       LC_MESSAGES determines the locale that should be used to affect the       format and contents of diagnostic messages written to standard error       and informative messages written to standard output.       NLSPATH determines the location of message catalogues for the       processing of LC_MESSAGES.       PROJECTDIR provides a directory to be used to search for SCCS files       not found in the current directory. In all of the following cases, the       search for SCCS files will be made in the directory SCCS in the       identified directory. If the value of PROJECTDIR begins with a slash,       it is considered an absolute pathname; otherwise, the home directory       of a user of that name is examined for a subdirectory src or source.       If such a directory is found, it is used. Otherwise, the value is used       as a relative pathname.       If PROJECTDIR is not set or has a null value, the search for SCCS       files will be made in the directory SCCS in the current directory.       The setting of PROJECTDIR affects all files listed in the remainder of       this utility description for files with a component named SCCS.     International Code Set Support       Single and multi-byte character code sets are supported.  RETURN VALUES       make returns a 0 upon successful completion or a value greater than 0       if an error occurred. If the -q option is specified, make returns 0       if the target was up-to-date and a value greater than 0 if the target       was not up-to-date.  EXAMPLES       The following example creates an executable file from a C source code       file without a makefile, if program.c exists in the current directory:            make program       The following example shows more than one makefile specified and some       command line macros defined, and updates the first target in module1:            make -f module1 -f module2 RELEASE=1.0 CFLAGS=-g       The following example updates two targets in a default makefile       currently residing in the current directory:            make clobber prog       The following example updates the prog target in a specified makefile,       allows environment variables to override any common variables in the       makefile, clears the built-in suffix list and ignore the built-in       rules, and outputs exhaustive debugging information:            make -erd -f module1 prog  WARNINGS       Be wary of any file (such as an include file) whose access,       modification, and last change times cannot be altered by the make-ing       process. For example, if a program depends on an include file that in       turn depends on another include file, and if one or both of these       files are out-of-date, make tries to update these files each time it       is run, thus unnecessarily re-makeing up-to-date files that are       dependent on the include file. The solution is to manually update       these files with the touch command before running make (see touch(1)).       (Note that it is generally a bad idea to include the touch(1) command       in your makefile, because it can cause make to update a program that       otherwise did not need to be updated.)       Some commands return non-zero status inappropriately; use -i to       overcome the difficulty.       File names with the characters =:@$ do notwork.       Built-in commands that are directly executed by the shell such as cd       (see cd(1)), are ineffectual across new-lines in make.       The syntax (lib(file1.o file2.o file3.o) is illegal.       You cannot build lib(file.o) from file.o.       The macro $(a:.o=.cZ) does not work.       Expanded target lines cannot contain mo~e than 16384 characters,       including the terminating new-line.       If no makefile exists in the current directory, typing            make filename       results in make attempting to build filename from filename.c       If make is invoked in a shell script with a quoted argument that       evaluates to NULL (such as $@), make fails.  DEPENDENCIES     NFS Warning:       When comparing modification times of files located on different NFS       servers, make behaves unpredictably if the clocks on the servers are       not synchronized.  FILES       [Mm]akefile       s.[Mm]akefile       SCCS/s.[Mm]akefile  SEE ALSO       cc(1), cd(1), lex(1), mkmf(1), sh(1), yacc(1), environ(5), lang(5),       regexp(5).       A Nutshell Handbook, Managing Projects With Make by Steve Talbot,       Second Edition, O'Reilly & Associates, Inc., 1986.  STANDARDS CONFORMANCE       make: SVID2, SVID3, XPG2, XPG3, XPG4, POSIX.2 
CONTENTS


UNIX User's Handbook
UNIX Users Handbook (2nd Edition)
ISBN: 0130654191
EAN: 2147483647
Year: 2001
Pages: 34

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net