Using ifdef and ifndef directives

12,718

You can combine the shell's facilities with Make's to get a fairly succinct definition.

define compile
        @dir="${1}"; outdir="${2}"; outdir=$${outdir:-"$dir"}; \
        $(COMPILER) -output-directory "$${outdir}" "$${dir:-.}/*.tex

The double-dollar is an escape which passes a single dollar sign to the shell. The construct ${variable:-value} returns the value of $variable unless it is unset or empty, in which case it returns value. Because ${1} and ${2} are replaced by static strings before the shell evaluates this expression, we have to take the roundabout route of assigning them to variables before examining them.

This also demonstrates how to combine two "one-liners" into a single shell invocation. The semicolon is a statement terminator (basically equivalent to a newline) and the sequence of a backslash and a newline causes the next line to be merged with the current line into a single "logical line".

This is complex enough that I would recommend you omit the leading @ but I left it in just to show where it belongs. If you want silent operation, once you have it properly debugged, run with make -s.

Share:
12,718
Rubens
Author by

Rubens

#SOreadytohelp I'm a computer science undergrad and research assistant at the Federal University of Minas Gerais (UFMG), working with distributed computing and data mining. My favorite programming languages are bash and c++, and I'm amused by unix' wondrous set of magic tools, regular expressions, and Twelf. "Everything can happen. Everything is possible and probable. Time and space do not exist. On a flimsy framework of reality, the imagination spins, weaving new patterns." Ingmar Bergman -- Fanny and Alexander

Updated on June 04, 2022

Comments

  • Rubens
    Rubens almost 2 years

    I'm trying to check whether a variable is defined using ifndef/ifdef, but I keep getting a not found error from the execution. I'm using GNU Make 3.81, and here is a snippet of what I have:

    all: _images                 
        $(call clean, .)         
        $(call compile, .)       
        @$(OPENER) *.pdf &       
    
    _images:                     
        $(call clean, "images")  
        $(call compile, "images")
    
    define clean                                             
        @rm -f ${1}/*.log ${1}/*.aux ${1}/*.pdf              
    endef                                                    
    
    define compile                                           
    
        ifdef ${1}                                           
            dir = ${1}                                       
        else                                                 
            dir = .                                          
        endif                                                
    
        ifdef ${2}                                           
            outdir = ${2}                                    
        else                                                 
            outdir = ${1}                                    
        endif                                                
    
        @$(COMPILER) -output-directory ${outdir} ${dir}/*.tex
    
    endef                                                    
    

    And the exact error:

    $ make                       
    ifdef  "images"              
    /bin/sh: 1: ifdef: not found 
    make: *** [_images] Error 127
    

    Edit:

    Considering Barmar comments, here goes the conclusions:

    The contents of a define are shell command lines, not make directives; to break lines inside commands within a define block, the linebreak must be escaped -- with \; also, each block corresponding to one-liner commands is executed separately, each in a different shell execution, which means that, defining local variables won't work if the intention is to access the variable value in the next one-liner block.

    Thanks tripleee for the nice work around.

  • Rubens
    Rubens over 11 years
    Well done, bro'! Good to see this ${...:-...} being used (: Thanks!