TinyURL widget - shorten your URL's for free!

Enter a long URL to make tiny:

Thursday, April 6, 2017

How to add a full CHECK_HEADER() to configure.ac

Gary Vaughn's ( & Ben Ellison, Tom Tromey & Ian Lance Taylor ) book GNU AUTOCONF, AUTOMAKE, and LIBTOOL  covers a lot of the basics of how one uses GNU tools to automate Richard Stallman's GNU make process. One general criticism is that they don't cover enough of the gritty details to make the book generally useful.  Real developers have real problems in any one project apart from the basics, and if one can't get help with m4 or the underlying autotools process then often people turn to other methods that are easier. Easier but not better, there's a reason why these auto tools have been around since 1980's; they work if you understand them.


RMS 2014

While I have used and lauded the value, moral and commercial, of open source software and GNU in particular, with any new technology that disrupts old technologies we merely change the benefits and problems associated with the new way of business. Read W. Brian Arthur's book The Nature of Technology to understand more.

The single biggest failing of the GNU effort and Stallman's dogma is that unpaid free software doesn't employ people to clean it up and document everything properly, so it leaves the hapless users "free" to do it all themselves. Many free software project developers spend all their time living up to expectations getting the software working, and they often underdocument due to that time constraint. Many are new and not very seasoned. They pick up software ideas at school, full of idealism and vigour,  and believe in it for as long as they are interested in experimental jazz or neutropics.  Then they grow up, get a paying job, or drop out.  Software ebbs and flows and sits idle. Corporate knowledge is lost. People pick up the pieces years later or not. Now, it's up to you.

All that means is when you don't pay someone to increase the usability, you end up paying with your time.



Remember, Linus Torvalds (remember the GNU/Linux saga) is also an open source advocate and he argues projects are 99% perspiration - not "innovation". I would argue Linus is more substantial than any GNU project, even GCC which is considerable. Most small team coder projects, which is the GNU jungle,  end up in the dustbin of history because they don't catch on and maintain momentum. So if you want what they were working on and no one else is doing it then it falls to you.  I am lucky that I have a job where I work at my own pace. I can tinker and figure it out. It is my duty to explain to others not so fortunate because that is the sharing and community commitment of members.


In my case, I work on both Fedora and Ubuntu (Debian) distributions and I use the ATLAS linear algebra software library.  Both distributions bifurcate the locations of the libraries and the #include headers so if I want to use them I need to know where they are.  Adding to the complication, they change the name of the containing library RPM and the development RPM containing the headers. For example, under Ubuntu the library headers are in libXXX-dev RPMs and in Fedora, the library headers are in libXXX-devel RPMs. They install  /usr/include headers but some cases they are under atlas/ directories and other times not. The libraries are in /lib  or /lib64 or /usr/lib or /usr/lib64 and it's not consistent.

In this entry I show a complete AC_CHECK_HEADER example to find one header, the atlas_pthreads.h

Inside configure.ac you include the m4 defined macro AC_CHECK_HEADER  with an environmental variable:

AC_CHECK_HEADER([atlas_pthreads.h], [AC_DEFINE([HAVE_ATLAS_PTHREADS_H],[1],[[Checking for 1 level atlas.h header]])], [] ) 

You will need to add extra versions for any permutation of header location. You increase the CONSTANT_NAME_H appropriately and please make it intuitive( as in linked mentally to the reason for the constant). You will thank yourself later.  In case it's located inside the atlas/ directory you would need another one like this:

AC_CHECK_HEADER([atlas/atlas_pthreads.h], [AC_DEFINE([HAVE_ATLAS_ATLAS_PTHREADS_H],[1],[Checking for base level atlas.h header ])], [] ) 

This one above changes by constant value to one inside the atlas folder.

When you think about it, why this wasn't done in the 2001 edition of a book covering GNU autotools is quite shocking.  The software was mature by then. The lack of depth of Appendix D is really a disservice to those that paid $40.00 for it.

We don't use the last argument [ if-not-found] action because we are going to call other check header macros and include many variables so one of them will appear and the rest will not get defined. Since we only include them on action if found, they won't appear in config.h and in Makefile without a successful file location. The defined value largely doesn't matter in this technique. There are other ways to use that defined value but for this case you need #ifdef to find a constant.

Inside any .h file one would include these #ifdef macros:

#include "config.h"


#ifdef HAVE_ATLAS_PTHREADS_H
#include <atlas_pthreads.h>
#endif
#ifdef HAVE_ATLAS_ATLAS_PTHREADS_H
#include <atlas/atlas_pthreads.h>
#endif

I always forget to include the config.h header to start, and then when I compile the first time, it hits me when GCC doesn't understand any variables it should. You should always make header missing warnings an error so you don't get mistaken versions library references to another mistaken linked library that might be in some other software. There are ways around it but don't take the temptation. You will thank yourself later when you avoid phantom errors.


Here's a snippet of my latest configure.ac in case these help anyone:




