Как динамически включать make-файлы? - PullRequest
1 голос
/ 03 ноября 2010

Можно ли динамически включать Makefile?Например, в зависимости от некоторой переменной среды?У меня есть следующие файлы Makefile:

makefile
app1.1.mak
app1.2.mak

И есть переменная окружения APP_VER, которая может быть установлена ​​в 1.1.0.1, 1.1.0.2, 1.2.0.1, 1.2.0.2.
Но естьбудет только два разных make-файла для строк 1.1 и 1.2.

Я пытался написать следующий Makefile:

MAK_VER=$$(echo $(APP_VER) | sed -e 's/^\([0-9]*\.[0-9]*\).*$$/\1/')  
include makefile$(MAK_VER).mak  

all: PROD  
        echo MAK_VER=$(MAK_VER)  

Но он не работает:

$ make all
"makefile$(echo", line 0: make: Cannot open makefile$(echo
make: Fatal errors encountered -- cannot continue.

ОБНОВЛЕНИЕ:

Насколько я понимаю, make включает файлы перед вычислением макросов.
Вот почему он пытается выполнить следующий оператор

include makefile.mak

вместо

include makefile1.1.mak

Ответы [ 3 ]

2 голосов
/ 03 ноября 2010

У вас две проблемы: ваш метод получения версии слишком сложен, а ваша строка include имеет недостаток.Попробуйте это:

include app$(APP_VER).mak

Если APP_VER - это переменная окружения, то это будет работать.Если вы также хотите включить make-файл с именем makefile (то есть, если makefile не тот, который мы пишем), попробуйте следующее:

include makefile app$(APP_VER).mak

Обратите внимание, что это считается плохая идея .Если make-файл зависит от переменных среды, он будет работать для некоторых пользователей, а не для других, что считается плохим поведением.

РЕДАКТИРОВАТЬ:

Это должно сделатьэто:

MAK_VER := $(subst ., ,$(APP_VER))
MAK_VER := $(word 1, $(MAK_VER)).$(word 2, $(MAK_VER))

include makefile app$(MAK_VER).mak
0 голосов
/ 05 декабря 2010

Изменение схемы решения

Иметь четыре make-файла:

  • Makefile
  • app1.1.mak
  • app1.2.mak
  • appdummy.mak

Makefile app.dummy.mak может быть пустым - символическая ссылка на / dev / null, если хотите. И app.1.1.mak, и app.1.2.mak не отличаются от своего текущего содержимого.

Основной make-файл немного меняется:

MAK_VER = dummy
include makefile$(MAK_VER).mak  

dummy:  
        ${MAKE} MAK_VER=$$(echo $(APP_VER) | sed -e 's/^\([0-9]*\.[0-9]*\).*$$/\1/') all

all: PROD
        ...as now...

Если вы введете make, он прочитает (пустой) фиктивный make-файл, а затем попытается создать цель dummy, потому что она появляется первой. Чтобы построить фиктивную цель, она снова запустится make, с APP_VER=1.1 или APP_VER=1.2 в командной строке:

make APP_VER=1.1 all

Макросы, установленные в командной строке, не могут быть изменены в make-файле, поэтому это переопределяет строку в make-файле. Поэтому при втором вызове make будет прочитан правильный make-файл для конкретной версии, а затем будет построен all.

Эта техника имеет ограничения, наиболее заметно то, что очень трудно организовать, чтобы каждая цель рассматривалась таким образом. Есть способы обойти это, но обычно не стоит.


Проектная организация

Более серьезно, я думаю, вам нужно пересмотреть то, что вы делаете в целом. Предположительно, вы используете систему управления версиями (VCS) для управления исходным кодом. Кроме того, предположительно, есть некоторые (существенные) различия между исходным кодом версии 1.1 и 1.2. Таким образом, чтобы иметь возможность сделать сборку для версии 1.1, вы должны переключиться с ветки обслуживания версии 1.1 на ветку разработки версии 1.2 или что-то в этом роде. Итак, почему make-файл не имеет версии для 1.1 или 1.2? Если вы переключаетесь между версиями, вам нужно очистить все производные файлы (объектные файлы, библиотеки, исполняемые файлы и т. Д.), Которые могли быть созданы с неверным источником. Вы должны изменить исходный код. Так почему бы тоже не изменить make-файл?

Скрипт сборки для вызова make

Я также заметил, что, поскольку у вас есть переменная окружения APP_VER, управляющая вашим процессом, вы можете уладить проблему, потребовав стандартизированного 'make invoker', который сортирует значение APP_VER и правильно вызывает make. Представьте, что скрипт называется build:

#!/bin/sh
: ${APP_VER:=1.2.0.1}  # Latest version is default
case $APP_VER in
[0-9].[0-9].*)
    MAK_VER=`echo $APP_VER | sed -e 's/^\(...\).*/\1/'`
    ;;
*)  echo "`basename $0 .sh`: APP_VER ($APP_VER) should start with two digits followed by dots" 1>&2;
    exit 1;;
esac
exec make MAK_VER=$MAK_VER "$@"

Этот скрипт проверяет, что APP_VER установлен, давая соответствующее значение по умолчанию, если это не так. Затем он обрабатывает это значение для получения MAK_VER (или выдает ошибки, если оно неверно). Разумеется, вам нужно будет изменить этот тест после того, как вы достигнете версии 10, поскольку вы планируете добиться такого успеха, что со временем вы получите двузначные номера версий.

Учитывая правильную информацию о версии, теперь вы можете вызывать ваш make-файл с любыми аргументами командной строки.

Makefile может быть довольно простым:

MAK_VER = dummy

include app$(MAK_VER).mak  

all: PROD
        ...as now...

Файл appdummy.mak теперь содержит правило:

error:
        echo "You must invoke this makefile via the build script" 1>&2
        exit 1

Он просто указывает правильный способ сделать сборку.

Обратите внимание, что вы можете избежать переменной среды APP_VER, если вы сохраните номер версии продукта в VCS в файле, а сценарий затем прочитает номер версии из файла. Сценарий может выполнять любые другие действия, гарантируя, что установлены правильные инструменты, установлены другие переменные среды и т. Д.

0 голосов
/ 03 ноября 2010

Попробуйте это:

MAK_VER=$(shell echo $(APP_VER) | sed -e 's/^\([0-9]*\.[0-9]*\).*$$/\1/')
MAK_FILE=makefile$(MAK_VER).mak

include $(MAK_FILE)

all:
    echo $(MAK_VER)
    echo $(MAK_FILE)
...