Alcatel-Lucent nmake Product Builder

What is the difference between Alcatel-Lucent nmake and gnu make?

This document compares and contrast the features of GNU make version 3.75 and nmake version 3.x. The intention here is to facilitate Lucent software development product teams in deciding on the tool that best fits their environment. The strength and weakness of both tools are outlined and compared.

A GNU make to nmake makefile conversion example is provided to give users an idea of the mapping of the features of both tools and the ease of the conversion effort.

For additional discussion of nmake benefits see the Impact of Features section.

Table of Contents

  1. Compare GNU make and nmake
  2. Contrast of GNU make and nmake
  3. Makefile Conversion Example -- GNU make to nmake

I. Compare GNU make and nmake

This table provides a summary of the similarities of GNU make and nmake.

GNU make nmake
GENERAL RULE FORMAT
  • A target, usually the name of a file, is created/updated by commands triggered by changes in the files (usually) on which the target depends (called dependencies).
    
        target ... : dependencies ...
                command
    	    ...
    	    ...
        
  • Target created/updated via the accompanying action block shell script when prerequisites change.
    
        target : prerequisites
                action block shell script
        

IMPLICIT RULES DEFINITION
  • pattern rules using the wild-card '%' may be chained.
    To compile .c to .o :
        %.o : %.c
    	$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
        
  • metarules using the wild-card '%' may be chained.
    To compile .c to .o :
        %.o : %.c
    	$(CC) $(CCFLAGS) -c $(>)
        

VARIABLE DEFINITION
  • recursively expanded variable, defined using the '=' operator
  • simply expanded variable, defined using the ':=' operator
  • The same flavors of variable definition available (plus more).

[Table of Contents]


II. Contrast of GNU make and nmake

This table provides a summary of the differences between GNU make and nmake. It is not exhaustive. The intent was to highlight those areas where one would be likely to assume similarities and point out features present in one and absent in another that seem to be of significance.

GNU make nmake
MAKEFILE PROCESSING
  • Interprets the makefile at each execution.
  • Compiles the makefile and recompiles only if the original is altered.

RE-MAKING TARGETS
  • Has no knowledge of any previous run and must infer out-of-date targets by checking time stamps of targets and prerequisites.
  • Creates a statefile and uses the data in it to decide whether a target is out of date.

PREPROCESSING
  • No preprocessor
  • Uses a new C preprocessor for makefile and C files, if requested.

COMMAND EXECUTION
  • Each command line is executed by a new subshell. To get multiple lines executed by 1 subshell terminate each command line (except the last) with a ';' and a '\'. Default shell is /bin/sh.
  • Each shell action is sent as a unit (cf shell script) to the subshell. Default shell also /bin/sh.

AUTOMATIC DETECTION OF DEPENDENCIES
  • NO MECHANISM to scan a file and detect implicit dependencies. For example, included header files of C files MUST BE EXPLICITLY specified as dependencies in the makefile.
  • Has a powerful dynamic dependency generation mechanism that scans a source file for its implicit prerequisites-- file and preprocessor variable references. A great benefit of this mechanism is the fact that it is automatic and programmable - the scan can be extended to detect dependencies in new programming languages. For example C/C++ files: header files referenced with #include would become implicit file prerequisites while variables defined with a #define, implicit state variable prerequisites of the files scanned by nmake. Hence, they would NOT need to be explicitly specified as prerequisites of the source file, in the makefile.

SEARCHING DIRECTORIES FOR DEPENDENCIES
  • VPATH Variable -- a colon or blank separated list of directories to be searched - cf. nmake's patternless .SOURCE special atom. No notion of a "node" as in nmake.
  • VPATH Variable -- a colon-sep list of "nodes" to be searched. A node may be seen as a product's directory structure that accounts for proper directory partitioning of its source and destination (built) files. The whole structure usually can be referenced through a root node -- may be seen as an inverted tree.
  • "vpath" Directive -- colon or blank separated list of directories which allows one to search for files that match a particular pattern.
  • .SOURCE Atoms -- a blank-sep list of directories searched for files. It has pattern and no pattern forms and is used in conjunction with VPATH (when set).

