Нет, == между Integer, Long и т. д. будет проверяться на ссылочное равенство - то есть
Integer x = ...;
Integer y = ...;
System.out.println(x == y);
, это будет проверять, относятся ли x
и y
к тот же объект , а не , равный объектам.
Таким образом,
Integer x = new Integer(10);
Integer y = new Integer(10);
System.out.println(x == y);
гарантированно печатает false
. Интерполяция «малых» значений автобокса может привести к сложным результатам:
Integer x = 10;
Integer y = 10;
System.out.println(x == y);
Это будет печатать true
из-за правил бокса ( JLS раздел 5.1.7 ) , По-прежнему используется ссылочное равенство, но ссылки действительно равны .
Лично я бы использовал:
if (x.intValue() == y.intValue())
или
if (x.equals(y))
Последнее немного менее эффективно - нет перегрузки для Integer.equals(Integer)
, поэтому ему придется выполнять проверку типа времени выполнения, тогда как первый использует тот факт, что мы уже знаем, что оба объекта Integer
s.
К счастью, compareTo
знает о типах, поэтому:
if (x.compareTo(y) < 0)
все равно будет эффективным. Конечно, это область микрооптимизации, и вы должны использовать код, который вы найдете наиболее ясным - после того, как убедитесь, что он прав:)
Как вы говорите, для любого сравнения между типом оболочки (Integer
, Long
и числовой тип (int
, long
и т. д.) значение типа оболочки - unboxed , и тест применяется к примитивным значениям.
происходит как часть двоичной цифровой рекламы ( JLS раздел 5.6.2 ). Посмотрите документацию каждого отдельного оператора, чтобы узнать, применяется ли она. Например, из документов для == и! = ( JLS 15.21.1 ):
Если операнды оператора равенства являются как числовыми, так и один из них имеет числовой тип, а другой является конвертируемым (п. 5.1.8) в числовой тип, двоичная цифровая продвижение выполняется в операндах (§5.6.2).
и для & lt; , & lt; =,> and> = ( JLS 15.20.1 )
Тип каждого из операндов оператора цифрового сравнения должен быть типом, который является (§5.1.8) к примитивному числовому типу, или возникает ошибка времени компиляции. Бинарное числовое продвижение выполняется в операндах (§5.6.2). Если продвинутый тип операндов является int или long, выполняется сопоставление целого числа со знаком; если этот продвинутый тип является float или double, выполняется сравнение с плавающей запятой.
Обратите внимание, что ничто из этого не рассматривается как часть ситуации, когда ни тип является числовым.
Это сделало бы это - предполагая среду, подобную Unix.
MKDIR_P = mkdir -p
.PHONY: directories
all: directories program
directories: ${OUT_DIR}
${OUT_DIR}:
${MKDIR_P} ${OUT_DIR}
Это должно быть запущено в каталоге верхнего уровня - или определение $ {OUT_DIR} должно быть правильно относительно того, где он запускается. Конечно, если вы будете следовать указателям статьи « Recursive Make Considered Harmful » Питера Миллера, вы все равно будете запускать make в каталоге верхнего уровня.
I ' m играл с этим (RMCH) на данный момент. Это потребовало некоторой адаптации к набору программного обеспечения, которое я использую в качестве площадки для тестирования. В пакете есть дюжина отдельных программ, построенных с распространением источника по 15 каталогам, часть из которых разделена. Но с небольшой осторожностью это можно сделать. OTOH, это может быть неприемлемо для новичков.
Как отмечено в комментариях, перечисление команды «mkdir» как действие для «каталогов» неверно. Как также отмечено в комментариях, есть другие способы исправить ошибку «не знаю, как сделать вывод / отладочную ошибку». Один из них - удалить зависимость от линии «каталогов». Это работает, потому что «mkdir -p» не генерирует ошибок, если все каталоги, которые его просят создать, уже существуют. Другой показан механизм, который будет пытаться создать каталог, если он не существует. Версия «с поправками» - это то, что я имел в виду прошлой ночью, - но обе эти методы работают (и у обоих есть проблемы, если существует выход / debug, но это файл, а не каталог).
make
внутри и сам по себе обрабатывает цели каталога так же, как и целевые файлы. Таким образом, легко написать такие правила:
outDir/someTarget: Makefile outDir
touch outDir/someTarget
outDir:
mkdir -p outDir
Единственная проблема заключается в том, что временная метка каталогов зависит от того, что делается с файлами внутри. Для приведенных выше правил это приводит к следующему результату:
$ make
mkdir -p outDir
touch outDir/someTarget
$ make
touch outDir/someTarget
$ make
touch outDir/someTarget
$ make
touch outDir/someTarget
Это определенно не то, что вы хотите. Всякий раз, когда вы касаетесь файла, вы также прикасаетесь к каталогу. И поскольку файл зависит от каталога, файл, следовательно, выглядит устаревшим, заставляя его перестраивать.
Однако вы можете легко разбить этот цикл, указав make, чтобы игнорировать временную метку каталога , Это делается путем объявления каталога как только prerqusite для заказа:
# The pipe symbol tells make that the following prerequisites are order-only
# |
# v
outDir/someTarget: Makefile | outDir
touch outDir/someTarget
outDir:
mkdir -p outDir
Это правильно дает:
$ make
mkdir -p outDir
touch outDir/someTarget
$ make
make: 'outDir/someTarget' is up to date.
TL; DR:
Напишите правило для создания каталога:
$(OUT_DIR):
mkdir -p $(OUT_DIR)
И цели для содержимого внутри зависят от каталога только для заказа:
$(OUT_DIR)/someTarget: ... | $(OUT_DIR)
Все решения, в том числе принятые, имеют некоторые проблемы, как указано в их соответствующих комментариях. Принимаемый ответ by @ jonathan-leffler уже неплохой, но не предполагает, что предпосылки не обязательно должны быть построены по порядку (например, во время make -j
). Однако простое перемещение предпосылки directories
с all
до program
провоцирует перестройки на каждом запуске AFAICT. Следующее решение не имеет этой проблемы, и AFAICS работает по назначению.
MKDIR_P := mkdir -p
OUT_DIR := build
.PHONY: directories all clean
all: $(OUT_DIR)/program
directories: $(OUT_DIR)
$(OUT_DIR):
${MKDIR_P} $(OUT_DIR)
$(OUT_DIR)/program: | directories
touch $(OUT_DIR)/program
clean:
rm -rf $(OUT_DIR)
учитывая, что вы новичок, я бы сказал, не пытайтесь это сделать. это определенно возможно, но бесполезно усложнит ваш Makefile. придерживайтесь простых способов, пока вам не станет удобнее делать.
, который сказал, один из способов создания в каталоге, отличном от исходного каталога, - VPATH ; Я предпочитаю правила шаблона
Или, KISS.
DIRS=build build/bins
...
$(shell mkdir -p $(DIRS))
Это создаст все каталоги после анализа файла Makefile.
$(info $(shell mkdir -p $(DIRS)))
Без $(info ...)
вывод команды mkdir
будет вставлен в Makefile , что в лучшем случае приведет к синтаксическим ошибкам. Вызов $(info ...)
гарантирует, что: а) ошибки (если они есть) видны пользователю, и б) что вызов функции расширяется до нуля.
– cmaster
28 June 2018 в 11:38
На мой взгляд, каталоги не должны считаться объектами вашего файла makefile, как в техническом, так и в дизайнерском смысле. Вы должны создать файлы , и если для создания файла нужен новый каталог, тогда спокойно создайте каталог в правиле для соответствующего файла.
re, ориентируясь на обычный или «узорный» файл, просто используйте внутреннюю переменную make
$(@D)
, что означает «каталог, в котором находится текущая цель» (cmp. с $@
для цели). Например,
$(OUT_O_DIR)/%.o: %.cpp
@mkdir -p $(@D)
@$(CC) -c $< -o $@
title: $(OBJS)
Затем вы делаете то же самое: создайте каталоги для всех $(OBJS)
, но вы сделаете это менее сложным способом.
такая же политика (файлы - это цели, каталоги никогда не используются) используется в различных приложениях. Например, система управления версиями git
не хранит каталоги.
Примечание. Если вы собираетесь использовать его, может быть полезно ввести удобную переменную и использовать make
.
dir_guard=@mkdir -p $(@D)
$(OUT_O_DIR)/%.o: %.cpp
$(dir_guard)
@$(CC) -c $< -o $@
$(OUT_O_DIR_DEBUG)/%.o: %.cpp
$(dir_guard)
@$(CC) -g -c $< -o $@
title: $(OBJS)
Я только что придумал довольно разумное решение, которое позволяет вам определять файлы для сборки и создавать каталоги автоматически. Сначала определите переменную ALL_TARGET_FILES
, которая содержит имя файла для каждого файла, который будет создан ваш make-файл. Затем используйте следующий код:
define depend_on_dir
$(1): | $(dir $(1))
ifndef $(dir $(1))_DIRECTORY_RULE_IS_DEFINED
$(dir $(1)):
mkdir -p $$@
$(dir $(1))_DIRECTORY_RULE_IS_DEFINED := 1
endif
endef
$(foreach file,$(ALL_TARGET_FILES),$(eval $(call depend_on_dir,$(file))))
Вот как это работает. Я определяю функцию depend_on_dir
, которая принимает имя файла и генерирует правило, которое заставляет файл зависеть от каталога, который его содержит, а затем определяет правило для создания этого каталога, если это необходимо. Затем я использую foreach
в call
эту функцию для каждого имени файла и eval
.
Обратите внимание, что вам понадобится версия GNU make, которая поддерживает eval
, что я думаю - версии 3.81 и выше.
Независимость ОС важна для меня, поэтому mkdir -p
не является опцией. Я создал эту серию функций, которые используют eval
для создания целей каталога с предварительным условием в родительском каталоге. Это имеет то преимущество, что make -j 2
будет работать без проблем, поскольку зависимости определены правильно.
# convenience function for getting parent directory, will eventually return ./
# $(call get_parent_dir,somewhere/on/earth/) -> somewhere/on/
get_parent_dir=$(dir $(patsubst %/,%,$1))
# function to create directory targets.
# All directories have order-only-prerequisites on their parent directories
# https://www.gnu.org/software/make/manual/html_node/Prerequisite-Types.html#Prerequisite-Types
TARGET_DIRS:=
define make_dirs_recursively
TARGET_DIRS+=$1
$1: | $(if $(subst ./,,$(call get_parent_dir,$1)),$(call get_parent_dir,$1))
mkdir $1
endef
# function to recursively get all directories
# $(call get_all_dirs,things/and/places/) -> things/ things/and/ things/and/places/
# $(call get_all_dirs,things/and/places) -> things/ things/and/
get_all_dirs=$(if $(subst ./,,$(dir $1)),$(call get_all_dirs,$(call get_parent_dir,$1)) $1)
# function to turn all targets into directories
# $(call get_all_target_dirs,obj/a.o obj/three/b.o) -> obj/ obj/three/
get_all_target_dirs=$(sort $(foreach target,$1,$(call get_all_dirs,$(dir $(target)))))
# create target dirs
create_dirs=$(foreach dirname,$(call get_all_target_dirs,$1),$(eval $(call make_dirs_recursively,$(dirname))))
TARGETS := w/h/a/t/e/v/e/r/things.dat w/h/a/t/things.dat
all: $(TARGETS)
# this must be placed after your .DEFAULT_GOAL, or you can manually state what it is
# https://www.gnu.org/software/make/manual/html_node/Special-Variables.html
$(call create_dirs,$(TARGETS))
# $(TARGET_DIRS) needs to be an order-only-prerequisite
w/h/a/t/e/v/e/r/things.dat: w/h/a/t/things.dat | $(TARGET_DIRS)
echo whatever happens > $@
w/h/a/t/things.dat: | $(TARGET_DIRS)
echo whatever happens > $@
Например, при запуске выше создаются:
$ make
mkdir w/
mkdir w/h/
mkdir w/h/a/
mkdir w/h/a/t/
mkdir w/h/a/t/e/
mkdir w/h/a/t/e/v/
mkdir w/h/a/t/e/v/e/
mkdir w/h/a/t/e/v/e/r/
echo whatever happens > w/h/a/t/things.dat
echo whatever happens > w/h/a/t/e/v/e/r/things.dat
output/debug', needed by
каталогов. Stop & Quot. Но теперь я не буду беспокоиться об этом. будет придерживаться основных правил. :). Спасибо за руководство. И я запускаю & quot; make & quot; из каталога топлекса. – Jabez 23 December 2009 в 07:49directories
, не заставляя их всегда перестраивать. – mtalexan 30 December 2013 в 20:30