2017-09-07 1 views
2

J'ai besoin d'aide pour écrire un makefile GNU. J'ai un programme C "main.c", qui dépend de la valeur de "CONSTANT" définie dans le fichier "constants.h".Forcer les commandes dans les dépendances Makefile

"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 

Ce que je suis en train de faire ici est de compiler le programme avec des valeurs différentes pour "CONSTANT". Par exemple, "out1" est compilé avec "CONSTANT = 1" et avec "make all", je devrais être capable de produire toutes les variantes ("out1", "out2" et "out4").

Le problème est que "a.o" requis par "main.c" dépend aussi de la valeur de "CONSTANT". Donc "a.o" doit être compilé après "sed%". Cependant, autant que je comprenne, il n'y a aucun moyen de "faire" pour forcer des ordres dans les dépendances (je suppose que c'est le point entier d'utiliser makefiles).

Quelle est la méthode recommandée pour remédier à cette 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 [email protected] 

a.o: a.c constant.h 
    $(CC) $(CFLAGS) $< a.o -o [email protected] 

.PHONY: all 
all : $(targets) 

Notez que je suis conscient que je peux réécrire « main.c » pour qu'il prenne un paramètre de la ligne comman. En pratique, beaucoup d'autres fichiers que "main.c" dépendent de "CONSTANT", donc je veux éviter de réécrire tous ces fichiers. Je suis également conscient que je peux faire quelque chose comme "gcc-DCONSTANT = n main.c", mais chaque fichier dépendant de "CONSTANT" doit aussi être recompilé.

Questions connexes

+1

Marque assume e à la fois, il a construit un fichier ('a.o'), il est à jour et n'aura pas besoin d'être recompilé lors de la même exécution. Par conséquent, vous devez faire autre chose. Une option serait de créer 'a1.o',' a2.o' et 'a4.o' de' a.c' et 'constants.h' et sed-travail approprié. S'il n'y a qu'une constante, considérez '-DCONSTANT = 1' sur la ligne de commande lorsque vous créez' a1.o' à partir de 'a.c', etc, sans utiliser' constants.h'. Cependant, je soupçonne qu'il s'agit d'une question de minimisation pour SO, et vous avez plus de valeurs que celle à définir. J'ai toujours tendance à créer des fichiers objets nommés différemment. –

+0

Veuillez fournir un [mcve] avec un test. C'est à dire. définir une situation (constante.h) modifiée ou une certaine façon d'appeler le fichier make) et un résultat souhaité, c'est-à-dire une sortie ou un contenu résultant de fichiers. – Yunnosch

+0

@JonathanLeffler Je suis allé pour générer des fichiers objet séparés (a1.o, a2.o, ....) comme vous et Mike suggéré. Mon programme n'a qu'une seule constante à configurer, donc votre solution a fonctionné pour moi. Je vous remercie. – user3127171

Répondre

3

... Je suis conscient que je peux faire quelque chose comme « -DCONSTANT gcc = n principal. c ", mais chaque fichier dépendant de" CONSTANT "doit également être recompilé.

Cela ne doit pas être un obstacle si vous avez votre makefile générer le fichier objet -DCONSTANT=n et distinct correct dans chaque recette de compilation.

est ici une illustration:

constants.h

#ifndef CONSTANTS_H 
#define CONSTANTS_H 

#ifndef CONSTANT 
#define CONSTANT 4 
#endif 

#endif 

foo.c

#include "constants.h" 

int foo = CONSTANT; 

principale.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 [email protected] 
endef 

.PHONY: all clean 

all : $(TARGETS) 

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

out%: main%.o foo%.o 
    $(CC) $^ -o [email protected] 


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

Cela fonctionne comme:

$ 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 

et les programmes qui en résultent fonctionnent comme:

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

Les fichiers objets séparés ont du sens. J'ai eu mon truc qui marche. Je vous remercie. – user3127171