Makefile: удалять повторяющиеся слова без сортировки

Есть ли возможность удалить дубликаты в списке слов без сортировки в make файле?

$(sort foo bar lose)

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

[обновление]

bobbogo ответ работает очень хорошо. Просто не забудьте использовать define uniq для v3.81 и (не проверял это) define uniq = для более поздних версий.

larsmans ответ работает очень хорошо, если ваш разделитель записей не является пространством, например. если вы хотите удалить дубликаты из _foo_bar_lose_lose_bar_baz_ или тому подобное. Просто не забудьте использовать опции RS и ORS awk вместо tr, и заверните все это с помощью $(firstword $(shell ... ))

Ответ 1

Скучный метод $eval:

define uniq =
  $(eval seen :=)
  $(foreach _,$1,$(if $(filter $_,${seen}),,$(eval seen += $_)))
  ${seen}
endef

w := z z x x y c x

$(info $(sort $w))
$(info $(call uniq,$w))

Чрезвычайно жестокий рекурсивный вызов стандартной библиотеки (рекурсивный сборщик считается крайне дурацким?):

uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1)))

Стоит отметить, что в этой второй формулировке никакие переменные не повреждены (см. seen в первой). Это предпочтительно только для этого (учитывая нехватку локальных жителей в make)!

Ответ 2

Зависит от того, где вам это нужно, и используете ли вы GNU make. Если вы просто хотите унифицировать список целевых предпосылок, это так же просто, как (http://www.gnu.org/software/make/manual/make.html#Quick-Reference):

Значение $^ опускает повторяющиеся предпосылки, а $+ сохраняет их и сохраняет их порядок.

Итак, правило вроде

exe: $(OBJS)
        $(LD) -o [email protected] $^

автоматически отфильтровывает дубликаты из $(OBJS), оставаясь при этом другими элементами одинаковыми.

Ответ 3

Вы могли echo слова через awk:

echo foo bar foo baz bar | tr ' ' '\n' | awk '!a[$0]++'

Разделение однострочного изображения, взятого из catonmat.

(Не забудьте удвоить значение $ до $$ в Makefile.)

Ответ 4

У меня под GNU make v3.82 работает следующее:

uniq = $(eval _uniq := $1)$(strip $(foreach _,$(_uniq),$(if $(findstring $_,$(_uniq)),$(eval _uniq := $(filter-out $_,$(_uniq)))$_)))

Он не изменяет свой ввод путем создания копии в _uniq и не является рекурсивным.