aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am24
-rw-r--r--README321
-rw-r--r--clexer.l330
-rwxr-xr-xextract-exports81
-rw-r--r--gint.m463
-rw-r--r--gint.mk66
-rw-r--r--guile.m4120
7 files changed, 1005 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..3b720db
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,24 @@
+# This file is part of Gint
+# Copyright (C) 2010 Sergey Poznyakoff
+#
+# 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, 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 <http://www.gnu.org/licenses/>.
+
+noinst_PROGRAMS = clexer
+clexer_SOURCES = clexer.l
+INCLUDES = @GINT_INCLUDES@
+LDADD = @GINT_LDADD@
+EXTRA_DIST = gint.m4 gint.mk guile.m4
+if GINT_COND_INC
+EXTRA_DIST += extract-exports
+endif
diff --git a/README b/README
new file mode 100644
index 0000000..c5c6070
--- /dev/null
+++ b/README
@@ -0,0 +1,321 @@
+GINT
+====
+Sergey Poznyakoff <gray@gnu.org>
+1, April 5, 2010
+
+NAME
+----
+GINT -- Guile Integration Framework
+
+DESCRIPTION
+-----------
+Integrating *Guile* into a project requires performing a set of routine steps,
+such, e.g., as creating additional Makefile rules, which, however trivial,
+require additional efforts from authors and impose on them an extra
+maintenance burden. Authors maintaining several projects, each of which uses
+Guile as an extension language, soon find out that these steps differ only
+insigificantly between the projects. It is therefore natural to move their
+_common denominator_ into a separate module and share this module between
+the projects.
+
+*GINT* is an attempt to create such a module. It reduces the task of
+integrating Guile to importing a submodule and editing a couple of files.
+
+*GINT* is designed as a Git submodule easily embeddable into any project.
+The only requirement to this host project is that it must use GNU Automake
+and Autoconf. It is also recommended, but not required, that the host project
+use Git for its repository.
+
+INSTALLATION
+------------
+
+To illustrate how to use *GINT*, let's suppose your project has the
+following structure:
+
+.Sample project listing
+---------------------------------------------------------------------
+-rw-r--r-- 1 gray users 2993 2010-04-05 00:15 Makefile.am <1>
+-rw-r--r-- 1 gray users 3026 2010-04-05 19:21 configure.ac <2>
+drwxr-xr-x 2 gray users 240 2010-04-05 02:27 m4/ <3>
+drwxr-xr-x 5 gray users 1992 2010-04-05 19:20 src/ <4>
+-rw-r--r-- 1 gray users 1286 2010-04-05 13:18 src/Makefile.am <5>
+-rw-r--r-- 1 gray users 1034 2010-04-05 13:18 src/iface.c
+---------------------------------------------------------------------
+
+<1> Top-level +Makefile+ source.
+<2> Configuration script source.
+<3> Directory with macro definitions for *aclocal*.
+<4> Source directory. It contains actual +C+ and +scm+ sources,
+ which define new *Guile* interfaces.
+<5> Source +Makefile.am+.
+
+The purpose of *GINT* is to provide the autotools magic necessary to
+check, at configure time, whether Guile is installed, determine its version
+number and location of its components on the local file system, then to
+compile and _snarf_ the +C+ sources, and finally, to produce the
+documentation files (+guile-procedures.texi+ and +guile-procedures.txt+).
+
+Import GINT as a submodule
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+This needs to be done only once:
+
+----------------------------------------------------
+git submodule add git://git.gnu.org.ua/gint.git gint
+git init
+----------------------------------------------------
+
+[[gint-dir]]
+The *submodule add* command takes two arguments: the submodule repository,
+which should be exactly as shown above, and the is the pathname of the
+cloned submodule in your project. This latter is entirely at your option.
+Throughout this document we will suppose that the module pathname is
++gint+. You will need to adjust the examples if you chose another
+name for it.
+
+Edit the toplevel +Makefile.am+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Add +-I gint+ to the +ACLOCAL_AMFLAGS+ variable, and +gint+ to
+the +SUBDIRS+ variable. For example:
+
+----------------------------------------
+ACLOCAL_AMFLAGS = -I m4 -I gint
+SUBDIRS = gint src
+----------------------------------------
+
+Notice that in +SUBDIRS+, the +gint+ entry must precede the names of
+those directories that depend on it.
+
+Edit the +configure.ac+ file
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Obviously, you need to add the submodule's Makefile to the list of
++AC_CONFIG_FILES+, e.g.:
+
+----------------------------------------
+AC_CONFIG_FILES(Makefile
+ gint/Makefile
+ src/Makefile)
+----------------------------------------
+
+Next, add a call to <<GINT_INIT,+GINT_INIT+>> at an appropriate point.
+This macro serves two purposes. First, it informs the +gint+ submodule
+about its location relative to the top project directory and configures
+its features. Second, it checks for the presence of Guile's binaries
+and libraries, verifies if its version is modern enough, and runs a
+series of user-supplied commands, depending on the result of this check.
+
+In a simplest case, the following line will be enough:
+
+---------
+GINT_INIT
+---------
+
+For a detailed discussion, see <<GINT_INIT, macro description>>.
+
+Edit source `Makefile.am`
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The source `Makefile.am` (or `Makefile.am`'s, if there are several of these, in
+separate directories) must include the file `gint/gint.mk`, which provides
++Makefile+ rules necessary to properly build various files (e.g. +.x+ and
++.doc+ files from corresponding +.c+ sources, etc) and to compute dependencies
+between them. Usually, it is OK to use a relative location. For example, in our
+sample project the `gint` and `src` directories have same parent directory,
+therefore we could add to `src/Makefile.am` the following line:
+
+-----------------------
+include ../gint/gint.mk
+-----------------------
+
+The rules in `gint.mk` make certain assumptions about some `Makefile`
+variables. Namely, the following variables must be defined before
+including the file: +INCLUDES+, +EXTRA_DIST+, +CLEANFILES+,
++DISTCLEANFILES+, +SUFFIXES+. See the
+http://sources.redhat.com/automake/automake.html[`Automake` documentation],
+for more info on these. If no special value is needed, yo may define each
+of them to an empty string (see example below).
+
+Firthermore, the +MAKEINFO+ variable must contain the pathname (not
+necessarily an absolute one), of the +makeinfo+ binary. It is initialized
+by +Automake+ if your project has a `Makefile.am` with the +info_TEXINFOS+
+variable set. If not, you will have to initialize it manually.
+
+Finally, two +GINT+-specific variables must be defined:
+
+DOT_X_FILES::
+ A list of +.x+ files to be generated.
+DOT_DOC_FILES::
+ A list of +.doc+ files to be generated.
+
+These two can be easily produced from the list of source +c+ files
+using http://www.gnu.org/software/make/manual/html_node/Substitution-Refs.html[+make+ substitution references]:
+
+-----------------------------------------------
+lib_LTLIBRARIES = libproj.la
+libproj_la_SOURCES = iface.c var.c
+
+INCLUDES =-I$(top_builddir) -I$(srcdir)
+EXTRA_DIST=
+DOT_X_FILES=$(libproj_la_SOURCES:.c=.x)
+DOT_DOC_FILES=$(libproj_la_SOURCES:.c=.doc)
+
+SUFFIXES=
+CLEANFILES=
+DISTCLEANFILES=
+include ../gint/gint.mk
+------------------------------------------------
+
+[[GINT_INIT]]
+The +GINT_INIT+ macro
+---------------------
+
+------------------------------------------------
+GINT_INIT(DIR, OPTIONS, ACTION-IF-FOUND, ACTION-IF-NOT-FOUND)
+------------------------------------------------
+
+This macro configures +GINT+ submodule, located in subdirectory
+`DIR` according to the settings given in `OPTIONS`. It then
+verifies if Guile is installed on the system and if so executes
+commands supplied by `ACTION-IF-FOUND`. Additionaly, it sets
+a number of <<gint-subst-vars, substitution variables>> describing
+various details of Guile installation.
+
+Otherwise, if Guile is not installed or is found to be unusable,
+`ACTION-IF-NOT-FOUND` is executed.
+
+All parameters are optional:
+
+DIR::
++GINT+ <<gint-dir,submodule directory>> (defaults to `gint`).
+
+OPTIONS::
+A whitespace-separated list of options.
+
+ACTION-IF-FOUND::
+Commands to execute if Guile is present.
+
+IF-NOT-FOUND::
+Commands to execute if Guile is not found or its version is too old.
+If not given, the default action is to print a diagnostic message on
+the standard error and abort the execution.
+
+The +OPTIONS+ parameter allows to execute finer control over the
+functionality provided by +GINT_INIT+. Its value is a
+whitespace-separated list of words. Each word must be either the
+name of an option, or the minimum (i.e. the older) allowed version
+of Guile. For example, to check for Guile 1.8 or later one could
+write:
+
+------------------------
+GINT_INIT([gint], [1.8])
+------------------------
+
+Following is a list of valid options:
+
+inc::
+Enable generation of `.inc` files. Each such file contains a set of
+`export` statements, one for each `SCM_DEFINE` in the corresponding
+`.c` source file.
+
+std-site-dir::
+Set <<sitedir,sitedir>> to the standard Guile site directory, as
+returned by the +%site-dir+ primitive.
++
+This is one of locations where Guile looks for its modules.
+However, it breaks standard `distcheck` rules and automated builds,
+because this directory is normally outside of the installation prefix.
+Therefore by default, +GINT+ does not use it. <<guile-site-dir, See
+below>>, for a description of the method used to determine it.
+
+Here is a more complex example:
+
+
+.+GINT_INIT+ macro
+-------------------------------------------------------
+GINT_INIT([modules/gint], [1.8 std-site-dir],
+ [use_guile=yes],
+ [use_guile=no])
+-------------------------------------------------------
+
+This fragment initializes the +GINT+ module located in `modules/gint` and
+checks for Guile version 1.8 or newer. The resulting script sets
+<<sitedir,sitedir>> to the standard Guile site directory. The
+shell variable `use_guile` is set to `yes` or `no`, depending on
+whether Guile was found or not.
+
+[[gint-subst-vars]]
+Substitution Variables
+----------------------
+Upon successful return, +GINT_INIT+ sets the following Automake
+substitution variables:
+
+GUILE_VERSION::
+The version of Guile, as a string, e.g. `1.9.9`. Additionally,
+a +C+ preprocessor macro with the same name is defined.
+
+GUILE_VERSION_NUMBER::
+The version of Guile packed into a decimal number using the following formula:
++
+---------------------------------------
+MAJOR * 1000 + MINOR * 100 + PATCHLEVEL
+---------------------------------------
++
+where `MAJOR`, `MINOR` and `PATCHLEVEL` are the three parts of a version
+number, separated by dots. For example, the version string `1.9.9` will produce
+the value `1909`, and the version `2.0` will yield `2000`.
++
+A +C+ preprocessor macro with the same name is also defined.
+
+GUILE_INCLUDES::
+The +C+ compiler flags needed to compile with Guile, as
+returned by `guile-config compile`.
+
+GUILE_LIBS::
+The linker flags needed to link with +libguile+, as
+returned by `guile-config link`.
+
+GUILE_SNARF::
+The full pathname of the `guile-snarf` binary.
+
+GUILE_TOOLS::
+The full pathname of the `guile-tools` binary.
+
+[[sitedir]]
+GUILE_SITE::
+The full pathname of the Guile site-wide module directory.
+
+[[guile-site-dir]]
+THE `SITE DIRECTORY' PROBLEM
+----------------------------
+Projects installing some Scheme sources would normally want to install
+them under Guile's 'site directory' (+%site-dir+ Guile primitive). This way,
+Guile will be able to find them without any additional configuration. However,
+such usage breaks the standard GNU practice of not installing files outside
+of the project's install prefix, unless the user explicitly requires so.
+As a consequence, it also breaks the standard `make distcheck` rule.
+
+To avoid this, the configuration code generated by +GINT+ macros determines
+the site directory using the following algorithm:
+
+1. Determine actual value of the default Guile site directory, by inspecting
+the value returned by the +%site-dir+ primitive.
+2. If that value lies under the current installation prefix, it is accepted
+as the installation directory.
+3. Otherwise, if the +--with-guile-site-dir+ option is used:
+ a. If it is used without arguments, +%site-dir+ is enforced as the
+ installation directory.
+ b. Otherwise, the value of this option is taken as the new installation
+ directory. Notices, that this value must be an absolute directory name.
+4. Otherwise, a warning is issued and `$(datadir)/guile/site` is used as
+the installation directory.
+
+The use if this algorithm is suppressed and Guile site directory is
+used instead, if the <<GINT_INIT,+GINT_INIT+>> macros was invoked
+with the +std-site-dir+ option.
+
+COPYRIGHT
+---------
+[verse]
+Copyright (C) 2010 http://gray.gnu.org.ua[Sergey Poznyakoff]
+License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html[<http://gnu.org/licenses/gpl.html>].
+This is free software: you are free to change and redistribute it.
+There is NO WARRANTY, to the extent permitted by law.
diff --git a/clexer.l b/clexer.l
new file mode 100644
index 0000000..d7b3b5c
--- /dev/null
+++ b/clexer.l
@@ -0,0 +1,330 @@
+/* clexer -- show lexical structure of a C file.
+ Copyright (C) 2010 Sergey Poznyakoff
+
+ 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, 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 <http://www.gnu.org/licenses/>. */
+
+%option noyywrap
+
+%top {
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+}
+
+%{
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+enum state
+ {
+ s_init,
+ s_multiline,
+ s_cookie_multiline,
+ s_cookie
+ };
+
+enum token
+ {
+ t_token = 256,
+ t_open,
+ t_close,
+ t_cookie
+ };
+
+const char *progname;
+char *infilename;
+char *outfilename;
+int guile_snarfer_mode;
+enum state state;
+FILE *outfile;
+unsigned line_no = 1;
+
+static void
+advance_line (const char *text)
+{
+ for (; *text; text++)
+ if (*text == '\n')
+ line_no++;
+}
+
+#define outstr(text) \
+ do \
+ if (state != s_init) \
+ fprintf (outfile, "%s\n", text); \
+ while (0)
+
+#define outtok(tname,tval) \
+ do \
+ if (state != s_init) \
+ fprintf (outfile, "(%s . \"%s\")\n", \
+ tname, tval); \
+ while (0)
+
+#define RETTOK(t) { outstr (#t); return t_token; }
+#define RETTXT(t,s) { outtok (#t, s); return t_token; }
+
+%}
+
+N [0-9]
+X [0-9a-fA-F]
+O [0-7]
+ID [a-zA-Z_][a-zA-Z_0-9]*
+IQ (l|L|ll|LL|lL|Ll|u|U)
+FQ [fFlL]
+E [Ee][+-]?{N}+
+WS [ \t\v\f]
+
+%%
+\/\*(\n|[^*]|\*[^/])*\*\/ { advance_line (yytext);
+ outtok ("comment", yytext); }
+#.*\n { outstr ("hash"); line_no++; }
+\n { outstr ("eol"); line_no++; }
+{WS}+ ;
+\\ ;
+{ID} RETTXT (id, yytext);
+0[xX]{X}+{IQ}? RETTXT (int_hex, yytext + 1);
+0{O}+{IQ}? RETTXT (int_oct, yytext + 2);
+{N}+{IQ}? RETTXT (int_dec, yytext);
+L?\'[^\\']\' |
+L?\'\\[^0xX]\' |
+L?\'\\{O}{1,3}\' |
+L?\'\\[xX]{X}{1,2} RETTXT (char, yytext);
+{N}+E{FQ}? |
+{N}*"."{N}+({E})?{FQ}? |
+{N}+"."{N}*({E})?{FQ}? RETTXT (flo_dec, yytext);
+L?\"([^\\\"]|\\.|\\\n)*\" { outstr (yytext); advance_line (yytext); }
+
+"^"{WS}*"^" { fputs ("snarf_cookie\n", outfile);
+ return t_cookie; }
+"{" { outstr ("brace_open"); return t_open; }
+"}" { outstr ("brace_close"); return t_close; }
+"," RETTOK (comma);
+":" RETTOK (colon);
+"=" RETTOK (assign);
+"(" RETTOK (paren_open);
+")" RETTOK (paren_close);
+"[" RETTOK (bracket_open);
+"]" RETTOK (bracket_close);
+"&" RETTOK (amp);
+"^" RETTOK (caret);
+"|" RETTOK (pipe);
+"?" RETTOK (question);
+"!" RETTOK (bang);
+"~" RETTOK (tilde);
+"-" RETTOK (minus);
+"+" RETTOK (plus);
+"*" RETTOK (star);
+"/" RETTOK (slash);
+"%" RETTOK (percent);
+"..." RETTOK (ellipsis);
+"->" RETTOK (ptr);
+"." RETTOK (dot);
+"*=" RETTOK (mul_assign);
+"/=" RETTOK (div_assign);
+"%=" RETTOK (mod_assign);
+"+=" RETTOK (add_assign);
+"-=" RETTOK (sub_assign);
+"<<=" RETTOK (shift_left_assign);
+">>=" RETTOK (shift_right_assign);
+"&=" RETTOK (logand_assign);
+"|=" RETTOK (logior_assign);
+"^=" RETTOK (logxor_assign);
+"||" RETTOK (or);
+"&&" RETTOK (and);
+"==" RETTOK (eq);
+"!=" RETTOK (neq);
+">=" RETTOK (ge);
+">>" RETTOK (right_shift);
+">" RETTOK (gt);
+"<=" RETTOK (le);
+"<<" RETTOK (left_shift);
+"<" RETTOK (lt);
+"++" RETTOK (inc);
+"--" RETTOK (dec);
+";" RETTOK (semicolon);
+. { fprintf (stderr,
+ (isascii (yytext[0]) &&
+ isprint (yytext[0])) ?
+ "%s:%u: stray character %c\n" :
+ "%s:%u: stray character \\%03o",
+ infilename,
+ line_no, (unsigned char) yytext[0]);
+ return t_token; }
+
+%%
+
+void
+usage()
+{
+ printf ("\
+usage: clexer [OPTIONS] [FILE]\n\
+\n\
+Show lexical structure of a C source. When given the --snarfer option,\n\
+display only lexical tokens produced by Guile snarfer. The output may be\n\
+piped to the `guile-tools snarf-check-and-output-texi' command.\n\
+\n\
+OPTIONS are:\n\
+ -s, --snarfer filter out Guile docstrings\n\
+ -o, --output=FILE write output to FILE\n\
+ -h, --help show this help summary\n\
+\n");
+ printf ("Report bugs to <gray+clexer@gnu.org.ua>\n");
+}
+
+int
+main (int argc, char **argv)
+{
+ int i;
+ enum token tok, last_tok;
+
+ progname = argv[0];
+
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "-s") ||
+ !strcmp (argv[i], "--snarfer") ||
+ !strcmp (argv[i], "--guile-snarfer"))
+ {
+ guile_snarfer_mode = 1;
+ }
+ else if (!strcmp (argv[i], "-h") ||
+ !strcmp (argv[i], "--help"))
+ {
+ usage ();
+ exit (0);
+ }
+#if 0
+ else if (!strcmp (argv[i], "-v") ||
+ !strcmp (argv[i], "--version"))
+ {
+ version ();
+ exit (0);
+ }
+#endif
+ else if (!strncmp (argv[i], "-o", 2))
+ {
+ if (argv[i][2])
+ outfilename = argv[i] + 2;
+ else if (++i < argc)
+ outfilename = argv[i];
+ else
+ {
+ fprintf (stderr, "%s: option '-o' requires an argument\n",
+ progname);
+ exit (1);
+ }
+ }
+ else if (!strncmp (argv[i], "--output=", 9))
+ outfilename = argv[i] + 9;
+ else if (!strcmp (argv[i], "--output"))
+ {
+ if (++i < argc)
+ outfilename = argv[++i];
+ else
+ {
+ fprintf (stderr, "%s: option '--output' requires an argument\n",
+ progname);
+ exit (1);
+ }
+ }
+ else if (!strcmp (argv[i], "--"))
+ {
+ if (++i < argc)
+ infilename = argv[i];
+ break;
+ }
+ else if (argv[i][0] == '-')
+ {
+ fprintf (stderr, "%s: unknown option: %s\n",
+ progname, argv[i]);
+ exit (1);
+ }
+ else
+ {
+ infilename = argv[i];
+ }
+ }
+
+ if (infilename && strcmp (infilename, "-"))
+ {
+ FILE *fp = fopen (infilename, "r");
+ if (!fp)
+ {
+ fprintf (stderr, "%s: cannot open file `%s': %s\n",
+ progname, infilename, strerror (errno));
+ exit (1);
+ }
+ yyrestart (fp);
+ }
+ else
+ infilename = "stdin";
+
+ if (outfilename)
+ {
+ outfile = fopen (outfilename, "w");
+ if (!outfile)
+ {
+ fprintf (stderr, "%s: cannot open file `%s': %s\n",
+ progname, outfilename, strerror (errno));
+ exit (1);
+ }
+ }
+ else
+ outfile = stdout;
+
+ state = guile_snarfer_mode ? s_init : s_cookie;
+ last_tok = t_token;
+ while ((tok = yylex ()) > 0)
+ {
+ if (!guile_snarfer_mode)
+ continue;
+ switch (tok)
+ {
+ case t_token:
+ break;
+
+ case t_open:
+ if (last_tok == t_cookie && state == s_cookie)
+ state = s_multiline;
+ break;
+
+ case t_close:
+ if (last_tok == t_cookie && state == s_cookie_multiline)
+ state = s_init;
+ break;
+
+ case t_cookie:
+ switch (state)
+ {
+ case s_init:
+ state = s_cookie;
+ break;
+
+ case s_multiline:
+ case s_cookie_multiline:
+ state = s_cookie_multiline;
+ break;
+
+ case s_cookie:
+ state = s_init;
+ }
+ }
+ last_tok = tok;
+ }
+
+ fclose (outfile);
+ exit (0);
+}
diff --git a/extract-exports b/extract-exports
new file mode 100755
index 0000000..b0aeda6
--- /dev/null
+++ b/extract-exports
@@ -0,0 +1,81 @@
+#!/bin/sh
+# aside from this initial boilerplate, this is actually -*- scheme -*- code
+main="(module-ref (resolve-module '(gint extract-exports)) 'main)
+"
+exec ${GUILE-guile} -l $0 -c "(apply $main (command-line))" "$@"
+!#
+
+;;;; This file is part of Gint
+;;;; Copyright (C) 2010 Sergey Poznyakoff
+;;;;
+;;;; 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, 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 <http://www.gnu.org/licenses/>.
+
+(define-module (gint extract-exports)
+ :use-module (ice-9 getopt-long))
+
+(define (snarf-exports)
+ (let loop ((elt (read)))
+ (cond
+ ((not (eof-object? elt))
+ (if (and (pair? elt)
+ (eq? (car elt) 'id)
+ (string? (cdr elt))
+ (string=? (cdr elt) "fname"))
+ (let ((name (read)))
+ (if (string? name)
+ (format #t "(export ~A)~%" name))))
+ (loop (read))))))
+
+(define output-file-name #f)
+(define input-file-list '())
+
+(define (usage)
+ (display "usage: extract-exports [OPTIONS] [FILE [FILE...]]\n")
+ (display "\n")
+ (display "OPTIONS are:\n")
+ (display " -o, --output FILE set output file name\n")
+ (display " -h, --help display this help summary\n"))
+
+(define (do-file-list)
+ (if (null? input-file-list)
+ (snarf-exports)
+ (for-each
+ (lambda (file)
+ (with-input-from-file
+ file
+ snarf-exports))
+ input-file-list)))
+
+(define (main . cmdline)
+ (let ((grammar `((output (single-char #\o)
+ (value #t))
+ (help (single-char #\h)))))
+ (for-each
+ (lambda (x)
+ (case (car x)
+ ((output)
+ (set! output-file-name (cdr x)))
+ ((help)
+ (usage)
+ (exit 0))
+ ('()
+ (set! input-file-list (cdr x)))))
+ (getopt-long cmdline grammar)))
+
+ (if output-file-name
+ (with-output-to-file
+ output-file-name
+ do-file-list)
+ (do-file-list)))
+
diff --git a/gint.m4 b/gint.m4
new file mode 100644
index 0000000..cd0df0e
--- /dev/null
+++ b/gint.m4
@@ -0,0 +1,63 @@
+# gint.m4 serial 1
+dnl This file is part of Gint
+dnl Copyright (C) 2010 Sergey Poznyakoff
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 3, or (at your option)
+dnl any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+dnl The option stuff below is based on the similar code from Automake
+
+# _GINT_MANGLE_OPTION(NAME)
+# -------------------------
+# Convert NAME to a valid m4 identifier, by replacing invalid characters
+# with underscores, and prepend the _GINT_OPTION_ suffix to it.
+AC_DEFUN([_GINT_MANGLE_OPTION],
+[[_GINT_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _GINT_SET_OPTION(NAME)
+# ----------------------
+# Set option NAME. If NAME begins with a digit, treat it as a requested
+# Guile version number, and define _GINT_GUILE_VERSION to that number.
+# Otherwise, define the option using _GINT_MANGLE_OPTION.
+AC_DEFUN([_GINT_SET_OPTION],
+[m4_if(m4_bpatsubst($1,^[[0-9]].*,[]),,[m4_define([_GINT_GUILE_VERSION],[$1])],[m4_define(_GINT_MANGLE_OPTION([$1]), 1)])])
+
+# _GINT_IF_OPTION_SET(NAME,IF-SET,IF-NOT-SET)
+# -------------------------------------------
+# Check if option NAME is set.
+AC_DEFUN([_GINT_IF_OPTION_SET],
+[m4_ifset(_GINT_MANGLE_OPTION([$1]),[$2],[$3])])
+
+# _GINT_SET_OPTIONS(OPTIONS)
+# ----------------------------------
+# OPTIONS is a space-separated list of Gint options.
+AC_DEFUN([_GINT_SET_OPTIONS],
+[m4_foreach_w([_GINT_Option], [$1], [_GINT_SET_OPTION(_GINT_Option)])])
+
+dnl GINT_INIT([DIR], [OPTIONS], [IF-FOUND], [IF-NOT-FOUND])
+dnl -------------------------------------------------------
+dnl DIR Gint submodule directory (defaults to 'gint')
+dnl OPTIONS A whitespace-separated list of options. Currently recognized
+dnl options are: 'inc', 'std-site-dir' and version number.
+dnl IF-FOUND What to do if Guile is present.
+dnl IF-NOT-FOUND What to do otherwise.
+dnl
+AC_DEFUN([GINT_INIT],[
+ AM_PROG_LEX
+ _GINT_SET_OPTIONS([$2])
+ AC_SUBST([GINT_MODULE_DIR],[m4_if([$1],,[gint],[$1])])
+ AM_CONDITIONAL([GINT_COND_INC],[_GINT_IF_OPTION_SET([inc],[true],[false])])
+
+ GINT_CHECK_GUILE(m4_ifdef([_GINT_GUILE_VERSION],_GINT_GUILE_VERSION),[$3],[$4])
+])
+
diff --git a/gint.mk b/gint.mk
new file mode 100644
index 0000000..b691b3d
--- /dev/null
+++ b/gint.mk
@@ -0,0 +1,66 @@
+# This file is part of Gint
+# Copyright (C) 2010 Sergey Poznyakoff
+#
+# 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, 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 <http://www.gnu.org/licenses/>.
+
+INCLUDES += @GUILE_INCLUDES@
+
+EXTRA_DIST += guile-procedures.texi guile-procedures.txt
+
+site_DATA += guile-procedures.txt
+
+BUILT_SOURCES=$(DOT_X_FILES) $(DOT_DOC_FILES) guile-procedures.texi
+
+DISTCLEANFILES +=\
+ $(DOT_X_FILES)\
+ $(DOT_DOC_FILES)\
+ guile-procedures.texi\
+ guile-procedures.txt
+
+ETAGS_ARGS = --regex='/SCM_\(GLOBAL_\)?\(G?PROC\|G?PROC1\|SYMBOL\|VCELL\|CONST_LONG\).*\"\([^\"]\)*\"/\3/' \
+ --regex='/[ \t]*SCM_[G]?DEFINE1?[ \t]*(\([^,]*\),[^,]*/\1/'
+
+GUILE_DOC_SNARF=$(top_builddir)/$(GINT_MODULE_DIR)/clexer --snarfer
+
+SUFFIXES += .x .doc
+
+.c.x:
+ $(AM_V_GEN)AWK=$(AWK) \
+ $(GUILE_SNARF) -o $@ \
+ $< $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+
+.c.doc:
+ $(AM_V_GEN)$(CC) -DSCM_MAGIC_SNARF_DOCS \
+ $(DEFS) $(INCLUDES) $(CPPFLAGS) -E $< | \
+ $(GUILE_DOC_SNARF) -o $@ || { rm $@; false; }
+
+if GINT_COND_INC
+SUFFIXES += .inc
+CLEANFILES += *.inc
+
+.doc.inc:
+ $(AM_V_GEN)$(top_srcdir)/$(GINT_MODULE_DIR)/extract-exports -o $@ $<
+endif
+
+guile-procedures.texi: $(DOT_DOC_FILES)
+ $(AM_V_GEN)cat $(DOT_DOC_FILES) | \
+ $(GUILE_TOOLS) snarf-check-and-output-texi > $@
+
+guile-procedures.txt: guile-procedures.texi
+ $(AM_V_GEN) rm -f $@; \
+ $(MAKEINFO) --force -o $@ guile-procedures.texi || test -f $@
+
+## Add -MG to make the .x magic work with auto-dep code.
+MKDEP = $(CC) -M -MG $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+
diff --git a/guile.m4 b/guile.m4
new file mode 100644
index 0000000..1d340b4
--- /dev/null
+++ b/guile.m4
@@ -0,0 +1,120 @@
+# guile.m4 serial 1
+dnl This file is part of Gint
+dnl Copyright (C) 2010 Sergey Poznyakoff
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 3, or (at your option)
+dnl any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+m4_define([_gint_eval_version],
+[m4_if([$2],,[m4_errprint([Version number without dots: $1
+])],[m4_eval([$1] * 1000 + [$2] * 100[]m4_if([$3],,,[ + $3]))])])
+
+m4_define([_gint_mangle_version],[_gint_eval_version(m4_bpatsubst($1,\.,[,]))])
+
+m4_define([_gint_site_dir],[`guile -c '(write (%site-dir)) (newline)'`])
+
+dnl GINT_CHECK_GUILE(minversion, [act-if-found], [ac-if-not-found])
+dnl $1 $2 $3
+AC_DEFUN([GINT_CHECK_GUILE],
+[
+ AS_VAR_SET([gint_cv_guile], [no])
+ AC_PATH_PROG(GUILE_CONFIG, guile-config, no, $PATH)
+ if test "$GUILE_CONFIG" = no; then
+ m4_if([$3],,[AC_MSG_ERROR(cannot find Guile)], [$3])
+ else
+ AC_SUBST(GUILE_INCLUDES)
+ AC_SUBST(GUILE_LIBS)
+ AC_SUBST(GUILE_VERSION)
+ AC_SUBST(GUILE_VERSION_NUMBER)
+ AC_PATH_PROG(GUILE_SNARF, guile-snarf)
+ AC_PATH_PROG(GUILE_TOOLS, guile-tools)
+
+ GUILE_INCLUDES=`$GUILE_CONFIG compile`
+ GUILE_LIBS=`$GUILE_CONFIG link`
+ GUILE_VERSION=`($GUILE_CONFIG --version 2>&1; echo '')|sed 's/guile-config [[^0-9]]* \([[0-9]][[0-9.]]*\)$/\1/'`
+ VEX=`echo $GUILE_VERSION | sed 's/\./ \\\\* 1000 + /;s/\./ \\\\* 100 + /'`
+ GUILE_VERSION_NUMBER=`eval expr "$VEX"`
+
+ m4_if([$1],,,[
+ if test $GUILE_VERSION_NUMBER -lt _gint_mangle_version($1); then
+ m4_if($3,,
+ [AC_MSG_ERROR([Guile version too old; required is at least ]$1)],
+ [$3])
+ fi])
+
+ save_LIBS=$LIBS
+ save_CFLAGS=$CFLAGS
+ LIBS="$LIBS $GUILE_LIBS"
+ CFLAGS="$CFLAGS $GUILE_INCLUDES"
+ AC_TRY_LINK([#include <libguile.h>],
+ m4_if([$1], , scm_shell(0, NULL);, [$1]),
+ [AS_VAR_SET([gint_cv_guile], $GUILE_VERSION)])
+ LIBS=$save_LIBS
+ CFLAGS=$save_CFLAGS
+ fi
+
+ if test $gint_cv_guile = no; then
+ GUILE_INCLUDES=
+ GUILE_LIBS=
+ GUILE_VERSION=
+ GUILE_VERSION_NUMBER=
+ m4_if([$3],,[AC_MSG_ERROR(required library libguile not found)], [$3])
+ else
+ save_LIBS=$LIBS
+ save_CFLAGS=$CFLAGS
+ LIBS="$LIBS $GUILE_LIBS"
+ CFLAGS="$CFLAGS $GUILE_INCLUDES"
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <libguile.h>]],
+ [SCM_DEVAL_P = 1;
+ SCM_BACKTRACE_P = 1;
+ SCM_RECORD_POSITIONS_P = 1;
+ SCM_RESET_DEBUG_MODE;])],
+ [gint_cv_guile_debug=yes],
+ [gint_cv_guile_debug=no])
+ if test $gint_cv_guile_debug = yes; then
+ AC_DEFINE_UNQUOTED(GUILE_DEBUG_MACROS, 1,
+ [Define to 1 if SCM_DEVAL_P, SCM_BACKTRACE_P, SCM_RECORD_POSITIONS_P and SCM_RESET_DEBUG_MODE are defined])
+ fi
+ AC_CHECK_TYPES([scm_t_off],[],[],[#include <libguile.h>])
+ LIBS=$save_LIBS
+ CFLAGS=$save_CFLAGS
+
+ AC_SUBST(GUILE_SITE)
+ _GINT_IF_OPTION_SET([std-site-dir],
+ [GUILE_SITE=_gint_site_dir],
+ [AC_ARG_WITH([guile-site-dir],
+ AC_HELP_STRING([--with-guile-site-dir=DIR],
+ [specify directory to install guile modules to]),
+ [case $withval in
+ /*) GUILE_SITE=$withval;;
+ yes) GUILE_SITE=_gint_site_dir;;
+ *) AC_MSG_ERROR([Argument to --with-guile-site-dir must be an absolute directory name]);;
+ esac],
+ [GUILE_SITE=_gint_site_dir
+ pfx=$prefix
+ test "x$pfx" = xNONE && pfx=$ac_default_prefix
+ case $GUILE_SITE in
+ $pfx/*) ;; # OK
+ *) AC_MSG_WARN([guile site directory "$GUILE_SITE" lies outside your current prefix ($pfx).])
+ GUILE_SITE='$(datadir)/guile/site'
+ AC_MSG_WARN([Falling back to ${GUILE_SITE} instead. Use --with-guile-site-dir to force using site directory.])
+ ;;
+ esac])])
+ AC_DEFINE_UNQUOTED(GUILE_VERSION, "$GUILE_VERSION",
+ [Guile version number])
+ AC_DEFINE_UNQUOTED(GUILE_VERSION_NUMBER, $GUILE_VERSION_NUMBER,
+ [Guile version number: MAX*10 + MIN])
+ m4_if([$2],,,[$2])
+ fi
+])
+