tools/configurator: add manual page.
authorRusty Russell <rusty@rustcorp.com.au>
Tue, 12 Jun 2018 02:37:51 +0000 (12:07 +0930)
committerRusty Russell <rusty@rustcorp.com.au>
Tue, 12 Jun 2018 02:37:51 +0000 (12:07 +0930)
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
doc/Makefile
doc/configurator.1 [new file with mode: 0644]
doc/configurator.1.txt [new file with mode: 0644]
tools/configurator/configurator.c

index 573079233625cb8bc974ca28a1d2044d22c46594..5aea5606b5ba7bb47e54507c718fd3824b95dc8d 100644 (file)
@@ -1,5 +1,7 @@
-ccanlint.1: ccanlint.1.txt
-       a2x --format=manpage ccanlint.1.txt
+default: ccanlint.1 configurator.1
+
+%.1: %.1.txt
+       a2x --format=manpage $<
 
 distclean:
-       rm -f ccanlint.1
+       rm -f ccanlint.1 configurator.1
diff --git a/doc/configurator.1 b/doc/configurator.1
new file mode 100644 (file)
index 0000000..aaa92c5
--- /dev/null
@@ -0,0 +1,216 @@
+'\" t
+.\"     Title: configurator
+.\"    Author: [see the "AUTHOR" section]
+.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
+.\"      Date: 03/01/2018
+.\"    Manual: \ \&
+.\"    Source: \ \&
+.\"  Language: English
+.\"
+.TH "CONFIGURATOR" "1" "03/01/2018" "\ \&" "\ \&"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+configurator \- Generate a simple config\&.h or variable file
+.SH "SYNOPSIS"
+.sp
+\fBconfigurator\fR [\fIOPTIONS\fR] [\fICC\fR] [\fICFLAGS\fR\&...]
+.SH "DESCRIPTION"
+.sp
+\fBconfigurator\fR is a standalone C program which evaluates the C environment using code snippets\&.
+.sp
+The C compiler (and flags) can be provided on the command\-line, otherwise built\-in defaults are used\&.
+.sp
+It has a builtin set of tests, to which more can be added\&. By default it produces a C header file to standard output, but it can also produce a file containing simple "key=value" lines suitable for parsing by \fBsh\fR or \fBmake\fR\&.
+.SH "OPTIONS"
+.PP
+\fB\-v\fR
+.RS 4
+Print out every test result; specified twice, print out each test too\&.
+.RE
+.PP
+\fB\-vv\fR
+.RS 4
+Shortcut for two
+\fB\-v\fR
+options\&.
+.RE
+.PP
+\fB\-\-var\-file=<file>\fR
+.RS 4
+Output results in format
+\fI<key>=<value>\fR
+to
+\fI<file>\fR, or stdout if
+\fI<file>\fR
+is
+\fI\-\fR\&. Default is not to output this\&.
+.RE
+.PP
+\fB\-\-header\-file=<file>\fR
+.RS 4
+Output C\-style header to
+\fI<file>\fR
+instead out stdout\&.
+.RE
+.PP
+\fB\-\-autotools\-style\fR
+.RS 4
+Produce output to stdout like autotools\*(Aq configure script\&. This usually means you want to use
+\fB\-\-header\-file\fR
+so that doesn\(cqt mix with stdout\&.
+.RE
+.PP
+\fB\-O<outflag>\fR
+.RS 4
+Override option to set compiler output file\&.
+.RE
+.PP
+\fB\-\-configurator\-cc=<command>\fR
+.RS 4
+This gives the real compiler command to use for tests, instead of the first commandline argument or the default\&.
+.RE
+.PP
+\fB\-\-extra\-tests\fR
+.RS 4
+Read additional tests from stdin, see
+\fIEXTRA TESTS\fR
+below\&.
+.RE
+.SH "OUTPUT"
+.sp
+The header output is \fI#ifndef/#define\fR idempotent\-wrapped using \fICCAN_CONFIG_H\fR, and defines \fI_GNU_SOURCE\fR\&. It also defines \fICCAN_COMPILER\fR, \fICCAN_CFLAGS\fR and \fICCAN_OUTPUT_EXE_CFLAG\fR as either the built\-in definitions or those provided on the command line\&. The remainder is \fI#define\fR of the test names followed by a \fI0\fR or \fI1\fR: note that this means you should use \fI#if\fR not \fI#ifdef\fR to test features in your C programs!
+.sp
+The var\-file output is simply the test names followed by \fI=1\fR or \fI=0\fR\&.
+.SH "EXTRA TESTS"
+.sp
+Extra tests must be formatted as \fI<key>=<value>\fR pairs, with leading whitespace and \fI#\fR lines ignored\&.
+.sp
+The first three lines are always the same:
+.PP
+\fBvar=<varname>\fR
+.RS 4
+Define the variable set by the test, e\&.g\&.
+\fIvar=HAVE_FOO\fR\&.
+.RE
+.PP
+\fBdesc=<description>\fR
+.RS 4
+The description printed out with
+\fB\-\-autotools\-style\fR, e\&.g\&.
+\fIfoo support\fR\&.
+.RE
+.PP
+\fBstyle=<style>\fR
+.RS 4
+The set of strings defining how to treat the code snippet\&. It must include one of
+\fIOUTSIDE_MAIN\fR,
+\fIDEFINES_FUNC\fR,
+\fIINSIDE_MAIN\fR
+or
+\fIDEFINES_EVERYTHING\fR
+which control the boilerplate to surround the file, and may include
+\fIEXECUTE\fR
+or both
+\fIEXECUTE\fR
+and
+\fIMAY_NOT_COMPILE\fR\&. e\&.g\&.
+\fIINSIDE_MAIN|EXECUTE\fR\&.
+.RE
+.sp
+The following styles are defined:
+.PP
+\fBOUTSIDE_MAIN\fR
+.RS 4
+means we put a simple boilerplate main below it\&.
+.RE
+.PP
+\fBDEFINES_FUNC\fR
+.RS 4
+put a simple boilerplate main below it, which references
+\fIfunc\fR
+(to avoid any unused warnings)\&.
+.RE
+.PP
+\fBINSIDE_MAIN\fR
+.RS 4
+put this inside main()\&. This also means it must exit with status 0 if it compiles, unless
+\fBEXECUTE\fR
+is added\&.
+.RE
+.PP
+\fBDEFINES_EVERYTHING\fR
+.RS 4
+don\(cqt add any boilerplate at all\&.
+.RE
+.PP
+\fBEXECUTE\fR
+.RS 4
+this is an execution test; it must compile, but may not exit with status 0 when run\&.
+.RE
+.PP
+\fBMAY_NOT_COMPILE\fR
+.RS 4
+Only useful with EXECUTE: don\(cqt get upset if it doesn\(cqt compile\&.
+.RE
+.sp
+The following lines are optional, and may follow in any order:
+.PP
+\fBdepends=<varnames>\fR
+.RS 4
+A space\-separates set of vars which must pass to even try to pass this one\&. If the var begins with
+\fI!\fR
+then the dependency must fail to try this one\&. e\&.g\&.
+\fIdepends=HAVE_UCONTEXT !HAVE_VALGRIND_MEMCHECK_H\fR\&.
+.RE
+.PP
+\fBlink=<linkargs>\fR
+.RS 4
+Extra arguments for linking with this test, e\&.g\&.
+\fIlink=\-lrt\fR\&.
+.RE
+.PP
+\fBflags=<cflags>\fR
+.RS 4
+Extra flags for compiling with this test, e\&.g\&.
+\fIflags=\-fopenmp\fR\&.
+.RE
+.PP
+\fBoverrides=<varname>\fR
+.RS 4
+Tests to force passing if this one passes\&. e\&.g\&.
+\fIoverrides=HAVE_SOME_FOO\fR\&.
+.RE
+.sp
+The final line is the code to test, itself, either as a single \fIcode=<oneline>\fR or as multiple lines starting with \fIcode=\fR and ending with \fI/*END*/\fR on a line by itself\&. e\&.g\&. \fIcode=return 0;\fR\&.
+.SH "EXIT STATUS"
+.sp
+It will exit with non\-zero status if it has a problem\&. \fB1\fR means bad commandline options\&. \fB2\fR means some operational problem creating and running tests\&. \fB3\fR means a bad test\&. \fB4\fR means failure to parse an extra test\&.
+.SH "AUTHOR"
+.sp
+Rusty Russell wrote \fBconfigurator\fR\&.
+.SH "RESOURCES"
+.sp
+Main web site: http://ccodearchive\&.net/
+.sp
+Wiki: https://github\&.com/rustyrussell/ccan/wiki/
+.SH "COPYING"
+.sp
+This program is under the MIT\-style BSD license; see code for details\&.
diff --git a/doc/configurator.1.txt b/doc/configurator.1.txt
new file mode 100644 (file)
index 0000000..ef9f8ba
--- /dev/null
@@ -0,0 +1,152 @@
+CONFIGURATOR(1)
+===============
+:doctype: manpage
+
+
+NAME
+----
+configurator - Generate a simple config.h or variable file
+
+
+SYNOPSIS
+--------
+*configurator* ['OPTIONS'] ['CC'] ['CFLAGS'...]
+
+DESCRIPTION
+-----------
+*configurator* is a standalone C program which evaluates the C
+environment using code snippets.
+
+The C compiler (and flags) can be provided on the command-line,
+otherwise built-in defaults are used.
+
+It has a builtin set of tests, to which more can be added.  By default
+it produces a C header file to standard output, but it can also
+produce a file containing simple "key=value" lines suitable for parsing
+by *sh* or *make*.
+
+OPTIONS
+-------
+*-v*::
+  Print out every test result; specified twice, print out each test too.
+
+*-vv*::
+  Shortcut for two *-v* options.
+
+*--var-file=<file>*::
+  Output results in format '<key>=<value>' to '<file>', or stdout if '<file>'
+  is '-'.  Default is not to output this.
+
+*--header-file=<file>*::
+  Output C-style header to '<file>' instead out stdout.
+
+*--autotools-style*::
+  Produce output to stdout like autotools' configure script.  This
+  usually means you want to use *--header-file* so that doesn't mix with stdout.
+
+*-O<outflag>*::
+  Override option to set compiler output file.
+
+*--configurator-cc=<command>*::
+  This gives the real compiler command to use for tests, instead of the first
+  commandline argument or the default.
+
+*--extra-tests*::
+  Read additional tests from stdin, see 'EXTRA TESTS' below.
+
+OUTPUT
+------
+
+The header output is '#ifndef/#define' idempotent-wrapped using
+'CCAN_CONFIG_H', and defines '_GNU_SOURCE'.  It also defines
+'CCAN_COMPILER', 'CCAN_CFLAGS' and 'CCAN_OUTPUT_EXE_CFLAG' as
+either the built-in definitions or those provided on the command line.
+The remainder is '#define' of the test names followed by a '0' or '1':
+note that this means you should use '#if' not '#ifdef' to test features
+in your C programs!
+
+The var-file output is simply the test names followed by '=1' or '=0'.
+
+EXTRA TESTS
+-----------
+Extra tests must be formatted as '<key>=<value>' pairs, with leading
+whitespace and '#' lines ignored.
+
+The first three lines are always the same:
+
+*var=<varname>*::
+   Define the variable set by the test, e.g. 'var=HAVE_FOO'.
+
+*desc=<description>*::
+   The description printed out with *--autotools-style*, e.g. 'foo support'.
+
+*style=<style>*::
+   The set of strings defining how to treat the code snippet.  It must
+   include one of 'OUTSIDE_MAIN', 'DEFINES_FUNC', 'INSIDE_MAIN' or
+   'DEFINES_EVERYTHING' which control the boilerplate to surround the
+   file, and may include 'EXECUTE' or both 'EXECUTE' and
+   'MAY_NOT_COMPILE'.  e.g. 'INSIDE_MAIN|EXECUTE'.
+
+The following styles are defined:
+
+*OUTSIDE_MAIN*::
+  means we put a simple boilerplate main below it.
+
+*DEFINES_FUNC*::
+  put a simple boilerplate main below it, which references 'func' (to
+  avoid any unused warnings).
+
+*INSIDE_MAIN*::
+  put this inside main().  This also means it must exit with status 0
+  if it compiles, unless *EXECUTE* is added.
+
+*DEFINES_EVERYTHING*::
+  don't add any boilerplate at all.
+
+*EXECUTE*::
+  this is an execution test; it must compile, but may not exit with
+  status 0 when run.
+
+*MAY_NOT_COMPILE*::
+  Only useful with EXECUTE: don't get upset if it doesn't compile.
+
+The following lines are optional, and may follow in any order:
+
+*depends=<varnames>*::
+  A space-separates set of vars which must pass to even try to pass this
+  one.  If the var begins with '!' then the dependency must fail to try
+  this one. e.g. 'depends=HAVE_UCONTEXT !HAVE_VALGRIND_MEMCHECK_H'.
+
+*link=<linkargs>*::
+  Extra arguments for linking with this test, e.g. 'link=-lrt'.
+
+*flags=<cflags>*::
+  Extra flags for compiling with this test, e.g. 'flags=-fopenmp'.
+
+*overrides=<varname>*::
+  Tests to force passing if this one passes. e.g. 'overrides=HAVE_SOME_FOO'.
+
+The final line is the code to test, itself, either as a single
+'code=<oneline>' or as multiple lines starting with 'code=' and ending
+with '/\*END*/' on a line by itself. e.g. 'code=return 0;'
+
+EXIT STATUS
+-----------
+It will exit with non-zero status if it has a problem.  *1* means bad
+commandline options. *2* means some operational problem creating and
+running tests. *3* means a bad test. *4* means failure to parse an
+extra test.
+
+AUTHOR
+------
+Rusty Russell wrote *configurator*.
+
+RESOURCES
+---------
+Main web site: http://ccodearchive.net/
+
+Wiki: https://github.com/rustyrussell/ccan/wiki/
+
+COPYING
+-------
+This program is under the MIT-style BSD license; see code for details.
index 874ec12ad7c91fb2eb047374e7e7eeeda10f5fe5..239e91c962b9b3af8af341818055412ad3344f9a 100644 (file)
  */
 #define _POSIX_C_SOURCE 200809L                /* For pclose, popen, strdup */
 
+#define EXIT_BAD_USAGE           1
+#define EXIT_TROUBLE_RUNNING     2
+#define EXIT_BAD_TEST            3
+#define EXIT_BAD_INPUT           4
+
 #include <errno.h>
 #include <stdio.h>
 #include <stdarg.h>
@@ -544,7 +549,7 @@ static char *grab_stream(FILE *file)
        }
        size += ret;
        if (ferror(file))
-               c12r_err(1, "reading from command");
+               c12r_err(EXIT_TROUBLE_RUNNING, "reading from command");
        buffer[size] = '\0';
        return buffer;
 }
@@ -564,7 +569,7 @@ static char *run(const char *cmd, int *exitstatus)
 
        cmdout = popen(cmdredir, "r");
        if (!cmdout)
-               c12r_err(1, "popen \"%s\"", cmdredir);
+               c12r_err(EXIT_TROUBLE_RUNNING, "popen \"%s\"", cmdredir);
 
        free(cmdredir);
 
@@ -605,7 +610,7 @@ static struct test *find_test(const char *name)
                if (strcmp(tests[i].name, name) == 0)
                        return &tests[i];
        }
-       c12r_errx(2, "Unknown test %s", name);
+       c12r_errx(EXIT_BAD_TEST, "Unknown test %s", name);
        abort();
 }
 
@@ -661,7 +666,7 @@ static bool run_test(const char *cmd, struct test *test)
 
        outf = fopen(INPUT_FILE, verbose > 1 ? "w+" : "w");
        if (!outf)
-               c12r_err(1, "creating %s", INPUT_FILE);
+               c12r_err(EXIT_TROUBLE_RUNNING, "creating %s", INPUT_FILE);
 
        fprintf(outf, "%s", PRE_BOILERPLATE);
 
@@ -683,7 +688,7 @@ static bool run_test(const char *cmd, struct test *test)
        } else if (strstr(test->style, "DEFINES_EVERYTHING")) {
                fprintf(outf, "%s", test->fragment);
        } else