INCLUDING OTHER MAKEFILES
  • include Directive -- used to include other makefiles. It is of the form, [-]include filenames .... where '-' tells make not to give an error if specified filename was not found.
  • include Directive -- used to include other makefiles. It is of the form, include [-] filenames ... where '-' tells nmake not to generate a warning if the specified filename was not found.
  • The search -- if the specified file did not start with a '/' and is not found in PWD, then it searches a specified list of -Idir options and the following directories; /usr/local/include, /usr/gnu/include, /usr/local/include and /usr/include.
  • The search -- uses .SOURCE atoms to search for file (Note: PWD is always searched first).
  • filenames Syntax -- may be shell file name patterns.
  • filenames Syntax -- no patterns or wildcards.

A SPECIAL METARULE
  • Has a special type of pattern rule known as Static Pattern Rules. These are like metarules defined to act on specified targets. It is of the form,
        targ ... : targ_pat : dep_pat
    	    command
        
    For example,
        foo.o boo.o : %.o : %.c
    	    $(CC) -c $(CFLAGS) $< -o $@
        
  • Not available - however, may be implemented in nmake with .USE rule.

OPERATIONS ON VARIABLES
  • Variable values may be tested and modified by a set of builtin functions (over 20 in v3.76) - of the form, $(function arguments) There are functions for string substitution & analysis, filenames, repetitive substitution and testing the origin of a variable. For example, the following assigns all but the directory part (basename and suffix) of the filename in VAR1 to VAR2 (VAR2 becomes "myfile.c"): VAR1 = ../mydir/myfile.c VAR2 = $(notdir $(VAR1))
  • Comes with a powerful set of what it terms 'edit operators' (over 60), that allows one to test and modify variable values during expansion - of the form, $(variable[:[@]edop[sep arg]]...) Using the same example to set VAR2 from VAR1 would be, VAR1 = ../mydir/myfile.c VAR2 = $(VAR1:B:S)

VARIABLES (Used by Engine)
  • From the environment -- by default vars from the env have a lower precedence than those in the makefile, but may be overridden by the -e flag.
  • From the environment -- always have a lower precedence than those defined in user makefile, but higher than those defined in a project-defined global rules and the standard base rules (Makerules.mk).
  • Common Variables
    MAKEFILES
    env. variable whose definition is used as a list of names of additional makefiles to be read before the default or specified one.
    MAKECMDGOALS
    set by make to the list of goals/targets specified on the command line.
    CFLAGS
    used to pass extra flags to the C compiler of the built-in implicit rule for compiling a C program. This is built into the make engine.
  • Common Variables
    MAKEFILES
    an engine var. whose default value is 'Makefile:makefile', a colon-sep list of candidate implicit makefile names.
    $(*.ARGS)
    the prerequisites of the special atom .ARGS are the list of targets specified on the command line
    CCFLAGS
    variable used to pass extra flags to the C/C++ compilers for the metarules defined in the base rules (NOT the engine!) that compiles C/C++ source files.

AUTOMATIC VARIABLES
  • Form -- can evaluate single character automatic variables without parentheses.
  • ALL variables require parentheses!
  • $@ File name of current target. If target is archive member, $@ is archive file.
  • $(<) Current target in all cases.
    $(@) Action for the current target.
  • $? All the prerequisites newer than the target.
  • $(>) Current out-of-date file prerequisites in all cases.
    $(?) All prerequisites of current target.
  • $* The stem in a pattern rule definition.
  • $(*) All file prerequisites of current target.
  • $^ All the current prerequisites.
    $~ Not available.
    $< The name of the first prerequisite.
  • $(~) All explicit prerequisites of current target.
  • $% The target member name when target is an archive member
  • $(%) The file name portion matched by '%' in a metarule definition.
  • $! Not Available.
  • $(!) All explicit and implicit prereqs of current target.
  • $+ Like $^, but prerequisites listed more than once are duplicated in the order listed in the makefile.
  • $(+) The current option settings suitable for use by the 'set' option.

USING THE VALUE OF A VARIABLE AS A PREREQUISITE
  • Not available.
  • nmake not only allow targets to have file prerequisites but also variable prerequisites. It calls such variables STATE VARIABLES and saves its value and modification time (in the statefile) for subsequent update requests. These variables are useful in defining a command and its associated flags, such as $(CC) and $(CCFLAGS) for a C compiler. They also play a vital role in nmake's scan for implicit prerequisites.

