meson: remove no longer needed makefiles

parent a87a79e1
# Experimental client requires libedit
ifeq ($(HAS_libedit), yes)
kresc_SOURCES := client/kresc.c
kresc_CFLAGS += -fPIE $(libedit_CFLAGS)
kresc_LIBS += $(contrib_TARGET) $(libedit_LIBS)
kresc_DEPEND := $(libkres) $(contrib)
$(eval $(call make_sbin,kresc,client,yes))
client: $(kresc)
client-install: kresc-install
client-clean: kresc-clean
endif
.PHONY: client client-install client-clean
# Project
MAJOR := 3
MINOR := 2
PATCH := 1
EXTRA ?=
ABIVER := 9
BUILDMODE := dynamic
HARDENING := yes
VERSION := $(MAJOR).$(MINOR).$(PATCH)$(EXTRA)
# Paths
PREFIX ?= /usr/local
BINDIR ?= $(PREFIX)/bin
SBINDIR ?= $(PREFIX)/sbin
LIBDIR ?= $(PREFIX)/lib
PKGCONFIGDIR ?= $(LIBDIR)/pkgconfig
MANDIR ?= $(PREFIX)/share/man
INCLUDEDIR ?= $(PREFIX)/include
MODULEDIR ?= $(LIBDIR)/kdns_modules
ETCDIR ?= $(PREFIX)/etc/knot-resolver
ROOTHINTS ?= $(ETCDIR)/root.hints
COVERAGE_STAGE ?= gcov
COVERAGE_STATSDIR ?= $(CURDIR)/coverage.stats
TOPSRCDIR := $(CURDIR)
KEYFILE_DEFAULT ?=
# Tools
CC ?= cc
RM := rm -f
LN := ln -s
XXD_LUA := ./scripts/embed-lua.sh
INSTALL := install
# Flags
BUILD_LDFLAGS += $(LDFLAGS)
BUILD_CFLAGS := -std=c99 -D_GNU_SOURCE $(CFLAGS) $(CPPFLAGS)
BUILD_CFLAGS += -Wtype-limits -Wformat -Wformat-security -Wshadow -Wall
BUILD_CFLAGS += -I$(abspath .) -I$(abspath lib/generic) -I$(abspath contrib)
BUILD_CFLAGS += -DPACKAGE_VERSION="\"$(VERSION)\"" -DPREFIX="\"$(PREFIX)\"" -DMODULEDIR="\"$(MODULEDIR)\""
BUILD_CFLAGS += -fvisibility=hidden
ifeq (,$(findstring -O,$(CFLAGS)))
BUILD_CFLAGS += -O2
endif
contrib_SOURCES := \
contrib/ccan/asprintf/asprintf.c \
contrib/ccan/ilog/ilog.c \
contrib/ccan/json/json.c \
contrib/ucw/mempool.c \
contrib/ucw/mempool-fmt.c \
contrib/murmurhash3/murmurhash3.c \
contrib/base32hex.c \
contrib/base64.c
contrib_CFLAGS := -fPIC
contrib_TARGET := $(abspath contrib)/contrib$(AREXT)
# Use built-in LMDB if not found
ifneq ($(HAS_lmdb), yes)
contrib_SOURCES += contrib/lmdb/mdb.c \
contrib/lmdb/midl.c
contrib_CFLAGS += -pthread
contrib_LIBS += -pthread
lmdb_CFLAGS += -I$(abspath contrib/lmdb)
endif
$(eval $(call make_static,contrib,contrib))
kresd_SOURCES := \
daemon/bindings/cache.c \
daemon/bindings/event.c \
daemon/bindings/impl.c \
daemon/bindings/modules.c \
daemon/bindings/net.c \
daemon/bindings/worker.c \
daemon/io.c \
daemon/network.c \
daemon/engine.c \
daemon/worker.c \
daemon/ffimodule.c \
daemon/tls.c \
daemon/tls_ephemeral_credentials.c \
daemon/tls_session_ticket-srv.c \
daemon/zimport.c \
daemon/session.c \
daemon/main.c
kresd_DIST := daemon/lua/kres.lua daemon/lua/kres-gen.lua \
daemon/lua/trust_anchors.lua daemon/lua/zonefile.lua
# Embedded resources
%.inc: %.lua
@$(call quiet,XXD_LUA,$<) $< > $@
ifeq ($(AMALG), yes)
kresd.amalg.c: daemon/lua/sandbox.inc daemon/lua/config.inc
else
daemon/engine.o: daemon/lua/sandbox.inc daemon/lua/config.inc
kresd-lint: daemon/lua/sandbox.inc daemon/lua/config.inc
endif
# Installed FFI bindings
bindings-install: $(kresd_DIST) $(DESTDIR)$(MODULEDIR)
$(INSTALL) -m 0644 $(kresd_DIST) $(DESTDIR)$(MODULEDIR)
LUA_HAS_SETFUNCS := \
$(shell pkg-config luajit --atleast-version=2.1.0-beta3 && echo 1 || echo 0)
kresd_CFLAGS := -fPIE \
-Dlibknot_SONAME=\"$(libknot_SONAME)\" \
-Dlibzscanner_SONAME=\"$(libzscanner_SONAME)\" \
-DROOTHINTS=\"$(ROOTHINTS)\" \
-DLIBEXT=\"$(LIBEXT)\" \
-DLUA_HAS_SETFUNCS="$(LUA_HAS_SETFUNCS)"
kresd_DEPEND := $(libkres) $(contrib)
kresd_LIBS := $(libkres_TARGET) $(contrib_TARGET) $(libknot_LIBS) \
$(libzscanner_LIBS) $(libdnssec_LIBS) $(libuv_LIBS) $(lua_LIBS) \
$(gnutls_LIBS)
# Enable systemd
ifeq ($(HAS_libsystemd), yes)
kresd_CFLAGS += -DHAS_SYSTEMD
kresd_LIBS += $(libsystemd_LIBS)
endif
# Make binary
$(eval $(call make_sbin,kresd,daemon,yes))
# Targets
date := $(shell head -n1 < NEWS | sed 's/.*(\(.*\)).*/\1/' | grep -E '^[0-9]{4}-[0-9]{2}-[0-9]{2}$$' || date -u -r NEWS +%F)
daemon: $(kresd) $(kresd_DIST)
daemon-install: kresd-install bindings-install
ifneq ($(SED),)
$(SED) -e "s/@VERSION@/$(VERSION)/" -e "s/@DATE@/$(date)/" \
-e "s|@MODULEDIR@|$(MODULEDIR)|" \
-e "s|@KEYFILE_DEFAULT@|$(KEYFILE_DEFAULT)|" \
doc/kresd.8.in > doc/kresd.8
$(INSTALL) -d -m 0755 $(DESTDIR)$(MANDIR)/man8/
$(INSTALL) -m 0644 doc/kresd.8 $(DESTDIR)$(MANDIR)/man8/
endif
daemon-clean: kresd-clean
@$(RM) daemon/lua/*.inc daemon/lua/trust_anchors.lua
daemon/lua/trust_anchors.lua: daemon/lua/trust_anchors.lua.in
@$(call quiet,SED,$<) -e "s|@ETCDIR@|$(ETCDIR)|g;s|@KEYFILE_DEFAULT@|$(KEYFILE_DEFAULT)|g" $< > $@
daemon/lua/kres-gen.lua: | $(libkres)
@echo "WARNING: regenerating $@"
@# the sed saves some space(s)
daemon/lua/kres-gen.sh | sed 's/ /\t/g' > $@
.DELETE_ON_ERROR: daemon/lua/kres-gen.lua
.PHONY: daemon daemon-install daemon-clean
ifeq ($(HAS_doxygen)|$(HAS_sphinx-build), yes|yes)
doc-doxygen:
@cd doc && $(doxygen_BIN)
doc-html: doc-doxygen
@cd doc && $(sphinx-build_BIN) $(SPHINXFLAGS) -b html . html
else
doc-html:
$(error doxygen and sphinx must be installed)
endif
doc-clean:
rm -rf doc/doxyxml doc/*.db doc/html
.PHONY: doc-doxygen doc-html doc-clean
etc_SOURCES := icann-ca.pem \
config.cluster \
config.isp \
config.personal \
config.splitview \
root.hints
etc-install: $(DESTDIR)$(ETCDIR)
$(INSTALL) -m 0644 $(addprefix etc/,$(etc_SOURCES)) $(DESTDIR)$(ETCDIR)
etc: etc/root.hints
etc/root.hints:
wget -O $@ https://www.internic.net/domain/named.root
.PHONY: etc-install
libkres_SOURCES := \
lib/cache/api.c \
lib/cache/cdb_lmdb.c \
lib/cache/entry_list.c \
lib/cache/entry_pkt.c \
lib/cache/entry_rr.c \
lib/cache/knot_pkt.c \
lib/cache/nsec1.c \
lib/cache/nsec3.c \
lib/cache/peek.c \
lib/dnssec.c \
lib/dnssec/nsec.c \
lib/dnssec/nsec3.c \
lib/dnssec/signature.c \
lib/dnssec/ta.c \
lib/generic/lru.c \
lib/generic/map.c \
lib/generic/queue.c \
lib/generic/trie.c \
lib/layer/cache.c \
lib/layer/iterate.c \
lib/layer/validate.c \
lib/module.c \
lib/nsrep.c \
lib/resolve.c \
lib/rplan.c \
lib/utils.c \
lib/zonecut.c
libkres_HEADERS := \
lib/cache/api.h \
lib/cache/cdb_api.h \
lib/cache/cdb_lmdb.h \
lib/cache/impl.h \
lib/defines.h \
lib/dnssec.h \
lib/dnssec/nsec.h \
lib/dnssec/nsec3.h \
lib/dnssec/signature.h \
lib/dnssec/ta.h \
lib/generic/array.h \
lib/generic/lru.h \
lib/generic/map.h \
lib/generic/pack.h \
lib/generic/queue.h \
lib/generic/trie.h \
lib/layer.h \
lib/layer/iterate.h \
lib/module.h \
lib/nsrep.h \
lib/resolve.h \
lib/rplan.h \
lib/utils.h \
lib/zonecut.h
# Dependencies
libkres_DEPEND := $(contrib)
libkres_CFLAGS := -fPIC $(lmdb_CFLAGS)
libkres_LIBS := $(contrib_TARGET) $(libknot_LIBS) $(libdnssec_LIBS) $(lmdb_LIBS) \
$(libuv_LIBS) $(gnutls_LIBS)
libkres_TARGET := -L$(abspath lib) -lkres
ifeq ($(ENABLE_COOKIES),yes)
libkres_SOURCES += \
lib/cookies/alg_containers.c \
lib/cookies/alg_sha.c \
lib/cookies/helper.c \
lib/cookies/lru_cache.c \
lib/cookies/nonce.c
libkres_HEADERS += \
lib/cookies/alg_containers.h \
lib/cookies/alg_sha.h \
lib/cookies/control.h \
lib/cookies/helper.h \
lib/cookies/lru_cache.h \
lib/cookies/nonce.h
libkres_LIBS += $(nettle_LIBS)
endif
# Make library
ifeq ($(BUILDMODE), static)
$(eval $(call make_static,libkres,lib,yes))
else
$(eval $(call make_lib,libkres,lib,yes,$(ABIVER)))
endif
# Generate pkg-config file
libkres.pc:
@echo 'prefix='$(PREFIX) > $@
@echo 'exec_prefix=$${prefix}' >> $@
@echo 'libdir='$(LIBDIR) >> $@
@echo 'includedir='$(INCLUDEDIR) >> $@
@echo 'Name: libkres' >> $@
@echo 'Description: Knot Resolver library' >> $@
@echo 'URL: https://www.knot-resolver.cz' >> $@
@echo 'Version: $(VERSION)' >> $@
@echo 'Libs: -L$${libdir} -lkres' >> $@
@echo 'Cflags: -I$${includedir}' >> $@
libkres-pcinstall: libkres.pc libkres-install
$(INSTALL) -d -m 755 $(DESTDIR)$(PKGCONFIGDIR)
$(INSTALL) -m 644 $< $(DESTDIR)$(PKGCONFIGDIR)
# Targets
lib: $(libkres)
lib-install: libkres-install libkres-pcinstall
lib-clean: libkres-clean
.PHONY: lib lib-install lib-clean libkres.pc
bogus_log_CFLAGS := -fPIC
# We use a symbol that's not in libkres but the daemon.
# On darwin this isn't accepted by default.
bogus_log_LDFLAGS := -Wl,-undefined -Wl,dynamic_lookup
bogus_log_SOURCES := modules/bogus_log/bogus_log.c
bogus_log_DEPEND := $(libkres)
bogus_log_LIBS := $(contrib_TARGET) $(libkres_TARGET) $(libkres_LIBS)
$(call make_c_module,bogus_log)
cookies_CFLAGS := -fPIC
cookies_SOURCES := \
modules/cookies/cookiectl.c \
modules/cookies/cookiemonster.c \
modules/cookies/cookies.c
cookies_DEPEND := $(libkres)
cookies_LIBS := $(contrib_TARGET) $(libkres_TARGET) $(libkres_LIBS)
$(call make_c_module,cookies)
daf_SOURCES := daf.lua
daf_INSTALL := modules/daf/daf.js
$(call make_lua_module,daf)
detect_time_jump_SOURCES := detect_time_jump.lua
$(call make_lua_module,detect_time_jump)
detect_time_skew_SOURCES := detect_time_skew.lua
$(call make_lua_module,detect_time_skew)
dns64_SOURCES := dns64.lua
$(call make_lua_module,dns64)
dnstap_CFLAGS := -fPIC
dnstap_SOURCES := modules/dnstap/dnstap.pb-c.c modules/dnstap/dnstap.c
dnstap_DEPEND := $(libkres) modules/dnstap/dnstap.pb-c.c # because of generated *.h
dnstap_LIBS := $(contrib_TARGET) $(libkres_TARGET) $(libkres_LIBS) $(libprotobuf-c_LIBS) $(libfstrm_LIBS)
$(call make_c_module,dnstap)
modules/dnstap/dnstap.pb-c.c: modules/dnstap/dnstap.proto
protoc-c $< --c_out=.
edns_keepalive_CFLAGS := -fPIC
edns_keepalive_LDFLAGS := -Wl,-undefined -Wl,dynamic_lookup
edns_keepalive_SOURCES := modules/edns_keepalive/edns_keepalive.c
$(call make_c_module,edns_keepalive)
etcd_SOURCES := etcd.lua
$(call make_lua_module,etcd)
experimental_dot_auth_SOURCES := experimental_dot_auth.lua basexx.lua
$(call make_lua_module,experimental_dot_auth)
graphite_SOURCES := graphite.lua
$(call make_lua_module,graphite)
hints_CFLAGS := -fPIC
# We use a symbol that's not in libkres but the daemon.
# On darwin this isn't accepted by default.
hints_LDFLAGS := -Wl,-undefined -Wl,dynamic_lookup
hints_SOURCES := modules/hints/hints.c
hints_DEPEND := $(libkres)
hints_LIBS := $(contrib_TARGET) $(libkres_TARGET) $(libkres_LIBS)
$(call make_c_module,hints)
http_SOURCES := http.lua prometheus.lua http_trace.lua
http_INSTALL := $(wildcard modules/http/static/*)
$(call make_lua_module,http)
# List of built-in modules
modules_TARGETS := hints \
stats
# DNS cookies
ifeq ($(ENABLE_COOKIES),yes)
modules_TARGETS += cookies
endif
ifeq ($(ENABLE_DNSTAP),yes)
modules_TARGETS += dnstap
endif
# List of Lua modules
ifeq ($(HAS_lua),yes)
modules_TARGETS += bogus_log \
nsid \
etcd \
ta_sentinel \
experimental_dot_auth \
graphite \
policy \
view \
predict \
dns64 \
rebinding \
renumber \
http \
daf \
workarounds \
ta_signal_query \
priming \
serve_stale \
detect_time_skew \
detect_time_jump \
prefill \
edns_keepalive
endif
# Make C module
define make_c_module
$(1)-install: $(DESTDIR)$(MODULEDIR)
$(eval $(call make_module,$(1),modules/$(1)))
endef
# Make Lua module
define make_lua_module
$(eval $(call lua_target,$(1),modules/$(1)))
endef
# Lua target definition
define lua_target
$(1) := $(1) $$(addprefix $(2)/,$$($(1)_SOURCES))
$(1) : $$($(1)_DEPEND)
$(1)-clean:
ifeq ($$(strip $$($(1)_INSTALL)),)
$(1)-dist:
$(INSTALL) -d $(DESTDIR)$(MODULEDIR)
else
$(1)-dist: $$($(1)_INSTALL)
$(INSTALL) -d $(DESTDIR)$(MODULEDIR)/$(1)
$(INSTALL) -m 0644 $$^ $(DESTDIR)$(MODULEDIR)/$(1)
endif
$(1)-install: $$(addprefix $(2)/,$$($(1)_SOURCES)) $(DESTDIR)$(MODULEDIR) $(1)-dist
$(INSTALL) -m 0644 $$(addprefix $(2)/,$$($(1)_SOURCES)) $(DESTDIR)$(MODULEDIR)
.PHONY: $(1) $(1)-install $(1)-clean $(1)-dist
endef
# Make Go module
define make_go_module
$(eval $(call go_target,$(1),modules/$(1)))
endef
# Filter CGO flags
CGO_CFLAGS := $(filter-out -flto,$(BUILD_CFLAGS))
# Go target definition
define go_target
$(1) := $(2)/$(1)$(LIBEXT)
$(2)/$(1)$(LIBEXT): $$($(1)_SOURCES) $$($(1)_DEPEND)
@echo " GO $(2)"; CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$$($(1)_LIBS) $(CFLAGS)" $(GO) build -buildmode=c-shared -o $$@ $$($(1)_SOURCES)
$(1)-clean:
$(RM) -r $(2)/$(1).h $(2)/$(1)$(LIBEXT)
ifeq ($$(strip $$($(1)_INSTALL)),)
$(1)-dist:
$(INSTALL) -d $(DESTDIR)$(MODULEDIR)
else
$(1)-dist: $$($(1)_INSTALL)
$(INSTALL) -d $(DESTDIR)$(MODULEDIR)/$(1)
$(INSTALL) -m 0644 $$^ $(DESTDIR)$(MODULEDIR)/$(1)
endif
$(1)-install: $(2)/$(1)$(LIBEXT) $(1)-dist $(DESTDIR)$(MODULEDIR)
$(INSTALL) $(2)/$(1)$(LIBEXT) $(DESTDIR)$(MODULEDIR)
.PHONY: $(1)-clean $(1)-install $(1)-dist
endef
# Include modules
$(foreach module,$(modules_TARGETS),$(eval include modules/$(module)/$(module).mk))
$(eval modules = $(foreach module,$(modules_TARGETS),$$($(module))))
# Targets
modules: $(modules)
modules-clean: $(addsuffix -clean,$(modules_TARGETS))
modules-install: $(addsuffix -install,$(modules_TARGETS))
.PHONY: modules modules-clean modules-install
nsid_CFLAGS := -fPIC
nsid_LDFLAGS := -Wl,-undefined -Wl,dynamic_lookup
nsid_SOURCES := modules/nsid/nsid.c
nsid_DEPEND := $(libkres)
nsid_LIBS := $(contrib_TARGET) $(libkres_TARGET) $(libkres_LIBS)
$(call make_c_module,nsid)
AHOCORASICK_DIR = modules/policy/lua-aho-corasick/
policy_SOURCES := policy.lua
policy_DEPEND := $(AHOCORASICK_DIR)ahocorasick$(LIBEXT)
$(call make_lua_module,policy)
policy-clean:
$(MAKE) -C $(AHOCORASICK_DIR) clean
$(AHOCORASICK_DIR)ahocorasick$(LIBEXT): $(AHOCORASICK_DIR)Makefile
$(MAKE) -C $(AHOCORASICK_DIR) ahocorasick$(LIBEXT) CXXFLAGS="$(lua_CFLAGS)"
policy-install: ahocorasick-install
ahocorasick-install: $(AHOCORASICK_DIR)ahocorasick$(LIBEXT) $(DESTDIR)$(MODULEDIR)
$(INSTALL) -m 755 $(AHOCORASICK_DIR)ahocorasick$(LIBEXT) $(DESTDIR)$(MODULEDIR)
predict_SOURCES := predict.lua
$(call make_lua_module,predict)
prefill_SOURCES := prefill.lua
$(call make_lua_module,prefill)
priming_SOURCES := priming.lua
$(call make_lua_module,priming)
rebinding_SOURCES := rebinding.lua
$(call make_lua_module,rebinding)
renumber_SOURCES := renumber.lua
$(call make_lua_module,renumber)
serve_stale_SOURCES := serve_stale.lua
$(call make_lua_module,serve_stale)
stats_CFLAGS := -fPIC
stats_SOURCES := modules/stats/stats.c
stats_DEPEND := $(libkres)
stats_LIBS := $(contrib_TARGET) $(libkres_TARGET) $(libkres_LIBS)
$(call make_c_module,stats)
ta_sentinel_SOURCES := ta_sentinel.lua
$(call make_lua_module,ta_sentinel)
ta_signal_query_SOURCES := ta_signal_query.lua
$(call make_lua_module,ta_signal_query)
view_SOURCES := view.lua
$(call make_lua_module,view)
workarounds_SOURCES := workarounds.lua
$(call make_lua_module,workarounds)
# Platform-specific stuff
# Don't touch this unless you're changing the way targets are compiled
# You have been warned
# Platform-dependent stuff checks
CCLD := $(CC)
CLANG_TIDY ?= clang-tidy -quiet
CGO := go tool cgo
GO := go
CAT := cat
SED := sed
LCOV := lcov
GENHTML := genhtml
LIBEXT := .so
AREXT := .a
LIBTYPE := shared
MODTYPE := shared
ARTYPE := static
BINEXT :=
PLATFORM = Linux
ARCH := $(word 1, $(subst -, ,$(shell $(CC) -dumpmachine)))
# Library versioning flags (platform-specific)
comma := ,
SOVER = $(if $(1),-Wl$(comma)-soname$(comma)$(3)$(call SOVER_EXT,$(1)))
# Library versioned extension (platform-specific)
SOVER_EXT = $(LIBEXT).$(1)
ifeq ($(OS),Windows_NT)
PLATFORM := Windows
RM := del
LN := link
LIBEXT := .lib
BINEXT := .exe
else
UNAME := $(shell uname -s)
ifeq ($(UNAME),Darwin)
PLATFORM := Darwin
LIBEXT := .dylib
MODTYPE := dynamiclib
LDFLAGS += -Wl,-export_dynamic
# OS X specific hardening since -pie doesn't work
ifneq ($(HARDENING),no)
BINFLAGS += -Wl,-pie
endif
# Version is prepended to dylib
SOVER_EXT = .$(1)$(LIBEXT)
SOVER = $(if $(1), -compatibility_version $(2) -current_version $(1),)
else
PLATFORM := POSIX
LDFLAGS += -pthread -lm -Wl,--export-dynamic
# ELF hardening options
ifneq ($(HARDENING),no)
BINFLAGS += -pie
LDFLAGS += -Wl,-z,relro,-z,now
endif
ifeq ($(UNAME),Linux)
LDFLAGS += -ldl
endif
ifeq (GCC,$(shell $(CC) --version | grep -q -i '\<gcc\>' && echo GCC))
# Otherwise Fedora is making kresd symbols inaccessible for modules.
# Clang doesn't support this flag, so we hackily detect gcc.
BUILD_CFLAGS += -rdynamic
endif
endif
endif
# Silent compilation
ifeq ($(V),1)
quiet = $($1)
else
quiet = @echo " $1 $2"; $($1)
endif
# Make objects and depends (name)
define make_objs
$(1)_OBJ := $$($(1)_SOURCES:.c=.o)
$(1)_DEP := $$($(1)_SOURCES:.c=.d)
-include $$($(1)_DEP)
endef
define make_objrule
$(1): $(1:.o=.c)
$$(call quiet,CC,$$<) $(2) -MMD -MP -c $$< -o $$@
endef
# Make target (name,path,ext,ldflags, 5:dst,amalgable,abiver)
define make_target
ifeq ($(AMALG)|$(6), yes|yes)
$(1).amalg.c: $$($(1)_SOURCES)
$(call quiet,CAT,$$@) $$($(1)_SOURCES) > $$@
# AR requires .o compiled
$(1)_OBJ := $(1).amalg.c
ifeq ($(4),-$(ARTYPE))
$(1)_OBJ := $(1).amalg.o
endif
else
$$(eval $$(call make_objs,$(1)))
endif
# Rules to generate objects with custom CFLAGS and binary/library
$$(foreach obj,$$($(1)_OBJ),$$(eval $$(call make_objrule,$$(obj),$$(BUILD_CFLAGS) $$($(1)_CFLAGS))))
$(1) := $(2)/$(1)$(3)