From 27ba87c8e4330fd7b5ff4d5cfa0bbe59a938ead8 Mon Sep 17 00:00:00 2001 From: Chris Guillott Date: Thu, 20 Oct 2016 14:22:12 -0400 Subject: [PATCH 01/18] add compiler optimizations flag --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 020beaa..b0a3dcc 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,7 @@ endif CFLAGS += -std=c99 CFLAGS += -pipe CFLAGS += -Wall +CFLAGS += -O2 CPPFLAGS += -D_GNU_SOURCE CPPFLAGS += -DXKBCOMPOSE=$(shell if test -e /usr/include/xkbcommon/xkbcommon-compose.h ; then echo 1 ; else echo 0 ; fi ) CFLAGS += $(shell $(PKG_CONFIG) --cflags cairo xcb-dpms xcb-xinerama xcb-atom xcb-image xcb-xkb xkbcommon xkbcommon-x11) From db9e953bde01d4ed17ef72f6c7f2a987ca08a683 Mon Sep 17 00:00:00 2001 From: Chris Guillott Date: Tue, 1 Nov 2016 17:13:09 -0400 Subject: [PATCH 02/18] really hacky blur + overlayed image support --- i3lock.c | 27 +++++++++++++-------------- unlock_indicator.c | 32 ++++++++++++++++++++------------ 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/i3lock.c b/i3lock.c index c6a6a45..d411a37 100644 --- a/i3lock.c +++ b/i3lock.c @@ -114,6 +114,7 @@ static uint8_t xkb_base_event; static uint8_t xkb_base_error; cairo_surface_t *img = NULL; +cairo_surface_t *blur_img = NULL; bool tile = false; bool ignore_empty_password = false; bool skip_repeated_empty_password = false; @@ -1194,20 +1195,18 @@ int main(int argc, char *argv[]) { xcb_pixmap_t blur_pixmap; if (blur) { - if(!img) { - xcb_visualtype_t *vistype = get_root_visual_type(screen); - blur_pixmap = capture_bg_pixmap(conn, screen, last_resolution); - cairo_surface_t *xcb_img = cairo_xcb_surface_create(conn, blur_pixmap, vistype, last_resolution[0], last_resolution[1]); - - img = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, last_resolution[0], last_resolution[1]); - cairo_t *ctx = cairo_create(img); - cairo_set_source_surface(ctx, xcb_img, 0, 0); - cairo_paint(ctx); - - cairo_destroy(ctx); - cairo_surface_destroy(xcb_img); - } - blur_image_surface(img, 10000); + xcb_visualtype_t *vistype = get_root_visual_type(screen); + blur_pixmap = capture_bg_pixmap(conn, screen, last_resolution); + cairo_surface_t *xcb_img = cairo_xcb_surface_create(conn, blur_pixmap, vistype, last_resolution[0], last_resolution[1]); + + blur_img = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, last_resolution[0], last_resolution[1]); + cairo_t *ctx = cairo_create(blur_img); + cairo_set_source_surface(ctx, xcb_img, 0, 0); + cairo_paint(ctx); + + cairo_destroy(ctx); + cairo_surface_destroy(xcb_img); + blur_image_surface(blur_img, 10000); } /* Pixmap on which the image is rendered to (if any) */ diff --git a/unlock_indicator.c b/unlock_indicator.c index 8aad606..814de21 100644 --- a/unlock_indicator.c +++ b/unlock_indicator.c @@ -53,6 +53,7 @@ extern char *modifier_string; /* A Cairo surface containing the specified image (-i), if any. */ extern cairo_surface_t *img; +extern cairo_surface_t *blur_img; /* Whether the image should be tiled. */ extern bool tile; @@ -138,19 +139,26 @@ xcb_pixmap_t draw_image(uint32_t *resolution) { cairo_surface_t *xcb_output = cairo_xcb_surface_create(conn, bg_pixmap, vistype, resolution[0], resolution[1]); cairo_t *xcb_ctx = cairo_create(xcb_output); - if (img) { - if (!tile) { - cairo_set_source_surface(xcb_ctx, img, 0, 0); + if (img || blur_img) { + if (blur_img) { + cairo_set_source_surface(xcb_ctx, blur_img, 0, 0); cairo_paint(xcb_ctx); - } else { - /* create a pattern and fill a rectangle as big as the screen */ - cairo_pattern_t *pattern; - pattern = cairo_pattern_create_for_surface(img); - cairo_set_source(xcb_ctx, pattern); - cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); - cairo_rectangle(xcb_ctx, 0, 0, resolution[0], resolution[1]); - cairo_fill(xcb_ctx); - cairo_pattern_destroy(pattern); + } + if (img) { + if (!tile) { + cairo_set_source_surface(xcb_ctx, img, 0, 0); + cairo_paint(xcb_ctx); + } else { + /* create a pattern and fill a rectangle as big as the screen */ + cairo_pattern_t *pattern; + pattern = cairo_pattern_create_for_surface(img); + cairo_set_source(xcb_ctx, pattern); + cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); + cairo_rectangle(xcb_ctx, 0, 0, resolution[0], resolution[1]); + cairo_fill(xcb_ctx); + cairo_pattern_destroy(pattern); + } + } } else { char strgroups[3][3] = {{color[0], color[1], '\0'}, From 0fe47c14e8359db80eda2c29d613346d43034814 Mon Sep 17 00:00:00 2001 From: Chris Guillott Date: Tue, 1 Nov 2016 20:43:25 -0400 Subject: [PATCH 03/18] comment out (seemingly?) unused code to remove warnings --- blur.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/blur.c b/blur.c index a5b0bd3..94ff42a 100644 --- a/blur.c +++ b/blur.c @@ -32,7 +32,7 @@ blur_image_surface (cairo_surface_t *surface, int radius) { cairo_surface_t *tmp; int width, height; - int src_stride, dst_stride; +// int src_stride, dst_stride; uint32_t *src, *dst; if (cairo_surface_status (surface)) @@ -64,10 +64,10 @@ blur_image_surface (cairo_surface_t *surface, int radius) return; src = (uint32_t*)cairo_image_surface_get_data (surface); - src_stride = cairo_image_surface_get_stride (surface); +// src_stride = cairo_image_surface_get_stride (surface); dst = (uint32_t*)cairo_image_surface_get_data (tmp); - dst_stride = cairo_image_surface_get_stride (tmp); +// dst_stride = cairo_image_surface_get_stride (tmp); //blur_impl_naive(src, dst, width, height, src_stride, dst_stride, 10000); //blur_impl_sse2(src, dst, width, height, 4.5); From 18907f13ee42770b579c156048681cc0b37f0b24 Mon Sep 17 00:00:00 2001 From: Chris Guillott Date: Tue, 8 Nov 2016 14:37:34 -0500 Subject: [PATCH 04/18] update readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 07f0e13..9fef2d8 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ Many little improvements have been made to i3lock over time: - `-k, --clock` -- enables the clock display. - `--timestr="%H:%M:%S"` -- allows custom overriding of the time format string. Accepts `strftime` formatting. Default is `"%H:%M:%S"`. - `--datestr="%A, %m %Y"` -- allows custom overriding of the date format string. Accepts `strftime` formatting. Default is `"%A, %m %Y"`. + - `-B, --blur` -- enables capturing the display and blurring for use as a background image. - All the colors have an alpha channel now. Please keep in mind that this was not intended when the program was originally written, so making things transparent that weren't before can make it look strange. - You can specify whether i3lock should bell upon a wrong password. From d25d17e407149b644d1014fa18490962ec24bf1f Mon Sep 17 00:00:00 2001 From: Chris Guillott Date: Tue, 28 Nov 2017 09:59:21 -0500 Subject: [PATCH 05/18] update manpage --- README.md | 2 ++ i3lock.1 | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/README.md b/README.md index 795a96a..78b07ca 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,8 @@ Many little improvements have been made to i3lock over time: - `--radius=90` -- the radius of the circle indicator - `--ring-width=7` -- the width of the indicator ring + - The readme's list of options might be a bit out of date - please check the manpage, or look at the list of options in i3lock.c. + - You can specify whether i3lock should bell upon a wrong password. - i3lock uses PAM and therefore is compatible with LDAP etc. diff --git a/i3lock.1 b/i3lock.1 index 2454d7f..e1cffdc 100644 --- a/i3lock.1 +++ b/i3lock.1 @@ -252,6 +252,21 @@ ch - the clock height. .RE .RE +.TP +.B \-\-time\-align, \-\-date\-align, \-\-layout\-align +Sets the text alignment of the time, date, and keyboard layout. Values are: + +.RS +.RS +0 - centered (default) + +1 - left aligned + +2 - right aligned + +.RE +.RE + .TP .B \-\-datecolor=rrggbbaa Sets the color of the date in the clock. From 7f49a6dee48f78dd7808c1f1a1b131a02ce7cc0b Mon Sep 17 00:00:00 2001 From: Chris Guillott Date: Wed, 29 Nov 2017 15:03:53 -0500 Subject: [PATCH 06/18] update version to fix release --- I3LOCK_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/I3LOCK_VERSION b/I3LOCK_VERSION index 8eedd74..1c9698b 100644 --- a/I3LOCK_VERSION +++ b/I3LOCK_VERSION @@ -1 +1 @@ -2.10-non-git +2.10.1-color-non-git From ef4f9e40570d020571d277bde5703e32b126b9e4 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sat, 2 Dec 2017 10:08:54 +0100 Subject: [PATCH 07/18] Switch to autotools (#163) This was largely copied from the i3 configure.ac and Makefile.am. --- .gitignore | 29 +++- .travis.yml | 2 +- Makefile | 67 -------- Makefile.am | 53 +++++++ configure.ac | 145 +++++++++++++++++ i3lock.c | 8 +- m4/ax_append_flag.m4 | 71 +++++++++ m4/ax_cflags_warn_all.m4 | 122 +++++++++++++++ m4/ax_check_compile_flag.m4 | 74 +++++++++ m4/ax_check_enable_debug.m4 | 124 +++++++++++++++ m4/ax_check_gnu_make.m4 | 84 ++++++++++ m4/ax_check_link_flag.m4 | 74 +++++++++ m4/ax_code_coverage.m4 | 273 ++++++++++++++++++++++++++++++++ m4/ax_configure_args.m4 | 70 +++++++++ m4/ax_enable_builddir.m4 | 302 ++++++++++++++++++++++++++++++++++++ m4/ax_extend_srcdir.m4 | 86 ++++++++++ m4/ax_require_defined.m4 | 37 +++++ m4/ax_sanitizers.m4 | 130 ++++++++++++++++ i3lock.pam => pam/i3lock | 0 19 files changed, 1679 insertions(+), 72 deletions(-) delete mode 100644 Makefile create mode 100644 Makefile.am create mode 100644 configure.ac create mode 100644 m4/ax_append_flag.m4 create mode 100644 m4/ax_cflags_warn_all.m4 create mode 100644 m4/ax_check_compile_flag.m4 create mode 100644 m4/ax_check_enable_debug.m4 create mode 100644 m4/ax_check_gnu_make.m4 create mode 100644 m4/ax_check_link_flag.m4 create mode 100644 m4/ax_code_coverage.m4 create mode 100644 m4/ax_configure_args.m4 create mode 100644 m4/ax_enable_builddir.m4 create mode 100644 m4/ax_extend_srcdir.m4 create mode 100644 m4/ax_require_defined.m4 create mode 100644 m4/ax_sanitizers.m4 rename i3lock.pam => pam/i3lock (100%) diff --git a/.gitignore b/.gitignore index 6958816..eb37b56 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,31 @@ -i3lock +/i3lock *.o tags *.swp + +################################################################################ +# https://raw.githubusercontent.com/github/gitignore/master/Autotools.gitignore +################################################################################ + +# http://www.gnu.org/software/automake + +Makefile.in +/ar-lib +/test-driver + +# http://www.gnu.org/software/autoconf + +/autom4te.cache +/autoscan.log +/autoscan-*.log +/aclocal.m4 +/compile +/config.h.in +/config.guess +/config.sub +/configure +/configure.scan +/depcomp +/install-sh +/missing +/stamp-h1 diff --git a/.travis.yml b/.travis.yml index 23be3b0..c9db585 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,5 +25,5 @@ before_install: - sudo apt-get update - sudo apt-get --force-yes -y install -t xenial libxkbcommon-dev libxkbcommon-x11-dev script: - - make -j + - autoreconf -fi && mkdir -p build && cd build && (../configure || (cat config.log; false)) && make -j CFLAGS="-Wformat -Wformat-security -Wextra -Wno-unused-parameter -Werror" - clang-format-3.5 -i *.[ch] && git diff --exit-code || (echo 'Code was not formatted using clang-format!'; false) diff --git a/Makefile b/Makefile deleted file mode 100644 index c59ad0e..0000000 --- a/Makefile +++ /dev/null @@ -1,67 +0,0 @@ -TOPDIR=$(shell pwd) -UNAME=$(shell uname) - -INSTALL=install -PREFIX=/usr -SYSCONFDIR=/etc -PKG_CONFIG=pkg-config - -# Check if pkg-config is installed, we need it for building CFLAGS/LIBS -ifeq ($(shell which $(PKG_CONFIG) 2>/dev/null 1>/dev/null || echo 1),1) -$(error "$(PKG_CONFIG) was not found") -endif - -CFLAGS += -std=c99 -CFLAGS += -pipe -CFLAGS += -Wall -CPPFLAGS += -D_GNU_SOURCE -CFLAGS += $(shell $(PKG_CONFIG) --cflags cairo xcb-xinerama xcb-randr xcb-atom xcb-image xcb-xkb xkbcommon xkbcommon-x11) -LIBS += $(shell $(PKG_CONFIG) --libs cairo xcb-xinerama xcb-randr xcb-atom xcb-image xcb-xkb xkbcommon xkbcommon-x11) -LIBS += -lev -LIBS += -lm - -# OpenBSD lacks PAM, use bsd_auth(3) instead. -ifneq ($(UNAME),OpenBSD) - LIBS += -lpam -endif - -FILES:=$(wildcard *.c) -FILES:=$(FILES:.c=.o) - -ifeq ($(wildcard .git),) - # not in git repository - VERSION := $(shell [ -f $(TOPDIR)/I3LOCK_VERSION ] && cat $(TOPDIR)/I3LOCK_VERSION | cut -d '-' -f 1) - I3LOCK_VERSION:='$(shell [ -f $(TOPDIR)/I3LOCK_VERSION ] && cat $(TOPDIR)/I3LOCK_VERSION)' -else - VERSION:=$(shell git describe --tags --abbrev=0) - I3LOCK_VERSION:="$(shell git describe --tags --always) ($(shell git log --pretty=format:%cd --date=short -n1))" -endif -CPPFLAGS += -DVERSION=\"${I3LOCK_VERSION}\" - -.PHONY: install clean uninstall - -all: i3lock - -i3lock: ${FILES} - $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) - -clean: - rm -f i3lock ${FILES} i3lock-${VERSION}.tar.gz - -install: all - $(INSTALL) -d $(DESTDIR)$(PREFIX)/bin - $(INSTALL) -d $(DESTDIR)$(SYSCONFDIR)/pam.d - $(INSTALL) -m 755 i3lock $(DESTDIR)$(PREFIX)/bin/i3lock - $(INSTALL) -m 644 i3lock.pam $(DESTDIR)$(SYSCONFDIR)/pam.d/i3lock - -uninstall: - rm -f $(DESTDIR)$(PREFIX)/bin/i3lock - -dist: clean - [ ! -d i3lock-${VERSION} ] || rm -rf i3lock-${VERSION} - [ ! -e i3lock-${VERSION}.tar.bz2 ] || rm i3lock-${VERSION}.tar.bz2 - mkdir i3lock-${VERSION} - cp *.c *.h i3lock.1 i3lock.pam Makefile LICENSE README.md CHANGELOG i3lock-${VERSION} - sed -e 's/^\s*I3LOCK_VERSION:=\(.*\)/I3LOCK_VERSION:=$(shell /bin/echo '${I3LOCK_VERSION}' | sed 's/\\/\\\\/g')/g;s/^VERSION:=\(.*\)/VERSION:=${VERSION}/g' Makefile > i3lock-${VERSION}/Makefile - tar cfj i3lock-${VERSION}.tar.bz2 i3lock-${VERSION} - rm -rf i3lock-${VERSION} diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..aa70ded --- /dev/null +++ b/Makefile.am @@ -0,0 +1,53 @@ +@CODE_COVERAGE_RULES@ + +echo-version: + @echo "@I3LOCK_VERSION@" + +bin_PROGRAMS = i3lock + +dist_man1_MANS = i3lock.1 + +pamddir = $(sysconfdir)/pam.d +pamd_files = pam/i3lock +pamd_DATA = $(pamd_files) + +AM_CPPFLAGS = \ + @AX_EXTEND_SRCDIR_CPPFLAGS@ + +i3lock_CFLAGS = \ + $(AM_CFLAGS) \ + $(XCB_CFLAGS) \ + $(XCB_IMAGE_CFLAGS) \ + $(XCB_UTIL_CFLAGS) \ + $(XKBCOMMON_CFLAGS) \ + $(CAIRO_CFLAGS) \ + $(CODE_COVERAGE_CFLAGS) + +i3lock_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + $(CODE_COVERAGE_CPPFLAGS) + +i3lock_LDADD = \ + $(XCB_LIBS) \ + $(XCB_IMAGE_LIBS) \ + $(XCB_UTIL_LIBS) \ + $(XKBCOMMON_LIBS) \ + $(CAIRO_LIBS) \ + $(CODE_COVERAGE_LDFLAGS) + +i3lock_SOURCES = \ + cursors.h \ + i3lock.c \ + i3lock.h \ + randr.c \ + randr.h \ + unlock_indicator.c \ + unlock_indicator.h \ + xcb.c \ + xcb.h + +EXTRA_DIST = \ + $(pamd_files) \ + CHANGELOG \ + LICENSE \ + README.md diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..d4bceb0 --- /dev/null +++ b/configure.ac @@ -0,0 +1,145 @@ +# -*- Autoconf -*- +# Run autoreconf -fi to generate a configure script from this file. + +AC_PREREQ([2.69]) +AC_INIT([i3lock], [2.10], [https://github.com/i3/i3lock/issues]) +# For AX_EXTEND_SRCDIR +AX_ENABLE_BUILDDIR +AM_INIT_AUTOMAKE([foreign subdir-objects -Wall no-dist-gzip dist-bzip2]) +# Default to silent rules, use V=1 to get verbose compilation output. +AM_SILENT_RULES([yes]) +# Make it possible to disable maintainer mode to disable re-generation of build +# system files. +AM_MAINTAINER_MODE([enable]) +AC_CONFIG_SRCDIR([i3lock.c]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) + +dnl Verify macros defined in m4/ such as AX_SANITIZERS are not present in the +dnl output, i.e. are replaced as expected. This line results in a better error +dnl message when using aclocal < 1.13 (which does not understand +dnl AC_CONFIG_MACRO_DIR) without passing the -I m4 parameter. +m4_pattern_forbid([AX_SANITIZERS]) + +# Verify we are using GNU make because we use '%'-style pattern rules in +# Makefile.am, which are a GNU make extension. Pull requests to replace +# '%'-style pattern rules with a more portable alternative are welcome. +AX_CHECK_GNU_MAKE +AS_VAR_IF([_cv_gnu_make_command], [""], [AC_MSG_ERROR([the i3lock Makefile.am requires GNU make])]) + +AX_EXTEND_SRCDIR + +AS_IF([test -d ${srcdir}/.git], + [ + VERSION="$(git -C ${srcdir} describe --tags --abbrev=0)" + I3LOCK_VERSION="$(git -C ${srcdir} describe --tags --always) ($(git -C ${srcdir} log --pretty=format:%cd --date=short -n1), branch \\\"$(git -C ${srcdir} describe --tags --always --all | sed s:heads/::)\\\")" + # Mirrors what libi3/is_debug_build.c does: + is_release=$(test $(echo "${I3LOCK_VERSION}" | cut -d '(' -f 1 | wc -m) -lt 10 && echo yes || echo no) + ], + [ + VERSION="$(cut -d '-' -f 1 ${srcdir}/I3LOCK_VERSION | cut -d ' ' -f 1)" + I3LOCK_VERSION="$(sed -e 's/@<:@\"?\\@:>@/\\&/g' ${srcdir}/I3LOCK_VERSION)" + is_release="$(grep -q non-git ${srcdir}/I3LOCK_VERSION && echo no || echo yes)" + ]) +AC_SUBST([I3LOCK_VERSION], [$I3LOCK_VERSION]) +AC_DEFINE_UNQUOTED([I3LOCK_VERSION], ["${I3LOCK_VERSION}"], [i3lock version]) + +AX_CODE_COVERAGE + +dnl is_release must be lowercase because AX_CHECK_ENABLE_DEBUG calls m4_tolower +dnl on its fourth argument. +AX_CHECK_ENABLE_DEBUG([yes], , [UNUSED_NDEBUG], [$is_release]) + +AC_PROG_CC_C99 + +# For strnlen() and vasprintf(). +AC_USE_SYSTEM_EXTENSIONS + +# Checks for typedefs, structures, and compiler characteristics. +AC_CHECK_HEADER_STDBOOL +dnl The error message should include the specific type which could not be +dnl found, but I do not see a way to achieve that. +AC_CHECK_TYPES([mode_t, off_t, pid_t, size_t, ssize_t], , [AC_MSG_FAILURE([cannot find required type])]) + +# Checks for library functions. +AC_FUNC_FORK +AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK +AC_FUNC_STRNLEN +AC_CHECK_FUNCS([atexit dup2 ftruncate getcwd gettimeofday localtime_r memchr memset mkdir rmdir setlocale socket strcasecmp strchr strdup strerror strncasecmp strndup strrchr strspn strstr strtol strtoul], , [AC_MSG_FAILURE([cannot find the $ac_func function, which i3lock requires])]) + +# Checks for libraries. + +AC_SEARCH_LIBS([floor], [m], , [AC_MSG_FAILURE([cannot find the required floor() function despite trying to link with -lm])]) + +# libev does not ship with a pkg-config file :(. +AC_SEARCH_LIBS([ev_run], [ev], , [AC_MSG_FAILURE([cannot find the required ev_run() function despite trying to link with -lev])]) + +AC_SEARCH_LIBS([shm_open], [rt]) + +AC_SEARCH_LIBS([pam_authenticate], [pam]) + +AC_SEARCH_LIBS([iconv_open], [iconv], , [AC_MSG_FAILURE([cannot find the required iconv_open() function despite trying to link with -liconv])]) + +dnl Each prefix corresponds to a source tarball which users might have +dnl downloaded in a newer version and would like to overwrite. +PKG_CHECK_MODULES([XCB], [xcb xcb-xkb xcb-xinerama xcb-randr]) +PKG_CHECK_MODULES([XCB_IMAGE], [xcb-image]) +PKG_CHECK_MODULES([XCB_UTIL], [xcb-event xcb-util xcb-atom]) +PKG_CHECK_MODULES([XKBCOMMON], [xkbcommon xkbcommon-x11]) +PKG_CHECK_MODULES([CAIRO], [cairo]) + +# Checks for programs. +AC_PROG_AWK +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_MAKE_SET +AC_PROG_RANLIB +AC_PROG_LN_S + +AM_PROG_AR + +AX_FLAGS_WARN_ALL +AX_CHECK_COMPILE_FLAG([-Wunused-value], [AX_APPEND_FLAG([-Wunused-value], [AM_CFLAGS])]) +AC_SUBST(AM_CFLAGS) + +# Checks for header files. +AC_CHECK_HEADERS([fcntl.h float.h inttypes.h limits.h locale.h netinet/in.h paths.h stddef.h stdint.h stdlib.h string.h sys/param.h sys/socket.h sys/time.h unistd.h], , [AC_MSG_FAILURE([cannot find the $ac_header header, which i3lock requires])]) + +AC_CONFIG_FILES([Makefile]) + +# Enable address sanitizer for non-release builds. The performance hit is a +# 50% increase of wallclock time for the testsuite on my machine. +if test x$is_release = xyes; then + default_sanitizers= +else + default_sanitizers=address +fi +AX_SANITIZERS(, [$default_sanitizers], [AC_DEFINE([I3LOCK_ASAN_ENABLED], [], [Enable ASAN])]) + +AC_OUTPUT + +in_git_worktree=`git rev-parse --is-inside-work-tree 2>/dev/null` +if [[ "$in_git_worktree" = "true" ]]; then + git_dir=`git rev-parse --git-dir 2>/dev/null` + srcdir=`dirname "$git_dir"` + exclude_dir=`pwd | sed "s,^$srcdir,,g"` + if ! grep -q "^$exclude_dir" "$git_dir/info/exclude"; then + echo "$exclude_dir" >> "$git_dir/info/exclude" + fi +fi + +echo \ +"-------------------------------------------------------------------------------- +build configured: + +AS_HELP_STRING([i3lock version:], [`echo ${I3LOCK_VERSION} | sed 's,\\\\,,g'`]) +AS_HELP_STRING([is release version:], [${is_release}]) + +AS_HELP_STRING([enable debug flags:], [${ax_enable_debug}]) +AS_HELP_STRING([code coverage:], [${CODE_COVERAGE_ENABLED}]) +AS_HELP_STRING([enabled sanitizers:], [${ax_enabled_sanitizers}]) + +To compile, run: + + cd `pwd` && make -j8 +--------------------------------------------------------------------------------" diff --git a/i3lock.c b/i3lock.c index a836240..d6f2151 100644 --- a/i3lock.c +++ b/i3lock.c @@ -6,6 +6,8 @@ * See LICENSE for licensing information * */ +#include + #include #include #include @@ -178,7 +180,7 @@ static void clear_password_memory(void) { /* A volatile pointer to the password buffer to prevent the compiler from * optimizing this out. */ volatile char *vpassword = password; - for (int c = 0; c < sizeof(password); c++) + for (size_t c = 0; c < sizeof(password); c++) /* We store a non-random pattern which consists of the (irrelevant) * index plus (!) the value of the beep variable. This prevents the * compiler from optimizing the calls away, since the value of 'beep' @@ -486,7 +488,7 @@ static void handle_key_press(xcb_key_press_event_t *event) { return; } - if ((input_position + 8) >= sizeof(password)) + if ((input_position + 8) >= (int)sizeof(password)) return; #if 0 @@ -852,7 +854,7 @@ int main(int argc, char *argv[]) { while ((o = getopt_long(argc, argv, optstring, longopts, &longoptind)) != -1) { switch (o) { case 'v': - errx(EXIT_SUCCESS, "version " VERSION " © 2010 Michael Stapelberg"); + errx(EXIT_SUCCESS, "version " I3LOCK_VERSION " © 2010 Michael Stapelberg"); case 'n': dont_fork = true; break; diff --git a/m4/ax_append_flag.m4 b/m4/ax_append_flag.m4 new file mode 100644 index 0000000..08f2e07 --- /dev/null +++ b/m4/ax_append_flag.m4 @@ -0,0 +1,71 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_append_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE]) +# +# DESCRIPTION +# +# FLAG is appended to the FLAGS-VARIABLE shell variable, with a space +# added in between. +# +# If FLAGS-VARIABLE is not specified, the current language's flags (e.g. +# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains +# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly +# FLAG. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 6 + +AC_DEFUN([AX_APPEND_FLAG], +[dnl +AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF +AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])]) +AS_VAR_SET_IF(FLAGS,[ + AS_CASE([" AS_VAR_GET(FLAGS) "], + [*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])], + [ + AS_VAR_APPEND(FLAGS,[" $1"]) + AC_RUN_LOG([: FLAGS="$FLAGS"]) + ]) + ], + [ + AS_VAR_SET(FLAGS,[$1]) + AC_RUN_LOG([: FLAGS="$FLAGS"]) + ]) +AS_VAR_POPDEF([FLAGS])dnl +])dnl AX_APPEND_FLAG diff --git a/m4/ax_cflags_warn_all.m4 b/m4/ax_cflags_warn_all.m4 new file mode 100644 index 0000000..1f07799 --- /dev/null +++ b/m4/ax_cflags_warn_all.m4 @@ -0,0 +1,122 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_cflags_warn_all.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])] +# AX_CXXFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])] +# AX_FCFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])] +# +# DESCRIPTION +# +# Try to find a compiler option that enables most reasonable warnings. +# +# For the GNU compiler it will be -Wall (and -ansi -pedantic) The result +# is added to the shellvar being CFLAGS, CXXFLAGS, or FCFLAGS by default. +# +# Currently this macro knows about the GCC, Solaris, Digital Unix, AIX, +# HP-UX, IRIX, NEC SX-5 (Super-UX 10), Cray J90 (Unicos 10.0.0.8), and +# Intel compilers. For a given compiler, the Fortran flags are much more +# experimental than their C equivalents. +# +# - $1 shell-variable-to-add-to : CFLAGS, CXXFLAGS, or FCFLAGS +# - $2 add-value-if-not-found : nothing +# - $3 action-if-found : add value to shellvariable +# - $4 action-if-not-found : nothing +# +# NOTE: These macros depend on AX_APPEND_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2010 Rhys Ulerich +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 15 + +AC_DEFUN([AX_FLAGS_WARN_ALL],[dnl +AS_VAR_PUSHDEF([FLAGS],[_AC_LANG_PREFIX[]FLAGS])dnl +AS_VAR_PUSHDEF([VAR],[ac_cv_[]_AC_LANG_ABBREV[]flags_warn_all])dnl +AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum warnings], +VAR,[VAR="no, unknown" +ac_save_[]FLAGS="$[]FLAGS" +for ac_arg dnl +in "-warn all % -warn all" dnl Intel + "-pedantic % -Wall" dnl GCC + "-xstrconst % -v" dnl Solaris C + "-std1 % -verbose -w0 -warnprotos" dnl Digital Unix + "-qlanglvl=ansi % -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX + "-ansi -ansiE % -fullwarn" dnl IRIX + "+ESlit % +w1" dnl HP-UX C + "-Xc % -pvctl[,]fullmsg" dnl NEC SX-5 (Super-UX 10) + "-h conform % -h msglevel 2" dnl Cray C (Unicos) + # +do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` + AC_COMPILE_IFELSE([AC_LANG_PROGRAM], + [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) +done +FLAGS="$ac_save_[]FLAGS" +]) +AS_VAR_POPDEF([FLAGS])dnl +AX_REQUIRE_DEFINED([AX_APPEND_FLAG]) +case ".$VAR" in + .ok|.ok,*) m4_ifvaln($3,$3) ;; + .|.no|.no,*) m4_default($4,[m4_ifval($2,[AX_APPEND_FLAG([$2], [$1])])]) ;; + *) m4_default($3,[AX_APPEND_FLAG([$VAR], [$1])]) ;; +esac +AS_VAR_POPDEF([VAR])dnl +])dnl AX_FLAGS_WARN_ALL +dnl implementation tactics: +dnl the for-argument contains a list of options. The first part of +dnl these does only exist to detect the compiler - usually it is +dnl a global option to enable -ansi or -extrawarnings. All other +dnl compilers will fail about it. That was needed since a lot of +dnl compilers will give false positives for some option-syntax +dnl like -Woption or -Xoption as they think of it is a pass-through +dnl to later compile stages or something. The "%" is used as a +dnl delimiter. A non-option comment can be given after "%%" marks +dnl which will be shown but not added to the respective C/CXXFLAGS. + +AC_DEFUN([AX_CFLAGS_WARN_ALL],[dnl +AC_LANG_PUSH([C]) +AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4]) +AC_LANG_POP([C]) +]) + +AC_DEFUN([AX_CXXFLAGS_WARN_ALL],[dnl +AC_LANG_PUSH([C++]) +AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4]) +AC_LANG_POP([C++]) +]) + +AC_DEFUN([AX_FCFLAGS_WARN_ALL],[dnl +AC_LANG_PUSH([Fortran]) +AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4]) +AC_LANG_POP([Fortran]) +]) diff --git a/m4/ax_check_compile_flag.m4 b/m4/ax_check_compile_flag.m4 new file mode 100644 index 0000000..ca36397 --- /dev/null +++ b/m4/ax_check_compile_flag.m4 @@ -0,0 +1,74 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the current language's compiler +# or gives an error. (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 4 + +AC_DEFUN([AX_CHECK_COMPILE_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl +AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ + ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" + AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_COMPILE_FLAGS diff --git a/m4/ax_check_enable_debug.m4 b/m4/ax_check_enable_debug.m4 new file mode 100644 index 0000000..f99d75f --- /dev/null +++ b/m4/ax_check_enable_debug.m4 @@ -0,0 +1,124 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_check_enable_debug.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_ENABLE_DEBUG([enable by default=yes/info/profile/no], [ENABLE DEBUG VARIABLES ...], [DISABLE DEBUG VARIABLES NDEBUG ...], [IS-RELEASE]) +# +# DESCRIPTION +# +# Check for the presence of an --enable-debug option to configure, with +# the specified default value used when the option is not present. Return +# the value in the variable $ax_enable_debug. +# +# Specifying 'yes' adds '-g -O0' to the compilation flags for all +# languages. Specifying 'info' adds '-g' to the compilation flags. +# Specifying 'profile' adds '-g -pg' to the compilation flags and '-pg' to +# the linking flags. Otherwise, nothing is added. +# +# Define the variables listed in the second argument if debug is enabled, +# defaulting to no variables. Defines the variables listed in the third +# argument if debug is disabled, defaulting to NDEBUG. All lists of +# variables should be space-separated. +# +# If debug is not enabled, ensure AC_PROG_* will not add debugging flags. +# Should be invoked prior to any AC_PROG_* compiler checks. +# +# IS-RELEASE can be used to change the default to 'no' when making a +# release. Set IS-RELEASE to 'yes' or 'no' as appropriate. By default, it +# uses the value of $ax_is_release, so if you are using the AX_IS_RELEASE +# macro, there is no need to pass this parameter. +# +# AX_IS_RELEASE([git-directory]) +# AX_CHECK_ENABLE_DEBUG() +# +# LICENSE +# +# Copyright (c) 2011 Rhys Ulerich +# Copyright (c) 2014, 2015 Philip Withnall +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. + +#serial 5 + +AC_DEFUN([AX_CHECK_ENABLE_DEBUG],[ + AC_BEFORE([$0],[AC_PROG_CC])dnl + AC_BEFORE([$0],[AC_PROG_CXX])dnl + AC_BEFORE([$0],[AC_PROG_F77])dnl + AC_BEFORE([$0],[AC_PROG_FC])dnl + + AC_MSG_CHECKING(whether to enable debugging) + + ax_enable_debug_default=m4_tolower(m4_normalize(ifelse([$1],,[no],[$1]))) + ax_enable_debug_is_release=m4_tolower(m4_normalize(ifelse([$4],, + [$ax_is_release], + [$4]))) + + # If this is a release, override the default. + AS_IF([test "$ax_enable_debug_is_release" = "yes"], + [ax_enable_debug_default="no"]) + + m4_define(ax_enable_debug_vars,[m4_normalize(ifelse([$2],,,[$2]))]) + m4_define(ax_disable_debug_vars,[m4_normalize(ifelse([$3],,[NDEBUG],[$3]))]) + + AC_ARG_ENABLE(debug, + [AS_HELP_STRING([--enable-debug=]@<:@yes/info/profile/no@:>@,[compile with debugging])], + [],enable_debug=$ax_enable_debug_default) + + # empty mean debug yes + AS_IF([test "x$enable_debug" = "x"], + [enable_debug="yes"]) + + # case of debug + AS_CASE([$enable_debug], + [yes],[ + AC_MSG_RESULT(yes) + CFLAGS="${CFLAGS} -g -O0" + CXXFLAGS="${CXXFLAGS} -g -O0" + FFLAGS="${FFLAGS} -g -O0" + FCFLAGS="${FCFLAGS} -g -O0" + OBJCFLAGS="${OBJCFLAGS} -g -O0" + ], + [info],[ + AC_MSG_RESULT(info) + CFLAGS="${CFLAGS} -g" + CXXFLAGS="${CXXFLAGS} -g" + FFLAGS="${FFLAGS} -g" + FCFLAGS="${FCFLAGS} -g" + OBJCFLAGS="${OBJCFLAGS} -g" + ], + [profile],[ + AC_MSG_RESULT(profile) + CFLAGS="${CFLAGS} -g -pg" + CXXFLAGS="${CXXFLAGS} -g -pg" + FFLAGS="${FFLAGS} -g -pg" + FCFLAGS="${FCFLAGS} -g -pg" + OBJCFLAGS="${OBJCFLAGS} -g -pg" + LDFLAGS="${LDFLAGS} -pg" + ], + [ + AC_MSG_RESULT(no) + dnl Ensure AC_PROG_CC/CXX/F77/FC/OBJC will not enable debug flags + dnl by setting any unset environment flag variables + AS_IF([test "x${CFLAGS+set}" != "xset"], + [CFLAGS=""]) + AS_IF([test "x${CXXFLAGS+set}" != "xset"], + [CXXFLAGS=""]) + AS_IF([test "x${FFLAGS+set}" != "xset"], + [FFLAGS=""]) + AS_IF([test "x${FCFLAGS+set}" != "xset"], + [FCFLAGS=""]) + AS_IF([test "x${OBJCFLAGS+set}" != "xset"], + [OBJCFLAGS=""]) + ]) + + dnl Define various variables if debugging is disabled. + dnl assert.h is a NOP if NDEBUG is defined, so define it by default. + AS_IF([test "x$enable_debug" = "xyes"], + [m4_map_args_w(ax_enable_debug_vars, [AC_DEFINE(], [,,[Define if debugging is enabled])])], + [m4_map_args_w(ax_disable_debug_vars, [AC_DEFINE(], [,,[Define if debugging is disabled])])]) + ax_enable_debug=$enable_debug +]) diff --git a/m4/ax_check_gnu_make.m4 b/m4/ax_check_gnu_make.m4 new file mode 100644 index 0000000..6762e9e --- /dev/null +++ b/m4/ax_check_gnu_make.m4 @@ -0,0 +1,84 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_check_gnu_make.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_GNU_MAKE() +# +# DESCRIPTION +# +# This macro searches for a GNU version of make. If a match is found: +# +# * The makefile variable `ifGNUmake' is set to the empty string, otherwise +# it is set to "#". This is useful for including a special features in a +# Makefile, which cannot be handled by other versions of make. +# * The variable `_cv_gnu_make_command` is set to the command to invoke +# GNU make if it exists, the empty string otherwise. +# * The variable `ax_cv_gnu_make_command` is set to the command to invoke +# GNU make by copying `_cv_gnu_make_command`, otherwise it is unset. +# * If GNU Make is found, its version is extracted from the output of +# `make --version` as the last field of a record of space-separated +# columns and saved into the variable `ax_check_gnu_make_version`. +# +# Here is an example of its use: +# +# Makefile.in might contain: +# +# # A failsafe way of putting a dependency rule into a makefile +# $(DEPEND): +# $(CC) -MM $(srcdir)/*.c > $(DEPEND) +# +# @ifGNUmake@ ifeq ($(DEPEND),$(wildcard $(DEPEND))) +# @ifGNUmake@ include $(DEPEND) +# @ifGNUmake@ endif +# +# Then configure.in would normally contain: +# +# AX_CHECK_GNU_MAKE() +# AC_OUTPUT(Makefile) +# +# Then perhaps to cause gnu make to override any other make, we could do +# something like this (note that GNU make always looks for GNUmakefile +# first): +# +# if ! test x$_cv_gnu_make_command = x ; then +# mv Makefile GNUmakefile +# echo .DEFAULT: > Makefile ; +# echo \ $_cv_gnu_make_command \$@ >> Makefile; +# fi +# +# Then, if any (well almost any) other make is called, and GNU make also +# exists, then the other make wraps the GNU make. +# +# LICENSE +# +# Copyright (c) 2008 John Darrington +# Copyright (c) 2015 Enrico M. Crisostomo +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 8 + +AC_DEFUN([AX_CHECK_GNU_MAKE],dnl + [AC_PROG_AWK + AC_CACHE_CHECK([for GNU make],[_cv_gnu_make_command],[dnl + _cv_gnu_make_command="" ; +dnl Search all the common names for GNU make + for a in "$MAKE" make gmake gnumake ; do + if test -z "$a" ; then continue ; fi ; + if "$a" --version 2> /dev/null | grep GNU 2>&1 > /dev/null ; then + _cv_gnu_make_command=$a ; + AX_CHECK_GNU_MAKE_HEADLINE=$("$a" --version 2> /dev/null | grep "GNU Make") + ax_check_gnu_make_version=$(echo ${AX_CHECK_GNU_MAKE_HEADLINE} | ${AWK} -F " " '{ print $(NF); }') + break ; + fi + done ;]) +dnl If there was a GNU version, then set @ifGNUmake@ to the empty string, '#' otherwise + AS_VAR_IF([_cv_gnu_make_command], [""], [AS_VAR_SET([ifGNUmake], ["#"])], [AS_VAR_SET([ifGNUmake], [""])]) + AS_VAR_IF([_cv_gnu_make_command], [""], [AS_UNSET(ax_cv_gnu_make_command)], [AS_VAR_SET([ax_cv_gnu_make_command], [${_cv_gnu_make_command}])]) + AC_SUBST([ifGNUmake]) +]) diff --git a/m4/ax_check_link_flag.m4 b/m4/ax_check_link_flag.m4 new file mode 100644 index 0000000..eb01a6c --- /dev/null +++ b/m4/ax_check_link_flag.m4 @@ -0,0 +1,74 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the linker or gives an error. +# (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the linker's default flags +# when the check is done. The check is thus made with the flags: "LDFLAGS +# EXTRA-FLAGS FLAG". This can for example be used to force the linker to +# issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_LINK_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 4 + +AC_DEFUN([AX_CHECK_LINK_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl +AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ + ax_check_save_flags=$LDFLAGS + LDFLAGS="$LDFLAGS $4 $1" + AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + LDFLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_LINK_FLAGS diff --git a/m4/ax_code_coverage.m4 b/m4/ax_code_coverage.m4 new file mode 100644 index 0000000..6c985eb --- /dev/null +++ b/m4/ax_code_coverage.m4 @@ -0,0 +1,273 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_code_coverage.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CODE_COVERAGE() +# +# DESCRIPTION +# +# Defines CODE_COVERAGE_CPPFLAGS, CODE_COVERAGE_CFLAGS, +# CODE_COVERAGE_CXXFLAGS and CODE_COVERAGE_LDFLAGS which should be +# included in the CPPFLAGS, CFLAGS CXXFLAGS and LIBS/LDFLAGS variables of +# every build target (program or library) which should be built with code +# coverage support. Also defines CODE_COVERAGE_RULES which should be +# substituted in your Makefile; and $enable_code_coverage which can be +# used in subsequent configure output. CODE_COVERAGE_ENABLED is defined +# and substituted, and corresponds to the value of the +# --enable-code-coverage option, which defaults to being disabled. +# +# Test also for gcov program and create GCOV variable that could be +# substituted. +# +# Note that all optimisation flags in CFLAGS must be disabled when code +# coverage is enabled. +# +# Usage example: +# +# configure.ac: +# +# AX_CODE_COVERAGE +# +# Makefile.am: +# +# @CODE_COVERAGE_RULES@ +# my_program_LIBS = ... $(CODE_COVERAGE_LDFLAGS) ... +# my_program_CPPFLAGS = ... $(CODE_COVERAGE_CPPFLAGS) ... +# my_program_CFLAGS = ... $(CODE_COVERAGE_CFLAGS) ... +# my_program_CXXFLAGS = ... $(CODE_COVERAGE_CXXFLAGS) ... +# +# This results in a "check-code-coverage" rule being added to any +# Makefile.am which includes "@CODE_COVERAGE_RULES@" (assuming the module +# has been configured with --enable-code-coverage). Running `make +# check-code-coverage` in that directory will run the module's test suite +# (`make check`) and build a code coverage report detailing the code which +# was touched, then print the URI for the report. +# +# This code was derived from Makefile.decl in GLib, originally licenced +# under LGPLv2.1+. +# +# LICENSE +# +# Copyright (c) 2012, 2016 Philip Withnall +# Copyright (c) 2012 Xan Lopez +# Copyright (c) 2012 Christian Persch +# Copyright (c) 2012 Paolo Borelli +# Copyright (c) 2012 Dan Winship +# Copyright (c) 2015 Bastien ROUCARIES +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or (at +# your option) any later version. +# +# This library is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . + +#serial 15 + +AC_DEFUN([AX_CODE_COVERAGE],[ + dnl Check for --enable-code-coverage + AC_REQUIRE([AC_PROG_SED]) + + # allow to override gcov location + AC_ARG_WITH([gcov], + [AS_HELP_STRING([--with-gcov[=GCOV]], [use given GCOV for coverage (GCOV=gcov).])], + [_AX_CODE_COVERAGE_GCOV_PROG_WITH=$with_gcov], + [_AX_CODE_COVERAGE_GCOV_PROG_WITH=gcov]) + + AC_MSG_CHECKING([whether to build with code coverage support]) + AC_ARG_ENABLE([code-coverage], + AS_HELP_STRING([--enable-code-coverage], + [Whether to enable code coverage support]),, + enable_code_coverage=no) + + AM_CONDITIONAL([CODE_COVERAGE_ENABLED], [test x$enable_code_coverage = xyes]) + AC_SUBST([CODE_COVERAGE_ENABLED], [$enable_code_coverage]) + AC_MSG_RESULT($enable_code_coverage) + + AS_IF([ test "$enable_code_coverage" = "yes" ], [ + # check for gcov + AC_CHECK_TOOL([GCOV], + [$_AX_CODE_COVERAGE_GCOV_PROG_WITH], + [:]) + AS_IF([test "X$GCOV" = "X:"], + [AC_MSG_ERROR([gcov is needed to do coverage])]) + AC_SUBST([GCOV]) + + dnl Check if gcc is being used + AS_IF([ test "$GCC" = "no" ], [ + AC_MSG_ERROR([not compiling with gcc, which is required for gcov code coverage]) + ]) + + # List of supported lcov versions. + lcov_version_list="1.6 1.7 1.8 1.9 1.10 1.11 1.12" + + AC_CHECK_PROG([LCOV], [lcov], [lcov]) + AC_CHECK_PROG([GENHTML], [genhtml], [genhtml]) + + AS_IF([ test "$LCOV" ], [ + AC_CACHE_CHECK([for lcov version], ax_cv_lcov_version, [ + ax_cv_lcov_version=invalid + lcov_version=`$LCOV -v 2>/dev/null | $SED -e 's/^.* //'` + for lcov_check_version in $lcov_version_list; do + if test "$lcov_version" = "$lcov_check_version"; then + ax_cv_lcov_version="$lcov_check_version (ok)" + fi + done + ]) + ], [ + lcov_msg="To enable code coverage reporting you must have one of the following lcov versions installed: $lcov_version_list" + AC_MSG_ERROR([$lcov_msg]) + ]) + + case $ax_cv_lcov_version in + ""|invalid[)] + lcov_msg="You must have one of the following versions of lcov: $lcov_version_list (found: $lcov_version)." + AC_MSG_ERROR([$lcov_msg]) + LCOV="exit 0;" + ;; + esac + + AS_IF([ test -z "$GENHTML" ], [ + AC_MSG_ERROR([Could not find genhtml from the lcov package]) + ]) + + dnl Build the code coverage flags + CODE_COVERAGE_CPPFLAGS="-DNDEBUG" + CODE_COVERAGE_CFLAGS="-O0 -g -fprofile-arcs -ftest-coverage" + CODE_COVERAGE_CXXFLAGS="-O0 -g -fprofile-arcs -ftest-coverage" + CODE_COVERAGE_LDFLAGS="-lgcov" + + AC_SUBST([CODE_COVERAGE_CPPFLAGS]) + AC_SUBST([CODE_COVERAGE_CFLAGS]) + AC_SUBST([CODE_COVERAGE_CXXFLAGS]) + AC_SUBST([CODE_COVERAGE_LDFLAGS]) + ]) + +[CODE_COVERAGE_RULES=' +# Code coverage +# +# Optional: +# - CODE_COVERAGE_DIRECTORY: Top-level directory for code coverage reporting. +# Multiple directories may be specified, separated by whitespace. +# (Default: $(top_builddir)) +# - CODE_COVERAGE_OUTPUT_FILE: Filename and path for the .info file generated +# by lcov for code coverage. (Default: +# $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info) +# - CODE_COVERAGE_OUTPUT_DIRECTORY: Directory for generated code coverage +# reports to be created. (Default: +# $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage) +# - CODE_COVERAGE_BRANCH_COVERAGE: Set to 1 to enforce branch coverage, +# set to 0 to disable it and leave empty to stay with the default. +# (Default: empty) +# - CODE_COVERAGE_LCOV_SHOPTS_DEFAULT: Extra options shared between both lcov +# instances. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE) +# - CODE_COVERAGE_LCOV_SHOPTS: Extra options to shared between both lcov +# instances. (Default: $CODE_COVERAGE_LCOV_SHOPTS_DEFAULT) +# - CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH: --gcov-tool pathtogcov +# - CODE_COVERAGE_LCOV_OPTIONS_DEFAULT: Extra options to pass to the +# collecting lcov instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH) +# - CODE_COVERAGE_LCOV_OPTIONS: Extra options to pass to the collecting lcov +# instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_DEFAULT) +# - CODE_COVERAGE_LCOV_RMOPTS_DEFAULT: Extra options to pass to the filtering +# lcov instance. (Default: empty) +# - CODE_COVERAGE_LCOV_RMOPTS: Extra options to pass to the filtering lcov +# instance. (Default: $CODE_COVERAGE_LCOV_RMOPTS_DEFAULT) +# - CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT: Extra options to pass to the +# genhtml instance. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE) +# - CODE_COVERAGE_GENHTML_OPTIONS: Extra options to pass to the genhtml +# instance. (Default: $CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT) +# - CODE_COVERAGE_IGNORE_PATTERN: Extra glob pattern of files to ignore +# +# The generated report will be titled using the $(PACKAGE_NAME) and +# $(PACKAGE_VERSION). In order to add the current git hash to the title, +# use the git-version-gen script, available online. + +# Optional variables +CODE_COVERAGE_DIRECTORY ?= $(top_builddir) +CODE_COVERAGE_OUTPUT_FILE ?= $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info +CODE_COVERAGE_OUTPUT_DIRECTORY ?= $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage +CODE_COVERAGE_BRANCH_COVERAGE ?= +CODE_COVERAGE_LCOV_SHOPTS_DEFAULT ?= $(if $(CODE_COVERAGE_BRANCH_COVERAGE),\ +--rc lcov_branch_coverage=$(CODE_COVERAGE_BRANCH_COVERAGE)) +CODE_COVERAGE_LCOV_SHOPTS ?= $(CODE_COVERAGE_LCOV_SHOPTS_DEFAULT) +CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH ?= --gcov-tool "$(GCOV)" +CODE_COVERAGE_LCOV_OPTIONS_DEFAULT ?= $(CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH) +CODE_COVERAGE_LCOV_OPTIONS ?= $(CODE_COVERAGE_LCOV_OPTIONS_DEFAULT) +CODE_COVERAGE_LCOV_RMOPTS_DEFAULT ?= +CODE_COVERAGE_LCOV_RMOPTS ?= $(CODE_COVERAGE_LCOV_RMOPTS_DEFAULT) +CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT ?=\ +$(if $(CODE_COVERAGE_BRANCH_COVERAGE),\ +--rc genhtml_branch_coverage=$(CODE_COVERAGE_BRANCH_COVERAGE)) +CODE_COVERAGE_GENHTML_OPTIONS ?= $(CODE_COVERAGE_GENHTML_OPTIONS_DEFAULTS) +CODE_COVERAGE_IGNORE_PATTERN ?= + +code_coverage_v_lcov_cap = $(code_coverage_v_lcov_cap_$(V)) +code_coverage_v_lcov_cap_ = $(code_coverage_v_lcov_cap_$(AM_DEFAULT_VERBOSITY)) +code_coverage_v_lcov_cap_0 = @echo " LCOV --capture"\ + $(CODE_COVERAGE_OUTPUT_FILE); +code_coverage_v_lcov_ign = $(code_coverage_v_lcov_ign_$(V)) +code_coverage_v_lcov_ign_ = $(code_coverage_v_lcov_ign_$(AM_DEFAULT_VERBOSITY)) +code_coverage_v_lcov_ign_0 = @echo " LCOV --remove /tmp/*"\ + $(CODE_COVERAGE_IGNORE_PATTERN); +code_coverage_v_genhtml = $(code_coverage_v_genhtml_$(V)) +code_coverage_v_genhtml_ = $(code_coverage_v_genhtml_$(AM_DEFAULT_VERBOSITY)) +code_coverage_v_genhtml_0 = @echo " GEN " $(CODE_COVERAGE_OUTPUT_DIRECTORY); +code_coverage_quiet = $(code_coverage_quiet_$(V)) +code_coverage_quiet_ = $(code_coverage_quiet_$(AM_DEFAULT_VERBOSITY)) +code_coverage_quiet_0 = --quiet + +# sanitizes the test-name: replaces with underscores: dashes and dots +code_coverage_sanitize = $(subst -,_,$(subst .,_,$(1))) + +# Use recursive makes in order to ignore errors during check +check-code-coverage: +ifeq ($(CODE_COVERAGE_ENABLED),yes) + -$(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) -k check + $(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) code-coverage-capture +else + @echo "Need to reconfigure with --enable-code-coverage" +endif + +# Capture code coverage data +code-coverage-capture: code-coverage-capture-hook +ifeq ($(CODE_COVERAGE_ENABLED),yes) + $(code_coverage_v_lcov_cap)$(LCOV) $(code_coverage_quiet) $(addprefix --directory ,$(CODE_COVERAGE_DIRECTORY)) --capture --output-file "$(CODE_COVERAGE_OUTPUT_FILE).tmp" --test-name "$(call code_coverage_sanitize,$(PACKAGE_NAME)-$(PACKAGE_VERSION))" --no-checksum --compat-libtool $(CODE_COVERAGE_LCOV_SHOPTS) $(CODE_COVERAGE_LCOV_OPTIONS) + $(code_coverage_v_lcov_ign)$(LCOV) $(code_coverage_quiet) $(addprefix --directory ,$(CODE_COVERAGE_DIRECTORY)) --remove "$(CODE_COVERAGE_OUTPUT_FILE).tmp" "/tmp/*" $(CODE_COVERAGE_IGNORE_PATTERN) --output-file "$(CODE_COVERAGE_OUTPUT_FILE)" $(CODE_COVERAGE_LCOV_SHOPTS) $(CODE_COVERAGE_LCOV_RMOPTS) + -@rm -f $(CODE_COVERAGE_OUTPUT_FILE).tmp + $(code_coverage_v_genhtml)LANG=C $(GENHTML) $(code_coverage_quiet) $(addprefix --prefix ,$(CODE_COVERAGE_DIRECTORY)) --output-directory "$(CODE_COVERAGE_OUTPUT_DIRECTORY)" --title "$(PACKAGE_NAME)-$(PACKAGE_VERSION) Code Coverage" --legend --show-details "$(CODE_COVERAGE_OUTPUT_FILE)" $(CODE_COVERAGE_GENHTML_OPTIONS) + @echo "file://$(abs_builddir)/$(CODE_COVERAGE_OUTPUT_DIRECTORY)/index.html" +else + @echo "Need to reconfigure with --enable-code-coverage" +endif + +# Hook rule executed before code-coverage-capture, overridable by the user +code-coverage-capture-hook: + +ifeq ($(CODE_COVERAGE_ENABLED),yes) +clean: code-coverage-clean +code-coverage-clean: + -$(LCOV) --directory $(top_builddir) -z + -rm -rf $(CODE_COVERAGE_OUTPUT_FILE) $(CODE_COVERAGE_OUTPUT_FILE).tmp $(CODE_COVERAGE_OUTPUT_DIRECTORY) + -find . -name "*.gcda" -o -name "*.gcov" -delete +endif + +GITIGNOREFILES ?= +GITIGNOREFILES += $(CODE_COVERAGE_OUTPUT_FILE) $(CODE_COVERAGE_OUTPUT_DIRECTORY) + +A''M_DISTCHECK_CONFIGURE_FLAGS ?= +A''M_DISTCHECK_CONFIGURE_FLAGS += --disable-code-coverage + +.PHONY: check-code-coverage code-coverage-capture code-coverage-capture-hook code-coverage-clean +'] + + AC_SUBST([CODE_COVERAGE_RULES]) + m4_ifdef([_AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([CODE_COVERAGE_RULES])]) +]) diff --git a/m4/ax_configure_args.m4 b/m4/ax_configure_args.m4 new file mode 100644 index 0000000..0726b1b --- /dev/null +++ b/m4/ax_configure_args.m4 @@ -0,0 +1,70 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_configure_args.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CONFIGURE_ARGS +# +# DESCRIPTION +# +# Helper macro for AX_ENABLE_BUILDDIR. +# +# The traditional way of starting a subdir-configure is running the script +# with ${1+"$@"} but since autoconf 2.60 this is broken. Instead we have +# to rely on eval'ing $ac_configure_args however some old autoconf +# versions do not provide that. To ensure maximum portability of autoconf +# extension macros this helper can be AC_REQUIRE'd so that +# $ac_configure_args will alsways be present. +# +# Sadly, the traditional "exec $SHELL" of the enable_builddir macros is +# spoiled now and must be replaced by "eval + exit $?". +# +# Example: +# +# AC_DEFUN([AX_ENABLE_SUBDIR],[dnl +# AC_REQUIRE([AX_CONFIGURE_ARGS])dnl +# eval $SHELL $ac_configure_args || exit $? +# ...]) +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 9 + +AC_DEFUN([AX_CONFIGURE_ARGS],[ + # [$]@ is unsable in 2.60+ but earlier autoconf had no ac_configure_args + if test "${ac_configure_args+set}" != "set" ; then + ac_configure_args= + for ac_arg in ${1+"[$]@"}; do + ac_configure_args="$ac_configure_args '$ac_arg'" + done + fi +]) diff --git a/m4/ax_enable_builddir.m4 b/m4/ax_enable_builddir.m4 new file mode 100644 index 0000000..5f4ba32 --- /dev/null +++ b/m4/ax_enable_builddir.m4 @@ -0,0 +1,302 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_enable_builddir.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_ENABLE_BUILDDIR [(dirstring-or-command [,Makefile.mk [,-all]])] +# +# DESCRIPTION +# +# If the current configure was run within the srcdir then we move all +# configure-files into a subdir and let the configure steps continue +# there. We provide an option --disable-builddir to suppress the move into +# a separate builddir. +# +# Defaults: +# +# $1 = $host (overridden with $HOST) +# $2 = Makefile.mk +# $3 = -all +# +# This macro must be called before AM_INIT_AUTOMAKE. It creates a default +# toplevel srcdir Makefile from the information found in the created +# toplevel builddir Makefile. It just copies the variables and +# rule-targets, each extended with a default rule-execution that recurses +# into the build directory of the current "HOST". You can override the +# auto-dection through `config.guess` and build-time of course, as in +# +# make HOST=i386-mingw-cross +# +# which can of course set at configure time as well using +# +# configure --host=i386-mingw-cross +# +# After the default has been created, additional rules can be appended +# that will not just recurse into the subdirectories and only ever exist +# in the srcdir toplevel makefile - these parts are read from the $2 = +# Makefile.mk file +# +# The automatic rules are usually scanning the toplevel Makefile for lines +# like '#### $host |$builddir' to recognize the place where to recurse +# into. Usually, the last one is the only one used. However, almost all +# targets have an additional "*-all" rule which makes the script to +# recurse into _all_ variants of the current HOST (!!) setting. The "-all" +# suffix can be overriden for the macro as well. +# +# a special rule is only given for things like "dist" that will copy the +# tarball from the builddir to the sourcedir (or $(PUB)) for reason of +# convenience. +# +# LICENSE +# +# Copyright (c) 2009 Guido U. Draheim +# Copyright (c) 2009 Alan Jenkins +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 25 + +AC_DEFUN([AX_ENABLE_BUILDDIR],[ +AC_REQUIRE([AC_CANONICAL_HOST])[]dnl +AC_REQUIRE([AC_CANONICAL_TARGET])[]dnl +AC_REQUIRE([AX_CONFIGURE_ARGS])[]dnl +AC_REQUIRE([AM_AUX_DIR_EXPAND])[]dnl +AC_BEFORE([$0],[AM_INIT_AUTOMAKE])dnl +AS_VAR_PUSHDEF([SUB],[ax_enable_builddir])dnl +AS_VAR_PUSHDEF([AUX],[ax_enable_builddir_auxdir])dnl +AS_VAR_PUSHDEF([SED],[ax_enable_builddir_sed])dnl +SUB="." +AC_ARG_ENABLE([builddir], AS_HELP_STRING( + [--disable-builddir],[disable automatic build in subdir of sources]) + ,[SUB="$enableval"], [SUB="auto"]) +if test ".$ac_srcdir_defaulted" != ".no" ; then +if test ".$srcdir" = ".." ; then + if test -f config.status ; then + AC_MSG_NOTICE(toplevel srcdir already configured... skipping subdir build) + else + test ".$SUB" = "." && SUB="." + test ".$SUB" = ".no" && SUB="." + test ".$TARGET" = "." && TARGET="$target" + test ".$SUB" = ".auto" && SUB="m4_ifval([$1], [$1],[$TARGET])" + if test ".$SUB" != ".." ; then # we know where to go and + AS_MKDIR_P([$SUB]) + echo __.$SUB.__ > $SUB/conftest.tmp + cd $SUB + if grep __.$SUB.__ conftest.tmp >/dev/null 2>/dev/null ; then + rm conftest.tmp + AC_MSG_RESULT([continue configure in default builddir "./$SUB"]) + else + AC_MSG_ERROR([could not change to default builddir "./$SUB"]) + fi + srcdir=`echo "$SUB" | + sed -e 's,^\./,,;s,[[^/]]$,&/,;s,[[^/]]*/,../,g;s,[[/]]$,,;'` + # going to restart from subdirectory location + test -f $srcdir/config.log && mv $srcdir/config.log . + test -f $srcdir/confdefs.h && mv $srcdir/confdefs.h . + test -f $srcdir/conftest.log && mv $srcdir/conftest.log . + test -f $srcdir/$cache_file && mv $srcdir/$cache_file . + AC_MSG_RESULT(....exec $SHELL $srcdir/[$]0 "--srcdir=$srcdir" "--enable-builddir=$SUB" ${1+"[$]@"}) + case "[$]0" in # restart + [[\\/]]* | ?:[[\\/]]*) # Asbolute name + eval $SHELL "'[$]0'" "'--srcdir=$srcdir'" "'--enable-builddir=$SUB'" $ac_configure_args ;; + *) eval $SHELL "'$srcdir/[$]0'" "'--srcdir=$srcdir'" "'--enable-builddir=$SUB'" $ac_configure_args ;; + esac ; exit $? + fi + fi +fi fi +test ".$SUB" = ".auto" && SUB="." +dnl ac_path_prog uses "set dummy" to override $@ which would defeat the "exec" +AC_PATH_PROG(SED,gsed sed, sed) +AUX="$am_aux_dir" +AS_VAR_POPDEF([SED])dnl +AS_VAR_POPDEF([AUX])dnl +AS_VAR_POPDEF([SUB])dnl +AC_CONFIG_COMMANDS([buildir],[dnl .............. config.status .............. +AS_VAR_PUSHDEF([SUB],[ax_enable_builddir])dnl +AS_VAR_PUSHDEF([TOP],[top_srcdir])dnl +AS_VAR_PUSHDEF([SRC],[ac_top_srcdir])dnl +AS_VAR_PUSHDEF([AUX],[ax_enable_builddir_auxdir])dnl +AS_VAR_PUSHDEF([SED],[ax_enable_builddir_sed])dnl +pushdef([END],[Makefile.mk])dnl +pushdef([_ALL],[ifelse([$3],,[-all],[$3])])dnl + SRC="$ax_enable_builddir_srcdir" + if test ".$SUB" = ".." ; then + if test -f "$TOP/Makefile" ; then + AC_MSG_NOTICE([skipping TOP/Makefile - left untouched]) + else + AC_MSG_NOTICE([skipping TOP/Makefile - not created]) + fi + else + if test -f "$SRC/Makefile" ; then + a=`grep "^VERSION " "$SRC/Makefile"` ; b=`grep "^VERSION " Makefile` + test "$a" != "$b" && rm "$SRC/Makefile" + fi + if test -f "$SRC/Makefile" ; then + echo "$SRC/Makefile : $SRC/Makefile.in" > $tmp/conftemp.mk + echo " []@ echo 'REMOVED,,,' >\$[]@" >> $tmp/conftemp.mk + eval "${MAKE-make} -f $tmp/conftemp.mk 2>/dev/null >/dev/null" + if grep '^REMOVED,,,' "$SRC/Makefile" >/dev/null + then rm $SRC/Makefile ; fi + cp $tmp/conftemp.mk $SRC/makefiles.mk~ ## DEBUGGING + fi + if test ! -f "$SRC/Makefile" ; then + AC_MSG_NOTICE([create TOP/Makefile guessed from local Makefile]) + x='`' ; cat >$tmp/conftemp.sed <<_EOF +/^\$/n +x +/^\$/bS +x +/\\\\\$/{H;d;} +{H;s/.*//;x;} +bM +:S +x +/\\\\\$/{h;d;} +{h;s/.*//;x;} +:M +s/\\(\\n\\) /\\1 /g +/^ /d +/^[[ ]]*[[\\#]]/d +/^VPATH *=/d +s/^srcdir *=.*/srcdir = ./ +s/^top_srcdir *=.*/top_srcdir = ./ +/[[:=]]/!d +/^\\./d +dnl Now handle rules (i.e. lines containing ":" but not " = "). +/ = /b +/ .= /b +/:/!b +s/:.*/:/ +s/ / /g +s/ \\([[a-z]][[a-z-]]*[[a-zA-Z0-9]]\\)\\([[ :]]\\)/ \\1 \\1[]_ALL\\2/g +s/^\\([[a-z]][[a-z-]]*[[a-zA-Z0-9]]\\)\\([[ :]]\\)/\\1 \\1[]_ALL\\2/ +s/ / /g +/^all all[]_ALL[[ :]]/i\\ +all-configured : all[]_ALL +dnl dist-all exists... and would make for dist-all-all +s/ [[a-zA-Z0-9-]]*[]_ALL [[a-zA-Z0-9-]]*[]_ALL[]_ALL//g +/[]_ALL[]_ALL/d +a\\ + @ HOST="\$(HOST)\" \\\\\\ + ; test ".\$\$HOST" = "." && HOST=$x sh $AUX/config.guess $x \\\\\\ + ; BUILD=$x grep "^#### \$\$HOST " Makefile | sed -e 's/.*|//' $x \\\\\\ + ; use=$x basename "\$\@" _ALL $x; n=$x echo \$\$BUILD | wc -w $x \\\\\\ + ; echo "MAKE \$\$HOST : \$\$n * \$\@"; if test "\$\$n" -eq "0" ; then : \\\\\\ + ; BUILD=$x grep "^####.*|" Makefile |tail -1| sed -e 's/.*|//' $x ; fi \\\\\\ + ; test ".\$\$BUILD" = "." && BUILD="." \\\\\\ + ; test "\$\$use" = "\$\@" && BUILD=$x echo "\$\$BUILD" | tail -1 $x \\\\\\ + ; for i in \$\$BUILD ; do test ".\$\$i" = "." && continue \\\\\\ + ; (cd "\$\$i" && test ! -f configure && \$(MAKE) \$\$use) || exit; done +dnl special rule add-on: "dist" copies the tarball to $(PUB). (source tree) +/dist[]_ALL *:/a\\ + @ HOST="\$(HOST)\" \\\\\\ + ; test ".\$\$HOST" = "." && HOST=$x sh $AUX/config.guess $x \\\\\\ + ; BUILD=$x grep "^#### \$\$HOST " Makefile | sed -e 's/.*|//' $x \\\\\\ + ; found=$x echo \$\$BUILD | wc -w $x \\\\\\ + ; echo "MAKE \$\$HOST : \$\$found \$(PACKAGE)-\$(VERSION).tar.*" \\\\\\ + ; if test "\$\$found" -eq "0" ; then : \\\\\\ + ; BUILD=$x grep "^#### .*|" Makefile |tail -1| sed -e 's/.*|//' $x \\\\\\ + ; fi ; for i in \$\$BUILD ; do test ".\$\$i" = "." && continue \\\\\\ + ; for f in \$\$i/\$(PACKAGE)-\$(VERSION).tar.* \\\\\\ + ; do test -f "\$\$f" && mv "\$\$f" \$(PUB). ; done ; break ; done +dnl special rule add-on: "dist-foo" copies all the archives to $(PUB). (source tree) +/dist-[[a-zA-Z0-9]]*[]_ALL *:/a\\ + @ HOST="\$(HOST)\" \\\\\\ + ; test ".\$\$HOST" = "." && HOST=$x sh ./config.guess $x \\\\\\ + ; BUILD=$x grep "^#### \$\$HOST " Makefile | sed -e 's/.*|//' $x \\\\\\ + ; found=$x echo \$\$BUILD | wc -w $x \\\\\\ + ; echo "MAKE \$\$HOST : \$\$found \$(PACKAGE)-\$(VERSION).*" \\\\\\ + ; if test "\$\$found" -eq "0" ; then : \\\\\\ + ; BUILD=$x grep "^#### .*|" Makefile |tail -1| sed -e 's/.*|//' $x \\\\\\ + ; fi ; for i in \$\$BUILD ; do test ".\$\$i" = "." && continue \\\\\\ + ; for f in \$\$i/\$(PACKAGE)-\$(VERSION).* \\\\\\ + ; do test -f "\$\$f" && mv "\$\$f" \$(PUB). ; done ; break ; done +dnl special rule add-on: "distclean" removes all local builddirs completely +/distclean[]_ALL *:/a\\ + @ HOST="\$(HOST)\" \\\\\\ + ; test ".\$\$HOST" = "." && HOST=$x sh $AUX/config.guess $x \\\\\\ + ; BUILD=$x grep "^#### .*|" Makefile | sed -e 's/.*|//' $x \\\\\\ + ; use=$x basename "\$\@" _ALL $x; n=$x echo \$\$BUILD | wc -w $x \\\\\\ + ; echo "MAKE \$\$HOST : \$\$n * \$\@ (all local builds)" \\\\\\ + ; test ".\$\$BUILD" = "." && BUILD="." \\\\\\ + ; for i in \$\$BUILD ; do test ".\$\$i" = "." && continue \\\\\\ + ; echo "# rm -r \$\$i"; done ; echo "# (sleep 3)" ; sleep 3 \\\\\\ + ; for i in \$\$BUILD ; do test ".\$\$i" = "." && continue \\\\\\ + ; echo "\$\$i" | grep "^/" > /dev/null && continue \\\\\\ + ; echo "\$\$i" | grep "^../" > /dev/null && continue \\\\\\ + ; echo "rm -r \$\$i"; (rm -r "\$\$i") ; done ; rm Makefile +_EOF + cp "$tmp/conftemp.sed" "$SRC/makefile.sed~" ## DEBUGGING + $SED -f $tmp/conftemp.sed Makefile >$SRC/Makefile + if test -f "$SRC/m4_ifval([$2],[$2],[END])" ; then + AC_MSG_NOTICE([extend TOP/Makefile with TOP/m4_ifval([$2],[$2],[END])]) + cat $SRC/END >>$SRC/Makefile + fi ; xxxx="####" + echo "$xxxx CONFIGURATIONS FOR TOPLEVEL MAKEFILE: " >>$SRC/Makefile + # sanity check + if grep '^; echo "MAKE ' $SRC/Makefile >/dev/null ; then + AC_MSG_NOTICE([buggy sed found - it deletes tab in "a" text parts]) + $SED -e '/^@ HOST=/s/^/ /' -e '/^; /s/^/ /' $SRC/Makefile \ + >$SRC/Makefile~ + (test -s $SRC/Makefile~ && mv $SRC/Makefile~ $SRC/Makefile) 2>/dev/null + fi + else + xxxx="\\#\\#\\#\\#" + # echo "/^$xxxx *$ax_enable_builddir_host /d" >$tmp/conftemp.sed + echo "s!^$xxxx [[^|]]* | *$SUB *\$!$xxxx ...... $SUB!" >$tmp/conftemp.sed + $SED -f "$tmp/conftemp.sed" "$SRC/Makefile" >$tmp/mkfile.tmp + cp "$tmp/conftemp.sed" "$SRC/makefiles.sed~" ## DEBUGGING + cp "$tmp/mkfile.tmp" "$SRC/makefiles.out~" ## DEBUGGING + if cmp -s "$SRC/Makefile" "$tmp/mkfile.tmp" 2>/dev/null ; then + AC_MSG_NOTICE([keeping TOP/Makefile from earlier configure]) + rm "$tmp/mkfile.tmp" + else + AC_MSG_NOTICE([reusing TOP/Makefile from earlier configure]) + mv "$tmp/mkfile.tmp" "$SRC/Makefile" + fi + fi + AC_MSG_NOTICE([build in $SUB (HOST=$ax_enable_builddir_host)]) + xxxx="####" + echo "$xxxx" "$ax_enable_builddir_host" "|$SUB" >>$SRC/Makefile + fi +popdef([END])dnl +AS_VAR_POPDEF([SED])dnl +AS_VAR_POPDEF([AUX])dnl +AS_VAR_POPDEF([SRC])dnl +AS_VAR_POPDEF([TOP])dnl +AS_VAR_POPDEF([SUB])dnl +],[dnl +ax_enable_builddir_srcdir="$srcdir" # $srcdir +ax_enable_builddir_host="$HOST" # $HOST / $host +ax_enable_builddir_version="$VERSION" # $VERSION +ax_enable_builddir_package="$PACKAGE" # $PACKAGE +ax_enable_builddir_auxdir="$ax_enable_builddir_auxdir" # $AUX +ax_enable_builddir_sed="$ax_enable_builddir_sed" # $SED +ax_enable_builddir="$ax_enable_builddir" # $SUB +])dnl +]) diff --git a/m4/ax_extend_srcdir.m4 b/m4/ax_extend_srcdir.m4 new file mode 100644 index 0000000..40f3787 --- /dev/null +++ b/m4/ax_extend_srcdir.m4 @@ -0,0 +1,86 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_extend_srcdir.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_EXTEND_SRCDIR +# +# DESCRIPTION +# +# The AX_EXTEND_SRCDIR macro extends $srcdir by one path component. +# +# As an example, when working in /home/michael/i3-4.12/build and calling +# ../configure, your $srcdir is "..". After calling AX_EXTEND_SRCDIR, +# $srcdir will be set to "../../i3-4.12". +# +# The result of extending $srcdir is that filenames (e.g. in the output of +# the "backtrace" gdb command) will include one more path component of the +# absolute source path. The additional path component makes it easy for +# users to recognize which files belong to the PACKAGE, and -- provided a +# dist tarball was unpacked -- which version of PACKAGE was used. +# +# As an example, in "backtrace", you will see: +# +# #0 main (argc=1, argv=0x7fffffff1fc8) at ../../i3-4.12/src/main.c:187 +# +# instead of: +# +# #0 main (argc=1, argv=0x7fffffff1fc8) at ../src/main.c:187 +# +# In case your code uses the __FILE__ preprocessor directive to refer to +# the filename of the current source file (e.g. in debug messages), using +# the extended path might be undesirable. For this purpose, +# AX_EXTEND_SRCDIR defines the output variable AX_EXTEND_SRCDIR_CPPFLAGS, +# which can be added to AM_CPPFLAGS in Makefile.am in order to define the +# preprocessor directive STRIPPED__FILE__. As an example, when compiling +# the file "../../i3-4.12/src/main.c", STRIPPED__FILE__ evaluates to +# "main.c". +# +# There are some caveats: When $srcdir is "." (i.e. when ./configure was +# called instead of ../configure in a separate build directory), +# AX_EXTEND_SRCDIR will still extend $srcdir, but the intended effect will +# not be achieved because of the way automake specifies file paths: +# automake defines COMPILE to use "`test -f '$source' || echo +# '\$(srcdir)/'`$source" in order to prefer files in the current directory +# over specifying $srcdir explicitly. +# +# The AX_EXTEND_SRCDIR author is not aware of any way to influence this +# automake behavior. Patches very welcome. +# +# To work around this issue, you can use AX_ENABLE_BUILDDIR i.e. by adding +# the following code to configure.ac: +# +# AX_ENABLE_BUILDDIR +# dnl ... +# AX_EXTEND_SRCDIR +# +# Then also add this bit to Makefile.am (if you wish to use +# STRIPPED__FILE__ in your code): +# +# AM_CPPFLAGS = @AX_EXTEND_SRCDIR_CPPFLAGS@ +# +# LICENSE +# +# Copyright (c) 2016 Michael Stapelberg +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 3 + +AC_DEFUN([AX_EXTEND_SRCDIR], +[dnl +AS_CASE([$srcdir], + [.|.*|/*], + [ + # pwd -P is specified in IEEE 1003.1 from 2004 + as_dir=`cd "$srcdir" && pwd -P` + as_base=`AS_BASENAME([$as_dir])` + srcdir=${srcdir}/../${as_base} + + AC_SUBST([AX_EXTEND_SRCDIR_CPPFLAGS], ["-DSTRIPPED__FILE__=AS_ESCAPE([\"$$(basename $<)\"])"]) + ]) +])dnl AX_EXTEND_SRCDIR diff --git a/m4/ax_require_defined.m4 b/m4/ax_require_defined.m4 new file mode 100644 index 0000000..cae1111 --- /dev/null +++ b/m4/ax_require_defined.m4 @@ -0,0 +1,37 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_require_defined.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_REQUIRE_DEFINED(MACRO) +# +# DESCRIPTION +# +# AX_REQUIRE_DEFINED is a simple helper for making sure other macros have +# been defined and thus are available for use. This avoids random issues +# where a macro isn't expanded. Instead the configure script emits a +# non-fatal: +# +# ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found +# +# It's like AC_REQUIRE except it doesn't expand the required macro. +# +# Here's an example: +# +# AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) +# +# LICENSE +# +# Copyright (c) 2014 Mike Frysinger +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 1 + +AC_DEFUN([AX_REQUIRE_DEFINED], [dnl + m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])]) +])dnl AX_REQUIRE_DEFINED diff --git a/m4/ax_sanitizers.m4 b/m4/ax_sanitizers.m4 new file mode 100644 index 0000000..836d4af --- /dev/null +++ b/m4/ax_sanitizers.m4 @@ -0,0 +1,130 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_sanitizers.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_SANITIZERS([SANITIZERS], [ENABLED-BY-DEFAULT], [ACTION-SUCCESS]) +# +# DESCRIPTION +# +# Offers users to enable one or more sanitizers (see +# https://github.com/google/sanitizers) with the corresponding +# --enable--sanitizer option. +# +# SANITIZERS is a whitespace-separated list of sanitizers to offer via +# --enable--sanitizer options, e.g. "address memory" for the +# address sanitizer and the memory sanitizer. If SANITIZERS is not specified, +# all known sanitizers to AX_SANITIZERS will be offered, which at the time of +# writing are "address memory undefined". +# NOTE that SANITIZERS is expanded at autoconf time, not at configure time, +# i.e. you cannot use shell variables in SANITIZERS. +# +# ENABLED-BY-DEFAULT is a whitespace-separated list of sanitizers which +# should be enabled by default, e.g. "memory undefined". Note that not all +# sanitizers can be combined, e.g. memory sanitizer cannot be enabled when +# address sanitizer is already enabled. +# Set ENABLED-BY-DEFAULT to a single whitespace in order to disable all +# sanitizers by default. +# ENABLED-BY-DEFAULT is expanded at configure time, so you can use shell +# variables. +# +# ACTION-SUCCESS allows to specify shell commands to execute on success, i.e. +# when one of the sanitizers was successfully enabled. This is a good place +# to call AC_DEFINE for any precompiler constants you might need to make your +# code play nice with sanitizers. +# +# The variable ax_enabled_sanitizers contains a whitespace-separated list of +# all enabled sanitizers, so that you can print them at the end of configure, +# if you wish. +# +# The additional --enable-sanitizers option allows users to enable/disable +# all sanitizers, effectively overriding ENABLED-BY-DEFAULT. +# +# EXAMPLES +# +# AX_SANITIZERS([address]) +# dnl offer users to enable address sanitizer via --enable-address-sanitizer +# +# is_debug_build=… +# if test "x$is_debug_build" = "xyes"; then +# default_sanitizers="address memory" +# else +# default_sanitizers= +# fi +# AX_SANITIZERS([address memory], [$default_sanitizers]) +# dnl enable address sanitizer and memory sanitizer by default for debug +# dnl builds, e.g. when building from git instead of a dist tarball. +# +# AX_SANITIZERS(, , [ +# AC_DEFINE([SANITIZERS_ENABLED], +# [], +# [At least one sanitizer was enabled])]) +# dnl enable all sanitizers known to AX_SANITIZERS by default and set the +# dnl SANITIZERS_ENABLED precompiler constant. +# +# AX_SANITIZERS(, [ ]) +# dnl provide all sanitizers, but enable none by default. +# +# LICENSE +# +# Copyright (c) 2016 Michael Stapelberg +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. This file is offered as-is, +# without any warranty. + +AC_DEFUN([AX_SANITIZERS], +[AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG]) +AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) +AX_REQUIRE_DEFINED([AX_APPEND_FLAG]) +AC_ARG_ENABLE(sanitizers, + AS_HELP_STRING( + [--enable-sanitizers], + [enable all known sanitizers]), + [ax_sanitizers_default=$enableval], + [ax_sanitizers_default=]) +ax_enabled_sanitizers= +m4_foreach_w([mysan], m4_default($1, [address memory undefined]), [ + dnl If ax_sanitizers_default is unset, i.e. the user neither explicitly + dnl enabled nor explicitly disabled all sanitizers, we get the default value + dnl for this sanitizer based on whether it is listed in ENABLED-BY-DEFAULT. + AS_IF([test "x$ax_sanitizers_default" = "x"], [dnl + ax_sanitizer_default= + for mycheck in m4_default([$2], [address memory undefined]); do + AS_IF([test "x$mycheck" = "x[]mysan"], [ax_sanitizer_default=yes]) + done + AS_IF([test "x$ax_sanitizer_default" = "x"], [ax_sanitizer_default=no]) + ], + [ax_sanitizer_default=$ax_sanitizers_default]) + AC_ARG_ENABLE(mysan[]-sanitizer, + AS_HELP_STRING( + [--enable-[]mysan[]-sanitizer], + [enable -fsanitize=mysan]), + [ax_sanitizer_enabled=$enableval], + [ax_sanitizer_enabled=$ax_sanitizer_default]) + +AS_IF([test "x$ax_sanitizer_enabled" = "xyes"], [ +dnl Not using AX_APPEND_COMPILE_FLAGS and AX_APPEND_LINK_FLAGS because they +dnl lack the ability to specify ACTION-SUCCESS. + AX_CHECK_COMPILE_FLAG([-fsanitize=[]mysan], [ + AX_CHECK_LINK_FLAG([-fsanitize=[]mysan], [ + AX_APPEND_FLAG([-fsanitize=[]mysan], []) +dnl If and only if libtool is being used, LDFLAGS needs to contain -Wc,-fsanitize=…. +dnl See e.g. https://sources.debian.net/src/systemd/231-7/configure.ac/?hl=128#L135 +dnl TODO: how can recognize that situation and add -Wc,? + AX_APPEND_FLAG([-fsanitize=[]mysan], [LDFLAGS]) +dnl TODO: add -fPIE -pie for memory + # -fno-omit-frame-pointer results in nicer stack traces in error + # messages, see http://clang.llvm.org/docs/AddressSanitizer.html#usage + AX_CHECK_COMPILE_FLAG([-fno-omit-frame-pointer], [ + AX_APPEND_FLAG([-fno-omit-frame-pointer], [])]) +dnl TODO: at least for clang, we should specify exactly -O1, not -O2 or -O0, so that performance is reasonable but stacktraces are not tampered with (due to inlining), see http://clang.llvm.org/docs/AddressSanitizer.html#usage + m4_default([$3], :) + ax_enabled_sanitizers="[]mysan $ax_enabled_sanitizers" + ]) + ]) +]) +])dnl +])dnl AX_SANITIZERS diff --git a/i3lock.pam b/pam/i3lock similarity index 100% rename from i3lock.pam rename to pam/i3lock From 5e0aeccbb38c98c576deb33d5b238e3dc71bc368 Mon Sep 17 00:00:00 2001 From: Chris Guillott Date: Tue, 5 Dec 2017 12:53:54 -0500 Subject: [PATCH 08/18] first commit towards fixing this --- .gitignore | 27 ++++ .travis.yml | 2 +- Makefile | 80 ---------- Makefile.am | 62 ++++++++ blur.c | 2 +- blur.h | 2 +- blur_simd.c | 24 ++- configure.ac | 148 ++++++++++++++++++ i3lock.c | 8 +- m4/ax_append_flag.m4 | 71 +++++++++ m4/ax_cflags_warn_all.m4 | 122 +++++++++++++++ m4/ax_check_compile_flag.m4 | 74 +++++++++ m4/ax_check_enable_debug.m4 | 124 +++++++++++++++ m4/ax_check_gnu_make.m4 | 84 ++++++++++ m4/ax_check_link_flag.m4 | 74 +++++++++ m4/ax_code_coverage.m4 | 273 ++++++++++++++++++++++++++++++++ m4/ax_configure_args.m4 | 70 +++++++++ m4/ax_enable_builddir.m4 | 302 ++++++++++++++++++++++++++++++++++++ m4/ax_extend_srcdir.m4 | 86 ++++++++++ m4/ax_require_defined.m4 | 37 +++++ m4/ax_sanitizers.m4 | 130 ++++++++++++++++ i3lock.pam => pam/i3lock | 0 unlock_indicator.c | 147 ++++++++++-------- unlock_indicator.h | 14 +- 24 files changed, 1794 insertions(+), 169 deletions(-) delete mode 100644 Makefile create mode 100644 Makefile.am create mode 100644 configure.ac create mode 100644 m4/ax_append_flag.m4 create mode 100644 m4/ax_cflags_warn_all.m4 create mode 100644 m4/ax_check_compile_flag.m4 create mode 100644 m4/ax_check_enable_debug.m4 create mode 100644 m4/ax_check_gnu_make.m4 create mode 100644 m4/ax_check_link_flag.m4 create mode 100644 m4/ax_code_coverage.m4 create mode 100644 m4/ax_configure_args.m4 create mode 100644 m4/ax_enable_builddir.m4 create mode 100644 m4/ax_extend_srcdir.m4 create mode 100644 m4/ax_require_defined.m4 create mode 100644 m4/ax_sanitizers.m4 rename i3lock.pam => pam/i3lock (100%) diff --git a/.gitignore b/.gitignore index 4cf0fac..ea71e48 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,30 @@ i3lock tags *.swp *.gz + +################################################################################ +# https://raw.githubusercontent.com/github/gitignore/master/Autotools.gitignore +################################################################################ + +# http://www.gnu.org/software/automake + +Makefile.in +/ar-lib +/test-driver + +# http://www.gnu.org/software/autoconf + +/autom4te.cache +/autoscan.log +/autoscan-*.log +/aclocal.m4 +/compile +/config.h.in +/config.guess +/config.sub +/configure +/configure.scan +/depcomp +/install-sh +/missing +/stamp-h1 diff --git a/.travis.yml b/.travis.yml index 23be3b0..c9db585 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,5 +25,5 @@ before_install: - sudo apt-get update - sudo apt-get --force-yes -y install -t xenial libxkbcommon-dev libxkbcommon-x11-dev script: - - make -j + - autoreconf -fi && mkdir -p build && cd build && (../configure || (cat config.log; false)) && make -j CFLAGS="-Wformat -Wformat-security -Wextra -Wno-unused-parameter -Werror" - clang-format-3.5 -i *.[ch] && git diff --exit-code || (echo 'Code was not formatted using clang-format!'; false) diff --git a/Makefile b/Makefile deleted file mode 100644 index d0aa1e8..0000000 --- a/Makefile +++ /dev/null @@ -1,80 +0,0 @@ -TOPDIR=$(shell pwd) -UNAME=$(shell uname) - -INSTALL=install -PREFIX=/usr -SYSCONFDIR=/etc -PKG_CONFIG=pkg-config -MANDIR=/usr/share/man - -# Check if pkg-config is installed, we need it for building CFLAGS/LIBS -ifeq ($(shell which $(PKG_CONFIG) 2>/dev/null 1>/dev/null || echo 1),1) -$(error "$(PKG_CONFIG) was not found") -endif - -CFLAGS += -std=c99 -CFLAGS += -pipe -CFLAGS += -Wall -CFLAGS += -O2 -SIMD_CFLAGS += -funroll-loops -SIMD_CFLAGS += -msse2 -CPPFLAGS += -D_GNU_SOURCE -CPPFLAGS += -DXKBCOMPOSE=$(shell if test -e /usr/include/xkbcommon/xkbcommon-compose.h ; then echo 1 ; else echo 0 ; fi ) -CFLAGS += $(shell $(PKG_CONFIG) --cflags cairo xcb-composite xcb-xinerama xcb-randr xcb-atom xcb-image xcb-xkb xkbcommon xkbcommon-x11 x11) -LIBS += $(shell $(PKG_CONFIG) --libs cairo xcb-composite xcb-xinerama xcb-randr xcb-atom xcb-image xcb-xkb xkbcommon xkbcommon-x11 x11) -LIBS += -lev -LIBS += -lm - -# OpenBSD lacks PAM, use bsd_auth(3) instead. -ifneq ($(UNAME),OpenBSD) - LIBS += -lpam -endif - -FILES:=$(wildcard *.c) -FILES:=$(FILES:.c=.o) - -ifeq ($(wildcard .git),) - # not in git repository - VERSION := $(shell [ -f $(TOPDIR)/I3LOCK_VERSION ] && cat $(TOPDIR)/I3LOCK_VERSION | cut -d '-' -f 1) - I3LOCK_VERSION:='$(shell [ -f $(TOPDIR)/I3LOCK_VERSION ] && cat $(TOPDIR)/I3LOCK_VERSION)' -else - VERSION:=$(shell git describe --tags --abbrev=0) - I3LOCK_VERSION:="$(shell git describe --tags --always) ($(shell git log --pretty=format:%cd --date=short -n1))" -endif -CPPFLAGS += -DVERSION=\"${I3LOCK_VERSION}\" - -.PHONY: install clean uninstall - -all: i3lock - -debug: CFLAGS += -g -debug: i3lock - -blur_simd.o : CFLAGS += $(SIMD_CFLAGS) -i3lock: ${FILES} - $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) - -clean: - rm -f i3lock ${FILES} i3lock-${VERSION}.tar.gz - -install: all - $(INSTALL) -d $(DESTDIR)$(PREFIX)/bin - $(INSTALL) -d $(DESTDIR)$(SYSCONFDIR)/pam.d - $(INSTALL) -d $(DESTDIR)$(MANDIR)/man1 - $(INSTALL) -m 755 i3lock $(DESTDIR)$(PREFIX)/bin/i3lock - $(INSTALL) -m 644 i3lock.pam $(DESTDIR)$(SYSCONFDIR)/pam.d/i3lock - gzip -kf i3lock.1 - $(INSTALL) -m 644 i3lock.1.gz $(DESTDIR)$(MANDIR)/man1/i3lock.1.gz - -uninstall: - rm -f $(DESTDIR)$(PREFIX)/bin/i3lock - rm -f $(DESTDIR)$(MANDIR)/man1/i3lock.1.gz - -dist: clean - [ ! -d i3lock-${VERSION} ] || rm -rf i3lock-${VERSION} - [ ! -e i3lock-${VERSION}.tar.bz2 ] || rm i3lock-${VERSION}.tar.bz2 - mkdir i3lock-${VERSION} - cp *.c *.h i3lock.1 i3lock.pam Makefile LICENSE README.md CHANGELOG i3lock-${VERSION} - sed -e 's/^\s*I3LOCK_VERSION:=\(.*\)/I3LOCK_VERSION:=$(shell /bin/echo '${I3LOCK_VERSION}' | sed 's/\\/\\\\/g')/g;s/^VERSION:=\(.*\)/VERSION:=${VERSION}/g' Makefile > i3lock-${VERSION}/Makefile - tar cfj i3lock-${VERSION}.tar.bz2 i3lock-${VERSION} - rm -rf i3lock-${VERSION} diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..642ec60 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,62 @@ +@CODE_COVERAGE_RULES@ + +echo-version: + @echo "@I3LOCK_VERSION@" + +bin_PROGRAMS = i3lock + +dist_man1_MANS = i3lock.1 + +pamddir = $(sysconfdir)/pam.d +pamd_files = pam/i3lock +pamd_DATA = $(pamd_files) + +AM_CPPFLAGS = \ + @AX_EXTEND_SRCDIR_CPPFLAGS@ + +i3lock_CFLAGS = \ + $(AM_CFLAGS) \ + $(XCB_CFLAGS) \ + $(XCB_IMAGE_CFLAGS) \ + $(XCB_UTIL_CFLAGS) \ + $(XKBCOMMON_CFLAGS) \ + $(CAIRO_CFLAGS) \ + $(CODE_COVERAGE_CFLAGS) \ + $(X11_CFLAGS) \ + $(SIMD_CFLAGS) + +i3lock_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + $(CODE_COVERAGE_CPPFLAGS) + +i3lock_LDADD = \ + $(XCB_LIBS) \ + $(XCB_IMAGE_LIBS) \ + $(XCB_UTIL_LIBS) \ + $(XKBCOMMON_LIBS) \ + $(CAIRO_LIBS) \ + $(CODE_COVERAGE_LDFLAGS) \ + $(X11_LIBS) + +i3lock_SOURCES = \ + cursors.h \ + i3lock.c \ + i3lock.h \ + randr.c \ + randr.h \ + unlock_indicator.c \ + unlock_indicator.h \ + xcb.c \ + xcb.h \ + tinyexpr.c \ + tinyexpr.h \ + blur_simd.c \ + blur.c \ + blur.h + + +EXTRA_DIST = \ + $(pamd_files) \ + CHANGELOG \ + LICENSE \ + README.md diff --git a/blur.c b/blur.c index 1838df4..a63751e 100644 --- a/blur.c +++ b/blur.c @@ -65,7 +65,7 @@ blur_image_surface (cairo_surface_t *surface, int sigma) // according to a paper by Peter Kovesi [1], box filter of width w, equals to Gaussian blur of following sigma: // σ_av = sqrt((w*w-1)/12) - // for our 7x7 filter we have σ_av = 2.0. + // for our 8x8 filter we have σ_av = 2.0. // applying the same Gaussian filter n times results in σ_n = sqrt(n*σ_av*σ_av) [2] // after some trivial math, we arrive at n = ((σ_d)/(σ_av))^2 // since it's a box blur filter, n >= 3 diff --git a/blur.h b/blur.h index dfc1c3d..2c42fd5 100644 --- a/blur.h +++ b/blur.h @@ -4,7 +4,7 @@ #include #include -#define KERNEL_SIZE 7 +#define KERNEL_SIZE 8 #define SIGMA_AV 2 #define HALF_KERNEL KERNEL_SIZE / 2 diff --git a/blur_simd.c b/blur_simd.c index b654e98..48c3fba 100644 --- a/blur_simd.c +++ b/blur_simd.c @@ -10,24 +10,30 @@ #include "blur.h" #include +#include + // number of xmm registers needed to store input pixels for given kernel size #define REGISTERS_CNT (KERNEL_SIZE + 4/2) / 4 void blur_impl_horizontal_pass_sse2(uint32_t *src, uint32_t *dst, int width, int height) { + printf("height %d by width %d\n", height, width); for (int row = 0; row < height; row++) { + printf("row %d\n", row); for (int column = 0; column < width; column++, src++) { + printf("\tcol %d\n", column); __m128i rgbaIn[REGISTERS_CNT]; // handle borders int leftBorder = column < HALF_KERNEL; - int rightBorder = column > width - HALF_KERNEL; + int rightBorder = column > (width - HALF_KERNEL); + // +1 to make memory checkers not complain uint32_t _rgbaIn[KERNEL_SIZE] __attribute__((aligned(16))); int i = 0; if (leftBorder) { - // for kernel size 7x7 and column == 0, we have: - // x x x P0 P1 P2 P3 - // first loop mirrors P{0..3} to fill x's, - // second one loads P{0..3} + // for kernel size 8x8 and column == 0, we have: + // x x x x P0 P1 P2 P3 + // first loop mirrors P{0..4} to fill x's, + // second one loads P{0..4} for (; i < HALF_KERNEL - column; i++) _rgbaIn[i] = *(src + (HALF_KERNEL - i)); for (; i < KERNEL_SIZE; i++) @@ -44,8 +50,10 @@ void blur_impl_horizontal_pass_sse2(uint32_t *src, uint32_t *dst, int width, int for (int k = 0; k < REGISTERS_CNT; k++) rgbaIn[k] = _mm_load_si128((__m128i*)(_rgbaIn + 4*k)); } else { - for (int k = 0; k < REGISTERS_CNT; k++) - rgbaIn[k] = _mm_loadu_si128((__m128i*)(src + 4*k - HALF_KERNEL)); + for (int k = 0; k < REGISTERS_CNT; k++) { + printf("\t\tk: %d\n", k); + rgbaIn[k] = _mm_load_si128((__m128i*)(src + 4*k - HALF_KERNEL)); + } } __m128i zero = _mm_setzero_si128(); @@ -57,10 +65,12 @@ void blur_impl_horizontal_pass_sse2(uint32_t *src, uint32_t *dst, int width, int // kernel size equals to 7, but we can only load multiples of 4 pixels // we have to set 8th pixel to zero +/* acc = _mm_add_epi16(acc, _mm_andnot_si128(_mm_set_epi32(0xFFFFFFFF, 0xFFFFFFFF, 0, 0), _mm_unpackhi_epi8(rgbaIn[1], zero))); acc = _mm_add_epi32(_mm_unpacklo_epi16(acc, zero), _mm_unpackhi_epi16(acc, zero)); +*/ // multiplication is significantly faster than division acc = _mm_cvtps_epi32(_mm_mul_ps(_mm_cvtepi32_ps(acc), diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..0a2dc80 --- /dev/null +++ b/configure.ac @@ -0,0 +1,148 @@ +# -*- Autoconf -*- +# Run autoreconf -fi to generate a configure script from this file. + +AC_PREREQ([2.69]) +AC_INIT([i3lock-color], [2.10], [https://github.com/chrjguill/i3lock-color/issues]) +# For AX_EXTEND_SRCDIR +AX_ENABLE_BUILDDIR +AM_INIT_AUTOMAKE([foreign subdir-objects -Wall no-dist-gzip dist-bzip2]) +# Default to silent rules, use V=1 to get verbose compilation output. +AM_SILENT_RULES([yes]) +# Make it possible to disable maintainer mode to disable re-generation of build +# system files. +AM_MAINTAINER_MODE([enable]) +AC_CONFIG_SRCDIR([i3lock.c]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) + +dnl Verify macros defined in m4/ such as AX_SANITIZERS are not present in the +dnl output, i.e. are replaced as expected. This line results in a better error +dnl message when using aclocal < 1.13 (which does not understand +dnl AC_CONFIG_MACRO_DIR) without passing the -I m4 parameter. +# m4_pattern_forbid([AX_SANITIZERS]) + +# Verify we are using GNU make because we use '%'-style pattern rules in +# Makefile.am, which are a GNU make extension. Pull requests to replace +# '%'-style pattern rules with a more portable alternative are welcome. +AX_CHECK_GNU_MAKE +AS_VAR_IF([_cv_gnu_make_command], [""], [AC_MSG_ERROR([the i3lock Makefile.am requires GNU make])]) + +AX_EXTEND_SRCDIR + +AS_IF([test -d ${srcdir}/.git], + [ + VERSION="$(git -C ${srcdir} describe --tags --abbrev=0)" + I3LOCK_VERSION="$(git -C ${srcdir} describe --tags --always) ($(git -C ${srcdir} log --pretty=format:%cd --date=short -n1), branch \\\"$(git -C ${srcdir} describe --tags --always --all | sed s:heads/::)\\\")" + # Mirrors what libi3/is_debug_build.c does: + is_release=$(test $(echo "${I3LOCK_VERSION}" | cut -d '(' -f 1 | wc -m) -lt 11 && echo yes || echo no) + ], + [ + VERSION="$(cut -d '-' -f 1 ${srcdir}/I3LOCK_VERSION | cut -d ' ' -f 1)" + I3LOCK_VERSION="$(sed -e 's/@<:@\"?\\@:>@/\\&/g' ${srcdir}/I3LOCK_VERSION)" + is_release="$(grep -q non-git ${srcdir}/I3LOCK_VERSION && echo no || echo yes)" + ]) +AC_SUBST([I3LOCK_VERSION], [$I3LOCK_VERSION]) +AC_DEFINE_UNQUOTED([I3LOCK_VERSION], ["${I3LOCK_VERSION}"], [i3lock version]) + +AX_CODE_COVERAGE + +dnl is_release must be lowercase because AX_CHECK_ENABLE_DEBUG calls m4_tolower +dnl on its fourth argument. +AX_CHECK_ENABLE_DEBUG([yes], , [UNUSED_NDEBUG], [$is_release]) + +AC_PROG_CC_C99 + +# For strnlen() and vasprintf(). +AC_USE_SYSTEM_EXTENSIONS + +# Checks for typedefs, structures, and compiler characteristics. +AC_CHECK_HEADER_STDBOOL +dnl The error message should include the specific type which could not be +dnl found, but I do not see a way to achieve that. +AC_CHECK_TYPES([mode_t, off_t, pid_t, size_t, ssize_t], , [AC_MSG_FAILURE([cannot find required type])]) + +# Checks for library functions. +AC_FUNC_FORK +AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK +AC_FUNC_STRNLEN +AC_CHECK_FUNCS([atexit dup2 ftruncate getcwd gettimeofday localtime_r memchr memset mkdir rmdir setlocale socket strcasecmp strchr strdup strerror strncasecmp strndup strrchr strspn strstr strtol strtoul], , [AC_MSG_FAILURE([cannot find the $ac_func function, which i3lock requires])]) + +# Checks for libraries. + +AC_SEARCH_LIBS([floor], [m], , [AC_MSG_FAILURE([cannot find the required floor() function despite trying to link with -lm])]) + +# libev does not ship with a pkg-config file :(. +AC_SEARCH_LIBS([ev_run], [ev], , [AC_MSG_FAILURE([cannot find the required ev_run() function despite trying to link with -lev])]) + +AC_SEARCH_LIBS([shm_open], [rt]) + +AC_SEARCH_LIBS([pam_authenticate], [pam]) + +AC_SEARCH_LIBS([iconv_open], [iconv], , [AC_MSG_FAILURE([cannot find the required iconv_open() function despite trying to link with -liconv])]) + +dnl Each prefix corresponds to a source tarball which users might have +dnl downloaded in a newer version and would like to overwrite. +PKG_CHECK_MODULES([XCB], [xcb xcb-xkb xcb-xinerama xcb-randr xcb-composite]) +PKG_CHECK_MODULES([XCB_IMAGE], [xcb-image]) +PKG_CHECK_MODULES([XCB_UTIL], [xcb-event xcb-util xcb-atom]) +PKG_CHECK_MODULES([XKBCOMMON], [xkbcommon xkbcommon-x11]) +PKG_CHECK_MODULES([CAIRO], [cairo]) +PKG_CHECK_MODULES([X11], [x11]) + +SIMD_CFLAGS=" -funroll-loops -msse2 -std=c99 -pipe -O2" + +# Checks for programs. +AC_PROG_AWK +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_MAKE_SET +AC_PROG_RANLIB +AC_PROG_LN_S + +AM_PROG_AR + +AX_FLAGS_WARN_ALL +AX_CHECK_COMPILE_FLAG([-Wunused-value], [AX_APPEND_FLAG([-Wunused-value], [AM_CFLAGS])]) +AC_SUBST(AM_CFLAGS) + +# Checks for header files. +AC_CHECK_HEADERS([fcntl.h float.h inttypes.h limits.h locale.h netinet/in.h paths.h stddef.h stdint.h stdlib.h string.h sys/param.h sys/socket.h sys/time.h unistd.h], , [AC_MSG_FAILURE([cannot find the $ac_header header, which i3lock requires])]) + +AC_CONFIG_FILES([Makefile]) + +# Enable address sanitizer for non-release builds. The performance hit is a +# 50% increase of wallclock time for the testsuite on my machine. +if test x$is_release = xyes; then + default_sanitizers= +else + default_sanitizers=address +fi +AX_SANITIZERS(, [$default_sanitizers], [AC_DEFINE([I3LOCK_ASAN_ENABLED], [], [Enable ASAN])]) + +AC_OUTPUT + +in_git_worktree=`git rev-parse --is-inside-work-tree 2>/dev/null` +if [[ "$in_git_worktree" = "true" ]]; then + git_dir=`git rev-parse --git-dir 2>/dev/null` + srcdir=`dirname "$git_dir"` + exclude_dir=`pwd | sed "s,^$srcdir,,g"` + if ! grep -q "^$exclude_dir" "$git_dir/info/exclude"; then + echo "$exclude_dir" >> "$git_dir/info/exclude" + fi +fi + +echo \ +"-------------------------------------------------------------------------------- +build configured: + +AS_HELP_STRING([i3lock version:], [`echo ${I3LOCK_VERSION} | sed 's,\\\\,,g'`]) +AS_HELP_STRING([is release version:], [${is_release}]) + +AS_HELP_STRING([enable debug flags:], [${ax_enable_debug}]) +AS_HELP_STRING([code coverage:], [${CODE_COVERAGE_ENABLED}]) +AS_HELP_STRING([enabled sanitizers:], [${ax_enabled_sanitizers}]) + +To compile, run: + + cd `pwd` && make -j8 +--------------------------------------------------------------------------------" diff --git a/i3lock.c b/i3lock.c index 0b63550..0e5ad88 100644 --- a/i3lock.c +++ b/i3lock.c @@ -6,6 +6,8 @@ * See LICENSE for licensing information * */ +#include + #include #include #include @@ -333,7 +335,7 @@ static void clear_password_memory(void) { /* A volatile pointer to the password buffer to prevent the compiler from * optimizing this out. */ volatile char *vpassword = password; - for (int c = 0; c < sizeof(password); c++) + for (size_t c = 0; c < sizeof(password); c++) /* We store a non-random pattern which consists of the (irrelevant) * index plus (!) the value of the beep variable. This prevents the * compiler from optimizing the calls away, since the value of 'beep' @@ -647,7 +649,7 @@ static void handle_key_press(xcb_key_press_event_t *event) { return; } - if ((input_position + 8) >= sizeof(password)) + if ((input_position + 8) >= (int)sizeof(password)) return; #if 0 @@ -1067,7 +1069,7 @@ int main(int argc, char *argv[]) { while ((o = getopt_long(argc, argv, optstring, longopts, &longoptind)) != -1) { switch (o) { case 'v': - errx(EXIT_SUCCESS, "version " VERSION " © 2010 Michael Stapelberg"); + errx(EXIT_SUCCESS, "version " I3LOCK_VERSION " © 2010 Michael Stapelberg"); case 'n': dont_fork = true; break; diff --git a/m4/ax_append_flag.m4 b/m4/ax_append_flag.m4 new file mode 100644 index 0000000..08f2e07 --- /dev/null +++ b/m4/ax_append_flag.m4 @@ -0,0 +1,71 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_append_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE]) +# +# DESCRIPTION +# +# FLAG is appended to the FLAGS-VARIABLE shell variable, with a space +# added in between. +# +# If FLAGS-VARIABLE is not specified, the current language's flags (e.g. +# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains +# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly +# FLAG. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 6 + +AC_DEFUN([AX_APPEND_FLAG], +[dnl +AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF +AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])]) +AS_VAR_SET_IF(FLAGS,[ + AS_CASE([" AS_VAR_GET(FLAGS) "], + [*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])], + [ + AS_VAR_APPEND(FLAGS,[" $1"]) + AC_RUN_LOG([: FLAGS="$FLAGS"]) + ]) + ], + [ + AS_VAR_SET(FLAGS,[$1]) + AC_RUN_LOG([: FLAGS="$FLAGS"]) + ]) +AS_VAR_POPDEF([FLAGS])dnl +])dnl AX_APPEND_FLAG diff --git a/m4/ax_cflags_warn_all.m4 b/m4/ax_cflags_warn_all.m4 new file mode 100644 index 0000000..1f07799 --- /dev/null +++ b/m4/ax_cflags_warn_all.m4 @@ -0,0 +1,122 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_cflags_warn_all.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])] +# AX_CXXFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])] +# AX_FCFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])] +# +# DESCRIPTION +# +# Try to find a compiler option that enables most reasonable warnings. +# +# For the GNU compiler it will be -Wall (and -ansi -pedantic) The result +# is added to the shellvar being CFLAGS, CXXFLAGS, or FCFLAGS by default. +# +# Currently this macro knows about the GCC, Solaris, Digital Unix, AIX, +# HP-UX, IRIX, NEC SX-5 (Super-UX 10), Cray J90 (Unicos 10.0.0.8), and +# Intel compilers. For a given compiler, the Fortran flags are much more +# experimental than their C equivalents. +# +# - $1 shell-variable-to-add-to : CFLAGS, CXXFLAGS, or FCFLAGS +# - $2 add-value-if-not-found : nothing +# - $3 action-if-found : add value to shellvariable +# - $4 action-if-not-found : nothing +# +# NOTE: These macros depend on AX_APPEND_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2010 Rhys Ulerich +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 15 + +AC_DEFUN([AX_FLAGS_WARN_ALL],[dnl +AS_VAR_PUSHDEF([FLAGS],[_AC_LANG_PREFIX[]FLAGS])dnl +AS_VAR_PUSHDEF([VAR],[ac_cv_[]_AC_LANG_ABBREV[]flags_warn_all])dnl +AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum warnings], +VAR,[VAR="no, unknown" +ac_save_[]FLAGS="$[]FLAGS" +for ac_arg dnl +in "-warn all % -warn all" dnl Intel + "-pedantic % -Wall" dnl GCC + "-xstrconst % -v" dnl Solaris C + "-std1 % -verbose -w0 -warnprotos" dnl Digital Unix + "-qlanglvl=ansi % -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX + "-ansi -ansiE % -fullwarn" dnl IRIX + "+ESlit % +w1" dnl HP-UX C + "-Xc % -pvctl[,]fullmsg" dnl NEC SX-5 (Super-UX 10) + "-h conform % -h msglevel 2" dnl Cray C (Unicos) + # +do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` + AC_COMPILE_IFELSE([AC_LANG_PROGRAM], + [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) +done +FLAGS="$ac_save_[]FLAGS" +]) +AS_VAR_POPDEF([FLAGS])dnl +AX_REQUIRE_DEFINED([AX_APPEND_FLAG]) +case ".$VAR" in + .ok|.ok,*) m4_ifvaln($3,$3) ;; + .|.no|.no,*) m4_default($4,[m4_ifval($2,[AX_APPEND_FLAG([$2], [$1])])]) ;; + *) m4_default($3,[AX_APPEND_FLAG([$VAR], [$1])]) ;; +esac +AS_VAR_POPDEF([VAR])dnl +])dnl AX_FLAGS_WARN_ALL +dnl implementation tactics: +dnl the for-argument contains a list of options. The first part of +dnl these does only exist to detect the compiler - usually it is +dnl a global option to enable -ansi or -extrawarnings. All other +dnl compilers will fail about it. That was needed since a lot of +dnl compilers will give false positives for some option-syntax +dnl like -Woption or -Xoption as they think of it is a pass-through +dnl to later compile stages or something. The "%" is used as a +dnl delimiter. A non-option comment can be given after "%%" marks +dnl which will be shown but not added to the respective C/CXXFLAGS. + +AC_DEFUN([AX_CFLAGS_WARN_ALL],[dnl +AC_LANG_PUSH([C]) +AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4]) +AC_LANG_POP([C]) +]) + +AC_DEFUN([AX_CXXFLAGS_WARN_ALL],[dnl +AC_LANG_PUSH([C++]) +AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4]) +AC_LANG_POP([C++]) +]) + +AC_DEFUN([AX_FCFLAGS_WARN_ALL],[dnl +AC_LANG_PUSH([Fortran]) +AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4]) +AC_LANG_POP([Fortran]) +]) diff --git a/m4/ax_check_compile_flag.m4 b/m4/ax_check_compile_flag.m4 new file mode 100644 index 0000000..ca36397 --- /dev/null +++ b/m4/ax_check_compile_flag.m4 @@ -0,0 +1,74 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the current language's compiler +# or gives an error. (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 4 + +AC_DEFUN([AX_CHECK_COMPILE_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl +AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ + ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" + AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_COMPILE_FLAGS diff --git a/m4/ax_check_enable_debug.m4 b/m4/ax_check_enable_debug.m4 new file mode 100644 index 0000000..f99d75f --- /dev/null +++ b/m4/ax_check_enable_debug.m4 @@ -0,0 +1,124 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_check_enable_debug.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_ENABLE_DEBUG([enable by default=yes/info/profile/no], [ENABLE DEBUG VARIABLES ...], [DISABLE DEBUG VARIABLES NDEBUG ...], [IS-RELEASE]) +# +# DESCRIPTION +# +# Check for the presence of an --enable-debug option to configure, with +# the specified default value used when the option is not present. Return +# the value in the variable $ax_enable_debug. +# +# Specifying 'yes' adds '-g -O0' to the compilation flags for all +# languages. Specifying 'info' adds '-g' to the compilation flags. +# Specifying 'profile' adds '-g -pg' to the compilation flags and '-pg' to +# the linking flags. Otherwise, nothing is added. +# +# Define the variables listed in the second argument if debug is enabled, +# defaulting to no variables. Defines the variables listed in the third +# argument if debug is disabled, defaulting to NDEBUG. All lists of +# variables should be space-separated. +# +# If debug is not enabled, ensure AC_PROG_* will not add debugging flags. +# Should be invoked prior to any AC_PROG_* compiler checks. +# +# IS-RELEASE can be used to change the default to 'no' when making a +# release. Set IS-RELEASE to 'yes' or 'no' as appropriate. By default, it +# uses the value of $ax_is_release, so if you are using the AX_IS_RELEASE +# macro, there is no need to pass this parameter. +# +# AX_IS_RELEASE([git-directory]) +# AX_CHECK_ENABLE_DEBUG() +# +# LICENSE +# +# Copyright (c) 2011 Rhys Ulerich +# Copyright (c) 2014, 2015 Philip Withnall +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. + +#serial 5 + +AC_DEFUN([AX_CHECK_ENABLE_DEBUG],[ + AC_BEFORE([$0],[AC_PROG_CC])dnl + AC_BEFORE([$0],[AC_PROG_CXX])dnl + AC_BEFORE([$0],[AC_PROG_F77])dnl + AC_BEFORE([$0],[AC_PROG_FC])dnl + + AC_MSG_CHECKING(whether to enable debugging) + + ax_enable_debug_default=m4_tolower(m4_normalize(ifelse([$1],,[no],[$1]))) + ax_enable_debug_is_release=m4_tolower(m4_normalize(ifelse([$4],, + [$ax_is_release], + [$4]))) + + # If this is a release, override the default. + AS_IF([test "$ax_enable_debug_is_release" = "yes"], + [ax_enable_debug_default="no"]) + + m4_define(ax_enable_debug_vars,[m4_normalize(ifelse([$2],,,[$2]))]) + m4_define(ax_disable_debug_vars,[m4_normalize(ifelse([$3],,[NDEBUG],[$3]))]) + + AC_ARG_ENABLE(debug, + [AS_HELP_STRING([--enable-debug=]@<:@yes/info/profile/no@:>@,[compile with debugging])], + [],enable_debug=$ax_enable_debug_default) + + # empty mean debug yes + AS_IF([test "x$enable_debug" = "x"], + [enable_debug="yes"]) + + # case of debug + AS_CASE([$enable_debug], + [yes],[ + AC_MSG_RESULT(yes) + CFLAGS="${CFLAGS} -g -O0" + CXXFLAGS="${CXXFLAGS} -g -O0" + FFLAGS="${FFLAGS} -g -O0" + FCFLAGS="${FCFLAGS} -g -O0" + OBJCFLAGS="${OBJCFLAGS} -g -O0" + ], + [info],[ + AC_MSG_RESULT(info) + CFLAGS="${CFLAGS} -g" + CXXFLAGS="${CXXFLAGS} -g" + FFLAGS="${FFLAGS} -g" + FCFLAGS="${FCFLAGS} -g" + OBJCFLAGS="${OBJCFLAGS} -g" + ], + [profile],[ + AC_MSG_RESULT(profile) + CFLAGS="${CFLAGS} -g -pg" + CXXFLAGS="${CXXFLAGS} -g -pg" + FFLAGS="${FFLAGS} -g -pg" + FCFLAGS="${FCFLAGS} -g -pg" + OBJCFLAGS="${OBJCFLAGS} -g -pg" + LDFLAGS="${LDFLAGS} -pg" + ], + [ + AC_MSG_RESULT(no) + dnl Ensure AC_PROG_CC/CXX/F77/FC/OBJC will not enable debug flags + dnl by setting any unset environment flag variables + AS_IF([test "x${CFLAGS+set}" != "xset"], + [CFLAGS=""]) + AS_IF([test "x${CXXFLAGS+set}" != "xset"], + [CXXFLAGS=""]) + AS_IF([test "x${FFLAGS+set}" != "xset"], + [FFLAGS=""]) + AS_IF([test "x${FCFLAGS+set}" != "xset"], + [FCFLAGS=""]) + AS_IF([test "x${OBJCFLAGS+set}" != "xset"], + [OBJCFLAGS=""]) + ]) + + dnl Define various variables if debugging is disabled. + dnl assert.h is a NOP if NDEBUG is defined, so define it by default. + AS_IF([test "x$enable_debug" = "xyes"], + [m4_map_args_w(ax_enable_debug_vars, [AC_DEFINE(], [,,[Define if debugging is enabled])])], + [m4_map_args_w(ax_disable_debug_vars, [AC_DEFINE(], [,,[Define if debugging is disabled])])]) + ax_enable_debug=$enable_debug +]) diff --git a/m4/ax_check_gnu_make.m4 b/m4/ax_check_gnu_make.m4 new file mode 100644 index 0000000..6762e9e --- /dev/null +++ b/m4/ax_check_gnu_make.m4 @@ -0,0 +1,84 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_check_gnu_make.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_GNU_MAKE() +# +# DESCRIPTION +# +# This macro searches for a GNU version of make. If a match is found: +# +# * The makefile variable `ifGNUmake' is set to the empty string, otherwise +# it is set to "#". This is useful for including a special features in a +# Makefile, which cannot be handled by other versions of make. +# * The variable `_cv_gnu_make_command` is set to the command to invoke +# GNU make if it exists, the empty string otherwise. +# * The variable `ax_cv_gnu_make_command` is set to the command to invoke +# GNU make by copying `_cv_gnu_make_command`, otherwise it is unset. +# * If GNU Make is found, its version is extracted from the output of +# `make --version` as the last field of a record of space-separated +# columns and saved into the variable `ax_check_gnu_make_version`. +# +# Here is an example of its use: +# +# Makefile.in might contain: +# +# # A failsafe way of putting a dependency rule into a makefile +# $(DEPEND): +# $(CC) -MM $(srcdir)/*.c > $(DEPEND) +# +# @ifGNUmake@ ifeq ($(DEPEND),$(wildcard $(DEPEND))) +# @ifGNUmake@ include $(DEPEND) +# @ifGNUmake@ endif +# +# Then configure.in would normally contain: +# +# AX_CHECK_GNU_MAKE() +# AC_OUTPUT(Makefile) +# +# Then perhaps to cause gnu make to override any other make, we could do +# something like this (note that GNU make always looks for GNUmakefile +# first): +# +# if ! test x$_cv_gnu_make_command = x ; then +# mv Makefile GNUmakefile +# echo .DEFAULT: > Makefile ; +# echo \ $_cv_gnu_make_command \$@ >> Makefile; +# fi +# +# Then, if any (well almost any) other make is called, and GNU make also +# exists, then the other make wraps the GNU make. +# +# LICENSE +# +# Copyright (c) 2008 John Darrington +# Copyright (c) 2015 Enrico M. Crisostomo +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 8 + +AC_DEFUN([AX_CHECK_GNU_MAKE],dnl + [AC_PROG_AWK + AC_CACHE_CHECK([for GNU make],[_cv_gnu_make_command],[dnl + _cv_gnu_make_command="" ; +dnl Search all the common names for GNU make + for a in "$MAKE" make gmake gnumake ; do + if test -z "$a" ; then continue ; fi ; + if "$a" --version 2> /dev/null | grep GNU 2>&1 > /dev/null ; then + _cv_gnu_make_command=$a ; + AX_CHECK_GNU_MAKE_HEADLINE=$("$a" --version 2> /dev/null | grep "GNU Make") + ax_check_gnu_make_version=$(echo ${AX_CHECK_GNU_MAKE_HEADLINE} | ${AWK} -F " " '{ print $(NF); }') + break ; + fi + done ;]) +dnl If there was a GNU version, then set @ifGNUmake@ to the empty string, '#' otherwise + AS_VAR_IF([_cv_gnu_make_command], [""], [AS_VAR_SET([ifGNUmake], ["#"])], [AS_VAR_SET([ifGNUmake], [""])]) + AS_VAR_IF([_cv_gnu_make_command], [""], [AS_UNSET(ax_cv_gnu_make_command)], [AS_VAR_SET([ax_cv_gnu_make_command], [${_cv_gnu_make_command}])]) + AC_SUBST([ifGNUmake]) +]) diff --git a/m4/ax_check_link_flag.m4 b/m4/ax_check_link_flag.m4 new file mode 100644 index 0000000..eb01a6c --- /dev/null +++ b/m4/ax_check_link_flag.m4 @@ -0,0 +1,74 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the linker or gives an error. +# (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the linker's default flags +# when the check is done. The check is thus made with the flags: "LDFLAGS +# EXTRA-FLAGS FLAG". This can for example be used to force the linker to +# issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_LINK_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 4 + +AC_DEFUN([AX_CHECK_LINK_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl +AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ + ax_check_save_flags=$LDFLAGS + LDFLAGS="$LDFLAGS $4 $1" + AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + LDFLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_LINK_FLAGS diff --git a/m4/ax_code_coverage.m4 b/m4/ax_code_coverage.m4 new file mode 100644 index 0000000..6c985eb --- /dev/null +++ b/m4/ax_code_coverage.m4 @@ -0,0 +1,273 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_code_coverage.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CODE_COVERAGE() +# +# DESCRIPTION +# +# Defines CODE_COVERAGE_CPPFLAGS, CODE_COVERAGE_CFLAGS, +# CODE_COVERAGE_CXXFLAGS and CODE_COVERAGE_LDFLAGS which should be +# included in the CPPFLAGS, CFLAGS CXXFLAGS and LIBS/LDFLAGS variables of +# every build target (program or library) which should be built with code +# coverage support. Also defines CODE_COVERAGE_RULES which should be +# substituted in your Makefile; and $enable_code_coverage which can be +# used in subsequent configure output. CODE_COVERAGE_ENABLED is defined +# and substituted, and corresponds to the value of the +# --enable-code-coverage option, which defaults to being disabled. +# +# Test also for gcov program and create GCOV variable that could be +# substituted. +# +# Note that all optimisation flags in CFLAGS must be disabled when code +# coverage is enabled. +# +# Usage example: +# +# configure.ac: +# +# AX_CODE_COVERAGE +# +# Makefile.am: +# +# @CODE_COVERAGE_RULES@ +# my_program_LIBS = ... $(CODE_COVERAGE_LDFLAGS) ... +# my_program_CPPFLAGS = ... $(CODE_COVERAGE_CPPFLAGS) ... +# my_program_CFLAGS = ... $(CODE_COVERAGE_CFLAGS) ... +# my_program_CXXFLAGS = ... $(CODE_COVERAGE_CXXFLAGS) ... +# +# This results in a "check-code-coverage" rule being added to any +# Makefile.am which includes "@CODE_COVERAGE_RULES@" (assuming the module +# has been configured with --enable-code-coverage). Running `make +# check-code-coverage` in that directory will run the module's test suite +# (`make check`) and build a code coverage report detailing the code which +# was touched, then print the URI for the report. +# +# This code was derived from Makefile.decl in GLib, originally licenced +# under LGPLv2.1+. +# +# LICENSE +# +# Copyright (c) 2012, 2016 Philip Withnall +# Copyright (c) 2012 Xan Lopez +# Copyright (c) 2012 Christian Persch +# Copyright (c) 2012 Paolo Borelli +# Copyright (c) 2012 Dan Winship +# Copyright (c) 2015 Bastien ROUCARIES +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or (at +# your option) any later version. +# +# This library is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . + +#serial 15 + +AC_DEFUN([AX_CODE_COVERAGE],[ + dnl Check for --enable-code-coverage + AC_REQUIRE([AC_PROG_SED]) + + # allow to override gcov location + AC_ARG_WITH([gcov], + [AS_HELP_STRING([--with-gcov[=GCOV]], [use given GCOV for coverage (GCOV=gcov).])], + [_AX_CODE_COVERAGE_GCOV_PROG_WITH=$with_gcov], + [_AX_CODE_COVERAGE_GCOV_PROG_WITH=gcov]) + + AC_MSG_CHECKING([whether to build with code coverage support]) + AC_ARG_ENABLE([code-coverage], + AS_HELP_STRING([--enable-code-coverage], + [Whether to enable code coverage support]),, + enable_code_coverage=no) + + AM_CONDITIONAL([CODE_COVERAGE_ENABLED], [test x$enable_code_coverage = xyes]) + AC_SUBST([CODE_COVERAGE_ENABLED], [$enable_code_coverage]) + AC_MSG_RESULT($enable_code_coverage) + + AS_IF([ test "$enable_code_coverage" = "yes" ], [ + # check for gcov + AC_CHECK_TOOL([GCOV], + [$_AX_CODE_COVERAGE_GCOV_PROG_WITH], + [:]) + AS_IF([test "X$GCOV" = "X:"], + [AC_MSG_ERROR([gcov is needed to do coverage])]) + AC_SUBST([GCOV]) + + dnl Check if gcc is being used + AS_IF([ test "$GCC" = "no" ], [ + AC_MSG_ERROR([not compiling with gcc, which is required for gcov code coverage]) + ]) + + # List of supported lcov versions. + lcov_version_list="1.6 1.7 1.8 1.9 1.10 1.11 1.12" + + AC_CHECK_PROG([LCOV], [lcov], [lcov]) + AC_CHECK_PROG([GENHTML], [genhtml], [genhtml]) + + AS_IF([ test "$LCOV" ], [ + AC_CACHE_CHECK([for lcov version], ax_cv_lcov_version, [ + ax_cv_lcov_version=invalid + lcov_version=`$LCOV -v 2>/dev/null | $SED -e 's/^.* //'` + for lcov_check_version in $lcov_version_list; do + if test "$lcov_version" = "$lcov_check_version"; then + ax_cv_lcov_version="$lcov_check_version (ok)" + fi + done + ]) + ], [ + lcov_msg="To enable code coverage reporting you must have one of the following lcov versions installed: $lcov_version_list" + AC_MSG_ERROR([$lcov_msg]) + ]) + + case $ax_cv_lcov_version in + ""|invalid[)] + lcov_msg="You must have one of the following versions of lcov: $lcov_version_list (found: $lcov_version)." + AC_MSG_ERROR([$lcov_msg]) + LCOV="exit 0;" + ;; + esac + + AS_IF([ test -z "$GENHTML" ], [ + AC_MSG_ERROR([Could not find genhtml from the lcov package]) + ]) + + dnl Build the code coverage flags + CODE_COVERAGE_CPPFLAGS="-DNDEBUG" + CODE_COVERAGE_CFLAGS="-O0 -g -fprofile-arcs -ftest-coverage" + CODE_COVERAGE_CXXFLAGS="-O0 -g -fprofile-arcs -ftest-coverage" + CODE_COVERAGE_LDFLAGS="-lgcov" + + AC_SUBST([CODE_COVERAGE_CPPFLAGS]) + AC_SUBST([CODE_COVERAGE_CFLAGS]) + AC_SUBST([CODE_COVERAGE_CXXFLAGS]) + AC_SUBST([CODE_COVERAGE_LDFLAGS]) + ]) + +[CODE_COVERAGE_RULES=' +# Code coverage +# +# Optional: +# - CODE_COVERAGE_DIRECTORY: Top-level directory for code coverage reporting. +# Multiple directories may be specified, separated by whitespace. +# (Default: $(top_builddir)) +# - CODE_COVERAGE_OUTPUT_FILE: Filename and path for the .info file generated +# by lcov for code coverage. (Default: +# $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info) +# - CODE_COVERAGE_OUTPUT_DIRECTORY: Directory for generated code coverage +# reports to be created. (Default: +# $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage) +# - CODE_COVERAGE_BRANCH_COVERAGE: Set to 1 to enforce branch coverage, +# set to 0 to disable it and leave empty to stay with the default. +# (Default: empty) +# - CODE_COVERAGE_LCOV_SHOPTS_DEFAULT: Extra options shared between both lcov +# instances. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE) +# - CODE_COVERAGE_LCOV_SHOPTS: Extra options to shared between both lcov +# instances. (Default: $CODE_COVERAGE_LCOV_SHOPTS_DEFAULT) +# - CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH: --gcov-tool pathtogcov +# - CODE_COVERAGE_LCOV_OPTIONS_DEFAULT: Extra options to pass to the +# collecting lcov instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH) +# - CODE_COVERAGE_LCOV_OPTIONS: Extra options to pass to the collecting lcov +# instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_DEFAULT) +# - CODE_COVERAGE_LCOV_RMOPTS_DEFAULT: Extra options to pass to the filtering +# lcov instance. (Default: empty) +# - CODE_COVERAGE_LCOV_RMOPTS: Extra options to pass to the filtering lcov +# instance. (Default: $CODE_COVERAGE_LCOV_RMOPTS_DEFAULT) +# - CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT: Extra options to pass to the +# genhtml instance. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE) +# - CODE_COVERAGE_GENHTML_OPTIONS: Extra options to pass to the genhtml +# instance. (Default: $CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT) +# - CODE_COVERAGE_IGNORE_PATTERN: Extra glob pattern of files to ignore +# +# The generated report will be titled using the $(PACKAGE_NAME) and +# $(PACKAGE_VERSION). In order to add the current git hash to the title, +# use the git-version-gen script, available online. + +# Optional variables +CODE_COVERAGE_DIRECTORY ?= $(top_builddir) +CODE_COVERAGE_OUTPUT_FILE ?= $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info +CODE_COVERAGE_OUTPUT_DIRECTORY ?= $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage +CODE_COVERAGE_BRANCH_COVERAGE ?= +CODE_COVERAGE_LCOV_SHOPTS_DEFAULT ?= $(if $(CODE_COVERAGE_BRANCH_COVERAGE),\ +--rc lcov_branch_coverage=$(CODE_COVERAGE_BRANCH_COVERAGE)) +CODE_COVERAGE_LCOV_SHOPTS ?= $(CODE_COVERAGE_LCOV_SHOPTS_DEFAULT) +CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH ?= --gcov-tool "$(GCOV)" +CODE_COVERAGE_LCOV_OPTIONS_DEFAULT ?= $(CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH) +CODE_COVERAGE_LCOV_OPTIONS ?= $(CODE_COVERAGE_LCOV_OPTIONS_DEFAULT) +CODE_COVERAGE_LCOV_RMOPTS_DEFAULT ?= +CODE_COVERAGE_LCOV_RMOPTS ?= $(CODE_COVERAGE_LCOV_RMOPTS_DEFAULT) +CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT ?=\ +$(if $(CODE_COVERAGE_BRANCH_COVERAGE),\ +--rc genhtml_branch_coverage=$(CODE_COVERAGE_BRANCH_COVERAGE)) +CODE_COVERAGE_GENHTML_OPTIONS ?= $(CODE_COVERAGE_GENHTML_OPTIONS_DEFAULTS) +CODE_COVERAGE_IGNORE_PATTERN ?= + +code_coverage_v_lcov_cap = $(code_coverage_v_lcov_cap_$(V)) +code_coverage_v_lcov_cap_ = $(code_coverage_v_lcov_cap_$(AM_DEFAULT_VERBOSITY)) +code_coverage_v_lcov_cap_0 = @echo " LCOV --capture"\ + $(CODE_COVERAGE_OUTPUT_FILE); +code_coverage_v_lcov_ign = $(code_coverage_v_lcov_ign_$(V)) +code_coverage_v_lcov_ign_ = $(code_coverage_v_lcov_ign_$(AM_DEFAULT_VERBOSITY)) +code_coverage_v_lcov_ign_0 = @echo " LCOV --remove /tmp/*"\ + $(CODE_COVERAGE_IGNORE_PATTERN); +code_coverage_v_genhtml = $(code_coverage_v_genhtml_$(V)) +code_coverage_v_genhtml_ = $(code_coverage_v_genhtml_$(AM_DEFAULT_VERBOSITY)) +code_coverage_v_genhtml_0 = @echo " GEN " $(CODE_COVERAGE_OUTPUT_DIRECTORY); +code_coverage_quiet = $(code_coverage_quiet_$(V)) +code_coverage_quiet_ = $(code_coverage_quiet_$(AM_DEFAULT_VERBOSITY)) +code_coverage_quiet_0 = --quiet + +# sanitizes the test-name: replaces with underscores: dashes and dots +code_coverage_sanitize = $(subst -,_,$(subst .,_,$(1))) + +# Use recursive makes in order to ignore errors during check +check-code-coverage: +ifeq ($(CODE_COVERAGE_ENABLED),yes) + -$(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) -k check + $(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) code-coverage-capture +else + @echo "Need to reconfigure with --enable-code-coverage" +endif + +# Capture code coverage data +code-coverage-capture: code-coverage-capture-hook +ifeq ($(CODE_COVERAGE_ENABLED),yes) + $(code_coverage_v_lcov_cap)$(LCOV) $(code_coverage_quiet) $(addprefix --directory ,$(CODE_COVERAGE_DIRECTORY)) --capture --output-file "$(CODE_COVERAGE_OUTPUT_FILE).tmp" --test-name "$(call code_coverage_sanitize,$(PACKAGE_NAME)-$(PACKAGE_VERSION))" --no-checksum --compat-libtool $(CODE_COVERAGE_LCOV_SHOPTS) $(CODE_COVERAGE_LCOV_OPTIONS) + $(code_coverage_v_lcov_ign)$(LCOV) $(code_coverage_quiet) $(addprefix --directory ,$(CODE_COVERAGE_DIRECTORY)) --remove "$(CODE_COVERAGE_OUTPUT_FILE).tmp" "/tmp/*" $(CODE_COVERAGE_IGNORE_PATTERN) --output-file "$(CODE_COVERAGE_OUTPUT_FILE)" $(CODE_COVERAGE_LCOV_SHOPTS) $(CODE_COVERAGE_LCOV_RMOPTS) + -@rm -f $(CODE_COVERAGE_OUTPUT_FILE).tmp + $(code_coverage_v_genhtml)LANG=C $(GENHTML) $(code_coverage_quiet) $(addprefix --prefix ,$(CODE_COVERAGE_DIRECTORY)) --output-directory "$(CODE_COVERAGE_OUTPUT_DIRECTORY)" --title "$(PACKAGE_NAME)-$(PACKAGE_VERSION) Code Coverage" --legend --show-details "$(CODE_COVERAGE_OUTPUT_FILE)" $(CODE_COVERAGE_GENHTML_OPTIONS) + @echo "file://$(abs_builddir)/$(CODE_COVERAGE_OUTPUT_DIRECTORY)/index.html" +else + @echo "Need to reconfigure with --enable-code-coverage" +endif + +# Hook rule executed before code-coverage-capture, overridable by the user +code-coverage-capture-hook: + +ifeq ($(CODE_COVERAGE_ENABLED),yes) +clean: code-coverage-clean +code-coverage-clean: + -$(LCOV) --directory $(top_builddir) -z + -rm -rf $(CODE_COVERAGE_OUTPUT_FILE) $(CODE_COVERAGE_OUTPUT_FILE).tmp $(CODE_COVERAGE_OUTPUT_DIRECTORY) + -find . -name "*.gcda" -o -name "*.gcov" -delete +endif + +GITIGNOREFILES ?= +GITIGNOREFILES += $(CODE_COVERAGE_OUTPUT_FILE) $(CODE_COVERAGE_OUTPUT_DIRECTORY) + +A''M_DISTCHECK_CONFIGURE_FLAGS ?= +A''M_DISTCHECK_CONFIGURE_FLAGS += --disable-code-coverage + +.PHONY: check-code-coverage code-coverage-capture code-coverage-capture-hook code-coverage-clean +'] + + AC_SUBST([CODE_COVERAGE_RULES]) + m4_ifdef([_AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([CODE_COVERAGE_RULES])]) +]) diff --git a/m4/ax_configure_args.m4 b/m4/ax_configure_args.m4 new file mode 100644 index 0000000..0726b1b --- /dev/null +++ b/m4/ax_configure_args.m4 @@ -0,0 +1,70 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_configure_args.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CONFIGURE_ARGS +# +# DESCRIPTION +# +# Helper macro for AX_ENABLE_BUILDDIR. +# +# The traditional way of starting a subdir-configure is running the script +# with ${1+"$@"} but since autoconf 2.60 this is broken. Instead we have +# to rely on eval'ing $ac_configure_args however some old autoconf +# versions do not provide that. To ensure maximum portability of autoconf +# extension macros this helper can be AC_REQUIRE'd so that +# $ac_configure_args will alsways be present. +# +# Sadly, the traditional "exec $SHELL" of the enable_builddir macros is +# spoiled now and must be replaced by "eval + exit $?". +# +# Example: +# +# AC_DEFUN([AX_ENABLE_SUBDIR],[dnl +# AC_REQUIRE([AX_CONFIGURE_ARGS])dnl +# eval $SHELL $ac_configure_args || exit $? +# ...]) +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 9 + +AC_DEFUN([AX_CONFIGURE_ARGS],[ + # [$]@ is unsable in 2.60+ but earlier autoconf had no ac_configure_args + if test "${ac_configure_args+set}" != "set" ; then + ac_configure_args= + for ac_arg in ${1+"[$]@"}; do + ac_configure_args="$ac_configure_args '$ac_arg'" + done + fi +]) diff --git a/m4/ax_enable_builddir.m4 b/m4/ax_enable_builddir.m4 new file mode 100644 index 0000000..5f4ba32 --- /dev/null +++ b/m4/ax_enable_builddir.m4 @@ -0,0 +1,302 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_enable_builddir.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_ENABLE_BUILDDIR [(dirstring-or-command [,Makefile.mk [,-all]])] +# +# DESCRIPTION +# +# If the current configure was run within the srcdir then we move all +# configure-files into a subdir and let the configure steps continue +# there. We provide an option --disable-builddir to suppress the move into +# a separate builddir. +# +# Defaults: +# +# $1 = $host (overridden with $HOST) +# $2 = Makefile.mk +# $3 = -all +# +# This macro must be called before AM_INIT_AUTOMAKE. It creates a default +# toplevel srcdir Makefile from the information found in the created +# toplevel builddir Makefile. It just copies the variables and +# rule-targets, each extended with a default rule-execution that recurses +# into the build directory of the current "HOST". You can override the +# auto-dection through `config.guess` and build-time of course, as in +# +# make HOST=i386-mingw-cross +# +# which can of course set at configure time as well using +# +# configure --host=i386-mingw-cross +# +# After the default has been created, additional rules can be appended +# that will not just recurse into the subdirectories and only ever exist +# in the srcdir toplevel makefile - these parts are read from the $2 = +# Makefile.mk file +# +# The automatic rules are usually scanning the toplevel Makefile for lines +# like '#### $host |$builddir' to recognize the place where to recurse +# into. Usually, the last one is the only one used. However, almost all +# targets have an additional "*-all" rule which makes the script to +# recurse into _all_ variants of the current HOST (!!) setting. The "-all" +# suffix can be overriden for the macro as well. +# +# a special rule is only given for things like "dist" that will copy the +# tarball from the builddir to the sourcedir (or $(PUB)) for reason of +# convenience. +# +# LICENSE +# +# Copyright (c) 2009 Guido U. Draheim +# Copyright (c) 2009 Alan Jenkins +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 25 + +AC_DEFUN([AX_ENABLE_BUILDDIR],[ +AC_REQUIRE([AC_CANONICAL_HOST])[]dnl +AC_REQUIRE([AC_CANONICAL_TARGET])[]dnl +AC_REQUIRE([AX_CONFIGURE_ARGS])[]dnl +AC_REQUIRE([AM_AUX_DIR_EXPAND])[]dnl +AC_BEFORE([$0],[AM_INIT_AUTOMAKE])dnl +AS_VAR_PUSHDEF([SUB],[ax_enable_builddir])dnl +AS_VAR_PUSHDEF([AUX],[ax_enable_builddir_auxdir])dnl +AS_VAR_PUSHDEF([SED],[ax_enable_builddir_sed])dnl +SUB="." +AC_ARG_ENABLE([builddir], AS_HELP_STRING( + [--disable-builddir],[disable automatic build in subdir of sources]) + ,[SUB="$enableval"], [SUB="auto"]) +if test ".$ac_srcdir_defaulted" != ".no" ; then +if test ".$srcdir" = ".." ; then + if test -f config.status ; then + AC_MSG_NOTICE(toplevel srcdir already configured... skipping subdir build) + else + test ".$SUB" = "." && SUB="." + test ".$SUB" = ".no" && SUB="." + test ".$TARGET" = "." && TARGET="$target" + test ".$SUB" = ".auto" && SUB="m4_ifval([$1], [$1],[$TARGET])" + if test ".$SUB" != ".." ; then # we know where to go and + AS_MKDIR_P([$SUB]) + echo __.$SUB.__ > $SUB/conftest.tmp + cd $SUB + if grep __.$SUB.__ conftest.tmp >/dev/null 2>/dev/null ; then + rm conftest.tmp + AC_MSG_RESULT([continue configure in default builddir "./$SUB"]) + else + AC_MSG_ERROR([could not change to default builddir "./$SUB"]) + fi + srcdir=`echo "$SUB" | + sed -e 's,^\./,,;s,[[^/]]$,&/,;s,[[^/]]*/,../,g;s,[[/]]$,,;'` + # going to restart from subdirectory location + test -f $srcdir/config.log && mv $srcdir/config.log . + test -f $srcdir/confdefs.h && mv $srcdir/confdefs.h . + test -f $srcdir/conftest.log && mv $srcdir/conftest.log . + test -f $srcdir/$cache_file && mv $srcdir/$cache_file . + AC_MSG_RESULT(....exec $SHELL $srcdir/[$]0 "--srcdir=$srcdir" "--enable-builddir=$SUB" ${1+"[$]@"}) + case "[$]0" in # restart + [[\\/]]* | ?:[[\\/]]*) # Asbolute name + eval $SHELL "'[$]0'" "'--srcdir=$srcdir'" "'--enable-builddir=$SUB'" $ac_configure_args ;; + *) eval $SHELL "'$srcdir/[$]0'" "'--srcdir=$srcdir'" "'--enable-builddir=$SUB'" $ac_configure_args ;; + esac ; exit $? + fi + fi +fi fi +test ".$SUB" = ".auto" && SUB="." +dnl ac_path_prog uses "set dummy" to override $@ which would defeat the "exec" +AC_PATH_PROG(SED,gsed sed, sed) +AUX="$am_aux_dir" +AS_VAR_POPDEF([SED])dnl +AS_VAR_POPDEF([AUX])dnl +AS_VAR_POPDEF([SUB])dnl +AC_CONFIG_COMMANDS([buildir],[dnl .............. config.status .............. +AS_VAR_PUSHDEF([SUB],[ax_enable_builddir])dnl +AS_VAR_PUSHDEF([TOP],[top_srcdir])dnl +AS_VAR_PUSHDEF([SRC],[ac_top_srcdir])dnl +AS_VAR_PUSHDEF([AUX],[ax_enable_builddir_auxdir])dnl +AS_VAR_PUSHDEF([SED],[ax_enable_builddir_sed])dnl +pushdef([END],[Makefile.mk])dnl +pushdef([_ALL],[ifelse([$3],,[-all],[$3])])dnl + SRC="$ax_enable_builddir_srcdir" + if test ".$SUB" = ".." ; then + if test -f "$TOP/Makefile" ; then + AC_MSG_NOTICE([skipping TOP/Makefile - left untouched]) + else + AC_MSG_NOTICE([skipping TOP/Makefile - not created]) + fi + else + if test -f "$SRC/Makefile" ; then + a=`grep "^VERSION " "$SRC/Makefile"` ; b=`grep "^VERSION " Makefile` + test "$a" != "$b" && rm "$SRC/Makefile" + fi + if test -f "$SRC/Makefile" ; then + echo "$SRC/Makefile : $SRC/Makefile.in" > $tmp/conftemp.mk + echo " []@ echo 'REMOVED,,,' >\$[]@" >> $tmp/conftemp.mk + eval "${MAKE-make} -f $tmp/conftemp.mk 2>/dev/null >/dev/null" + if grep '^REMOVED,,,' "$SRC/Makefile" >/dev/null + then rm $SRC/Makefile ; fi + cp $tmp/conftemp.mk $SRC/makefiles.mk~ ## DEBUGGING + fi + if test ! -f "$SRC/Makefile" ; then + AC_MSG_NOTICE([create TOP/Makefile guessed from local Makefile]) + x='`' ; cat >$tmp/conftemp.sed <<_EOF +/^\$/n +x +/^\$/bS +x +/\\\\\$/{H;d;} +{H;s/.*//;x;} +bM +:S +x +/\\\\\$/{h;d;} +{h;s/.*//;x;} +:M +s/\\(\\n\\) /\\1 /g +/^ /d +/^[[ ]]*[[\\#]]/d +/^VPATH *=/d +s/^srcdir *=.*/srcdir = ./ +s/^top_srcdir *=.*/top_srcdir = ./ +/[[:=]]/!d +/^\\./d +dnl Now handle rules (i.e. lines containing ":" but not " = "). +/ = /b +/ .= /b +/:/!b +s/:.*/:/ +s/ / /g +s/ \\([[a-z]][[a-z-]]*[[a-zA-Z0-9]]\\)\\([[ :]]\\)/ \\1 \\1[]_ALL\\2/g +s/^\\([[a-z]][[a-z-]]*[[a-zA-Z0-9]]\\)\\([[ :]]\\)/\\1 \\1[]_ALL\\2/ +s/ / /g +/^all all[]_ALL[[ :]]/i\\ +all-configured : all[]_ALL +dnl dist-all exists... and would make for dist-all-all +s/ [[a-zA-Z0-9-]]*[]_ALL [[a-zA-Z0-9-]]*[]_ALL[]_ALL//g +/[]_ALL[]_ALL/d +a\\ + @ HOST="\$(HOST)\" \\\\\\ + ; test ".\$\$HOST" = "." && HOST=$x sh $AUX/config.guess $x \\\\\\ + ; BUILD=$x grep "^#### \$\$HOST " Makefile | sed -e 's/.*|//' $x \\\\\\ + ; use=$x basename "\$\@" _ALL $x; n=$x echo \$\$BUILD | wc -w $x \\\\\\ + ; echo "MAKE \$\$HOST : \$\$n * \$\@"; if test "\$\$n" -eq "0" ; then : \\\\\\ + ; BUILD=$x grep "^####.*|" Makefile |tail -1| sed -e 's/.*|//' $x ; fi \\\\\\ + ; test ".\$\$BUILD" = "." && BUILD="." \\\\\\ + ; test "\$\$use" = "\$\@" && BUILD=$x echo "\$\$BUILD" | tail -1 $x \\\\\\ + ; for i in \$\$BUILD ; do test ".\$\$i" = "." && continue \\\\\\ + ; (cd "\$\$i" && test ! -f configure && \$(MAKE) \$\$use) || exit; done +dnl special rule add-on: "dist" copies the tarball to $(PUB). (source tree) +/dist[]_ALL *:/a\\ + @ HOST="\$(HOST)\" \\\\\\ + ; test ".\$\$HOST" = "." && HOST=$x sh $AUX/config.guess $x \\\\\\ + ; BUILD=$x grep "^#### \$\$HOST " Makefile | sed -e 's/.*|//' $x \\\\\\ + ; found=$x echo \$\$BUILD | wc -w $x \\\\\\ + ; echo "MAKE \$\$HOST : \$\$found \$(PACKAGE)-\$(VERSION).tar.*" \\\\\\ + ; if test "\$\$found" -eq "0" ; then : \\\\\\ + ; BUILD=$x grep "^#### .*|" Makefile |tail -1| sed -e 's/.*|//' $x \\\\\\ + ; fi ; for i in \$\$BUILD ; do test ".\$\$i" = "." && continue \\\\\\ + ; for f in \$\$i/\$(PACKAGE)-\$(VERSION).tar.* \\\\\\ + ; do test -f "\$\$f" && mv "\$\$f" \$(PUB). ; done ; break ; done +dnl special rule add-on: "dist-foo" copies all the archives to $(PUB). (source tree) +/dist-[[a-zA-Z0-9]]*[]_ALL *:/a\\ + @ HOST="\$(HOST)\" \\\\\\ + ; test ".\$\$HOST" = "." && HOST=$x sh ./config.guess $x \\\\\\ + ; BUILD=$x grep "^#### \$\$HOST " Makefile | sed -e 's/.*|//' $x \\\\\\ + ; found=$x echo \$\$BUILD | wc -w $x \\\\\\ + ; echo "MAKE \$\$HOST : \$\$found \$(PACKAGE)-\$(VERSION).*" \\\\\\ + ; if test "\$\$found" -eq "0" ; then : \\\\\\ + ; BUILD=$x grep "^#### .*|" Makefile |tail -1| sed -e 's/.*|//' $x \\\\\\ + ; fi ; for i in \$\$BUILD ; do test ".\$\$i" = "." && continue \\\\\\ + ; for f in \$\$i/\$(PACKAGE)-\$(VERSION).* \\\\\\ + ; do test -f "\$\$f" && mv "\$\$f" \$(PUB). ; done ; break ; done +dnl special rule add-on: "distclean" removes all local builddirs completely +/distclean[]_ALL *:/a\\ + @ HOST="\$(HOST)\" \\\\\\ + ; test ".\$\$HOST" = "." && HOST=$x sh $AUX/config.guess $x \\\\\\ + ; BUILD=$x grep "^#### .*|" Makefile | sed -e 's/.*|//' $x \\\\\\ + ; use=$x basename "\$\@" _ALL $x; n=$x echo \$\$BUILD | wc -w $x \\\\\\ + ; echo "MAKE \$\$HOST : \$\$n * \$\@ (all local builds)" \\\\\\ + ; test ".\$\$BUILD" = "." && BUILD="." \\\\\\ + ; for i in \$\$BUILD ; do test ".\$\$i" = "." && continue \\\\\\ + ; echo "# rm -r \$\$i"; done ; echo "# (sleep 3)" ; sleep 3 \\\\\\ + ; for i in \$\$BUILD ; do test ".\$\$i" = "." && continue \\\\\\ + ; echo "\$\$i" | grep "^/" > /dev/null && continue \\\\\\ + ; echo "\$\$i" | grep "^../" > /dev/null && continue \\\\\\ + ; echo "rm -r \$\$i"; (rm -r "\$\$i") ; done ; rm Makefile +_EOF + cp "$tmp/conftemp.sed" "$SRC/makefile.sed~" ## DEBUGGING + $SED -f $tmp/conftemp.sed Makefile >$SRC/Makefile + if test -f "$SRC/m4_ifval([$2],[$2],[END])" ; then + AC_MSG_NOTICE([extend TOP/Makefile with TOP/m4_ifval([$2],[$2],[END])]) + cat $SRC/END >>$SRC/Makefile + fi ; xxxx="####" + echo "$xxxx CONFIGURATIONS FOR TOPLEVEL MAKEFILE: " >>$SRC/Makefile + # sanity check + if grep '^; echo "MAKE ' $SRC/Makefile >/dev/null ; then + AC_MSG_NOTICE([buggy sed found - it deletes tab in "a" text parts]) + $SED -e '/^@ HOST=/s/^/ /' -e '/^; /s/^/ /' $SRC/Makefile \ + >$SRC/Makefile~ + (test -s $SRC/Makefile~ && mv $SRC/Makefile~ $SRC/Makefile) 2>/dev/null + fi + else + xxxx="\\#\\#\\#\\#" + # echo "/^$xxxx *$ax_enable_builddir_host /d" >$tmp/conftemp.sed + echo "s!^$xxxx [[^|]]* | *$SUB *\$!$xxxx ...... $SUB!" >$tmp/conftemp.sed + $SED -f "$tmp/conftemp.sed" "$SRC/Makefile" >$tmp/mkfile.tmp + cp "$tmp/conftemp.sed" "$SRC/makefiles.sed~" ## DEBUGGING + cp "$tmp/mkfile.tmp" "$SRC/makefiles.out~" ## DEBUGGING + if cmp -s "$SRC/Makefile" "$tmp/mkfile.tmp" 2>/dev/null ; then + AC_MSG_NOTICE([keeping TOP/Makefile from earlier configure]) + rm "$tmp/mkfile.tmp" + else + AC_MSG_NOTICE([reusing TOP/Makefile from earlier configure]) + mv "$tmp/mkfile.tmp" "$SRC/Makefile" + fi + fi + AC_MSG_NOTICE([build in $SUB (HOST=$ax_enable_builddir_host)]) + xxxx="####" + echo "$xxxx" "$ax_enable_builddir_host" "|$SUB" >>$SRC/Makefile + fi +popdef([END])dnl +AS_VAR_POPDEF([SED])dnl +AS_VAR_POPDEF([AUX])dnl +AS_VAR_POPDEF([SRC])dnl +AS_VAR_POPDEF([TOP])dnl +AS_VAR_POPDEF([SUB])dnl +],[dnl +ax_enable_builddir_srcdir="$srcdir" # $srcdir +ax_enable_builddir_host="$HOST" # $HOST / $host +ax_enable_builddir_version="$VERSION" # $VERSION +ax_enable_builddir_package="$PACKAGE" # $PACKAGE +ax_enable_builddir_auxdir="$ax_enable_builddir_auxdir" # $AUX +ax_enable_builddir_sed="$ax_enable_builddir_sed" # $SED +ax_enable_builddir="$ax_enable_builddir" # $SUB +])dnl +]) diff --git a/m4/ax_extend_srcdir.m4 b/m4/ax_extend_srcdir.m4 new file mode 100644 index 0000000..40f3787 --- /dev/null +++ b/m4/ax_extend_srcdir.m4 @@ -0,0 +1,86 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_extend_srcdir.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_EXTEND_SRCDIR +# +# DESCRIPTION +# +# The AX_EXTEND_SRCDIR macro extends $srcdir by one path component. +# +# As an example, when working in /home/michael/i3-4.12/build and calling +# ../configure, your $srcdir is "..". After calling AX_EXTEND_SRCDIR, +# $srcdir will be set to "../../i3-4.12". +# +# The result of extending $srcdir is that filenames (e.g. in the output of +# the "backtrace" gdb command) will include one more path component of the +# absolute source path. The additional path component makes it easy for +# users to recognize which files belong to the PACKAGE, and -- provided a +# dist tarball was unpacked -- which version of PACKAGE was used. +# +# As an example, in "backtrace", you will see: +# +# #0 main (argc=1, argv=0x7fffffff1fc8) at ../../i3-4.12/src/main.c:187 +# +# instead of: +# +# #0 main (argc=1, argv=0x7fffffff1fc8) at ../src/main.c:187 +# +# In case your code uses the __FILE__ preprocessor directive to refer to +# the filename of the current source file (e.g. in debug messages), using +# the extended path might be undesirable. For this purpose, +# AX_EXTEND_SRCDIR defines the output variable AX_EXTEND_SRCDIR_CPPFLAGS, +# which can be added to AM_CPPFLAGS in Makefile.am in order to define the +# preprocessor directive STRIPPED__FILE__. As an example, when compiling +# the file "../../i3-4.12/src/main.c", STRIPPED__FILE__ evaluates to +# "main.c". +# +# There are some caveats: When $srcdir is "." (i.e. when ./configure was +# called instead of ../configure in a separate build directory), +# AX_EXTEND_SRCDIR will still extend $srcdir, but the intended effect will +# not be achieved because of the way automake specifies file paths: +# automake defines COMPILE to use "`test -f '$source' || echo +# '\$(srcdir)/'`$source" in order to prefer files in the current directory +# over specifying $srcdir explicitly. +# +# The AX_EXTEND_SRCDIR author is not aware of any way to influence this +# automake behavior. Patches very welcome. +# +# To work around this issue, you can use AX_ENABLE_BUILDDIR i.e. by adding +# the following code to configure.ac: +# +# AX_ENABLE_BUILDDIR +# dnl ... +# AX_EXTEND_SRCDIR +# +# Then also add this bit to Makefile.am (if you wish to use +# STRIPPED__FILE__ in your code): +# +# AM_CPPFLAGS = @AX_EXTEND_SRCDIR_CPPFLAGS@ +# +# LICENSE +# +# Copyright (c) 2016 Michael Stapelberg +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 3 + +AC_DEFUN([AX_EXTEND_SRCDIR], +[dnl +AS_CASE([$srcdir], + [.|.*|/*], + [ + # pwd -P is specified in IEEE 1003.1 from 2004 + as_dir=`cd "$srcdir" && pwd -P` + as_base=`AS_BASENAME([$as_dir])` + srcdir=${srcdir}/../${as_base} + + AC_SUBST([AX_EXTEND_SRCDIR_CPPFLAGS], ["-DSTRIPPED__FILE__=AS_ESCAPE([\"$$(basename $<)\"])"]) + ]) +])dnl AX_EXTEND_SRCDIR diff --git a/m4/ax_require_defined.m4 b/m4/ax_require_defined.m4 new file mode 100644 index 0000000..cae1111 --- /dev/null +++ b/m4/ax_require_defined.m4 @@ -0,0 +1,37 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_require_defined.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_REQUIRE_DEFINED(MACRO) +# +# DESCRIPTION +# +# AX_REQUIRE_DEFINED is a simple helper for making sure other macros have +# been defined and thus are available for use. This avoids random issues +# where a macro isn't expanded. Instead the configure script emits a +# non-fatal: +# +# ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found +# +# It's like AC_REQUIRE except it doesn't expand the required macro. +# +# Here's an example: +# +# AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) +# +# LICENSE +# +# Copyright (c) 2014 Mike Frysinger +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 1 + +AC_DEFUN([AX_REQUIRE_DEFINED], [dnl + m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])]) +])dnl AX_REQUIRE_DEFINED diff --git a/m4/ax_sanitizers.m4 b/m4/ax_sanitizers.m4 new file mode 100644 index 0000000..836d4af --- /dev/null +++ b/m4/ax_sanitizers.m4 @@ -0,0 +1,130 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_sanitizers.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_SANITIZERS([SANITIZERS], [ENABLED-BY-DEFAULT], [ACTION-SUCCESS]) +# +# DESCRIPTION +# +# Offers users to enable one or more sanitizers (see +# https://github.com/google/sanitizers) with the corresponding +# --enable--sanitizer option. +# +# SANITIZERS is a whitespace-separated list of sanitizers to offer via +# --enable--sanitizer options, e.g. "address memory" for the +# address sanitizer and the memory sanitizer. If SANITIZERS is not specified, +# all known sanitizers to AX_SANITIZERS will be offered, which at the time of +# writing are "address memory undefined". +# NOTE that SANITIZERS is expanded at autoconf time, not at configure time, +# i.e. you cannot use shell variables in SANITIZERS. +# +# ENABLED-BY-DEFAULT is a whitespace-separated list of sanitizers which +# should be enabled by default, e.g. "memory undefined". Note that not all +# sanitizers can be combined, e.g. memory sanitizer cannot be enabled when +# address sanitizer is already enabled. +# Set ENABLED-BY-DEFAULT to a single whitespace in order to disable all +# sanitizers by default. +# ENABLED-BY-DEFAULT is expanded at configure time, so you can use shell +# variables. +# +# ACTION-SUCCESS allows to specify shell commands to execute on success, i.e. +# when one of the sanitizers was successfully enabled. This is a good place +# to call AC_DEFINE for any precompiler constants you might need to make your +# code play nice with sanitizers. +# +# The variable ax_enabled_sanitizers contains a whitespace-separated list of +# all enabled sanitizers, so that you can print them at the end of configure, +# if you wish. +# +# The additional --enable-sanitizers option allows users to enable/disable +# all sanitizers, effectively overriding ENABLED-BY-DEFAULT. +# +# EXAMPLES +# +# AX_SANITIZERS([address]) +# dnl offer users to enable address sanitizer via --enable-address-sanitizer +# +# is_debug_build=… +# if test "x$is_debug_build" = "xyes"; then +# default_sanitizers="address memory" +# else +# default_sanitizers= +# fi +# AX_SANITIZERS([address memory], [$default_sanitizers]) +# dnl enable address sanitizer and memory sanitizer by default for debug +# dnl builds, e.g. when building from git instead of a dist tarball. +# +# AX_SANITIZERS(, , [ +# AC_DEFINE([SANITIZERS_ENABLED], +# [], +# [At least one sanitizer was enabled])]) +# dnl enable all sanitizers known to AX_SANITIZERS by default and set the +# dnl SANITIZERS_ENABLED precompiler constant. +# +# AX_SANITIZERS(, [ ]) +# dnl provide all sanitizers, but enable none by default. +# +# LICENSE +# +# Copyright (c) 2016 Michael Stapelberg +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. This file is offered as-is, +# without any warranty. + +AC_DEFUN([AX_SANITIZERS], +[AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG]) +AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) +AX_REQUIRE_DEFINED([AX_APPEND_FLAG]) +AC_ARG_ENABLE(sanitizers, + AS_HELP_STRING( + [--enable-sanitizers], + [enable all known sanitizers]), + [ax_sanitizers_default=$enableval], + [ax_sanitizers_default=]) +ax_enabled_sanitizers= +m4_foreach_w([mysan], m4_default($1, [address memory undefined]), [ + dnl If ax_sanitizers_default is unset, i.e. the user neither explicitly + dnl enabled nor explicitly disabled all sanitizers, we get the default value + dnl for this sanitizer based on whether it is listed in ENABLED-BY-DEFAULT. + AS_IF([test "x$ax_sanitizers_default" = "x"], [dnl + ax_sanitizer_default= + for mycheck in m4_default([$2], [address memory undefined]); do + AS_IF([test "x$mycheck" = "x[]mysan"], [ax_sanitizer_default=yes]) + done + AS_IF([test "x$ax_sanitizer_default" = "x"], [ax_sanitizer_default=no]) + ], + [ax_sanitizer_default=$ax_sanitizers_default]) + AC_ARG_ENABLE(mysan[]-sanitizer, + AS_HELP_STRING( + [--enable-[]mysan[]-sanitizer], + [enable -fsanitize=mysan]), + [ax_sanitizer_enabled=$enableval], + [ax_sanitizer_enabled=$ax_sanitizer_default]) + +AS_IF([test "x$ax_sanitizer_enabled" = "xyes"], [ +dnl Not using AX_APPEND_COMPILE_FLAGS and AX_APPEND_LINK_FLAGS because they +dnl lack the ability to specify ACTION-SUCCESS. + AX_CHECK_COMPILE_FLAG([-fsanitize=[]mysan], [ + AX_CHECK_LINK_FLAG([-fsanitize=[]mysan], [ + AX_APPEND_FLAG([-fsanitize=[]mysan], []) +dnl If and only if libtool is being used, LDFLAGS needs to contain -Wc,-fsanitize=…. +dnl See e.g. https://sources.debian.net/src/systemd/231-7/configure.ac/?hl=128#L135 +dnl TODO: how can recognize that situation and add -Wc,? + AX_APPEND_FLAG([-fsanitize=[]mysan], [LDFLAGS]) +dnl TODO: add -fPIE -pie for memory + # -fno-omit-frame-pointer results in nicer stack traces in error + # messages, see http://clang.llvm.org/docs/AddressSanitizer.html#usage + AX_CHECK_COMPILE_FLAG([-fno-omit-frame-pointer], [ + AX_APPEND_FLAG([-fno-omit-frame-pointer], [])]) +dnl TODO: at least for clang, we should specify exactly -O1, not -O2 or -O0, so that performance is reasonable but stacktraces are not tampered with (due to inlining), see http://clang.llvm.org/docs/AddressSanitizer.html#usage + m4_default([$3], :) + ax_enabled_sanitizers="[]mysan $ax_enabled_sanitizers" + ]) + ]) +]) +])dnl +])dnl AX_SANITIZERS diff --git a/i3lock.pam b/pam/i3lock similarity index 100% rename from i3lock.pam rename to pam/i3lock diff --git a/unlock_indicator.c b/unlock_indicator.c index fd8be65..ef37936 100644 --- a/unlock_indicator.c +++ b/unlock_indicator.c @@ -145,22 +145,22 @@ unlock_state_t unlock_state; auth_state_t auth_state; // color arrays -rgba_t insidever16[4]; -rgba_t insidewrong16[4]; -rgba_t inside16[4]; -rgba_t ringver16[4]; -rgba_t ringwrong16[4]; -rgba_t ring16[4]; -rgba_t line16[4]; -rgba_t text16[4]; -rgba_t layout16[4]; -rgba_t time16[4]; -rgba_t date16[4]; -rgba_t keyhl16[4]; -rgba_t bshl16[4]; -rgba_t sep16[4]; +rgba_t insidever16; +rgba_t insidewrong16; +rgba_t inside16; +rgba_t ringver16; +rgba_t ringwrong16; +rgba_t ring16; +rgba_t line16; +rgba_t text16; +rgba_t layout16; +rgba_t time16; +rgba_t date16; +rgba_t keyhl16; +rgba_t bshl16; +rgba_t sep16; // just rgb -rgb_t rgb16[3]; +rgb_t rgb16; /* * Initialize all the color arrays once. @@ -182,32 +182,32 @@ rgb_t rgb16[3]; (strtol(colorstring_tmparr[3], NULL, 16))}; */ -inline void set_color(char* dest, const char* src, int offset) { +void set_color(char* dest, const char* src, int offset) { dest[0] = src[offset]; dest[1] = src[offset + 1]; dest[2] = '\0'; } -inline void colorgen(rgba_str_t* tmp, const char* src, rgba_t* dest) { +void colorgen(rgba_str_t* tmp, const char* src, rgba_t* dest) { set_color(tmp->red, src, 0); set_color(tmp->green, src, 2); set_color(tmp->blue, src, 4); set_color(tmp->alpha, src, 6); - dest->red = strtol(tmp->red, NULL, 16); - dest->green = strtol(tmp->green, NULL, 16); - dest->blue = strtol(tmp->blue, NULL, 16); - dest->alpha = strtol(tmp->alpha, NULL, 16); + dest->red = strtol(tmp->red, NULL, 16) / 255.0; + dest->green = strtol(tmp->green, NULL, 16) / 255.0; + dest->blue = strtol(tmp->blue, NULL, 16) / 255.0; + dest->alpha = strtol(tmp->alpha, NULL, 16) / 255.0; } -inline void colorgen_rgb(rgb_str_t* tmp, const char* src, rgb_t* dest) { +void colorgen_rgb(rgb_str_t* tmp, const char* src, rgb_t* dest) { set_color(tmp->red, src, 0); set_color(tmp->green, src, 2); set_color(tmp->blue, src, 4); - dest->red = strtol(tmp->red, NULL, 16); - dest->green = strtol(tmp->green, NULL, 16); - dest->blue = strtol(tmp->blue, NULL, 16); + dest->red = strtol(tmp->red, NULL, 16) / 255.0; + dest->green = strtol(tmp->green, NULL, 16) / 255.0; + dest->blue = strtol(tmp->blue, NULL, 16) / 255.0; } void init_colors_once(void) { @@ -215,21 +215,21 @@ void init_colors_once(void) { rgb_str_t tmp_rgb; /* build indicator color arrays */ - colorgen(&tmp, insidevercolor, insidever16); - colorgen(&tmp, insidewrongcolor, insidewrong16); - colorgen(&tmp, insidecolor, inside16); - colorgen(&tmp, ringvercolor, ringver16); - colorgen(&tmp, ringwrongcolor, ringwrong16); - colorgen(&tmp, ringcolor, ring16); - colorgen(&tmp, linecolor, line16); - colorgen(&tmp, textcolor, text16); - colorgen(&tmp, layoutcolor, layout16); - colorgen(&tmp, timecolor, time16); - colorgen(&tmp, datecolor, date16); - colorgen(&tmp, keyhlcolor, keyhl16); - colorgen(&tmp, bshlcolor, bshl16); - colorgen(&tmp, separatorcolor, sep16); - colorgen_rgb(&tmp_rgb, color, rgb16); + colorgen(&tmp, insidevercolor, &insidever16); + colorgen(&tmp, insidewrongcolor, &insidewrong16); + colorgen(&tmp, insidecolor, &inside16); + colorgen(&tmp, ringvercolor, &ringver16); + colorgen(&tmp, ringwrongcolor, &ringwrong16); + colorgen(&tmp, ringcolor, &ring16); + colorgen(&tmp, linecolor, &line16); + colorgen(&tmp, textcolor, &text16); + colorgen(&tmp, layoutcolor, &layout16); + colorgen(&tmp, timecolor, &time16); + colorgen(&tmp, datecolor, &date16); + colorgen(&tmp, keyhlcolor, &keyhl16); + colorgen(&tmp, bshlcolor, &bshl16); + colorgen(&tmp, separatorcolor, &sep16); + colorgen_rgb(&tmp_rgb, color, &rgb16); } /* @@ -238,8 +238,8 @@ void init_colors_once(void) { * */ static double scaling_factor(void) { - const int dpi = (double)screen->height_in_pixels * 25.4 / - (double)screen->height_in_millimeters; + const int dpi = (double) screen->height_in_pixels * 25.4 / + (double) screen->height_in_millimeters; return (dpi / 96.0); } @@ -301,7 +301,7 @@ xcb_pixmap_t draw_image(uint32_t *resolution) { } } } else { - cairo_set_source_rgb(xcb_ctx, rgb16->red / 255.0, rgb16->green / 255.0, rgb16->blue / 255.0); + cairo_set_source_rgb(xcb_ctx, rgb16.red, rgb16.green, rgb16.blue); cairo_rectangle(xcb_ctx, 0, 0, resolution[0], resolution[1]); cairo_fill(xcb_ctx); } @@ -331,14 +331,14 @@ xcb_pixmap_t draw_image(uint32_t *resolution) { switch (auth_state) { case STATE_AUTH_VERIFY: case STATE_AUTH_LOCK: - cairo_set_source_rgba(ctx, (double)insidever16->red/255, (double)insidever16->green/255, (double)insidever16->blue/255, (double)insidever16->alpha/255); + cairo_set_source_rgba(ctx, insidever16.red, insidever16.green, insidever16.blue, insidever16.alpha); break; case STATE_AUTH_WRONG: case STATE_I3LOCK_LOCK_FAILED: - cairo_set_source_rgba(ctx, (double)insidewrong16->red/255, (double)insidewrong16->green/255, (double)insidewrong16->blue/255, (double)insidewrong16->alpha/255); + cairo_set_source_rgba(ctx, insidewrong16.red, insidewrong16.green, insidewrong16.blue, insidewrong16.alpha); break; default: - cairo_set_source_rgba(ctx, (double)inside16->red/255, (double)inside16->green/255, (double)inside16->blue/255, (double)inside16->alpha/255); + cairo_set_source_rgba(ctx, inside16.red, inside16.green, inside16.blue, inside16.alpha); break; } cairo_fill_preserve(ctx); @@ -346,31 +346,31 @@ xcb_pixmap_t draw_image(uint32_t *resolution) { switch (auth_state) { case STATE_AUTH_VERIFY: case STATE_AUTH_LOCK: - cairo_set_source_rgba(ctx, (double)ringver16->red/255, (double)ringver16->green/255, (double)ringver16->blue/255, (double)ringver16->alpha/255); + cairo_set_source_rgba(ctx, ringver16.red, ringver16.green, ringver16.blue, ringver16.alpha); if (internal_line_source == 1) { - line16->red = ringver16->red; - line16->green = ringver16->green; - line16->blue = ringver16->blue; - line16->alpha = ringver16->alpha; + line16.red = ringver16.red; + line16.green = ringver16.green; + line16.blue = ringver16.blue; + line16.alpha = ringver16.alpha; } break; case STATE_AUTH_WRONG: case STATE_I3LOCK_LOCK_FAILED: - cairo_set_source_rgba(ctx, (double)ringwrong16->red/255, (double)ringwrong16->green/255, (double)ringwrong16->blue/255, (double)ringwrong16->alpha/255); + cairo_set_source_rgba(ctx, ringwrong16.red, ringwrong16.green, ringwrong16.blue, ringwrong16.alpha); if (internal_line_source == 1) { - line16->red = ringwrong16->red; - line16->green = ringwrong16->green; - line16->blue = ringwrong16->blue; - line16->alpha = ringwrong16->alpha; + line16.red = ringwrong16.red; + line16.green = ringwrong16.green; + line16.blue = ringwrong16.blue; + line16.alpha = ringwrong16.alpha; } break; case STATE_AUTH_IDLE: - cairo_set_source_rgba(ctx, (double)ring16->red/255, (double)ring16->green/255, (double)ring16->blue/255, (double)ring16->alpha/255); + cairo_set_source_rgba(ctx, ring16.red, ring16.green, ring16.blue, ring16.alpha); if (internal_line_source == 1) { - line16->red = ring16->red; - line16->green = ring16->green; - line16->blue = ring16->blue; - line16->alpha = ring16->alpha; + line16.red = ring16.red; + line16.green = ring16.green; + line16.blue = ring16.blue; + line16.alpha = ring16.alpha; } break; } @@ -378,7 +378,7 @@ xcb_pixmap_t draw_image(uint32_t *resolution) { /* Draw an inner separator line. */ if (internal_line_source != 2) { //pretty sure this only needs drawn if it's being drawn over the inside? - cairo_set_source_rgba(ctx, (double)line16->red/255, (double)line16->green/255, (double)line16->blue/255, (double)line16->alpha/255); + cairo_set_source_rgba(ctx, line16.red, line16.green, line16.blue, line16.alpha); cairo_set_line_width(ctx, 2.0); cairo_arc(ctx, BUTTON_CENTER /* x */, @@ -397,7 +397,7 @@ xcb_pixmap_t draw_image(uint32_t *resolution) { /* We don't want to show more than a 3-digit number. */ char buf[4]; - cairo_set_source_rgba(ctx, (double)text16->red/255, (double)text16->green/255, (double)text16->blue/255, (double)text16->alpha/255); + cairo_set_source_rgba(ctx, text16.red, text16.green, text16.blue, text16.alpha); cairo_select_font_face(ctx, status_font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size(ctx, text_size); @@ -472,17 +472,17 @@ xcb_pixmap_t draw_image(uint32_t *resolution) { highlight_start + (M_PI / 3.0)); if (unlock_state == STATE_KEY_ACTIVE) { /* For normal keys, we use a lighter green. */ //lol no - cairo_set_source_rgba(ctx, (double)keyhl16->red/255, (double)keyhl16->green/255, (double)keyhl16->blue/255, (double)keyhl16->alpha/255); + cairo_set_source_rgba(ctx, keyhl16.red, keyhl16.green, keyhl16.blue, keyhl16.alpha); } else { /* For backspace, we use red. */ //lol no - cairo_set_source_rgba(ctx, (double)bshl16->red/255, (double)bshl16->green/255, (double)bshl16->blue/255, (double)bshl16->alpha/255); + cairo_set_source_rgba(ctx, bshl16.red, bshl16.green, bshl16.blue, bshl16.alpha); } cairo_stroke(ctx); /* Draw two little separators for the highlighted part of the * unlock indicator. */ - cairo_set_source_rgba(ctx, (double)sep16->red/255, (double)sep16->green/255, (double)sep16->blue/255, (double)sep16->alpha/255); + cairo_set_source_rgba(ctx, sep16.red, sep16.green, sep16.blue, sep16.alpha); cairo_arc(ctx, BUTTON_CENTER /* x */, BUTTON_CENTER /* y */, @@ -517,7 +517,7 @@ xcb_pixmap_t draw_image(uint32_t *resolution) { if (text) { cairo_set_font_size(time_ctx, time_size); cairo_select_font_face(time_ctx, time_font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_source_rgba(time_ctx, (double)time16->red/255, (double)time16->green/255, (double)time16->blue/255, (double)time16->alpha/255); + cairo_set_source_rgba(time_ctx, time16.red, time16.green, time16.blue, time16.alpha); cairo_text_extents(time_ctx, text, &extents); switch(time_align) { @@ -542,7 +542,7 @@ xcb_pixmap_t draw_image(uint32_t *resolution) { if (date) { cairo_select_font_face(date_ctx, date_font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_source_rgba(date_ctx, (double)date16->red/255, (double)date16->green/255, (double)date16->blue/255, (double)date16->alpha/255); + cairo_set_source_rgba(date_ctx, date16.red, date16.green, date16.blue, date16.alpha); cairo_set_font_size(date_ctx, date_size); cairo_text_extents(date_ctx, date, &extents); @@ -568,7 +568,7 @@ xcb_pixmap_t draw_image(uint32_t *resolution) { } if (layout_text) { cairo_select_font_face(layout_ctx, layout_font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_source_rgba(layout_ctx, (double)layout16->red/255, (double)layout16->green/255, (double)layout16->blue/255, (double)layout16->alpha/255); + cairo_set_source_rgba(layout_ctx, layout16.red, layout16.green, layout16.blue, layout16.alpha); cairo_set_font_size(layout_ctx, layout_size); cairo_text_extents(layout_ctx, layout_text, &extents); @@ -763,6 +763,15 @@ xcb_pixmap_t draw_image(uint32_t *resolution) { cairo_fill(xcb_ctx); } } + + te_free(te_ind_x_expr); + te_free(te_ind_y_expr); + te_free(te_time_x_expr); + te_free(te_time_y_expr); + te_free(te_date_x_expr); + te_free(te_date_y_expr); + te_free(te_layout_x_expr); + te_free(te_layout_y_expr); cairo_surface_destroy(xcb_output); cairo_surface_destroy(time_output); diff --git a/unlock_indicator.h b/unlock_indicator.h index 7947c3d..b26e4bd 100644 --- a/unlock_indicator.h +++ b/unlock_indicator.h @@ -4,9 +4,9 @@ #include typedef struct rgb { - uint32_t red; - uint32_t green; - uint32_t blue; + double red; + double green; + double blue; } rgb_t; typedef struct rgb_str { @@ -16,10 +16,10 @@ typedef struct rgb_str { } rgb_str_t; typedef struct rgba { - uint32_t red; - uint32_t green; - uint32_t blue; - uint32_t alpha; + double red; + double green; + double blue; + double alpha; } rgba_t; typedef struct rgba_str { From ef9d84128fca260b63806107368f9e081147da52 Mon Sep 17 00:00:00 2001 From: Chris Guillott Date: Tue, 5 Dec 2017 13:27:43 -0500 Subject: [PATCH 09/18] fix some leaks; update lock.sh --- i3lock.c | 10 ++++++++-- lock.sh | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/i3lock.c b/i3lock.c index 0e5ad88..5f39b31 100644 --- a/i3lock.c +++ b/i3lock.c @@ -216,11 +216,15 @@ char* get_keylayoutname(int mode) { if (XkbGetNames(display, XkbGroupNamesMask, keyboard) != Success ) { DEBUG("Error obtaining symbolic names"); + XCloseDisplay(display); + XkbFreeClientMap(keyboard, 0, true); return NULL; } if(XkbGetState(display, XkbUseCoreKbd, &state) != Success) { DEBUG("Error getting keyboard state"); + XCloseDisplay(display); + XkbFreeClientMap(keyboard, 0, true); return NULL; } @@ -258,10 +262,12 @@ char* get_keylayoutname(int mode) { default: break; } + // note: this is called in option parsing, so this debug() may not trigger unless --debug is the first option DEBUG("answer after mode parsing: [%s]\n", answer); // Free symbolic names structures - XkbFreeNames(keyboard, XkbGroupNamesMask, True); - // note: this is called in option parsing, so this debug() may not trigger unless --debug is the first option + XkbFreeClientMap(keyboard, 0, true); + XCloseDisplay(display); + display = NULL; return answer; } diff --git a/lock.sh b/lock.sh index 82a82c2..cd42316 100755 --- a/lock.sh +++ b/lock.sh @@ -7,7 +7,7 @@ T='#ee00eeee' # text W='#880000bb' # wrong V='#bb00bbbb' # verifying -./i3lock \ +./x86_64-pc-linux-gnu/i3lock \ --insidevercolor=$C \ --ringvercolor=$V \ \ From 8946358b26e5b6e19ee4a46fbc6859b8ebd5db4c Mon Sep 17 00:00:00 2001 From: Chris Guillott Date: Tue, 5 Dec 2017 14:27:52 -0500 Subject: [PATCH 10/18] revert to former implementation with array size fix --- blur.h | 2 +- blur_simd.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/blur.h b/blur.h index 2c42fd5..dfc1c3d 100644 --- a/blur.h +++ b/blur.h @@ -4,7 +4,7 @@ #include #include -#define KERNEL_SIZE 8 +#define KERNEL_SIZE 7 #define SIGMA_AV 2 #define HALF_KERNEL KERNEL_SIZE / 2 diff --git a/blur_simd.c b/blur_simd.c index 48c3fba..80cfd05 100644 --- a/blur_simd.c +++ b/blur_simd.c @@ -27,7 +27,7 @@ void blur_impl_horizontal_pass_sse2(uint32_t *src, uint32_t *dst, int width, int int leftBorder = column < HALF_KERNEL; int rightBorder = column > (width - HALF_KERNEL); // +1 to make memory checkers not complain - uint32_t _rgbaIn[KERNEL_SIZE] __attribute__((aligned(16))); + uint32_t _rgbaIn[KERNEL_SIZE + 1] __attribute__((aligned(16))); int i = 0; if (leftBorder) { // for kernel size 8x8 and column == 0, we have: @@ -51,7 +51,7 @@ void blur_impl_horizontal_pass_sse2(uint32_t *src, uint32_t *dst, int width, int rgbaIn[k] = _mm_load_si128((__m128i*)(_rgbaIn + 4*k)); } else { for (int k = 0; k < REGISTERS_CNT; k++) { - printf("\t\tk: %d\n", k); + printf("\t\tk: %d %p\n", k, src); rgbaIn[k] = _mm_load_si128((__m128i*)(src + 4*k - HALF_KERNEL)); } } From 9f8496441c777849c31d2a3965dc5168de5fe68b Mon Sep 17 00:00:00 2001 From: Chris Guillott Date: Tue, 5 Dec 2017 22:07:38 -0500 Subject: [PATCH 11/18] blurring stuff should work perfectly fine now --- blur.c | 16 +++++++++------- blur_simd.c | 23 ++++++++++++++++++++--- configure.ac | 4 ++-- m4/ax_check_enable_debug.m4 | 10 +++++----- m4/ax_code_coverage.m4 | 4 ++-- 5 files changed, 38 insertions(+), 19 deletions(-) diff --git a/blur.c b/blur.c index 94ff42a..b91ffe6 100644 --- a/blur.c +++ b/blur.c @@ -32,7 +32,6 @@ blur_image_surface (cairo_surface_t *surface, int radius) { cairo_surface_t *tmp; int width, height; -// int src_stride, dst_stride; uint32_t *src, *dst; if (cairo_surface_status (surface)) @@ -64,15 +63,18 @@ blur_image_surface (cairo_surface_t *surface, int radius) return; src = (uint32_t*)cairo_image_surface_get_data (surface); -// src_stride = cairo_image_surface_get_stride (surface); dst = (uint32_t*)cairo_image_surface_get_data (tmp); -// dst_stride = cairo_image_surface_get_stride (tmp); - - //blur_impl_naive(src, dst, width, height, src_stride, dst_stride, 10000); - //blur_impl_sse2(src, dst, width, height, 4.5); + +#ifdef __SSE4_1__ blur_impl_ssse3(src, dst, width, height, 4.5); - +#elif __SSE2__ + blur_impl_sse2(src, dst, width, height, 4.5); +#else + int src_stride = cairo_image_surface_get_stride (surface); + int dst_stride = cairo_image_surface_get_stride (tmp); + blur_impl_naive(src, dst, width, height, src_stride, dst_stride, 10000); +#endif cairo_surface_destroy (tmp); cairo_surface_flush (surface); cairo_surface_mark_dirty (surface); diff --git a/blur_simd.c b/blur_simd.c index 52954ed..9ee4abd 100644 --- a/blur_simd.c +++ b/blur_simd.c @@ -51,6 +51,7 @@ void blur_impl_sse2(uint32_t *src, uint32_t *dst, int width, int height, float s } void blur_impl_horizontal_pass_sse2(uint32_t *src, uint32_t *dst, float *kernel, int width, int height) { + uint32_t* o_src = src; for (int row = 0; row < height; row++) { for (int column = 0; column < width; column++, src++) { __m128i rgbaIn[REGISTERS_CNT]; @@ -59,7 +60,7 @@ void blur_impl_horizontal_pass_sse2(uint32_t *src, uint32_t *dst, float *kernel, int leftBorder = column < HALF_KERNEL; int rightBorder = column > width - HALF_KERNEL; if (leftBorder || rightBorder) { - uint32_t _rgbaIn[KERNEL_SIZE] ALIGN16; + uint32_t _rgbaIn[KERNEL_SIZE + 1] ALIGN16; int i = 0; if (leftBorder) { // for kernel size 7x7 and column == 0, we have: @@ -80,8 +81,22 @@ void blur_impl_horizontal_pass_sse2(uint32_t *src, uint32_t *dst, float *kernel, for (int k = 0; k < REGISTERS_CNT; k++) rgbaIn[k] = _mm_load_si128((__m128i*)(_rgbaIn + 4*k)); } else { - for (int k = 0; k < REGISTERS_CNT; k++) + for (int k = 0; k < REGISTERS_CNT; k++) { +#if 0 + printf("%p -> %p (%ld) || %p->%p\n", + o_src, + o_src + (height * width), + o_src + (height * width) - src, + src + 4*k - HALF_KERNEL, + ((__m128i*)src + 4*k - HALF_KERNEL) + 1 + ); +#endif + // if this copy would go out of bounds, break + if ((long long) (((__m128i*) src + 4*k - HALF_KERNEL) + 1) + > (long long) (o_src + (height * width))) + break; rgbaIn[k] = _mm_loadu_si128((__m128i*)(src + 4*k - HALF_KERNEL)); + } } // unpack each pixel, convert to float, @@ -198,7 +213,9 @@ void blur_impl_horizontal_pass_ssse3(uint32_t *src, uint32_t *dst, int8_t *kerne } } else { for (int k = 0; k < REGISTERS_CNT; k++) { - if ((long long)(((__m128i*) src + 4*k - HALF_KERNEL) + 1) > (long long)((o_src + (width * height)))) break; + if ((long long) (((__m128i*) src + 4*k - HALF_KERNEL) + 1) + > (long long) (o_src + (height * width))) + break; #if 0 printf("K: %d; p: %p -> %p\n", k, src+4*k - HALF_KERNEL, ((__m128i*) (src +4*k - HALF_KERNEL)) + 1); printf("%p->%p, %p->%p (%ld)\n", (__m128i*) src + 4*k - HALF_KERNEL, ((__m128i*) src + 4*k - HALF_KERNEL) + 1, o_src, o_src + (width * height), o_src + (width * height) - src); diff --git a/configure.ac b/configure.ac index 319a6bf..0ae5567 100644 --- a/configure.ac +++ b/configure.ac @@ -101,8 +101,8 @@ AC_PROG_LN_S AM_PROG_AR AX_FLAGS_WARN_ALL -AX_APPEND_FLAG([-msse4.1], [AM_CFLAGS]) -AX_APPEND_FLAG([-O2], [AM_CFLAGS]) +AX_APPEND_FLAG([-march=native], [AM_CFLAGS]) + AX_APPEND_FLAG([-O2], [AM_CFLAGS]) AX_APPEND_FLAG([-funroll-loops], [AM_CFLAGS]) AX_APPEND_FLAG([-std=gnu99], [AM_CFLAGS]) AX_CHECK_COMPILE_FLAG([-Wunused-value], [AX_APPEND_FLAG([-Wunused-value], [AM_CFLAGS])]) diff --git a/m4/ax_check_enable_debug.m4 b/m4/ax_check_enable_debug.m4 index 56c9fc1..f99d75f 100644 --- a/m4/ax_check_enable_debug.m4 +++ b/m4/ax_check_enable_debug.m4 @@ -76,11 +76,11 @@ AC_DEFUN([AX_CHECK_ENABLE_DEBUG],[ AS_CASE([$enable_debug], [yes],[ AC_MSG_RESULT(yes) - CFLAGS="${CFLAGS} -g -O2" - CXXFLAGS="${CXXFLAGS} -g -O2" - FFLAGS="${FFLAGS} -g -O2" - FCFLAGS="${FCFLAGS} -g -O2" - OBJCFLAGS="${OBJCFLAGS} -g -O2" + CFLAGS="${CFLAGS} -g -O0" + CXXFLAGS="${CXXFLAGS} -g -O0" + FFLAGS="${FFLAGS} -g -O0" + FCFLAGS="${FCFLAGS} -g -O0" + OBJCFLAGS="${OBJCFLAGS} -g -O0" ], [info],[ AC_MSG_RESULT(info) diff --git a/m4/ax_code_coverage.m4 b/m4/ax_code_coverage.m4 index eebf062..6c985eb 100644 --- a/m4/ax_code_coverage.m4 +++ b/m4/ax_code_coverage.m4 @@ -141,8 +141,8 @@ AC_DEFUN([AX_CODE_COVERAGE],[ dnl Build the code coverage flags CODE_COVERAGE_CPPFLAGS="-DNDEBUG" - CODE_COVERAGE_CFLAGS="-O2 -g -fprofile-arcs -ftest-coverage" - CODE_COVERAGE_CXXFLAGS="-O2 -g -fprofile-arcs -ftest-coverage" + CODE_COVERAGE_CFLAGS="-O0 -g -fprofile-arcs -ftest-coverage" + CODE_COVERAGE_CXXFLAGS="-O0 -g -fprofile-arcs -ftest-coverage" CODE_COVERAGE_LDFLAGS="-lgcov" AC_SUBST([CODE_COVERAGE_CPPFLAGS]) From b0056a5907876ab276dce9359db797560a73e618 Mon Sep 17 00:00:00 2001 From: Pandora Date: Tue, 5 Dec 2017 22:34:30 -0500 Subject: [PATCH 12/18] tweak configure script so that aur builds will be nicer to deal with --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 0ae5567..15706c9 100644 --- a/configure.ac +++ b/configure.ac @@ -34,7 +34,7 @@ AS_IF([test -d ${srcdir}/.git], VERSION="$(git -C ${srcdir} describe --tags --abbrev=0)" I3LOCK_VERSION="$(git -C ${srcdir} describe --tags --always) ($(git -C ${srcdir} log --pretty=format:%cd --date=short -n1), branch \\\"$(git -C ${srcdir} describe --tags --always --all | sed s:heads/::)\\\")" # Mirrors what libi3/is_debug_build.c does: - is_release=$(test $(echo "${I3LOCK_VERSION}" | cut -d '(' -f 1 | wc -m) -lt 11 && echo yes || echo no) + is_release=$(test $(echo "${I3LOCK_VERSION}" | cut -d '(' -f 1 | wc -m) -lt 12 && echo yes || echo no) ], [ VERSION="$(cut -d '-' -f 1 ${srcdir}/I3LOCK_VERSION | cut -d ' ' -f 1)" From 613e9cb66df0349c86ef2bf6f47c6e08e27d9852 Mon Sep 17 00:00:00 2001 From: Pandora Date: Wed, 6 Dec 2017 12:25:04 -0500 Subject: [PATCH 13/18] fix SSE version check --- blur.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blur.c b/blur.c index b91ffe6..7509f3e 100644 --- a/blur.c +++ b/blur.c @@ -66,7 +66,7 @@ blur_image_surface (cairo_surface_t *surface, int radius) dst = (uint32_t*)cairo_image_surface_get_data (tmp); -#ifdef __SSE4_1__ +#ifdef __SSE3__ blur_impl_ssse3(src, dst, width, height, 4.5); #elif __SSE2__ blur_impl_sse2(src, dst, width, height, 4.5); From 6c7ab082c674c02236e0c462872b9b94bfa5ab9d Mon Sep 17 00:00:00 2001 From: Pandora Date: Wed, 6 Dec 2017 13:05:33 -0500 Subject: [PATCH 14/18] fix release checking to play nicely with AUR builds --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 15706c9..5efbfcd 100644 --- a/configure.ac +++ b/configure.ac @@ -34,7 +34,7 @@ AS_IF([test -d ${srcdir}/.git], VERSION="$(git -C ${srcdir} describe --tags --abbrev=0)" I3LOCK_VERSION="$(git -C ${srcdir} describe --tags --always) ($(git -C ${srcdir} log --pretty=format:%cd --date=short -n1), branch \\\"$(git -C ${srcdir} describe --tags --always --all | sed s:heads/::)\\\")" # Mirrors what libi3/is_debug_build.c does: - is_release=$(test $(echo "${I3LOCK_VERSION}" | cut -d '(' -f 1 | wc -m) -lt 12 && echo yes || echo no) + is_release=$(test $(echo "${I3LOCK_VERSION}" | cut -d ' ' -f 1 | wc -m) -lt 13 && echo yes || echo no) ], [ VERSION="$(cut -d '-' -f 1 ${srcdir}/I3LOCK_VERSION | cut -d ' ' -f 1)" From 345195a3ef2cefd2f3109fbe68cac783554f88b9 Mon Sep 17 00:00:00 2001 From: Pandora Date: Wed, 6 Dec 2017 13:19:34 -0500 Subject: [PATCH 15/18] update readme; fix version number --- I3LOCK_VERSION | 2 +- README.md | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/I3LOCK_VERSION b/I3LOCK_VERSION index 1c9698b..39c5a31 100644 --- a/I3LOCK_VERSION +++ b/I3LOCK_VERSION @@ -1 +1 @@ -2.10.1-color-non-git +2.10.1c-non-git diff --git a/README.md b/README.md index 78b07ca..9d6064e 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ Before you build - check and see if there's a packaged version available for you If there's no packaged version available - think carefully, since you're using a forked screen locker at your own risk. -If you don't understand what makefiles are and how they work, start reading [here](http://www.tldp.org/HOWTO/Software-Building-HOWTO-3.html). If you're building from source - make sure you're keeping up to date. +i3lock now uses GNU autotools for building; you'll need to do something like `autoreconf -i && ./configure && make` to build. ### Required Packages - pkg-config @@ -98,10 +98,9 @@ If you don't understand what makefiles are and how they work, start reading [her sudo apt-get install pkg-config libxcb1 libpam-dev libcairo-dev libxcb-composite0 libxcb-composite0-dev libxcb-xinerama0-dev libev-dev libx11-dev libx11-xcb-dev libxkbcommon0 libxkbcommon-x11-0 libxcb-dpms0-dev libxcb-image0-dev libxcb-util0-dev libxcb-xkb-dev libxkbcommon-x11-dev libxkbcommon-dev ##### Aur Package -Stable: -https://aur.archlinux.org/packages/i3lock-color/ -Git: -https://aur.archlinux.org/packages/i3lock-color-git +[Stable](https://aur.archlinux.org/packages/i3lock-color/) + +[Git](https://aur.archlinux.org/packages/i3lock-color-git) Running i3lock ------------- From 2040285ce94949e91d4df57973ecaded59db45d2 Mon Sep 17 00:00:00 2001 From: Pandora Date: Wed, 6 Dec 2017 13:57:07 -0500 Subject: [PATCH 16/18] revert back to better blurring behaviour --- blur.c | 159 ++++++++++++++--------------- blur.h | 14 +-- blur_simd.c | 276 +++++++-------------------------------------------- configure.ac | 4 +- 4 files changed, 119 insertions(+), 334 deletions(-) diff --git a/blur.c b/blur.c index 7509f3e..737ece1 100644 --- a/blur.c +++ b/blur.c @@ -1,6 +1,6 @@ /* - * Copyright © 2008 Kristian Høgsberg - * Copyright © 2009 Chris Wilson + * Copyright © 2008 Kristian Høgsberg + * Copyright © 2009 Chris Wilson * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -23,12 +23,9 @@ #include #include "blur.h" - -#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) - -/* Performs a simple 2D Gaussian blur of radius @radius on surface @surface. */ +/* Performs a simple 2D Gaussian blur of standard devation @sigma surface @surface. */ void -blur_image_surface (cairo_surface_t *surface, int radius) +blur_image_surface (cairo_surface_t *surface, int sigma) { cairo_surface_t *tmp; int width, height; @@ -63,92 +60,86 @@ blur_image_surface (cairo_surface_t *surface, int radius) return; src = (uint32_t*)cairo_image_surface_get_data (surface); - dst = (uint32_t*)cairo_image_surface_get_data (tmp); - -#ifdef __SSE3__ - blur_impl_ssse3(src, dst, width, height, 4.5); -#elif __SSE2__ - blur_impl_sse2(src, dst, width, height, 4.5); + + // according to a paper by Peter Kovesi [1], box filter of width w, equals to Gaussian blur of following sigma: + // σ_av = sqrt((w*w-1)/12) + // for our 7x7 filter we have σ_av = 2.0. + // applying the same Gaussian filter n times results in σ_n = sqrt(n*σ_av*σ_av) [2] + // after some trivial math, we arrive at n = ((σ_d)/(σ_av))^2 + // since it's a box blur filter, n >= 3 + // + // [1]: http://www.peterkovesi.com/papers/FastGaussianSmoothing.pdf + // [2]: https://en.wikipedia.org/wiki/Gaussian_blur#Mathematics + + int n = lrintf((sigma*sigma)/(SIGMA_AV*SIGMA_AV)); + if (n < 3) n = 3; + + for (int i = 0; i < n; i++) + { + // horizontal pass includes image transposition: + // instead of writing pixel src[x] to dst[x], + // we write it to transposed location. + // (to be exact: dst[height * current_column + current_row]) +#ifdef __SSE2__ + blur_impl_horizontal_pass_sse2(src, dst, width, height); + blur_impl_horizontal_pass_sse2(dst, src, height, width); #else - int src_stride = cairo_image_surface_get_stride (surface); - int dst_stride = cairo_image_surface_get_stride (tmp); - blur_impl_naive(src, dst, width, height, src_stride, dst_stride, 10000); + blur_impl_horizontal_pass_generic(src, dst, width, height); + blur_impl_horizontal_pass_generic(dst, src, height, width); #endif + } + cairo_surface_destroy (tmp); cairo_surface_flush (surface); cairo_surface_mark_dirty (surface); } -void blur_impl_naive(uint32_t* _src, uint32_t* _dst, int width, int height, int src_stride, int dst_stride, int radius) -{ - int x, y, z, w; - uint32_t *s, *d, a, p; - int i, j, k; - uint8_t kernel[17]; - const int size = ARRAY_LENGTH (kernel); - const int half = size / 2; - - uint8_t *src = (uint8_t*)_src; - uint8_t *dst = (uint8_t*)_dst; - - a = 0; - for (i = 0; i < size; i++) { - double f = i - half; - a += kernel[i] = exp (- f * f / 30.0) * 80; - } - - /* Horizontally blur from surface -> tmp */ - for (i = 0; i < height; i++) { - s = (uint32_t *) (src + i * src_stride); - d = (uint32_t *) (dst + i * dst_stride); - for (j = 0; j < width; j++) { - if (radius < j && j < width - radius) { - d[j] = s[j]; - continue; - } - - x = y = z = w = 0; - for (k = 0; k < size; k++) { - if (j - half + k < 0 || j - half + k >= width) - continue; - - p = s[j - half + k]; - - x += ((p >> 24) & 0xff) * kernel[k]; - y += ((p >> 16) & 0xff) * kernel[k]; - z += ((p >> 8) & 0xff) * kernel[k]; - w += ((p >> 0) & 0xff) * kernel[k]; - } - d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a; - } - } - - /* Then vertically blur from tmp -> surface */ - for (i = 0; i < height; i++) { - s = (uint32_t *) (dst + i * dst_stride); - d = (uint32_t *) (src + i * src_stride); - for (j = 0; j < width; j++) { - if (radius <= i && i < height - radius) { - d[j] = s[j]; - continue; +void blur_impl_horizontal_pass_generic(uint32_t *src, uint32_t *dst, int width, int height) { + for (int row = 0; row < height; row++) { + for (int column = 0; column < width; column++, src++) { + uint32_t rgbaIn[KERNEL_SIZE]; + + // handle borders + int leftBorder = column < HALF_KERNEL; + int rightBorder = column > width - HALF_KERNEL; + int i = 0; + if (leftBorder) { + // for kernel size 7x7 and column == 0, we have: + // x x x P0 P1 P2 P3 + // first loop mirrors P{0..3} to fill x's, + // second one loads P{0..3} + for (; i < HALF_KERNEL - column; i++) + rgbaIn[i] = *(src + (HALF_KERNEL - i)); + for (; i < KERNEL_SIZE; i++) + rgbaIn[i] = *(src - (HALF_KERNEL - i)); + } else if (rightBorder) { + for (; i < width - column; i++) + rgbaIn[i] = *(src + i); + for (int k = 0; i < KERNEL_SIZE; i++, k++) + rgbaIn[i] = *(src - k); + } else { + for (; i < KERNEL_SIZE; i++) + rgbaIn[i] = *(src + i - HALF_KERNEL); + } + + uint32_t acc[4] = {0}; + + for (i = 0; i < KERNEL_SIZE; i++) { + acc[0] += (rgbaIn[i] & 0xFF000000) >> 24; + acc[1] += (rgbaIn[i] & 0x00FF0000) >> 16; + acc[2] += (rgbaIn[i] & 0x0000FF00) >> 8; + acc[3] += (rgbaIn[i] & 0x000000FF) >> 0; + } + + for(i = 0; i < 4; i++) + acc[i] *= 1.0/KERNEL_SIZE; + + *(dst + height * column + row) = (acc[0] << 24) | + (acc[1] << 16) | + (acc[2] << 8 ) | + (acc[3] << 0); } - - x = y = z = w = 0; - for (k = 0; k < size; k++) { - if (i - half + k < 0 || i - half + k >= height) - continue; - - s = (uint32_t *) (dst + (i - half + k) * dst_stride); - p = s[j]; - - x += ((p >> 24) & 0xff) * kernel[k]; - y += ((p >> 16) & 0xff) * kernel[k]; - z += ((p >> 8) & 0xff) * kernel[k]; - w += ((p >> 0) & 0xff) * kernel[k]; - } - d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a; - } } } diff --git a/blur.h b/blur.h index 478e2f0..fd93853 100644 --- a/blur.h +++ b/blur.h @@ -4,12 +4,14 @@ #include #include -void blur_image_surface (cairo_surface_t *surface, int radius); -void blur_impl_naive(uint32_t* src, uint32_t* dst, int width, int height, int src_stride, int dst_stride, int radius); -void blur_impl_sse2(uint32_t* src, uint32_t* dst, int width, int height, float sigma); -void blur_impl_horizontal_pass_sse2(uint32_t *src, uint32_t *dst, float *kernel, int width, int height); -void blur_impl_ssse3(uint32_t* src, uint32_t* dst, int width, int height, float sigma); -void blur_impl_horizontal_pass_ssse3(uint32_t *src, uint32_t *dst, int8_t *kernel, int width, int height); +#define KERNEL_SIZE 7 +#define SIGMA_AV 2 +#define HALF_KERNEL KERNEL_SIZE / 2 + +void blur_image_surface(cairo_surface_t *surface, int sigma); +void blur_impl_horizontal_pass_sse2(uint32_t *src, uint32_t *dst, int width, int height); +void blur_impl_horizontal_pass_generic(uint32_t *src, uint32_t *dst, int width, int height); #endif + diff --git a/blur_simd.c b/blur_simd.c index 9ee4abd..92aca9f 100644 --- a/blur_simd.c +++ b/blur_simd.c @@ -1,56 +1,19 @@ /* * vim:ts=4:sw=4:expandtab * - * © 2016 Sebastian Frysztak + * © 2016 Sebastian Frysztak * * See LICENSE for licensing information * */ #include "blur.h" -#include #include -#include -#include - -#define ALIGN16 __attribute__((aligned(16))) -#define KERNEL_SIZE 15 -#define HALF_KERNEL KERNEL_SIZE / 2 - -// number of xmm registers needed to store -// input pixels for given kernel size +// number of xmm registers needed to store input pixels for given kernel size #define REGISTERS_CNT (KERNEL_SIZE + 4/2) / 4 -// scaling factor for kernel coefficients. -// higher values cause desaturation. -// used in SSSE3 implementation. -#define SCALE_FACTOR 7 - -void blur_impl_sse2(uint32_t *src, uint32_t *dst, int width, int height, float sigma) { - // prepare kernel - float kernel[KERNEL_SIZE]; - float coeff = 1.0 / sqrtf(2 * M_PI * sigma * sigma), sum = 0; - - for (int i = 0; i < KERNEL_SIZE; i++) { - float x = HALF_KERNEL - i; - kernel[i] = coeff * expf(-x * x / (2.0 * sigma * sigma)); - sum += kernel[i]; - } - - // normalize kernel - for (int i = 0; i < KERNEL_SIZE; i++) - kernel[i] /= sum; - - // horizontal pass includes image transposition: - // instead of writing pixel src[x] to dst[x], - // we write it to transposed location. - // (to be exact: dst[height * current_column + current_row]) - blur_impl_horizontal_pass_sse2(src, dst, kernel, width, height); - blur_impl_horizontal_pass_sse2(dst, src, kernel, height, width); -} - -void blur_impl_horizontal_pass_sse2(uint32_t *src, uint32_t *dst, float *kernel, int width, int height) { +void blur_impl_horizontal_pass_sse2(uint32_t *src, uint32_t *dst, int width, int height) { uint32_t* o_src = src; for (int row = 0; row < height; row++) { for (int column = 0; column < width; column++, src++) { @@ -59,227 +22,58 @@ void blur_impl_horizontal_pass_sse2(uint32_t *src, uint32_t *dst, float *kernel, // handle borders int leftBorder = column < HALF_KERNEL; int rightBorder = column > width - HALF_KERNEL; - if (leftBorder || rightBorder) { - uint32_t _rgbaIn[KERNEL_SIZE + 1] ALIGN16; - int i = 0; - if (leftBorder) { - // for kernel size 7x7 and column == 0, we have: - // x x x P0 P1 P2 P3 - // first loop mirrors P{0..3} to fill x's, - // second one loads P{0..3} - for (; i < HALF_KERNEL - column; i++) - _rgbaIn[i] = *(src + (HALF_KERNEL - i)); - for (; i < KERNEL_SIZE; i++) - _rgbaIn[i] = *(src - (HALF_KERNEL - i)); - } else { - for (; i < width - column; i++) - _rgbaIn[i] = *(src + i); - for (int k = 0; i < KERNEL_SIZE; i++, k++) - _rgbaIn[i] = *(src - k); - } + uint32_t _rgbaIn[KERNEL_SIZE + 1] __attribute__((aligned(16))); + int i = 0; + if (leftBorder) { + // for kernel size 7x7 and column == 0, we have: + // x x x P0 P1 P2 P3 + // first loop mirrors P{0..3} to fill x's, + // second one loads P{0..3} + for (; i < HALF_KERNEL - column; i++) + _rgbaIn[i] = *(src + (HALF_KERNEL - i)); + for (; i < KERNEL_SIZE; i++) + _rgbaIn[i] = *(src - (HALF_KERNEL - i)); for (int k = 0; k < REGISTERS_CNT; k++) rgbaIn[k] = _mm_load_si128((__m128i*)(_rgbaIn + 4*k)); - } else { - for (int k = 0; k < REGISTERS_CNT; k++) { -#if 0 - printf("%p -> %p (%ld) || %p->%p\n", - o_src, - o_src + (height * width), - o_src + (height * width) - src, - src + 4*k - HALF_KERNEL, - ((__m128i*)src + 4*k - HALF_KERNEL) + 1 - ); -#endif - // if this copy would go out of bounds, break - if ((long long) (((__m128i*) src + 4*k - HALF_KERNEL) + 1) - > (long long) (o_src + (height * width))) - break; - rgbaIn[k] = _mm_loadu_si128((__m128i*)(src + 4*k - HALF_KERNEL)); - } - } - - // unpack each pixel, convert to float, - // multiply by corresponding kernel value - // and add to accumulator - __m128i tmp; - __m128i zero = _mm_setzero_si128(); - __m128 rgba_ps; - __m128 acc = _mm_setzero_ps(); - int counter = 0; - - for (int i = 0; i < 3; i++) - { - tmp = _mm_unpacklo_epi8(rgbaIn[i], zero); - rgba_ps = _mm_cvtepi32_ps(_mm_unpacklo_epi16(tmp, zero)); - acc = _mm_add_ps(acc, _mm_mul_ps(rgba_ps, _mm_set1_ps(kernel[counter++]))); - rgba_ps = _mm_cvtepi32_ps(_mm_unpackhi_epi16(tmp, zero)); - acc = _mm_add_ps(acc, _mm_mul_ps(rgba_ps, _mm_set1_ps(kernel[counter++]))); - - tmp = _mm_unpackhi_epi8(rgbaIn[i], zero); - rgba_ps = _mm_cvtepi32_ps(_mm_unpacklo_epi16(tmp, zero)); - acc = _mm_add_ps(acc, _mm_mul_ps(rgba_ps, _mm_set1_ps(kernel[counter++]))); - rgba_ps = _mm_cvtepi32_ps(_mm_unpackhi_epi16(tmp, zero)); - acc = _mm_add_ps(acc, _mm_mul_ps(rgba_ps, _mm_set1_ps(kernel[counter++]))); - } - - tmp = _mm_unpacklo_epi8(rgbaIn[3], zero); - rgba_ps = _mm_cvtepi32_ps(_mm_unpacklo_epi16(tmp, zero)); - acc = _mm_add_ps(acc, _mm_mul_ps(rgba_ps, _mm_set1_ps(kernel[counter++]))); - rgba_ps = _mm_cvtepi32_ps(_mm_unpackhi_epi16(tmp, zero)); - acc = _mm_add_ps(acc, _mm_mul_ps(rgba_ps, _mm_set1_ps(kernel[counter++]))); - - tmp = _mm_unpackhi_epi8(rgbaIn[3], zero); - rgba_ps = _mm_cvtepi32_ps(_mm_unpacklo_epi16(tmp, zero)); - acc = _mm_add_ps(acc, _mm_mul_ps(rgba_ps, _mm_set1_ps(kernel[counter++]))); - - __m128i rgbaOut = _mm_cvtps_epi32(acc); - rgbaOut = _mm_packs_epi32(rgbaOut, zero); - rgbaOut = _mm_packus_epi16(rgbaOut, zero); - *(dst + height * column + row) = _mm_cvtsi128_si32(rgbaOut); - } - } -} + } else if (rightBorder) { + for (; i < width - column; i++) + _rgbaIn[i] = *(src + i); + for (int k = 0; i < KERNEL_SIZE; i++, k++) + _rgbaIn[i] = *(src - k); -void blur_impl_ssse3(uint32_t *src, uint32_t *dst, int width, int height, float sigma) { - // prepare kernel - float kernelf[KERNEL_SIZE]; - int8_t kernel[KERNEL_SIZE + 1]; - float coeff = 1.0 / sqrtf(2 * M_PI * sigma * sigma), sum = 0; - - for (int i = 0; i < KERNEL_SIZE; i++) { - float x = HALF_KERNEL - i; - kernelf[i] = coeff * expf(-x * x / (2.0 * sigma * sigma)); - sum += kernelf[i]; - } - - // normalize kernel - for (int i = 0; i < KERNEL_SIZE; i++) - kernelf[i] /= sum; - - // round to nearest integer and convert to int - for (int i = 0; i < KERNEL_SIZE; i++) - kernel[i] = (int8_t)rintf(kernelf[i] * (1 << SCALE_FACTOR)); - kernel[KERNEL_SIZE] = 0; - - // horizontal pass includes image transposition: - // instead of writing pixel src[x] to dst[x], - // we write it to transposed location. - // (to be exact: dst[height * current_column + current_row]) - blur_impl_horizontal_pass_ssse3(src, dst, kernel, width, height); - blur_impl_horizontal_pass_ssse3(dst, src, kernel, height, width); -} - - -void blur_impl_horizontal_pass_ssse3(uint32_t *src, uint32_t *dst, int8_t *kernel, int width, int height) { - uint32_t* o_src = src; - __m128i _kern = _mm_loadu_si128((__m128i*)kernel); - __m128i rgbaIn[REGISTERS_CNT]; - - for (int row = 0; row < height; row++) { - for (int column = 0; column < width; column++, src++) { - uint32_t _rgbaIn[KERNEL_SIZE + 1] ALIGN16; -#if 0 - for (int j = 0; j < KERNEL_SIZE; ++j) { - printf("_rgbaIn[%d]: %p->%p\n", j, &_rgbaIn[j], &_rgbaIn[j] + 1); - } -#endif - // handle borders - int leftBorder = column < HALF_KERNEL; - int rightBorder = column > width - HALF_KERNEL; - if (leftBorder || rightBorder) { - int i = 0; - if (leftBorder) { - // for kernel size 7x7 and column == 0, we have: - // x x x P0 P1 P2 P3 - // first loop mirrors P{0..3} to fill x's, - // second one loads P{0..3} - for (; i < HALF_KERNEL - column; i++) - _rgbaIn[i] = *(src + (HALF_KERNEL - i)); - for (; i < KERNEL_SIZE; i++) - _rgbaIn[i] = *(src - (HALF_KERNEL - i)); - } else { - for (; i < width - column; i++) - _rgbaIn[i] = *(src + i); - for (int k = 0; i < KERNEL_SIZE; i++, k++) - _rgbaIn[i] = *(src - k); - } - - for (int k = 0; k < REGISTERS_CNT; k++) { -#if 0 - printf("K: %d; p: %p, p+4*k: %p, end of p: %p\n", k, _rgbaIn, _rgbaIn+4*k, ((__m128i*) (_rgbaIn +4*k)) + 1); -#endif + for (int k = 0; k < REGISTERS_CNT; k++) rgbaIn[k] = _mm_load_si128((__m128i*)(_rgbaIn + 4*k)); - } } else { for (int k = 0; k < REGISTERS_CNT; k++) { - if ((long long) (((__m128i*) src + 4*k - HALF_KERNEL) + 1) + if ((long long) (((__m128i*) src + 4*k - HALF_KERNEL) + 1) > (long long) (o_src + (height * width))) break; -#if 0 - printf("K: %d; p: %p -> %p\n", k, src+4*k - HALF_KERNEL, ((__m128i*) (src +4*k - HALF_KERNEL)) + 1); - printf("%p->%p, %p->%p (%ld)\n", (__m128i*) src + 4*k - HALF_KERNEL, ((__m128i*) src + 4*k - HALF_KERNEL) + 1, o_src, o_src + (width * height), o_src + (width * height) - src); -#endif rgbaIn[k] = _mm_loadu_si128((__m128i*)(src + 4*k - HALF_KERNEL)); } } - // basis of this implementation is _mm_maddubs_epi16 (aka pmaddubsw). - // 'rgba' holds 16 unsigned bytes, so 4 pixels. - // 'kern' holds 16 signed bytes kernel values multiplied by (1 << SCALE_FACTOR). - // before multiplication takes place, vectors need to be prepared: - // 'rgba' is shuffled from R1B1G1A1...R4B4G4A4 to R1R2R3R4...A1A2A3A4 - // 'kern' is shuffled from w1w2w3w4...w13w14w15w16 to w1w2w3w4 repeated 4 times - // then we call _mm_maddubs_epi16 and we get: - // -------------------------------------------------------------------------------------- - // | R1*w1 + R2*w2 | R3*w3 + R4*w4 | G1*w1 + G2*w2 | G3*w3 + G4*w4 | repeat for B and A | - // -------------------------------------------------------------------------------------- - // each 'rectangle' is a 16-byte signed int. - // then we repeat the process for the rest of input pixels, - // call _mm_hadds_epi16 to add adjacent ints and shift right to scale by SCALE_FACTOR. - - __m128i rgba, kern; __m128i zero = _mm_setzero_si128(); __m128i acc = _mm_setzero_si128(); - const __m128i rgba_shuf_mask = _mm_setr_epi8(0, 4, 8, 12, - 1, 5, 9, 13, - 2, 6, 10, 14, - 3, 7, 11, 15); - - const __m128i kern_shuf_mask = _mm_setr_epi8(0, 1, 2, 3, - 0, 1, 2, 3, - 0, 1, 2, 3, - 0, 1, 2, 3); - - rgba = _mm_shuffle_epi8(rgbaIn[0], rgba_shuf_mask); - kern = _mm_shuffle_epi8(_kern, kern_shuf_mask); - acc = _mm_adds_epi16(acc, _mm_maddubs_epi16(rgba, kern)); + acc = _mm_add_epi16(acc, _mm_unpacklo_epi8(rgbaIn[0], zero)); + acc = _mm_add_epi16(acc, _mm_unpackhi_epi8(rgbaIn[0], zero)); + acc = _mm_add_epi16(acc, _mm_unpacklo_epi8(rgbaIn[1], zero)); - rgba = _mm_shuffle_epi8(rgbaIn[1], rgba_shuf_mask); - kern = _mm_shuffle_epi8(_mm_srli_si128(_kern, 4), kern_shuf_mask); - acc = _mm_adds_epi16(acc, _mm_maddubs_epi16(rgba, kern)); + // kernel size equals to 7, but we can only load multiples of 4 pixels + // we have to set 8th pixel to zero + acc = _mm_add_epi16(acc, _mm_andnot_si128(_mm_set_epi32(0xFFFFFFFF, 0xFFFFFFFF, 0, 0), + _mm_unpackhi_epi8(rgbaIn[1], zero))); + acc = _mm_add_epi32(_mm_unpacklo_epi16(acc, zero), + _mm_unpackhi_epi16(acc, zero)); - rgba = _mm_shuffle_epi8(rgbaIn[2], rgba_shuf_mask); - kern = _mm_shuffle_epi8(_mm_srli_si128(_kern, 8), kern_shuf_mask); - acc = _mm_adds_epi16(acc, _mm_maddubs_epi16(rgba, kern)); + // multiplication is significantly faster than division + acc = _mm_cvtps_epi32(_mm_mul_ps(_mm_cvtepi32_ps(acc), + _mm_set1_ps(1.0/KERNEL_SIZE))); - rgba = _mm_shuffle_epi8(rgbaIn[3], rgba_shuf_mask); - kern = _mm_shuffle_epi8(_mm_srli_si128(_kern, 12), kern_shuf_mask); - acc = _mm_adds_epi16(acc, _mm_maddubs_epi16(rgba, kern)); - - acc = _mm_hadds_epi16(acc, zero); - acc = _mm_srai_epi16(acc, SCALE_FACTOR); - - // Cairo sets alpha channel to 255 - // (or -1, depending how you look at it) - // this quickly overflows accumulator, - // and alpha is calculated completely wrong. - // I assume most people don't use semi-transparent - // lock screen images, so no one will mind if we - // 'correct it' by setting alpha to 255. *(dst + height * column + row) = - _mm_cvtsi128_si32(_mm_packus_epi16(acc, zero)) | 0xFF000000; + _mm_cvtsi128_si32(_mm_packus_epi16(_mm_packs_epi32(acc, zero), zero)); } } } + diff --git a/configure.ac b/configure.ac index 5efbfcd..bef332d 100644 --- a/configure.ac +++ b/configure.ac @@ -101,10 +101,8 @@ AC_PROG_LN_S AM_PROG_AR AX_FLAGS_WARN_ALL -AX_APPEND_FLAG([-march=native], [AM_CFLAGS]) - AX_APPEND_FLAG([-O2], [AM_CFLAGS]) +AX_APPEND_FLAG([-O2], [AM_CFLAGS]) AX_APPEND_FLAG([-funroll-loops], [AM_CFLAGS]) -AX_APPEND_FLAG([-std=gnu99], [AM_CFLAGS]) AX_CHECK_COMPILE_FLAG([-Wunused-value], [AX_APPEND_FLAG([-Wunused-value], [AM_CFLAGS])]) AC_SUBST(AM_CFLAGS) From 29251d61cd94e26caddc7fc03a1464fedf49309c Mon Sep 17 00:00:00 2001 From: Chris Guillott Date: Wed, 6 Dec 2017 14:20:04 -0500 Subject: [PATCH 17/18] fix naive blur --- blur.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/blur.c b/blur.c index 737ece1..d91d231 100644 --- a/blur.c +++ b/blur.c @@ -96,9 +96,10 @@ blur_image_surface (cairo_surface_t *surface, int sigma) } void blur_impl_horizontal_pass_generic(uint32_t *src, uint32_t *dst, int width, int height) { + uint32_t *o_src = src; for (int row = 0; row < height; row++) { for (int column = 0; column < width; column++, src++) { - uint32_t rgbaIn[KERNEL_SIZE]; + uint32_t rgbaIn[KERNEL_SIZE + 1]; // handle borders int leftBorder = column < HALF_KERNEL; @@ -119,8 +120,12 @@ void blur_impl_horizontal_pass_generic(uint32_t *src, uint32_t *dst, int width, for (int k = 0; i < KERNEL_SIZE; i++, k++) rgbaIn[i] = *(src - k); } else { - for (; i < KERNEL_SIZE; i++) - rgbaIn[i] = *(src + i - HALF_KERNEL); + for (; i < KERNEL_SIZE; i++) { + if ((long long) ((src + 4*i - HALF_KERNEL) + 1) + > (long long) (o_src + (height * width))) + break; + rgbaIn[i] = *(src + i - HALF_KERNEL); + } } uint32_t acc[4] = {0}; From 4318dbe05142dd7229d4b44565b482ed50a7c381 Mon Sep 17 00:00:00 2001 From: Pandora Date: Thu, 7 Dec 2017 16:09:13 -0500 Subject: [PATCH 18/18] fix compiling for 32-bit machines / machine without SSE2 --- blur.c | 4 ++-- blur.h | 3 ++- blur_simd.c | 8 ++++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/blur.c b/blur.c index d91d231..74adf4d 100644 --- a/blur.c +++ b/blur.c @@ -121,8 +121,8 @@ void blur_impl_horizontal_pass_generic(uint32_t *src, uint32_t *dst, int width, rgbaIn[i] = *(src - k); } else { for (; i < KERNEL_SIZE; i++) { - if ((long long) ((src + 4*i - HALF_KERNEL) + 1) - > (long long) (o_src + (height * width))) + if ((uintptr_t) ((src + 4*i - HALF_KERNEL) + 1) + > (uintptr_t) (o_src + (height * width))) break; rgbaIn[i] = *(src + i - HALF_KERNEL); } diff --git a/blur.h b/blur.h index fd93853..d729e92 100644 --- a/blur.h +++ b/blur.h @@ -9,9 +9,10 @@ #define HALF_KERNEL KERNEL_SIZE / 2 void blur_image_surface(cairo_surface_t *surface, int sigma); +#ifdef __SSE2__ void blur_impl_horizontal_pass_sse2(uint32_t *src, uint32_t *dst, int width, int height); +#endif void blur_impl_horizontal_pass_generic(uint32_t *src, uint32_t *dst, int width, int height); - #endif diff --git a/blur_simd.c b/blur_simd.c index 92aca9f..1cc2711 100644 --- a/blur_simd.c +++ b/blur_simd.c @@ -12,7 +12,7 @@ // number of xmm registers needed to store input pixels for given kernel size #define REGISTERS_CNT (KERNEL_SIZE + 4/2) / 4 - +#ifdef __SSE2__ void blur_impl_horizontal_pass_sse2(uint32_t *src, uint32_t *dst, int width, int height) { uint32_t* o_src = src; for (int row = 0; row < height; row++) { @@ -46,8 +46,8 @@ void blur_impl_horizontal_pass_sse2(uint32_t *src, uint32_t *dst, int width, int rgbaIn[k] = _mm_load_si128((__m128i*)(_rgbaIn + 4*k)); } else { for (int k = 0; k < REGISTERS_CNT; k++) { - if ((long long) (((__m128i*) src + 4*k - HALF_KERNEL) + 1) - > (long long) (o_src + (height * width))) + if ((uintptr_t) (((__m128i*) src + 4*k - HALF_KERNEL) + 1) + > (uintptr_t) (o_src + (height * width))) break; rgbaIn[k] = _mm_loadu_si128((__m128i*)(src + 4*k - HALF_KERNEL)); } @@ -76,4 +76,4 @@ void blur_impl_horizontal_pass_sse2(uint32_t *src, uint32_t *dst, int width, int } } } - +#endif