RECURSIVE MAKES
  • Implementation -- using the MAKE variable in this fashion,
    	subsystem:
    		cd subdir && $(MAKE)
        
    OR
    	subsystem:
    		$(MAKE) -C subdir
        
  • Implementation -- with the :MAKE: operator, as follows,
    	 subsystem :MAKE: subdir
        
  • Sub-make Communication -- MAKEFLAGS - used by make to pass flags/options to the sub-make. Environment - explicit export of variables to the environment using 'export' directive.
  • Recursive make communication -- $(-) and $(=) -- used to pass flags and variables to recursive make. Environment - also read by sub-make.

DISTRIBUTED BUILDS
  • NO mechanism.
  • Uses a network shell coprocess server (coshell) that establishes shell co-processes to other homogenous machines within a LAN, sending user jobs (commands) to them to be executed. A working UNIX® system and TCP/IP are required.

DOUBLE COLON RULE
  • The rules of targets with multiple :: rules are independent of each other. Each rule is executed only if the target is older than any dependencies of that rule. This may result in none, any or all of the :: rules being executed.
  • Most commonly used assertion operator, the source dependency operator. It is a set of predefined base rules that simplifies making an executable or archive target from a list of source files.
  • When used in a pattern rule it makes the dependencies terminal (not intermediate) files.

COMPUTED VARIABLE NAMES
  • Referencing variables on the left-hand side of a variable assignment. For example,
    	a = foo
    	$(a)_foo := interesting
        
    defines variable, foo_foo as 'interesting'.
  • May be implemented as follows:
    	a = foo
    
    	$(a)_foo := interesting
        
    OR
    	eval
    	    $(a)_foo = interesting	
    	end
        

ATTRIBUTE DIFFERENCES
  • .IGNORE
    when making the dependencies of the .IGNORE special target, make will ignore all exit codes from commands executed for making those files.
  • .DONTCARE
    an assertion attribute that causes nmake to continue if it cannot make the target that has this attribute.
    .IGNORE
    an attribute that forces target generation.
  • .PHONY
    a special target whose dependencies are considered to be phony targets.
  • .VIRTUAL
    targets with this attribute are considered virtual/phony targets.

VARIABLE DEFINITION USING OUTPUT OF SHELL COMMANDS
  • Using the 'define' directive -- variables may be defined as a canned sequence of commands whose value is the result of executing these commands. The variable definition may contain functions and variable references. For example,
    	define mydotcees
    	cd $(MYDIR)
    	$(wildcard *.c) 
    	endef
        
    assigns to variable 'mydotcees' the list of .c files in the directory $(MYDIR).
  • Using the :COMMAND: -- variables may be defined using the :COMMAND: Using the same example,
    	mydotcees :COMMAND:
    	    cd $(MYDIR)
    	    ls *.c
        
  • Using the 'shell' function -- The shell function does what back-quotes do in most shells - command expansion. That is, it takes an argument which is a shell command and returns the output of the command. So the above example could be written mydotcees := $(shell cd $(MYDIR); ls *.c)

HIGH-LEVEL ACCESS TO CANNED BASIC ASSERTIONS
  • None available -- GNU make does NOT possess any feature to define canned assertions as it does canned command sequences.
  • nmake provides "macro-like" assertion operators that define various functionalitites, using a sequence of ':' dependency operators. Not only does nmake define various useful ones in its base rules (See Chapter 11 of the Reference Manual) it also allow users to define their own.

COMMON ACTIONS
  • All targets must be explicitly defined in the user's makefile, including the common targets/actions such as 'install', 'clean', 'all'.
  • nmake realizes that targets such as 'install', 'clean', 'all' represents actions that are frequently done by users. Hence, the user doesn't have to define these targets in the makefile - nmake provides them. Common actions are specified on the command line. So to remove all generated intermediate files, issue
        $ nmake clean
        
    For a list of nmake's common actions see Chapter 3 -- 'Common Actions' (pgs. 3-21 to 3-30) of the Reference Manual.

[Table of Contents]


III. A Makefile Conversion Example -- GNU make to nmake

