]> git.draconx.ca Git - dxcommon.git/commitdiff
Add libpng detection macro.
authorNick Bowler <nbowler@elliptictech.com>
Mon, 9 Jun 2014 23:46:34 +0000 (19:46 -0400)
committerNick Bowler <nbowler@draconx.ca>
Mon, 9 Jun 2014 23:46:34 +0000 (19:46 -0400)
I've been carrying around library detection in individual projects for
too long.  This is a from-scratch rewrite of the core probing code but
the actual libpng test is basically the same as before.

The idea is to better leverage M4 macros to reduce duplication, so it
should be easy to add more libraries in the future.

m4/cmdout.m4 [new file with mode: 0644]
m4/libhelper.m4 [new file with mode: 0644]
m4/libpng.m4 [new file with mode: 0644]
m4/pkg.m4 [new file with mode: 0644]

diff --git a/m4/cmdout.m4 b/m4/cmdout.m4
new file mode 100644 (file)
index 0000000..5aa3925
--- /dev/null
@@ -0,0 +1,39 @@
+dnl Copyright © 2014 Nick Bowler
+dnl
+dnl License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+dnl This is free software: you are free to do what the fuck you want to.
+dnl There is NO WARRANTY, to the extent permitted by law.
+
+dnl DX_COMMAND_OUTPUT(variable, command, [action-if-ok], [action-if-failed])
+dnl
+dnl Helper to capture standard output of a shell command.  If the command
+dnl is successful then variable is assigned with its output (with newlines
+dnl converted to spaces), and action-if-ok is performed.  Otherwise, if
+dnl the command is unsuccessful, then variable is not changed, and
+dnl action-if-failed is performed.
+AC_DEFUN([DX_COMMAND_OUTPUT], [AC_REQUIRE([_DX_COMMAND_OUTPUT_SETUP])dnl
+AS_IF([$2 >conftest.out 2>&AS_MESSAGE_LOG_FD],
+       [m4_do([dx_fn_cmdout_collect_output $1],
+               [m4_ifnblank([$3], [m4_newline([$3])])])],
+       [$4])
+rm -f conftest.out
+])
+
+AC_DEFUN_ONCE([_DX_COMMAND_OUTPUT_SETUP], [m4_divert_push([INIT_PREPARE])dnl
+# Helper function to store the contents of conftest.out into a shell variable.
+dx_fn_cmdout_collect_output () {
+  AS_UNSET([$][1])
+  exec 3<conftest.out
+  _dx_save_IFS=$IFS
+  IFS=
+  while read _dx_tmp <&3
+  do
+AS_VAR_SET_IF([$][1],
+       [AS_VAR_APPEND([$][1], [" $_dx_tmp"])],
+       [AS_VAR_SET([$][1], [$_dx_tmp])])
+  done
+  IFS=$_dx_save_IFS
+  exec 3<&-
+}
+
+m4_divert_pop()])
diff --git a/m4/libhelper.m4 b/m4/libhelper.m4
new file mode 100644 (file)
index 0000000..500389c
--- /dev/null
@@ -0,0 +1,141 @@
+dnl Copyright © 2014 Nick Bowler
+dnl
+dnl License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+dnl This is free software: you are free to do what the fuck you want to.
+dnl There is NO WARRANTY, to the extent permitted by law.
+
+dnl DX_LIB_SETUP(env-base, [human-name])
+dnl
+dnl Helper to setup a library test.  Defines two user variables FOO_CFLAGS
+dnl and FOO_LIBS, where FOO is replaced with env-base in uppercase.  The
+dnl human-name is the name of the library used in help text, by default the
+dnl same as env-base.
+AC_DEFUN([DX_LIB_SETUP], [m4_do(
+       [AC_ARG_VAR(m4_toupper([$1])[_CFLAGS],
+               [C compiler flags for ]m4_default([$2], [$1]))],
+       [AC_ARG_VAR(m4_toupper([$1])[_LIBS],
+               [linker flags for ]m4_default([$2], [$1]))])])
+
+dnl DX_LIB_PKGCONFIG_FLAGS(env-base, [library-name])
+dnl
+dnl Helper for querying a library's CFLAGS and LIBS values from the
+dnl pkg-config database.  The results are stored in the cache variables
+dnl dx_cv_foo_pkg_cflags and dx_cv_foo_pkg_libs, where foo is replaced with
+dnl env-base in lowercase.  If not specified, the library name defaults to
+dnl env-base.
+AC_DEFUN([DX_LIB_PKGCONFIG_FLAGS],
+       [_DX_LIB_PKGCONFIG_FLAGS(m4_tolower([$1]),
+               [m4_default([$2], [$1])])])
+
+dnl Internal helper macro for the above.
+AC_DEFUN([_DX_LIB_PKGCONFIG_FLAGS], [AS_IF([test x"$PKG_CONFIG" != x""],
+       [AC_CACHE_CHECK([pkg-config database for $2], [dx_cv_$1_pkg_found],
+               [m4_do([dx_cv_$1_pkg_found=yes],
+                       [m4_newline([DX_PKG_CONFIG([dx_cv_$1_pkg_cflags],
+                               [--cflags "$2"], [],
+                               [dx_cv_$1_pkg_found=no])])],
+                       [m4_newline([DX_PKG_CONFIG([dx_cv_$1_pkg_libs],
+                               [--libs "$2"], [],
+                               [dx_cv_$1_pkg_found=no])])])])])])
+
+dnl DX_LIB_SEARCH(env-base, test, test-matrix)
+dnl
+dnl Helper to search for the correct compiler/linker flags for a particular
+dnl library.  The test-matrix is an ordered, quoted list of quoted lists.
+dnl Each entry in the test matrix has the following form:
+dnl
+dnl    [cflags, libs, shell-condition]
+dnl
+dnl For each item, the specified cflags and libs are temporarily appended to
+dnl CFLAGS and LIBS, respectively, then the given test is run.  The test
+dnl argument must be an m4 macro which takes one argument (action-if-ok).
+dnl This macro shall expand to shell code which executes action-if-ok if and
+dnl only if the test was successful.  The test macro is expanded only once.
+dnl
+dnl If a test is successful, dx_cv_foo_lib_found is set to "yes", where foo is
+dnl replaced with env-base in lowercase.  Subsequent tests are not tried.
+dnl The cflags and libs values from a successful test are stored in FOO_CFLAGS
+dnl and FOO_LIBS, respectively, where FOO is replaced with env-base in
+dnl uppercase.  These values are AC_SUBST-ed.  If no test was successful,
+dnl dx_cv_foo_lib_found is set to "no".
+dnl
+dnl The result ("yes" or "no") are printed so this macro should be preceded
+dnl by a call to AC_MSG_CHECKING.
+AC_DEFUN([DX_LIB_SEARCH], [m4_divert_push([KILL])
+
+m4_pushdef([_DX_CVNAME], m4_tolower([dx_cv_$1_lib_])[$][1])
+m4_pushdef([_DX_FNNAME], m4_tolower([dx_fn_$1_lib_])[$][1])
+
+m4_divert([INIT_PREPARE])dnl
+# Helper function to test whether $1 works.
+_DX_FNNAME([test]) () {
+CFLAGS="$_dx_save_cflags $[]1"
+LIBS="$_dx_save_libs $[]2"
+m4_apply([$2], [dnl
+       _DX_CVNAME([found])=yes
+       _DX_CVNAME([cflags])=$[]1
+       _DX_CVNAME([libs])=$[]2])
+}
+
+m4_divert_pop()dnl
+AC_CACHE_VAL([_DX_CVNAME([found])], [dnl
+_DX_CVNAME([found])=no
+_dx_save_cflags=$CFLAGS
+_dx_save_libs=$LIBS
+m4_map_sep([_DX_LIB_TEST], [m4_newline], [$3])
+CFLAGS=$_dx_save_cflags
+LIBS=$_dx_save_libs])dnl
+
+AC_MSG_RESULT([$_DX_CVNAME([found])])
+AS_IF([test x"$_DX_CVNAME([found])" = x"yes"], [dnl
+       AC_SUBST(m4_toupper([$1_CFLAGS]), [$_DX_CVNAME([cflags])])dnl
+       AC_SUBST(m4_toupper([$1_LIBS]), [$_DX_CVNAME([libs])])])
+m4_popdef([_DX_CVNAME], [_DX_FNNAME])])
+
+dnl Internal helper macro for the above.
+AC_DEFUN([_DX_LIB_TEST],
+       [AS_IF([m4_do([test x"$_DX_CVNAME([found])" != x"yes"],
+               [m4_ifnblank([$3], [ && $3])])],
+       [_DX_FNNAME([test]) "$1" "$2"])])
+
+dnl DX_LIB_SEARCH_LINK(env-base, test-program, test-matrix)
+dnl
+dnl Convenience wrapper around DX_LIB_SEARCH which implements the test
+dnl function by attempting to linking the provided test program.
+AC_DEFUN([DX_LIB_SEARCH_LINK],
+       [DX_LIB_SEARCH([$1], [m4_curry([AC_LINK_IFELSE], [$2])], [$3])])
+
+dnl DX_LIB_USERFLAG_BLURB(env-base, [human-name])
+dnl
+dnl Expand to text explaining the FOO_CFLAGS and FOO_LIBS environment
+dnl variables, used in error messages, where FOO is replaced with env-base
+dnl in uppercase.  The human-name is the name of the library, by default the
+dnl same as env-base.
+AC_DEFUN([DX_LIB_USERFLAG_BLURB],
+       [_DX_LIB_USERFLAG_BLURB([m4_toupper([$1])], [m4_default([$2], [$1])])])
+
+dnl Internal helper macro for the above.
+AC_DEFUN([_DX_LIB_USERFLAG_BLURB], [dnl
+If $2 is installed but was not detected by this configure script,
+consider adjusting $1_CFLAGS and/or $1_LIBS as necessary.])
+
+dnl DX_LIB_USERFLAG_BLURB(env-base, [human-name])
+dnl
+dnl Expand to text explaining the PKG_CONFIG_PATH environment variable,
+dnl used in error messages.  The human-name is the name of the library, by
+dnl default the same as env-base.
+AC_DEFUN([DX_LIB_PKGCONFIG_BLURB],
+       [_DX_LIB_PKGCONFIG_BLURB([$1], [m4_default([$2], [$1])])])
+
+dnl Internal helper macro for the above.
+AC_DEFUN([_DX_LIB_PKGCONFIG_BLURB], [dnl
+If pkg-config is installed, it may help to adjust PKG_CONFIG_PATH if
+$2 is installed in a non-standard prefix.])
+
+dnl DX_LIB_COMPILE_ERROR([text])
+dnl
+dnl Expand to C code which should fail compilation.  The given text should
+dnl appear in any error message from the compiler, and should not contain
+dnl any newlines.
+AC_DEFUN([DX_LIB_COMPILE_ERROR], [m4_do([m4_newline([@%:@error $1])],
+       [m4_newline([static int AS_TR_SH([$1])@<:@-1@:>@;])])])
diff --git a/m4/libpng.m4 b/m4/libpng.m4
new file mode 100644 (file)
index 0000000..0f0af0b
--- /dev/null
@@ -0,0 +1,62 @@
+dnl Copyright © 2009-2010, 2014 Nick Bowler
+dnl
+dnl License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+dnl This is free software: you are free to do what the fuck you want to.
+dnl There is NO WARRANTY, to the extent permitted by law.
+
+dnl DX_LIB_LIBPNG([min-version], [action-if-ok], [acton-if-failed])
+dnl
+dnl Search for a suitable libpng.  If min-version is non-empty, the test will
+dnl attempt to reject a libpng installation which is older than the specified
+dnl version number (as determined by the libpng header file).
+dnl
+dnl If a working library is found, appropriate compiler and linker flags
+dnl are stored in LIBPNG_CFLAGS and LIBPNG_LIBS, respectively, and the
+dnl action-if-ok is performed (may be empty).  If no such library is found,
+dnl then action-if-failed is performed if non-empty; otherwise configure will
+dnl stop with a fatal error.
+AC_DEFUN([DX_LIB_LIBPNG], [dnl
+DX_LIB_SETUP([libpng])dnl
+DX_LIB_PKGCONFIG_FLAGS([libpng])
+AC_MSG_CHECKING([for libpng[]m4_ifnblank([$1], [ at least version $1])])
+DX_LIB_SEARCH_LINK([libpng],
+       [m4_apply([_DX_LIB_LIBPNG_TEST], m4_split([$1], [\.]))],
+       [
+               [[$LIBPNG_CFLAGS], [$LIBPNG_LIBS]],
+               [[$dx_cv_libpng_pkg_cflags], [$dx_cv_libpng_pkg_libs],
+                       [test x"$dx_cv_libpng_pkg_found" = x"yes"]],
+               [[], [-lpng]],
+       ])
+AS_IF([test x"$dx_cv_libpng_lib_found" = x"yes"], [$2],
+       [m4_default([$3], [AC_MSG_FAILURE([dnl
+libpng[]m4_ifnblank([$1], [ version $1 or newer]) is required.  The latest
+version may be found at <http://libpng.org/pub/png/libpng.html>.
+m4_newline([DX_LIB_USERFLAG_BLURB([libpng])])
+m4_newline([DX_LIB_PKGCONFIG_BLURB([libpng])])
+])])])])
+
+dnl Internal test program for libpng.  Check that the version numbers in the
+dnl header are sufficient and that some important functions are defined.
+m4_define([_DX_LIB_LIBPNG_TEST], [AC_LANG_PROGRAM([dnl
+#include <png.h>
+m4_ifnblank([$1], [dnl
+#if PNG_LIBPNG_VER_MAJOR < $1
+DX_LIB_COMPILE_ERROR([major version insufficient])
+m4_ifnblank([$2], [dnl
+#elif PNG_LIBPNG_VER_MAJOR == $1
+#  if PNG_LIBPNG_VER_MINOR < $2
+DX_LIB_COMPILE_ERROR([minor version insufficient])
+m4_ifnblank([$3], [dnl
+#  elif PNG_LIBPNG_VER_MINOR == $2
+#    if PNG_LIBPNG_VER_RELEASE < $3
+DX_LIB_COMPILE_ERROR([release version insufficient])
+#    endif
+])dnl
+#  endif
+])dnl
+#endif
+])], [dnl
+png_structp png = png_create_read_struct("", 0, 0, 0);
+png_infop info = png_create_info_struct(png);
+png_destroy_read_struct(&png, &info, 0);
+])])
diff --git a/m4/pkg.m4 b/m4/pkg.m4
new file mode 100644 (file)
index 0000000..9fd99a9
--- /dev/null
+++ b/m4/pkg.m4
@@ -0,0 +1,22 @@
+dnl Copyright © 2014 Nick Bowler
+dnl
+dnl License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+dnl This is free software: you are free to do what the fuck you want to.
+dnl There is NO WARRANTY, to the extent permitted by law.
+
+m4_pattern_forbid([^PKG_PROG_PKG_CONFIG$])
+
+dnl DX_PKG_CONFIG(shell-variable, arguments,
+dnl               [action-if-ok], [action-if-failed],
+dnl               [action-if-not-available])
+dnl
+dnl Execute pkg-config with the given arguments, and store the output in
+dnl the specified shell variable.  If successful, execute action-if-ok.  If
+dnl unsuccessful, execute action-if-failed.  If pkg-config is not available,
+dnl execute action-if-not-available.
+AC_DEFUN([DX_PKG_CONFIG], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AS_UNSET([$1])
+AS_IF([test x"$PKG_CONFIG" = x""],
+       [m4_default([$5], [AS_SET_STATUS([2])])],
+       [DX_COMMAND_OUTPUT([$1], [$PKG_CONFIG --print-errors $2],
+               [$3], [m4_default([$4], [AS_SET_STATUS([$?])])])])])