5
votes

I'm looking for help getting my Makefile to do what I want it to do.

I have figured out how to add preprocessing code to my C source which will compile only if I'm compiling for debug:

#if DEBUG
  printf("main()\n");

  {
    /* Pauses execution so gdb can attach. */
    int i=9;
    pid_t PID;
    char hostname[256];
    gethostname(hostname, sizeof(hostname));
    printf("PID %d on %s ready for attach.\n", PID=getpid(), hostname);
    fflush(stdout);
    while (i>0) {
      sleep(5);
      i--;
    }
  }
#endif

And I've figured out that if I add -DDEBUG=1 to my compile statement, that the above code will be compiled (otherwise it's not compiled).

Next, I want to pass a flag to my Makefile which will either include, or not include the -D option. Currently, I have two separate compile lines which I comment and uncomment as appropriate. Here is my Makefile (which I inherited from someone and am having a difficult time understanding). See the lines that say CFLAGS?:

SHELL = /bin/sh

prefix       = /home/schwarz/sundials/instdir
exec_prefix  = ${prefix}
includedir   = ${prefix}/include
libdir       = ${exec_prefix}/lib

CPP         = cc -E
CPPFLAGS    =
CC          = cc
# CFLAGS      = -Wall -g
CFLAGS      = -Wall -g -DDEBUG=1
# CFLAGS      = -g -O2
LDFLAGS     =
LIBS        = -lm
MPICC       = /usr/local/mpi/bin/mpicc
MPI_INC_DIR = /usr/local/mpi/bin/../include
MPI_LIB_DIR = /usr/local/mpi/bin/../lib
MPI_LIBS    =
MPI_FLAGS   =

INCLUDES = -I${includedir} -I${MPI_INC_DIR}
LIBRARIES = -lsundials_cvode -lsundials_nvecparallel ${LIBS}
LIBRARIES_BL =

EXAMPLES = FPU          # cvAdvDiff_non_p cvDiurnal_kry_bbd_p cvDiurnal_kry_p


OBJECTS = ${EXAMPLES:=.o}

# -----------------------------------------------------------------------------------------

.SUFFIXES : .o .c

.c.o :
        ${MPICC} ${CPPFLAGS} ${CFLAGS} ${MPI_FLAGS} ${INCLUDES} -c $<

# -----------------------------------------------------------------------------------------

all: ${OBJECTS}
        @for i in ${EXAMPLES} ; do \
          echo "${MPICC} -o $${i} $${i}.o ${MPI_FLAGS} ${CFLAGS} ${LDFLAGS} -L${libdir} ${LIBRARIES} -L${MPI_LIB_DIR} ${MPI_LIBS} ${LIBRARIES_BL}" ; \
          ${MPICC} -o $${i} $${i}.o ${MPI_FLAGS} ${CFLAGS} ${LDFLAGS} -L${libdir} ${LIBRARIES} -L${MPI_LIB_DIR} ${MPI_LIBS} ${LIBRARIES_BL}; \
        done

clean:
        rm -f ${OBJECTS}
        rm -f ${EXAMPLES}

I have searched the web - I swear! - but cannot figure out how to pass a parameter into the makefile. How can I set up my Makefile so that it does different types of compiles of the same code for different compile needs? Even better would be if I could pass a specific value to the Makefile, which would pass a specific value to the compile, which I could use to initialize i in the code. (IOW, I compile as make 8 and the C is compiled as int i=8;). Is any of that even possible in Make?

As an aside, I've read about Makefiles and how they work by listing files with labels (colons), followed by their dependencies. But I can't understand how this Makefile works or why it issues two compile statements. So a brief explanation would also be helpful.

5
Have you read this section of the manual? Also, don't use = and prefer := whenever possible.Kerrek SB
@KerrekSB Good link, though not many examples. I still needed how to pass values into make. Thanks.Jeff

5 Answers

10
votes

To choose between debug and release versions:

ifeq($(debug),1)
  CFLAGS      = -Wall -g -DDEBUG=1
else
  CFLAGS      = -Wall -g
endif

and then invoke make:

make debug=1

to compile with DEBUG, or:

make

to compile without debug.

For initializing i:

#include <stdio.h>

#ifndef INIT_I
# define INIT_I 9
#endif
int main() {
  int i = INIT_I;
  return 0;
}

and makefile:

ifneq ($(init_i),)
CFLAGS = "-DINIT_I=$(init_i)"
endif

all:
  gcc d.c $(CFLAGS) -E

to set initial i:

make init_i=10

or use default value:

make
3
votes

Example Makefile:

...
CFLAGS = whatever
....
ifeq ("$(DEBUG)","yes")
CFLAGS += -DDEBUG=1
endif

With this, you could run make as:

make "DEBUG=yes"

Basically, you can set makefile variables on the make command line. You can use these like any other variables in the makefile, so you could also use them directly.

EDIT: you have to be careful, though. Unless you take care to name your object files appropiately, or use different build dirs, running make with different "DEBUG" settings isn't going to recompile things automatically.

2
votes

Yes it is.

You can use gcc's -D option to declare a macro, using it in your code :

> gcc -DMYINT=8 foo.c

with foo.c

int foo(void)
{
  int my = MYINT;
}

and in your makefile use :

CFLAGS    =    -DMYINT=$(MYINT)

and call make :

> make MYINT=8
1
votes

One way to achieve what you want is to pass the value of CFLAGS to your makefile from your shell.

CFLAGS='-Wall -g -DDEBUG=1' make -e 

for you debug version, or

CFLAGS='-Wall -g' make -e

for your non debug one

1
votes

you can assign your CFLAGS variable in make like this : CFLAGS ?= -Wall -g -DDEBUG=1

if you run make command with no parameter, the CFLAGS will have a default value '-Wall -g -DDEBUG=1'

while if you run make like this: make CFLAGS='-DDEBUG=0'

this command will assign the CFLAGS value with the value '-DDEBUG=0' the assigned value will override the default value assigned in makefile