Gnu Make: переменная среза (сохранить все, кроме последнего элемента)

#makefile #build #slice #gnu-make

#makefile #сборка #срез #gnu-make

Вопрос:

Я пытаюсь выполнить срез переменной в моем makefile. Я использую это :

 C_SOURCES := $(foreach dir, $(C_SOURCEDIRS), $(wildcard $(dir)/*.cpp))
 

Чтобы сгенерировать список всех исходных файлов кода, а затем использовать это:

 C_OBJS := $(subst $(C_SOURCEDIR), $(CLIENT_BUILD_DIR), $(C_SOURCES:.cpp=.o))
 

Для генерации всех имен всех связанных объектных файлов. Однако сам каталог сборки (CLIENT_BUILD_DIR) продолжает отображаться как последний элемент C_OBJS. (Я также не совсем уверен, почему это происходит …)

В качестве своего рода взлома я решил удалить последний элемент C_OBJS (удалить его, сохранив все n — 1 первых элементов), и попытался сделать это следующим образом:

 C_OBJS := $(wordlist, 1, $(words $(C_OBJS)) - 1, $(C_OBJS))
 

Однако это приводит к тому, что C_OBJS становится пустым!
Я прочитал документацию по текстовым функциям, но если я что-то не понимаю правильно, это должно работать так, как ожидалось: make C_OBJS = все элементы в C_OBJS, кроме последнего.

Любая помощь приветствуется! (И бонусный файл cookie для всех, кто может объяснить, почему CLIENT_BUILD_DIR появляется в C_OBJS в первую очередь; и, возможно, как этого избежать)[РЕДАКТИРОВАТЬ: см. Ответ на эту часть]

При необходимости это полный сегмент рассматриваемого makefile:

 CLIENT_SRC_DIR   := $(SOURCEDIR)/Client
CLIENT_BUILD_DIR := $(BUILDDIR)/Client
C_DIRS           := $(notdir $(shell find $(CLIENT_SRC_DIR) -type d -print | tail -n  2))
C_SOURCEDIRS     := $(foreach dir, $(C_DIRS), $(addprefix $(CLIENT_SRC_DIR)/, $(dir)))
C_TARGETDIRS     := $(foreach dir, $(C_DIRS), $(addprefix $(CLIENT_BUILD_DIR)/, $(dir)))
C_SOURCES        := $(foreach dir, $(C_SOURCEDIRS), $(wildcard $(dir)/*.cpp))
C_OBJS           := $(subst $(C_SOURCEDIR), $(CLIENT_BUILD_DIR), $(C_SOURCES:.cpp=.o))
C_OBJS           := $(wordlist, 1, $(words $(C_OBJS)) - 1, $(C_OBJS))
C_DEPS           := $(C_OBJS:.o=.d)
 

Спасибо!

Комментарии:

1. Вместо исправления нежелательных свойств wildcard вы можете взглянуть на github.com/markpiffer/gmtt#call-wildcard-reclist-of-globs . Может быть, вы можете прямо сформулировать, что вы хотите, вместо того, чтобы обходить с помощью специального make программирования.

2. Кстати: ваше желание вычислить length-1 в $(words $(C_OBJS)) - 1 качестве второго параметра для wordlist функции неудачно, поскольку make он не знает, как вычислять. Он получает строку 123 - 1 , которую не может преобразовать в целое число, и поэтому вычисление wordlist также завершается неудачей. По совпадению, gmtt-Library тоже может вычислять, хотя, как я уже сказал, ИМХО, здесь лучше прямо сформулировать, чего вы пытаетесь достичь.

3. @Vroomfondel О, ты прав насчет — 1! (И я загляну в gmtt, спасибо!) Но я предполагаю, что я мог бы также выполнить работу с помощью bash, тогда нет? На самом деле я не знаю, возможно ли, чтобы bash в makefile взаимодействовал с переменными make

4. Я рекомендую вам не использовать subst для этого. Вы должны использовать patsubst : $(patsubst $(C_SOURCEDIR)/%,$(CLIENT_BUILD_DIR)/%,$(C_SOURCES:.cpp=.o)) . Это намного безопаснее.

5. subst заменит ВСЕ вхождения слова. Итак, если ваш файл есть src/mysrc.c , а ваш C_SOURCEDIR есть src и C_BUILD_DIR есть obj , то subst вернет obj/myobj.c не то, что вы хотите. patsubst заменяет только соответствующий шаблон, один раз, поэтому он будет делать правильные вещи здесь.

Ответ №1:

Благодаря комментарию Врумфонделя я понял, что «срез» не работает просто потому, что make обрабатывает строки и поэтому не знает, что означает -1.

Еще одно замечание: существует (почему-то всегда ошибки такого типа, на исправление которых уходит больше всего времени) опечатка в строке C_OBJS; C_SOURCEDIR это не существующая переменная! Поэтому make обрабатывает его как пустую строку, что, в свою очередь subst , приводит к тому, что команда не работает должным образом…

Урок: следите за опечатками ниндзя

Ответ №2:

Это приведет ко всем, кроме последнего слова $(VAR) :

 VAR2 := $(wordlist 2,$(words $(VAR)),x $(VAR))
 

Вы также можете превратить его в функцию:

 define firstwords
$(wordlist 2,$(words $(1)),x $(1))
endef

VAR2 := $(call firstwords,$(VAR))