user3127171
user3127171

Reputation: 63

Forcing Orders in Makefile Dependencies

I need some help writing a GNU makefile. I have a C program "main.c", which is dependent on the value of "CONSTANT" defined in the file "constants.h".

"main.c"

#include <stdio.h>
#include "constants.h"

void work(void)
{
    int array[CONSTANT];
    for (int i = 0; i < CONSTANT; i++) {
        printf("%d\n", i);
    }
}

int main(int argc, char const* argv[])
{
    printf("constant=%d\n", CONSTANT);
    work();
    return 0;
}

"constant.h"

#ifndef CONSTANTS_H
#define CONSTANTS_H

#define CONSTANT 4
#endif

What I'm trying to do here is to compile the program with different values for "CONSTANT". For example, "out1" is compiled with "CONSTANT=1" and with "make all", I should be able to produce all the variants ("out1", "out2" and "out4").

The problem is that "a.o" required by "main.c" also depends on the value of "CONSTANT". So "a.o" must be compiled after "sed%". However, as far as I understand, there is no way in "make" to force orders in dependencies (I guess this is the whole point of using makefiles).

What is the recommended way to address this situation?

"Makefile"

CC= gcc
CFLAGS  = -std=c99 -Wall

CONSTANTS = 1 2 4
targets = $(addprefix out, $(CONSTANTS))
seds = $(addprefix sed, $(CONSTANTS))

.PHONY: $(seds)
$(seds): sed%:
  sed -i 's/define CONSTANT [0-9]*/define CONSTANT $*/g' constants.h

$(targets): out%: main.c sed% a.o
  $(CC) $(CFLAGS) $< a.o -o $@

a.o: a.c constant.h
  $(CC) $(CFLAGS) $< a.o -o $@

 .PHONY: all
 all : $(targets)

Note that I'm aware that I can rewrite "main.c" so that it takes a parameter from the comman line. In practice, many other files other than "main.c" depend on "CONSTANT", so I want to avoid rewriting all these files. I'm also aware that I can do something like "gcc -DCONSTANT=n main.c", but every file dependent on "CONSTANT" must be recompiled as well.

Related Questions

Upvotes: 2

Views: 458

Answers (1)

Mike Kinghan
Mike Kinghan

Reputation: 61610

I'm ... aware that I can do something like "gcc -DCONSTANT=n main.c", but every file dependent on "CONSTANT" must be recompiled as well.

This needn't be a hindrance if you have your makefile generate the correct -DCONSTANT=n and distinct object file in every compilation recipe.

Here's an illustration:

constants.h

#ifndef CONSTANTS_H
#define CONSTANTS_H

#ifndef CONSTANT
#define CONSTANT 4
#endif

#endif

foo.c

#include "constants.h"

int foo = CONSTANT;

main.c

#include <stdio.h>
#include "constants.h"

extern int foo;

int main()
{
    printf("%d\n",CONSTANT + foo);
    return 0;
}

Makefile

CC := gcc
CFLAGS := -std=c99 -Wall

CONSTANTS = 1 2 4
TARGETS = $(addprefix out, $(CONSTANTS))
SRCS := main.c foo.c

define compile =
$(basename $(1))$(2).o: $(1) constants.h
    $$(CC) -c -DCONSTANT=$(2) $$(CFLAGS) $$< -o $$@
endef

.PHONY: all clean

all : $(TARGETS)

$(foreach src,$(SRCS),\
    $(foreach const,$(CONSTANTS),$(eval $(call compile,$(src),$(const))))) 

out%: main%.o foo%.o 
    $(CC) $^ -o $@


clean:
    rm -f $(TARGETS) *.o

This runs like:

$ make
gcc -c -DCONSTANT=1 -std=c99 -Wall main.c -o main1.o
gcc -c -DCONSTANT=1 -std=c99 -Wall foo.c -o foo1.o
gcc main1.o foo1.o -o out1
gcc -c -DCONSTANT=2 -std=c99 -Wall main.c -o main2.o
gcc -c -DCONSTANT=2 -std=c99 -Wall foo.c -o foo2.o
gcc main2.o foo2.o -o out2
gcc -c -DCONSTANT=4 -std=c99 -Wall main.c -o main4.o
gcc -c -DCONSTANT=4 -std=c99 -Wall foo.c -o foo4.o
gcc main4.o foo4.o -o out4

And the resulting programs run like:

$ for i in 1 2 4; do ./out$i; done
2
4
8

Upvotes: 3

Related Questions