A Sample GNU Makefile

    # NOTE: This makefile is a modified version of the one in the GNU make
    #       that generates the GNU 'tar' program.
    
    SHELL = /bin/sh
    
    srcdir = .
    
    CC = gcc -O
    YACC = bison -y
    INSTALL = /usr/local/bin/install -c
    INSTALLDATA = /usr/local/bin/install -c -m 644
    
    DEFS =  -DSIGTYPE=int -DDIRENT -DSTRSTR_MISSING \
            -DVPRINTF_MISSING -DBSD42
    
    LIBS =
    DEF_AR_FILE = /dev/rmt8
    DEFBLOCKING = 20
    
    CDEBUG = -g
    CFLAGS = $(CDEBUG) -I. -I$(srcdir) $(DEFS)	\
            -DDEF_AR_FILE=\"$(DEF_AR_FILE)\"	\
            -DDEFBLOCKING=$(DEFBLOCKING)
    LDFLAGS = -g
    
    # The directory to install tar in.
    bindir = /usr/local/bin
    
    # The directory to install the info files in.
    infodir = /usr/local/info
    
    OBJS =  tar.o create.o extract.o buffer.o	\
            getoldopt.o update.o gnu.o mangle.o	\
            version.o list.o names.o diffarch.o	\
            port.o wildmat.o getopt.o		\
            getopt1.o regex.o getdate.o rtapelib.o
    
    all:    tar rmt tar.info
    
    tar:    $(OBJS)
            $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
    
    rmt:    rmt.c
            $(CC) $(CFLAGS) $(LDFLAGS) -o $@ rmt.c
    
    tar.info: tar.texinfo
            makeinfo tar.texinfo
    
    install: all
            $(INSTALL) tar $(bindir)/$(binprefix)tar
            -test ! -f rmt || $(INSTALL) rmt /etc/rmt
            $(INSTALLDATA) $(srcdir)/tar.info* $(infodir)
    
    $(OBJS): tar.h port.h testpad.h
    regex.o buffer.o tar.o: regex.h
    
    testpad.h: testpad
            ./testpad
    
    testpad: testpad.o
            $(CC) -o $@ testpad.o
    
    clean:
            rm -f *.o tar rmt testpad testpad.h core

Conversion of above GNU Makefile to nmake Makefile

    /*
    **  NOTE: This makefile is a modified version of the one in the GNU make
    **  that generates the GNU 'tar' program.
    */
    YACC = bison -y
    
    SIGTYPE         == int
    DIRENT          == 1
    STRSTR_MISSING  == 1
    VPRINTF_MISSING == 1
    BSD42           == 1
    DEF_AR_FILE     == "/dev/rmt8"
    DEFBLOCKING     == 20
    
    CC = gcc
    CCFLAGS = -O -g
    
    LDFLAGS = -g
    
    BINDIR = /usr/local/bin
    INFODIR = /usr/local/info
    ETCDIR = /etc
    
    SRCS =  tar.c create.c extract.c buffer.c	\
            getoldopt.c update.c gnu.c mangle.c	\
            version.c list.c names.c diffarch.c	\
            port.c wildmat.c getopt.c		\
            getopt1.c regex.c getdate.c rtapelib.c
    
    :ALL: tar rmt tar.info
    
    $(BINDIR)  :INSTALLDIR: tar
    $(ETCDIR)  :INSTALLDIR: rmt
    $(INFODIR) :INSTALLDIR: tar.info mode=644
    
    tar :: $(SRCS) $(LIBS)
    rmt :: rmt.c
    
    tar.info : tar.texinfo
    	makeinfo $(*)
    
    testpad.h : testpad
    	$(*)
    
    testpad :: testpad.c

Conversion Notes

  • The clean target in the GNU Makefile is handled by the nmake command:
    $ nmake clean
  • The install target in the GNU Makefile is handled by the :INSTALLDIR: operators and the nmake command:
    $ nmake install
  • No need to specify header file dependencies, nmake scans for them!
  • No need to specify -I options in CCFLAGS, nmake generates the -I options using the '.SOURCE.h : .' (the default) defined in the base rules.
  • The -D<name> flags are declared as state variables (via '==') -- nmake scans the source files for their use and includes the -D flags when needed. There is no need to include them in CCFLAGS. The -D option values are true dependencies when state variables are used, nmake automatically recompiles affected files when the values change.
  • No need to specify the action blocks for creating the tar and rmt executables -- nmake knows how to create them using the '::' operator.

[Table of Contents]

Last Update: Wednesday,21-Aug-2013 12:32:52 EDT