# Checks for header files.
AC_CHECK_HEADERS([fcntl.h stdlib.h string.h stdio.h unistd.h  error.h ])
AC_CHECK_HEADERS([stdlib.h string.h unistd.h glib.h glibconfig.h math.h])
AC_CHECK_HEADERS([freeglut.h])
AC_CHECK_HEADERS([freeglut_ext.h])
AC_CHECK_HEADERS([freeglut_std.h])
AC_CHECK_HEADERS([glut.h])
AC_CHECK_HEADERS([glu.h])
AC_CHECK_HEADERS([gl.h])
AC_CHECK_HEADERS([gl/glut.h])
AC_CHECK_HEADERS([GL/freeglut.h])
AC_CHECK_HEADERS([GL/gl.h])
AC_CHECK_HEADERS([GL/glu.h])
AC_CHECK_HEADERS([GL/glut.h])
AC_CHECK_HEADERS([GL/freeglut.h])
AC_CHECK_HEADERS([GL/freeglut_ext.h])
AC_CHECK_HEADERS([GL/freeglut_std.h])
AC_CHECK_HEADERS([GL/glew.h])
AC_CHECK_HEADERS([GL/wglew.h])

AC_CHECK_HEADER([atlas.h], AC_DEFINE([HAVE_ATLAS_H],[1],[ [Checking for top level atlas.h header] ]), [])
AC_CHECK_HEADER([atlas/atlas.h], AC_DEFINE([HAVE_ATLAS_ATLAS_H],[1],[ [Checking for 1 level atlas.h header] ]), [])
AC_CHECK_HEADER([atlas_buildinfo.h], AC_DEFINE([HAVE_ATLAS_BUILDINFO_H],[1],[ [Checking for top level buildinfo.h header] ]), [])
AC_CHECK_HEADER([atlas/atlas_buildinfo.h], AC_DEFINE([HAVE_ATLAS_ATLAS_BUILDINFO_H],[1],[ [Checking for 1 level atlas_buildinfo.h header] ]), [])
AC_CHECK_HEADER([atlas/atlas_cacheedge.h], AC_DEFINE([HAVE_ATLAS_ATLAS_CACHEEDGE_H],[1],[ [Checking for 1 level atlas_cacheedge.h header] ]), [])
AC_CHECK_HEADER([atlas_pthreads.h], [AC_DEFINE([HAVE_ATLAS_PTHREADS_H],[1],[[Checking for 1 level atlas.h header]])], [] ) 
AC_CHECK_HEADER([atlas/atlas_pthreads.h], [AC_DEFINE([HAVE_ATLAS_ATLAS_PTHREADS_H],[1],[Checking for 1 level atlas.h header ])], [] ) 
AC_CHECK_HEADER([atlas/clapack.h], [AC_DEFINE([HAVE_ATLAS_CLAPACK_H],[1],[[Checking for 1 level atlas/clapack.h header]])], [])
AC_CHECK_HEADER([atlas/atlas_f77.h], [AC_DEFINE([HAVE_ATLAS_F77_H],[1],[[Checking for 1 level atlas_f77.h header]])], [] )
AC_CHECK_HEADER([atlas/blas.h], AC_DEFINE([HAVE_ATLAS_BLAS_H],[1],[ [Checking for 1 level atlas/blas.h header] ]), [])
AC_CHECK_HEADER([atlas/cblas.h], AC_DEFINE([HAVE_ATLAS_CBLAS_H],[1],[ [Checking for 1 level cblas.h header] ]), [])
AC_CHECK_HEADER([blas.h], AC_DEFINE([HAVE_BLAS_H],[1],[ [Checking for top level blas.h header] ]), [])
AC_CHECK_HEADER([lapack.h], AC_DEFINE([HAVE_LAPACK_H],[1],[ [Checking for top level lapack.h header] ]), [])
AC_CHECK_HEADER([cblas.h], AC_DEFINE([HAVE_CBLAS_H],[1],[ [Checking for top level cblas.h header] ]), [])
AC_CHECK_HEADER([clapack.h], AC_DEFINE([HAVE_CLAPACK_H],[1],[ [Checking for top level clapack.h header] ]), [])

AC_CHECK_HEADER([protobuf-c.h],[AC_DEFINE([HAVE_PROTOBUF_C_H],[1],[ [Checking for top level protobuf-c.h header] ])],[])
AC_CHECK_HEADER([protobuf-c/protobuf-c.h],[AC_DEFINE([HAVE_PROTOBUF_C_PROTOBUF_C_H],[1],[ [Checking for 1 level protobuf-c.h header] ])],[])
AC_CHECK_HEADER([google/protobuf-c/protobuf-c.h],[AC_DEFINE([HAVE_GOOGLE_PROTOBUF_C_PROTOBUF_C_H],[1],[ [Checking for 2 level protobuf-c.h header] ])],[])

# try to find libray in usual spaces - then insert Env Vars to indicate linkable libraries
AC_CHECK_LIB([m],[fabs],[],[echo fabs not found] )
# OpenGL libraries
AC_CHECK_LIB([glew],[glewInit],[AC_SUBST([HAVE_LIBGLEW],[-lglew])],[echo glew not found] )
AC_CHECK_LIB([GLEW],[glewInit],[AC_SUBST([HAVE_LIBGLEW],[-lGLEW])],[echo GLEW not found] )
AC_CHECK_LIB([glut],[glutSolidSphere],[AC_SUBST([HAVE_LIBGLUT],[-lglut])],[echo glut not found] )
AC_CHECK_LIB([glu],[gluPerspective],[AC_SUBST([HAVE_LIBGLU],[-lglu])],[echo glu not found] )
AC_CHECK_LIB([GLU],[gluPerspective],[AC_SUBST([HAVE_LIBGLU],[-lGLU])],[echo glu not found] )
AC_CHECK_LIB([gl],[glViewport],[AC_SUBST([HAVE_LIBGL],[-lgl])],[echo gl not found] )
AC_CHECK_LIB([GL],[glViewport],[AC_SUBST([HAVE_LIBGL],[-lGL])],[echo GL not found] )