несколько вопросов о файлах сборки GNU

Мне было интересно, есть ли у кого-нибудь время, чтобы ответить на некоторые вопросы о файлах сборки GNU ...

  1. как создать каталог, если он не существует ("./obj") для вывода?
  2. У меня есть один make-файл, но у меня есть 2 метода сборки: «Отладка» и «Выпуск». Могу ли я использовать оба в 1 make-файле и как определить, какой из них нужно собрать?
  3. Я использовал Code :: Blocks, который строит только измененные файлы, но мой make-файл строит их каждый раз, когда я вызываю команду make, не касаясь файлов. как я могу заставить его собирать только измененные файлы?

вот мой текущий make-файл

OBJPATH=./obj
COMPILER=gcc

Output: main.o Base64.o
 $(COMPILER) -o Output.exe $(OBJPATH)/main.o $(OBJPATH)/Base64.o
 strip Output.exe

main.o: main.c main.h
 $(COMPILER) -c main.c -o $(OBJPATH)/main.o

Base64.o: Base64.c Base64.h
 $(COMPILER) -c Base64.c -o $(OBJPATH)/Base64.o

Благодарю.


person killercode    schedule 20.01.2011    source источник
comment
Какие цели он строит, когда вы ничего не изменили?   -  person Beta    schedule 20.01.2011


Ответы (3)


Что касается первого вопроса, вы можете поставить фальшивую цель перед любыми другими, например:

preamble:
    -mkdir obj

main.o: preamble main.c
    blah blah blah

Это автоматически выполнит все, что указано в преамбуле (вы должны сделать это первой зависимостью в каждом правиле), прежде чем он построит что-либо еще. - в начале mkdir игнорирует сбои, если, например, каталог уже существует.

На второй вопрос вы можете указать что-то вроде:

all: debug release

debug: blah blah blah

release: blah blah blah

и фактически поместите код отладки и выпуска в отдельные подкаталоги. Таким образом, вы можете построить либо с make release, либо с make debug, и построить их оба с make all.

Третий вопрос: ваш make-файл строится каждый раз, потому что ему это говорят правила. Например, Output: main.o Base64.o всегда будет пытаться построить, поскольку Output никогда не существует (правильная цель кажется Output.exe).

Точно так же правила ваших объектных файлов всегда будут выполняться, поскольку ни main.o, ни Base64.o не обновляются их операторами (вместо этого они обновляют файлы в каталоге obj).

Возможно, вы сможете исправить этот случай, сделав цель $(OBJPATH)/main.o, но, честно говоря, я обычно не беспокоюсь о разделении объектов и исполняемых файлов в отдельные каталоги. Я обычно просто сваливаю их все в один каталог и позволяю make -clean их очистить.


Итак, make-файл, с которого я бы начал, будет:

COMPILER=gcc

# Meta rules

all: release debug

release: Output.exe

debug: Output-d.exe

# Release stuff

Output.exe: main.o Base64.o
    $(COMPILER) -o Output.exe main.o Base64.o
    strip Output.exe

main.o: main.c main.h
    $(COMPILER) -c main.c -o main.o

Base64.o: Base64.c Base64.h
    $(COMPILER) -c Base64.c -o Base64.o

# Debug stuff

Output-d.exe: main-d.o Base64-d.o
    $(COMPILER) -g -o Output-d.exe main-d.o Base64-d.o

main-d.o: main.c main.h
    $(COMPILER) -g -DDEBUG -c main.c -o main-d.o

Base64-d.o: Base64.c Base64.h
    $(COMPILER) -g -DDEBUG -c Base64.c -o Base64-d.o

В ответ на ваш вопрос-комментарий:

Есть ли способ переустановить переменную на основе выбранной цели? например, если выбранный выпуск OBJPATH будет "./obj/Release", если выбран отладочный OBJPATH = "./obj/Debug"?

GNU Make может быть более мощным, чем те, к которым я привык, но вы можете сделать это, установив переменную среды, а затем повторно запустив make, как показано ниже:

all: release debug

release:
        ( export zzvar=release ; $(MAKE) zz_Output.exe )

debug:
        ( export zzvar=debug ; $(MAKE) zz_Output-d.exe )

zz_Output.exe:
        echo $(zzvar)
        touch zz_Output.exe

zz_Output-d.exe: zz_main-d.o zz_Base64-d.o
        echo $(zzvar)
        touch zz_Output-d.exe

который выводит:

( export zzvar=release ; make zz_Output.exe )
make[1]: Entering directory '/home/pax'
echo release
release                                             <==
touch zz_Output.exe
make[1]: Leaving directory '/home/pax'

( export zzvar=debug ; make zz_Output-d.exe )
make[1]: Entering directory '/home/pax'
echo debug
debug                                               <==
touch zz_Output-d.exe
make[1]: Leaving directory '/home/pax'

Вы можете увидеть две отдельные переменные, отмеченные <== выше.

Как я уже сказал, возможно, есть более простой способ сделать это с помощью GNU Make, но это поможет вам начать.

person paxdiablo    schedule 20.01.2011
comment
первая и вторая исправлены, спасибо, но в-третьих, я действительно не понимаю, можете ли вы показать мне на примере в make-файле, который я предоставил? Благодарность - person killercode; 20.01.2011
comment
спасибо, я понял, и последнее (извините) можно ли как-нибудь переустановить переменную на основе выбранной цели? например, если выбранный выпуск OBJPATH будет ./obj/Release, если выбран отладочный OBJPATH = ./obj/Debug? - person killercode; 20.01.2011

как создать каталог, если он не существует ("./obj") для вывода?

rm -Rf ./obj && mkdir ./obj

У меня есть один make-файл, но у меня есть 2 метода сборки: «Отладка» и «Выпуск». Могу ли я использовать оба в 1 make-файле и как определить, какой из них нужно собрать?

У вас может быть несколько целей сборки верхнего уровня. Output в вашем make-файле - это цель верхнего уровня. Сделайте два. Один называется «Отладка», а другой - «Выпуск». Затем вы можете сказать make Debug для сборки отладки и make Release для сборки выпуска.

Я использовал Code :: Blocks, который строит только измененные файлы, но мой make-файл строит их каждый раз, когда я вызываю команду make, не касаясь файлов. как я могу заставить его собирать только измененные файлы?

Я не использовал Code::Blocks (я не знаю, что это такое), но если ваши Make-файлы написаны правильно (т.е. с правильно указанными зависимостями), он восстановит только требуемые цели.

person Noufal Ibrahim    schedule 20.01.2011

В ответ на ваш вопрос-комментарий:

Есть ли способ переустановить переменную на основе выбранной цели? например, если выбранный выпуск OBJPATH будет "./obj/Release", если выбран отладочный OBJPATH = "./obj/Debug"?

Вот как это сделать без рекурсии:

COMPILER=gcc

release: OBJPATH = obj
release: Output.exe

debug: OBJPATH = obj-dbg
debug: Outputd.exe

Output%.exe: main.o Base64.o
 $(COMPILER) -o $@ $(OBJPATH)/main.o $(OBJPATH)/Base64.o
 strip $@

main.o: main.c main.h
 $(COMPILER) -c main.c -o $(OBJPATH)/main.o

Base64.o: Base64.c Base64.h
 $(COMPILER) -c Base64.c -o $(OBJPATH)/Base64.o
person Alex Cohn    schedule 12.02.2013