#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))