Общий путь каталога файлов GNU

Я пытаюсь консолидировать некоторую информацию сборки, используя общий make файл. Моя проблема в том, что я хочу использовать этот makefile из разных уровней подкаталога, что делает непредсказуемым значение рабочего каталога (pwd). Например:

# Makefile.common
TOP := $(shell pwd)
COMPONENT_DIR := $(TOP)/component
COMPONENT_INC := $(COMPONENT_DIR)/include
COMPONENT_LIB := $(COMPONENT_DIR)/libcomponent.a

Если я включаю Makefile.common из подкаталога, так же, каталог $(TOP) неверен, и все остальное следует примеру:

# other_component/Makefile
include ../Makefile.common
# $(COMPONENT_LIB) is incorrectly other_component/component

Какой лучший способ получить Makefile.common использовать свой собственный путь к каталогу вместо более изменчивого pwd?

Ответ 1

Вы должны использовать MAKEFILE_LIST переменную, например:

# This must be the first this in Makefile.common
TOP := $(dir $(lastword $(MAKEFILE_LIST)))

Из документации:

Как make читает различные make файлы, в том числе любые, полученные из переменной MAKEFILES, командной строки, файлов по умолчанию или из директив include, их имена будут автоматически добавляться к переменной MAKEFILE_LIST. Они добавляются прямо перед тем, как make начинает их анализировать. Это означает, что если первое, что делает makefile, это проверка последнего слова в этой переменной, это будет имя текущего файла makefile. Однако, если текущий make файл был включен, последнее слово будет являться только что включенным make файлом.

Ответ 2

Это не хороший стиль, потому что он добавляет другую зависимость (т.е. бинарный файл realpath). В зависимости от вашего варианта использования, это может быть приемлемым.

ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))

Если у вас не установлен realpath:

$ sudo apt-get install realpath # on debian and derivatives

Изменить: Обязательно используйте := вместо =, потому что последнее приводит к тому, что make использует позднюю привязку, а MAKEFILE_LIST может быть изменен из-за более позднего включения.

Ответ 3

Вы пробовали:

# Makefile.common
TOP ?= $(shell pwd)
COMPONENT_DIR := $(TOP)/component
COMPONENT_INC := $(COMPONENT_DIR)/include
COMPONENT_LIB := $(COMPONENT_DIR)/libcomponent.a

# other_component/Makefile
TOP ?= ..
include ../Makefile.common

Использование конструкции? = будет удерживать TOP от переопределения, если оно уже установлено. Вы можете установить его на соответствующее значение в зависимости от того, где вы находитесь в дереве при вызове make. Я признаюсь, что прошло некоторое время, так как я использовал GNU make, так что это может не сработать или может потребоваться некоторые настройки.

Ответ 4

Мое решение:

cwd  :=  $(shell readlink -en $(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))) 

Это также работает для вызовов типа make -f /opt/some/dir/Makefile, когда вы находитесь в /opt/other/path/subdir.

Ответ 5

просто напишите обычный материал в common.mk. Затем поместите common.mk в папку по умолчанию, которая выполняет поиск, когда встречается с выражением common.mk.

См. справку об общих папках. Вы также можете поместить common.mk в свою домашнюю папку, а затем введите make -I$HOME из любой папки.

Внутри Makefile в каждой подпапке вы просто делаете

include common.mk

Вот и все. Не нужно беспокоиться о пути и двигаться вокруг.