2009-03-12 4 views
1

Я мало знаю о создании Makefiles, но я читал make manual, и я сделал некоторый прогресс. Мой Makefile работает и делает то, что я хочу.Как я могу улучшить этот Makefile?

В моей ситуации обычно используется от 1 до 3 различных программ, которые необходимо скомпилировать и отправить в мою TA для маркировки и, например, через веб-форму. Структура каждого приложения - «prog.c», «prog_lib.h» и «prog_lib.c». Раньше я создавал отдельные каталоги для каждой программы и создавал отдельные Make-файлы для каждого каталога для сборки программы, содержащейся внутри. Затем я деактивирую каждую папку и отправляю их отдельно.

Недавно TA запросили, чтобы все исходные файлы находились в одном каталоге и один Makefile с различными целями, которые должны быть построены, чтобы их приложения для маркировки могли работать без какого-либо вмешательства человека.

Мне было интересно, как кто-то более опытный улучшит этот Makefile и как моя ситуация обычно будет решена? Я хотел бы уменьшить объем ввода, который мне нужно сделать, когда я перехожу к следующему заданию и должен обновить несколько мест.

Вот мой Makefile:

ASSIGNMENT = 3 
TARNAME = Assignment$(ASSIGNMENT).tar.bz2 

CC = gcc 
CFLAGS = -O2 -Wall -ansi -pedantic -W # I like warnings 
LDFLAGS = -lm 
DEBUG = -g # to resolve symbols in GDB and valgrind 

FREQ_OUT = frequency_table 
FREQ_SOURCES = frequency_table.c frequency_table_lib.c 
FREQ_OBJECTS = frequency_table.o frequency_table_lib.o 

DECODE_OUT = decode 
DECODE_SOURCES = decode.c decode_lib.c 
DECODE_OBJECTS = decode.o decode_lib.o 

SOURCES = $(FREQ_SOURCES) $(DECODE_SOURCES) 
OBJECTS = $(FREQ_OBJECTS) $(DECODE_OBJECTS) 
OUT = $(FREQ_OUT) $(DECODE_OUT) 

.PHONY: info 
info: 
    @echo -e "make info\n" \ 
      "\tmake all \t\t\tMake all targets\n" \ 
      "\tmake frequency_table \t\tMakes frequency table\n" \ 
      "\tmake decode \t\t\tMakes decode\n" \ 
      "\tmake dist \t\t\tMakes tar archive of sources and Makefile\n" \ 
      "\tmake clean \t\t\tRemoves all the object files and executables\n" \ 
      "\tmake distclean \t\t\tPerforms clean and removes tar archive" 

.PHONY: all 
all: $(OUT) 

$(FREQ_OUT): $(FREQ_OBJECTS) 
    $(CC) $(CFLAGS) $(DEBUG) $(LDFLAGS) $(FREQ_OBJECTS) -o [email protected] 

$(DECODE_OUT): $(DECODE_OBJECTS) 
    $(CC) $(CFLAGS) $(DEBUG) $(LDFLAGS) $(DECODE_OBJECTS) -o [email protected] 

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

.PHONY: dist 
dist: $(SOURCES) 
    @echo "Creating tar archive. See $(TARNAME)" 
    tar cvjf $(TARNAME) $(SOURCES) $(wildcard *_lib.h) Makefile 

.PHONY: clean 
clean: 
    rm -f $(OUT) $(OBJECTS) 

.PHONY: distclean 
distclean: clean 
    rm -f $(TARNAME) 
+0

не выглядит так: «Я мало знаю о создании Makefiles» из кода :) – Lazer

ответ

3

Вам действительно не нужны линии $(CC) $(CFLAGS) $(DEBUG) $(LDFLAGS) $(FREQ_OBJECTS) -o [email protected]. make уже знает, как создавать двоичные файлы.

Если ваши имена файлов являются постоянными для различных бинарных файлов (binary.c и binary_lib.c), вы также можете создать общее правило, что:

FOO := $(shell ls *_lib.c) 
BIN = $(FOO:%_lib.c=%) 

$(BIN) : % : %.o %_lib.o 

EDIT: Вот как это работает:

  1. FOO список всех файлов, заканчивающихся _lib.c
  2. BIN в тот же список, с «_lib.c» суффиксы удалены, так что список ваших бинарных файлов
  3. Последняя строка - ваше правило make. Правило гласит, каждый Foo в $ (BIN) зависит от foo.o и foo_lib.o
+0

Это работает очень хорошо, но я не совсем уверен, почему он работает. Не могли бы вы это немного разъяснить? В частности, строка $ (BIN). Какую цель выполняет одиночный%? –

+0

Спасибо за объяснение. Я использую этот метод, и он работает очень хорошо. –

+2

синтаксический анализ вывода 'ls' является * очень * плохой практикой, в скриптах оболочки и Makefiles. 'FOO: = $ (wildcard * _lib.c)' намного лучше. – MestreLion

2

По моему опыту, вы не должны нуждаться в .o цели там, это подразумевается.

Кроме того, неявная версия обычно включает в себя стоимость $(CPPFLAGS), в котором вы должны поставить любые -Iпути или -Dмакросов параметров, которые могут потребоваться.

Я бы также включил $(DEBUG) в $(CFLAGS), а не перечислил его явно в любой из целей сборки.

1

Пример:

# CC, CFLAGS, etc. go here 

# Object variables go here 
MYPROG_OBJECTS = main.o someother.o 

# all, info, etc. targets go here 

# first actual target: 
myprog: $(MYPROG_OBJECTS) 
    <Do the linking stuff> 

# This will take care of the objects, sources are placed in src directory: 
%.o: src/%.c 
    <The usual compilation commands> 

# Automatic dependency magic: 
%.d: src/%.c 
    $(CC) -MM [email protected] $< 

-include (MYPROG_OBJECTS:%.o=%.d) 
3

Сделать «все» предназначаться первый, если вы действительно, что ваш пользователи должны будут ввести что-то после «make», чтобы получить проект для сборки. Цель «info» хороша, но обычна.

(У меня есть один файл makefile, где цель по умолчанию - не все - в каталоге с исходным кодом для более 100 команд. Я не хочу, чтобы все было установлено «по умолчанию», я рассчитываю построить только один или два, которые я хочу построить.Существует «все». Но это очень необычно. Обычно значение по умолчанию должно быть «все».)

Кроме того, ни «$ (FREQ_OUT)», ни «$ (DECODE_OUT)» не является целью PHONY; они настоящие программы, не так ли? Цели «все», «информация», «dist», «чистый», «realclean» и т. Д. - это фальшивые. Но программ, которые вы создаете, нет.

+0

Спасибо за подсказку и исправлю о реальных точках .PHONY. Я удалил эту часть и обновил этот пример. –

Смежные вопросы