guile-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Using guile as an extension language for GNU make


From: Ludovic Courtès
Subject: Re: Using guile as an extension language for GNU make
Date: Sun, 18 Sep 2011 14:10:19 +0200
User-agent: Gnus/5.110018 (No Gnus v0.18) Emacs/24.0.50 (gnu/linux)

Hi Paul,

Paul Smith <address@hidden> skribis:

> I've been experimenting with using Guile as an extension language to GNU
> make (optionally built-in of course).

Sounds like great news!  :-)

> What I've done so far:
>
>       * Modified GNU make's main to be invoked from scm_boot_guile(), if
>         Guile is enabled.

Ideally, when Guile support is enabled, GNU make would be turned into a
Guile extension (a shared library and its companion Scheme module that
loads it with ‘load-extension’) that would expose make’s functionality.

The main advantage is that make could then be used by “normal” Guile
programs:

  (use-modules (make))

  (define c->o
    (make-rule (make-target "foo.o")
               (make-prerequisites '("foo.c" "foo.h"))
               (list (make-expand "$(CC)") "-c -Wall"
                     (make-expand "$^") " -o "
                     (make-expand "$@"))))

  (eval-make-rule c->o)

Or:

  (use-modules (make))

  (define mf (parse-makefile "/foo/GNUmakefile"))
  (format #t "the targets are: ~a~%" (makefile-targets mf))

  ;; Imagine code that extracts the complete DAG, computes the critical
  ;; path length, and schedules tasks...

The ‘make’ executable would be a Guile script like:

  (use-modules (make))

  (apply run-make (command-line))

This is more intrusive than embedding libguile in make, but it’s also
more fruitful.  On the general patterns of embedding vs. extending, see
the excellent <http://www.twistedmatrix.com/users/glyph/rant/extendit.html>.

>       * Created a new GNU make function, $(guile ...), where the
>         argument is passed to Guile for expansion and the result is
>         turned into a string and used as the result; the code looks like
>         this:
>                 func_guile (char *o, char **argv, const char *funcname UNUSED)
>                 {
>                   if (argv[0] && argv[0][0] != '\0')
>                     {
>                       char *str = scm_to_locale_string (scm_object_to_string 
> (scm_c_eval_string (argv[0]),
>                                                                               
> SCM_UNDEFINED));
>                       char *s = str;
>                       unsigned int l = strlen (s);
>                 
>                       if (s[0] == '"' && s[l-1] == '"')

There are two problems I can think of here:

  - string unquoting is actually more complex than this (recall that
    ‘object->string’ merely calls ‘write’):

--8<---------------cut here---------------start------------->8---
(call-with-output-string
  (lambda (p)
    (set-port-encoding! p "ISO-8859-1")
    (set-port-conversion-strategy! p 'substitute)
    (write "\"λ\" is a Greek letter" p)))

=> "\"\\\"\\u03bb\\\" is a Greek letter\""
--8<---------------cut here---------------end--------------->8---

  - ‘scm_c_eval_string’ can return any Scheme objects, some of which
    have meaningless representations as strings:

--8<---------------cut here---------------start------------->8---
(object->string (current-module))
=> "#<directory (guile-user) 2405090>"
--8<---------------cut here---------------end--------------->8---

The latter is probably the most serious question.  I think you would
really want to constrain expressions passed in $(guile ...) to return a
string, and not any other type of objects.

In that case, you could solve the first problem by using (display ...)
instead of (write ...).

>       * Created two new functions and registered them with Guile:
>         (make-expand <string>) which takes a string argument and expands
>         it as a make expression, so it can be something like
>         (make-expand "$(VAR)") for example to get the value of the make
>         variable VAR.  And (make-eval <string>) which takes a string
>         argument and evaluates it as a makefile snippet; this is
>         essentially the same as running (make-expand "$(eval <string>)")
>         just shorter to type.  This lets you define make constructs like
>         rules and variables from within the Guile interpreter.  The code
>         looks like this:

Looks good to me.

Thanks!

Ludo’.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]