-               c12r_errx(2, "Unknown style for test %s: %s",
+               c12r_errx(EXIT_BAD_TEST, "Unknown style for test %s: %s",
                          test->name, test->style);
 
        if (verbose > 1) {
@@ -725,7 +730,8 @@ static bool run_test(const char *cmd, struct test *test)
                               test->name, status, output);
                if (strstr(test->style, "EXECUTE")
                    && !strstr(test->style, "MAY_NOT_COMPILE"))
-                       c12r_errx(1, "Test for %s did not compile:\n%s",
+                       c12r_errx(EXIT_BAD_TEST,
+                                 "Test for %s did not compile:\n%s",
                                  test->name, output);
                test->answer = false;
                free(output);
@@ -737,7 +743,8 @@ static bool run_test(const char *cmd, struct test *test)
                    || strstr(test->style, "INSIDE_MAIN")) {
                        output = run("." DIR_SEP OUTPUT_FILE, &status);
                        if (!strstr(test->style, "EXECUTE") && status != 0)
-                               c12r_errx(1, "Test for %s failed with %i:\n%s",
+                               c12r_errx(EXIT_BAD_TEST,
+                                         "Test for %s failed with %i:\n%s",
                                          test->name, status, output);
                        if (verbose && status)
                                printf("%s exited %i\n", test->name, status);
@@ -774,7 +781,7 @@ static char *any_field(char **fieldname)
 
                eq = strchr(p, '=');
                if (!eq)
-                       c12r_errx(2, "no = in line: %s", p);
+                       c12r_errx(EXIT_BAD_INPUT, "no = in line: %s", p);
                *eq = '\0';
                *fieldname = strdup(p);
                p = eq + 1;
@@ -792,10 +799,11 @@ static char *read_field(const char *name, bool compulsory)
        if (!value) {
                if (!compulsory)
                        return NULL;
-               c12r_errx(2, "Could not read field %s", name);
+               c12r_errx(EXIT_BAD_INPUT, "Could not read field %s", name);
        }
        if (strcmp(fieldname, name) != 0)
-               c12r_errx(2, "Expected field %s not %s", name, fieldname);
+               c12r_errx(EXIT_BAD_INPUT,
+                         "Expected field %s not %s", name, fieldname);
        return value;
 }
 
@@ -845,11 +853,11 @@ static bool read_test(struct test *test)
                else if (strcmp(field, "code") == 0)
                        break;
                else
-                       c12r_errx(2, "Unknown field %s in %s",
+                       c12r_errx(EXIT_BAD_INPUT, "Unknown field %s in %s",
                                  field, test->name);
        }
        if (!value)
-               c12r_errx(2, "Missing code in %s", test->name);
+               c12r_errx(EXIT_BAD_INPUT, "Missing code in %s", test->name);
 
        if (strlen(value) == 0) {
                /* Multiline program, read to END comment */
@@ -909,7 +917,7 @@ int main(int argc, const char *argv[])
                                fprintf(stderr,
                                        "%s: option requires an argument -- O\n",
                                        argv[0]);
-                               exit(1);
+                               exit(EXIT_BAD_USAGE);
                        }
                } else if (strcmp(argv[1], "-v") == 0) {
                        argc--;
@@ -942,7 +950,7 @@ int main(int argc, const char *argv[])
                } else if (strcmp(argv[1], "--") == 0) {
                        break;
                } else if (argv[1][0] == '-') {
-                       c12r_errx(2, "Unknown option %s", argv[1]);
+                       c12r_errx(EXIT_BAD_USAGE, "Unknown option %s", argv[1]);
                } else {
                        break;
                }
@@ -985,13 +993,15 @@ int main(int argc, const char *argv[])
                        start_test("Writing variables to ", varfile);
                        vars = fopen(varfile, "a");
                        if (!vars)
-                               c12r_err(2, "Could not open %s", varfile);
+                               c12r_err(EXIT_TROUBLE_RUNNING,
+                                        "Could not open %s", varfile);
                }
                for (i = 0; tests[i].name; i++)
                        fprintf(vars, "%s=%u\n", tests[i].name, tests[i].answer);
                if (vars != stdout) {
                        if (fclose(vars) != 0)
-                               c12r_err(2, "Closing %s", varfile);
+                               c12r_err(EXIT_TROUBLE_RUNNING,
+                                        "Closing %s", varfile);
                        end_test(1);
                }
        }
@@ -1000,7 +1010,8 @@ int main(int argc, const char *argv[])
                start_test("Writing header to ", headerfile);
                outf = fopen(headerfile, "w");
                if (!outf)
-                       c12r_err(2, "Could not open %s", headerfile);
+                       c12r_err(EXIT_TROUBLE_RUNNING,
+                                "Could not open %s", headerfile);
        } else
                outf = stdout;
 
@@ -1023,7 +1034,7 @@ int main(int argc, const char *argv[])
 
        if (headerfile) {
                if (fclose(outf) != 0)
-                       c12r_err(2, "Closing %s", headerfile);
+                       c12r_err(EXIT_TROUBLE_RUNNING, "Closing %s", headerfile);
                end_test(1);
        }