1# ################################################################ 2# Copyright (c) 2015-2020, Yann Collet, Facebook, Inc. 3# All rights reserved. 4# 5# This source code is licensed under both the BSD-style license (found in the 6# LICENSE file in the root directory of this source tree) and the GPLv2 (found 7# in the COPYING file in the root directory of this source tree). 8# You may select, at your option, one of the above-listed licenses. 9# ########################################################################## 10# zstd : Command Line Utility, supporting gzip-like arguments 11# zstd32 : Same as zstd, but forced to compile in 32-bits mode 12# zstd_nolegacy : zstd without support of decompression of legacy versions 13# zstd-small : minimal zstd without dictionary builder and benchmark 14# zstd-compress : compressor-only version of zstd 15# zstd-decompress : decompressor-only version of zstd 16# ########################################################################## 17 18ZSTDDIR = ../lib 19 20# Version numbers 21LIBVER_SRC := $(ZSTDDIR)/zstd.h 22LIBVER_MAJOR_SCRIPT:=`sed -n '/define ZSTD_VERSION_MAJOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < $(LIBVER_SRC)` 23LIBVER_MINOR_SCRIPT:=`sed -n '/define ZSTD_VERSION_MINOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < $(LIBVER_SRC)` 24LIBVER_PATCH_SCRIPT:=`sed -n '/define ZSTD_VERSION_RELEASE/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < $(LIBVER_SRC)` 25LIBVER_SCRIPT:= $(LIBVER_MAJOR_SCRIPT).$(LIBVER_MINOR_SCRIPT).$(LIBVER_PATCH_SCRIPT) 26LIBVER_MAJOR := $(shell echo $(LIBVER_MAJOR_SCRIPT)) 27LIBVER_MINOR := $(shell echo $(LIBVER_MINOR_SCRIPT)) 28LIBVER_PATCH := $(shell echo $(LIBVER_PATCH_SCRIPT)) 29LIBVER := $(shell echo $(LIBVER_SCRIPT)) 30 31ZSTD_VERSION = $(LIBVER) 32 33HAVE_COLORNEVER = $(shell echo a | grep --color=never a > /dev/null 2> /dev/null && echo 1 || echo 0) 34GREP_OPTIONS ?= 35ifeq ($HAVE_COLORNEVER, 1) 36GREP_OPTIONS += --color=never 37endif 38GREP = grep $(GREP_OPTIONS) 39 40ifeq ($(shell $(CC) -v 2>&1 | $(GREP) -c "gcc version "), 1) 41ALIGN_LOOP = -falign-loops=32 42else 43ALIGN_LOOP = 44endif 45 46CPPFLAGS+= -DXXH_NAMESPACE=ZSTD_ 47ifeq ($(OS),Windows_NT) # MinGW assumed 48CPPFLAGS += -D__USE_MINGW_ANSI_STDIO # compatibility with %zu formatting 49endif 50CFLAGS ?= -O3 51DEBUGFLAGS+=-Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \ 52 -Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement \ 53 -Wstrict-prototypes -Wundef -Wpointer-arith \ 54 -Wvla -Wformat=2 -Winit-self -Wfloat-equal -Wwrite-strings \ 55 -Wredundant-decls -Wmissing-prototypes -Wc++-compat 56CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS) 57FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) 58 59 60ZSTDCOMMON_FILES := $(ZSTDDIR)/common/*.c 61ZSTDCOMP_FILES := $(ZSTDDIR)/compress/*.c 62ZSTDDECOMP_FILES := $(ZSTDDIR)/decompress/*.c 63ZSTD_FILES := $(ZSTDDECOMP_FILES) $(ZSTDCOMMON_FILES) $(ZSTDCOMP_FILES) 64ZDICT_FILES := $(ZSTDDIR)/dictBuilder/*.c 65ZSTDDECOMP_O = $(ZSTDDIR)/decompress/zstd_decompress.o 66 67ZSTD_LEGACY_SUPPORT ?= 5 68ZSTDLEGACY_FILES := 69ifneq ($(ZSTD_LEGACY_SUPPORT), 0) 70ifeq ($(shell test $(ZSTD_LEGACY_SUPPORT) -lt 8; echo $$?), 0) 71 ZSTDLEGACY_FILES += $(shell ls $(ZSTDDIR)/legacy/*.c | $(GREP) 'v0[$(ZSTD_LEGACY_SUPPORT)-7]') 72endif 73else 74endif 75 76# Sort files in alphabetical order for reproducible builds 77ZSTDLIB_FILES := $(sort $(wildcard $(ZSTD_FILES)) $(wildcard $(ZSTDLEGACY_FILES)) $(wildcard $(ZDICT_FILES))) 78 79ZSTD_CLI_FILES := $(wildcard *.c) 80ZSTD_CLI_OBJ := $(patsubst %.c,%.o,$(ZSTD_CLI_FILES)) 81 82# Define *.exe as extension for Windows systems 83ifneq (,$(filter Windows%,$(OS))) 84EXT =.exe 85RES64_FILE = windres/zstd64.res 86RES32_FILE = windres/zstd32.res 87ifneq (,$(filter x86_64%,$(shell $(CC) -dumpmachine))) 88 RES_FILE = $(RES64_FILE) 89else 90 RES_FILE = $(RES32_FILE) 91endif 92else 93EXT = 94endif 95 96VOID = /dev/null 97 98# Make 4.3 doesn't support '\#' anymore (https://lwn.net/Articles/810071/) 99NUM_SYMBOL := \# 100 101# thread detection 102NO_THREAD_MSG := ==> no threads, building without multithreading support 103HAVE_PTHREAD := $(shell printf '$(NUM_SYMBOL)include <pthread.h>\nint main(void) { return 0; }' > have_pthread.c && $(CC) $(FLAGS) -o have_pthread$(EXT) have_pthread.c -pthread 2> $(VOID) && rm have_pthread$(EXT) && echo 1 || echo 0; rm have_pthread.c) 104HAVE_THREAD := $(shell [ "$(HAVE_PTHREAD)" -eq "1" -o -n "$(filter Windows%,$(OS))" ] && echo 1 || echo 0) 105ifeq ($(HAVE_THREAD), 1) 106THREAD_MSG := ==> building with threading support 107THREAD_CPP := -DZSTD_MULTITHREAD 108THREAD_LD := -pthread 109else 110THREAD_MSG := $(NO_THREAD_MSG) 111endif 112 113# zlib detection 114NO_ZLIB_MSG := ==> no zlib, building zstd without .gz support 115HAVE_ZLIB := $(shell printf '$(NUM_SYMBOL)include <zlib.h>\nint main(void) { return 0; }' > have_zlib.c && $(CC) $(FLAGS) -o have_zlib$(EXT) have_zlib.c -lz 2> $(VOID) && rm have_zlib$(EXT) && echo 1 || echo 0; rm have_zlib.c) 116ifeq ($(HAVE_ZLIB), 1) 117ZLIB_MSG := ==> building zstd with .gz compression support 118ZLIBCPP = -DZSTD_GZCOMPRESS -DZSTD_GZDECOMPRESS 119ZLIBLD = -lz 120else 121ZLIB_MSG := $(NO_ZLIB_MSG) 122endif 123 124# lzma detection 125NO_LZMA_MSG := ==> no liblzma, building zstd without .xz/.lzma support 126HAVE_LZMA := $(shell printf '$(NUM_SYMBOL)include <lzma.h>\nint main(void) { return 0; }' > have_lzma.c && $(CC) $(FLAGS) -o have_lzma$(EXT) have_lzma.c -llzma 2> $(VOID) && rm have_lzma$(EXT) && echo 1 || echo 0; rm have_lzma.c) 127ifeq ($(HAVE_LZMA), 1) 128LZMA_MSG := ==> building zstd with .xz/.lzma compression support 129LZMACPP = -DZSTD_LZMACOMPRESS -DZSTD_LZMADECOMPRESS 130LZMALD = -llzma 131else 132LZMA_MSG := $(NO_LZMA_MSG) 133endif 134 135# lz4 detection 136NO_LZ4_MSG := ==> no liblz4, building zstd without .lz4 support 137HAVE_LZ4 := $(shell printf '$(NUM_SYMBOL)include <lz4frame.h>\n$(NUM_SYMBOL)include <lz4.h>\nint main(void) { return 0; }' > have_lz4.c && $(CC) $(FLAGS) -o have_lz4$(EXT) have_lz4.c -llz4 2> $(VOID) && rm have_lz4$(EXT) && echo 1 || echo 0; rm have_lz4.c) 138ifeq ($(HAVE_LZ4), 1) 139LZ4_MSG := ==> building zstd with .lz4 compression support 140LZ4CPP = -DZSTD_LZ4COMPRESS -DZSTD_LZ4DECOMPRESS 141LZ4LD = -llz4 142else 143LZ4_MSG := $(NO_LZ4_MSG) 144endif 145 146# explicit backtrace enable/disable for Linux & Darwin 147ifeq ($(BACKTRACE), 0) 148DEBUGFLAGS += -DBACKTRACE_ENABLE=0 149endif 150ifeq (,$(filter Windows%, $(OS))) 151ifeq ($(BACKTRACE), 1) 152DEBUGFLAGS += -DBACKTRACE_ENABLE=1 153DEBUGFLAGS_LD += -rdynamic 154endif 155endif 156 157 158.PHONY: default 159default: zstd-release 160 161.PHONY: all 162all: zstd 163 164.PHONY: allVariants 165allVariants: zstd zstd-compress zstd-decompress zstd-small zstd-nolegacy zstd-dictBuilder 166 167$(ZSTDDECOMP_O): CFLAGS += $(ALIGN_LOOP) 168 169zstd : CPPFLAGS += $(THREAD_CPP) $(ZLIBCPP) $(LZMACPP) $(LZ4CPP) 170zstd : LDFLAGS += $(THREAD_LD) $(ZLIBLD) $(LZMALD) $(LZ4LD) $(DEBUGFLAGS_LD) 171zstd : CPPFLAGS += -DZSTD_LEGACY_SUPPORT=$(ZSTD_LEGACY_SUPPORT) 172ifneq (,$(filter Windows%,$(OS))) 173zstd : $(RES_FILE) 174endif 175zstd : $(ZSTDLIB_FILES) $(ZSTD_CLI_OBJ) 176 @echo "$(THREAD_MSG)" 177 @echo "$(ZLIB_MSG)" 178 @echo "$(LZMA_MSG)" 179 @echo "$(LZ4_MSG)" 180 $(CC) $(FLAGS) $^ -o $@$(EXT) $(LDFLAGS) 181 182.PHONY: zstd-release 183zstd-release: DEBUGFLAGS := -DBACKTRACE_ENABLE=0 184zstd-release: DEBUGFLAGS_LD := 185zstd-release: zstd 186 187zstd32 : CPPFLAGS += $(THREAD_CPP) 188zstd32 : LDFLAGS += $(THREAD_LD) 189zstd32 : CPPFLAGS += -DZSTD_LEGACY_SUPPORT=$(ZSTD_LEGACY_SUPPORT) 190ifneq (,$(filter Windows%,$(OS))) 191zstd32 : $(RES32_FILE) 192endif 193zstd32 : $(ZSTDLIB_FILES) $(ZSTD_CLI_FILES) 194 $(CC) -m32 $(FLAGS) $^ -o $@$(EXT) 195 196## zstd-nolegacy: same scope as zstd, with just support of legacy formats removed 197zstd-nolegacy : LDFLAGS += $(THREAD_LD) $(ZLIBLD) $(LZMALD) $(LZ4LD) $(DEBUGFLAGS_LD) 198zstd-nolegacy : $(ZSTD_FILES) $(ZDICT_FILES) $(ZSTD_CLI_OBJ) 199 $(CC) $(FLAGS) $^ -o $@$(EXT) $(LDFLAGS) 200 201zstd-nomt : THREAD_CPP := 202zstd-nomt : THREAD_LD := 203zstd-nomt : THREAD_MSG := - multi-threading disabled 204zstd-nomt : zstd 205 206zstd-nogz : ZLIBCPP := 207zstd-nogz : ZLIBLD := 208zstd-nogz : ZLIB_MSG := - gzip support is disabled 209zstd-nogz : zstd 210 211zstd-noxz : LZMACPP := 212zstd-noxz : LZMALD := 213zstd-noxz : LZMA_MSG := - xz/lzma support is disabled 214zstd-noxz : zstd 215 216## zstd-dll: zstd executable linked to dynamic library libzstd (must already exist) 217# note : the following target doesn't link 218# because zstd uses non-public symbols from libzstd 219# such as XXH64 (for benchmark), 220# ZDICT_trainFromBuffer_unsafe_legacy (for dictionary builder) 221# and ZSTD_cycleLog (likely for --patch-from). 222# It's unclear at this stage if this is a scenario that must be supported 223.PHONY: zstd-dll 224zstd-dll : LDFLAGS+= -L$(ZSTDDIR) -lzstd 225zstd-dll : ZSTDLIB_FILES = 226zstd-dll : $(ZSTD_CLI_OBJ) 227 $(CC) $(FLAGS) $^ -o $@$(EXT) $(LDFLAGS) 228 229 230## zstd-pgo: zstd executable optimized with pgo. `gcc` only. 231zstd-pgo : 232 $(MAKE) clean 233 $(MAKE) zstd MOREFLAGS=-fprofile-generate 234 ./zstd -b19i1 $(PROFILE_WITH) 235 ./zstd -b16i1 $(PROFILE_WITH) 236 ./zstd -b9i2 $(PROFILE_WITH) 237 ./zstd -b $(PROFILE_WITH) 238 ./zstd -b7i2 $(PROFILE_WITH) 239 ./zstd -b5 $(PROFILE_WITH) 240 $(RM) zstd *.o $(ZSTDDECOMP_O) $(ZSTDDIR)/compress/*.o 241 case $(CC) in *clang*) if ! [ -e default.profdata ]; then llvm-profdata merge -output=default.profdata default*.profraw; fi ;; esac 242 $(MAKE) zstd MOREFLAGS=-fprofile-use 243 244## zstd-small: minimal target, supporting only zstd compression and decompression. no bench. no legacy. no other format. 245zstd-small: CFLAGS = -Os -s 246zstd-frugal zstd-small: $(ZSTD_FILES) zstdcli.c util.c timefn.c fileio.c 247 $(CC) $(FLAGS) -DZSTD_NOBENCH -DZSTD_NODICT $^ -o $@$(EXT) 248 249zstd-decompress: $(ZSTDCOMMON_FILES) $(ZSTDDECOMP_FILES) zstdcli.c util.c timefn.c fileio.c 250 $(CC) $(FLAGS) -DZSTD_NOBENCH -DZSTD_NODICT -DZSTD_NOCOMPRESS $^ -o $@$(EXT) 251 252zstd-compress: $(ZSTDCOMMON_FILES) $(ZSTDCOMP_FILES) zstdcli.c util.c timefn.c fileio.c 253 $(CC) $(FLAGS) -DZSTD_NOBENCH -DZSTD_NODICT -DZSTD_NODECOMPRESS $^ -o $@$(EXT) 254 255## zstd-dictBuilder: executable supporting dictionary creation and compression (only) 256zstd-dictBuilder: CPPFLAGS += -DZSTD_NOBENCH -DZSTD_NODECOMPRESS 257zstd-dictBuilder: $(ZSTDCOMMON_FILES) $(ZSTDCOMP_FILES) $(ZDICT_FILES) zstdcli.c util.c timefn.c fileio.c dibio.c 258 $(CC) $(FLAGS) $^ -o $@$(EXT) 259 260zstdmt: zstd 261 ln -sf zstd zstdmt 262 263.PHONY: generate_res 264generate_res: $(RES64_FILE) $(RES32_FILE) 265 266ifneq (,$(filter Windows%,$(OS))) 267RC ?= windres 268# http://stackoverflow.com/questions/708238/how-do-i-add-an-icon-to-a-mingw-gcc-compiled-executable 269$(RES64_FILE): windres/zstd.rc 270 $(RC) -o $@ -I ../lib -I windres -i $< -O coff -F pe-x86-64 271$(RES32_FILE): windres/zstd.rc 272 $(RC) -o $@ -I ../lib -I windres -i $< -O coff -F pe-i386 273endif 274 275.PHONY: clean 276clean: 277 $(MAKE) -C $(ZSTDDIR) clean 278 @$(RM) $(ZSTDDIR)/decompress/*.o $(ZSTDDIR)/decompress/zstd_decompress.gcda 279 @$(RM) core *.o tmp* result* *.gcda dictionary *.zst \ 280 zstd$(EXT) zstd32$(EXT) zstd-compress$(EXT) zstd-decompress$(EXT) \ 281 zstd-small$(EXT) zstd-frugal$(EXT) zstd-nolegacy$(EXT) zstd4$(EXT) \ 282 zstd-dictBuilder$(EXT) *.gcda default*.profraw default.profdata have_zlib$(EXT) 283 @echo Cleaning completed 284 285MD2ROFF = ronn 286MD2ROFF_FLAGS = --roff --warnings --manual="User Commands" --organization="zstd $(ZSTD_VERSION)" 287 288zstd.1: zstd.1.md ../lib/zstd.h 289 cat $< | $(MD2ROFF) $(MD2ROFF_FLAGS) | sed -n '/^\.\\\".*/!p' > $@ 290 291zstdgrep.1: zstdgrep.1.md ../lib/zstd.h 292 cat $< | $(MD2ROFF) $(MD2ROFF_FLAGS) | sed -n '/^\.\\\".*/!p' > $@ 293 294zstdless.1: zstdless.1.md ../lib/zstd.h 295 cat $< | $(MD2ROFF) $(MD2ROFF_FLAGS) | sed -n '/^\.\\\".*/!p' > $@ 296 297.PHONY: man 298man: zstd.1 zstdgrep.1 zstdless.1 299 300.PHONY: clean-man 301clean-man: 302 $(RM) zstd.1 303 $(RM) zstdgrep.1 304 $(RM) zstdless.1 305 306.PHONY: preview-man 307preview-man: clean-man man 308 man ./zstd.1 309 man ./zstdgrep.1 310 man ./zstdless.1 311 312#----------------------------------------------------------------------------- 313# make install is validated only for Linux, macOS, BSD, Hurd and Solaris targets 314#----------------------------------------------------------------------------- 315ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku)) 316 317HAVE_COLORNEVER = $(shell echo a | egrep --color=never a > /dev/null 2> /dev/null && echo 1 || echo 0) 318EGREP_OPTIONS ?= 319ifeq ($HAVE_COLORNEVER, 1) 320EGREP_OPTIONS += --color=never 321endif 322EGREP = egrep $(EGREP_OPTIONS) 323AWK = awk 324 325# Print a two column output of targets and their description. To add a target description, put a 326# comment in the Makefile with the format "## <TARGET>: <DESCRIPTION>". For example: 327# 328## list: Print all targets and their descriptions (if provided) 329.PHONY: list 330list: 331 @TARGETS=$$($(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null \ 332 | $(AWK) -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' \ 333 | $(EGREP) -v -e '^[^[:alnum:]]' | sort); \ 334 { \ 335 printf "Target Name\tDescription\n"; \ 336 printf "%0.s-" {1..16}; printf "\t"; printf "%0.s-" {1..40}; printf "\n"; \ 337 for target in $$TARGETS; do \ 338 line=$$($(EGREP) "^##[[:space:]]+$$target:" $(lastword $(MAKEFILE_LIST))); \ 339 description=$$(echo $$line | $(AWK) '{i=index($$0,":"); print substr($$0,i+1)}' | xargs); \ 340 printf "$$target\t$$description\n"; \ 341 done \ 342 } | column -t -s $$'\t' 343 344 345DESTDIR ?= 346# directory variables : GNU conventions prefer lowercase 347# see https://www.gnu.org/prep/standards/html_node/Makefile-Conventions.html 348# support both lower and uppercase (BSD), use uppercase in script 349prefix ?= /usr/local 350PREFIX ?= $(prefix) 351exec_prefix ?= $(PREFIX) 352bindir ?= $(exec_prefix)/bin 353BINDIR ?= $(bindir) 354datarootdir ?= $(PREFIX)/share 355mandir ?= $(datarootdir)/man 356man1dir ?= $(mandir)/man1 357 358ifneq (,$(filter $(shell uname),OpenBSD FreeBSD NetBSD DragonFly SunOS)) 359MANDIR ?= $(PREFIX)/man 360MAN1DIR ?= $(MANDIR)/man1 361else 362MAN1DIR ?= $(man1dir) 363endif 364 365ifneq (,$(filter $(shell uname),SunOS)) 366INSTALL ?= ginstall 367else 368INSTALL ?= install 369endif 370 371INSTALL_PROGRAM ?= $(INSTALL) 372INSTALL_SCRIPT ?= $(INSTALL_PROGRAM) 373INSTALL_DATA ?= $(INSTALL) -m 644 374INSTALL_MAN ?= $(INSTALL_DATA) 375 376.PHONY: install 377install: zstd 378 @echo Installing binaries 379 @$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR)/ $(DESTDIR)$(MAN1DIR)/ 380 @$(INSTALL_PROGRAM) zstd$(EXT) $(DESTDIR)$(BINDIR)/zstd$(EXT) 381 @ln -sf zstd$(EXT) $(DESTDIR)$(BINDIR)/zstdcat$(EXT) 382 @ln -sf zstd$(EXT) $(DESTDIR)$(BINDIR)/unzstd$(EXT) 383 @ln -sf zstd$(EXT) $(DESTDIR)$(BINDIR)/zstdmt$(EXT) 384 @$(INSTALL_SCRIPT) zstdless $(DESTDIR)$(BINDIR)/zstdless 385 @$(INSTALL_SCRIPT) zstdgrep $(DESTDIR)$(BINDIR)/zstdgrep 386 @echo Installing man pages 387 @$(INSTALL_MAN) zstd.1 $(DESTDIR)$(MAN1DIR)/zstd.1 388 @ln -sf zstd.1 $(DESTDIR)$(MAN1DIR)/zstdcat.1 389 @ln -sf zstd.1 $(DESTDIR)$(MAN1DIR)/unzstd.1 390 @$(INSTALL_MAN) zstdgrep.1 $(DESTDIR)$(MAN1DIR)/zstdgrep.1 391 @$(INSTALL_MAN) zstdless.1 $(DESTDIR)$(MAN1DIR)/zstdless.1 392 @echo zstd installation completed 393 394.PHONY: uninstall 395uninstall: 396 @$(RM) $(DESTDIR)$(BINDIR)/zstdgrep 397 @$(RM) $(DESTDIR)$(BINDIR)/zstdless 398 @$(RM) $(DESTDIR)$(BINDIR)/zstdcat 399 @$(RM) $(DESTDIR)$(BINDIR)/unzstd 400 @$(RM) $(DESTDIR)$(BINDIR)/zstdmt 401 @$(RM) $(DESTDIR)$(BINDIR)/zstd 402 @$(RM) $(DESTDIR)$(MAN1DIR)/zstdless.1 403 @$(RM) $(DESTDIR)$(MAN1DIR)/zstdgrep.1 404 @$(RM) $(DESTDIR)$(MAN1DIR)/zstdcat.1 405 @$(RM) $(DESTDIR)$(MAN1DIR)/unzstd.1 406 @$(RM) $(DESTDIR)$(MAN1DIR)/zstd.1 407 @echo zstd programs successfully uninstalled 408 409endif 410