Как создать скрипт в Makefile? - PullRequest
       18

Как создать скрипт в Makefile?

65 голосов
/ 22 сентября 2011

Есть ли лучший способ получить сценарий, который устанавливает env vars, из make-файла?

FLAG ?= 0
ifeq ($(FLAG),0)
export FLAG=1
/bin/myshell -c '<source scripts here> ; $(MAKE) $@'
else
...targets...
endif

Ответы [ 13 ]

57 голосов
/ 23 апреля 2017

Оболочка Makefile по умолчанию - /bin/sh, которая не реализует source.

Изменение оболочки на /bin/bash делает возможным:

# Makefile

SHELL := /bin/bash

rule:
    source env.sh && YourCommand
40 голосов
/ 22 сентября 2011

Чтобы ответить на вопрос в виде вопроса: Вы не можете .

Основная проблема заключается в том, что дочерний процесс не может изменить среду родителя. Оболочка справляется с этим, не разветвляя новый процесс при source, а просто выполняя эти команды в текущем воплощении оболочки. Это прекрасно работает, но make не является /bin/sh (или оболочкой, для которой предназначен ваш скрипт) и не понимает этот язык (кроме общих битов).

Крис Додд и Фу Бах рассмотрели один возможный обходной путь, поэтому я предложу другой (при условии, что вы используете GNU make): постобработка сценария оболочки в make совместимый текст и включение результата:

shell-variable-setter.make: shell-varaible-setter.sh
    postprocess.py @^

# ...
else
include shell-variable-setter.make
endif

грязные детали, оставленные в качестве упражнения.

21 голосов
/ 22 сентября 2011

Если ваша цель - просто установить переменные окружения для Make, почему бы не сохранить его в синтаксисе Makefile и использовать команду include?

include other_makefile

Если вам нужно вызвать скрипт оболочки, захватитев результате shell команда:

JUST_DO_IT=$(shell source_script)

команда оболочки должна выполняться перед целями.Однако это не установит переменные среды.

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

Например, если ваш исходный make-файл имеет цель a, вы хотите сделать что-то вроде этого:

# mysetenv.sh
#!/bin/bash
. <script to source>
export FLAG=1
make "$@" 

# Makefile
ifeq($(FLAG),0)
export FLAG=1
a: 
    ./mysetenv.sh a
else
a:
    .. do it
endif
16 голосов
/ 31 декабря 2014

Используя GNU Make 3.81, я могу получить сценарий оболочки из make, используя:

rule:
<tab>source source_script.sh && build_files.sh

build_files.sh "получает" переменные среды, экспортированные source_script.sh.

Обратите внимание, что используя:

rule:
<tab>source source_script.sh
<tab>build_files.sh

не будет работать.Каждая строка запускается в своей собственной оболочке.

10 голосов
/ 11 мая 2013

Это работает для меня. Замените env.sh на имя файла, который вы хотите найти. Он работает путем получения файла в bash и вывода измененной среды после ее форматирования в файл с именем makeenv, который затем создается make-файлом.

IGNORE := $(shell bash -c "source env.sh; env | sed 's/=/:=/' | sed 's/^/export /' > makeenv")                         
include makeenv   
5 голосов
/ 06 декабря 2012

Некоторые конструкции одинаковы как в shell, так и в GNU Make.

var=1234
text="Some text"

Вы можете изменить свой сценарий оболочки для получения определений.Все они должны быть простыми name=value типами.

Т.е.

[script.sh]

. ./vars.sh

[Makefile]

include vars.sh

Тогда сценарий оболочки и Makefile могут использовать один и тот же «источник» информации.Я нашел этот вопрос, потому что искал манифест общего синтаксиса, который можно использовать в скриптах Gnu Make и оболочки (мне все равно, какая оболочка).

Редактировать: Оболочки исделать понимание $ {var} .Это означает, что вы можете объединить и т. Д., Var = "Одна строка" var = $ {var} "Вторая строка"

3 голосов
/ 10 марта 2016

Мне очень нравится ответ Фу Баха, где make вызывает скрипт, а скрипт перезванивает make. Чтобы расширить этот ответ, я сделал это:

# Makefile
.DEFAULT_GOAL := all 

ifndef SOME_DIR

%:
<tab>. ./setenv.sh $(MAKE) $@

else

all:
<tab>...

clean:
<tab>...

endif

-

# setenv.sh
export SOME_DIR=$PWD/path/to/some/dir

if [ -n "$1" ]; then
    # The first argument is set, call back into make.
    $1 $2
fi

Это дает дополнительное преимущество использования $ (MAKE) в случае, если кто-либо использует уникальную программу make, а также обрабатывает любое правило, указанное в командной строке, без необходимости дублировать имя каждого правила в случае, когда SOME_DIR не определено.

1 голос
/ 19 августа 2016

Другим возможным способом было бы создать сценарий sh, например run.sh, найти необходимые сценарии и вызвать make внутри сценария.

#!/bin/sh
source script1
source script2 and so on

make 
1 голос
/ 14 февраля 2016

Мое решение для этого: (при условии, что у вас есть bash, синтаксис для $@ отличается, например, для tcsh)

Есть сценарий sourceThenExec.sh, как таковой:

#!/bin/bash
source whatever.sh
$@

Затем в вашем make-файле предварите ваши цели с помощью bash sourceThenExec.sh, например:

ExampleTarget:
    bash sourceThenExec.sh gcc ExampleTarget.C

Конечно, вы можете поместить что-то вроде STE=bash sourceThenExec.sh в начало вашего make-файла.и сокращаем это:

ExampleTarget:
    $(STE) gcc ExampleTarget.C

Все это работает, потому что sourceThenExec.sh открывает подоболочку, но затем команды запускаются в одной и той же подоболочке.

Недостатком этого метода является то, чтофайл получает источник для каждой цели, что может быть нежелательно.

0 голосов
/ 21 августа 2018

В зависимости от вашей версии Make и оболочки, вы можете реализовать хорошее решение с помощью eval, cat и связывать вызовы с помощью &&:

ENVFILE=envfile

source-via-eval:
  @echo "FOO: $${FOO}"
  @echo "FOO=AMAZING!" > $(ENVFILE)
  @eval `cat $(ENVFILE)` && echo "FOO: $${FOO}"

И быстрый тест:

> make source-via-eval
FOO:
FOO: AMAZING!
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...