* Guile support in GNU make
@ 2012-01-14 19:55 Paul Smith
2012-01-15 8:51 ` Thien-Thi Nguyen
0 siblings, 1 reply; 19+ messages in thread
From: Paul Smith @ 2012-01-14 19:55 UTC (permalink / raw)
To: guile-user
[-- Attachment #1: Type: text/plain, Size: 1690 bytes --]
Hi all. I'm about to commit initial support for Guile to GNU make. I'm
interested in any comments you may have on the implementation (there is
still time to make changes before the next release of GNU make).
I'm committed to leaving Guile as an optional component for now. As a
result I'm not rewriting existing features of GNU make in terms of
Guile, or embedding it any more deeply than an extensions language. I
understand that some feel this is a sub-optimal solution and would like
to see Guile become a requirement, or even GNU make rewritten as a
loadable module for Guile, but I've decided that's not the way I'm going
to go at this time.
Attached please find three things:
1. The documentation I've added to the GNU make manual regarding
Guile
2. The default Guile scripting that is embedded in GNU make
3. The C code interface, for those who are curious
For #3 not ALL the code is provided: I left out the little bit that
wraps main() for example, and the part that wraps the $(guile ...)
function. But the critical parts are there. The rest should be
available in the GNU make repository sometime this weekend.
My Scheme-fu is fairly weak and my Guile-fu is even weaker. Any
suggestions about improvements to any of the above items from more
advanced users will be welcome--keeping in mind my comments of paragraph
#2 above, please, thanks!
--
-------------------------------------------------------------------------------
Paul D. Smith <psmith@gnu.org> Find some GNU make tips at:
http://www.gnu.org http://make.mad-scientist.net
"Please remain calm...I may be mad, but I am a professional." --Mad Scientist
[-- Attachment #2: guile-doc.txt --]
[-- Type: text/plain, Size: 4783 bytes --]
8.13 The `guile' Function
=========================
GNU make may be built with support for GNU Guile as an embedded
extension language. You can check the `.FEATURES' variable for the
word `guile' to determine if your version of GNU make provides this
capability.
GNU Guile implements the Scheme language. A review of GNU Guile and
the Scheme language and its features is beyond the scope of this
manual: see the documentation for GNU Guile and Scheme.
If GNU Guile is available as an extension language, there will be one
new `make' function available: `guile'. The `guile' function takes one
argument which is first expanded by `make' in the normal fashion, then
passed to the GNU Guile evaluator function. The result of the
evaluator is converted into a string and used as the expansion of the
`guile' function in the makefile.
8.13.1 Conversion of Guile Results
----------------------------------
When the `guile' function is evaluated, `make' will convert the result
of the function into a string and use it as the result of the
evaluation. The conversion of different Guile types into a string is
as follows:
`#f'
The empty string: in `make' the empty string is considered false.
`#t'
The string `t': in `make' any non-empty string is considered true.
`symbol'
`number'
A symbol or number is converted into the string representation of
that symbol or number.
`character'
A printable character is converted to the same character.
`string'
A string containing only printable characters is converted to the
same string.
`list'
A list is converted recursively according to the above rules. This
implies that any structured list will be flattened (that is, a
result of `'(a b (c d) e)' will be converted to the `make' string
`a b c d e').
`other'
Any other Guile type results in an error. In future versions of
`make', other Guile types may be converted.
As a consequence of these conversion rules you must be careful what
results your Guile forms evaluate to. If there is no natural result
for the script (that is the script exists solely for its side-effects,
not for its result), you should have it return `#f' to avoid syntax
errors in your makefile from result conversions.
8.13.2 Interfaces from Guile to `make'
--------------------------------------
In addition to the `guile' function available in makefiles, there are
three functions exported into GNU Guile by `make', for use in your
Guile scripts.
The `make' program creates a new module, `gnu make', and exports
these functions as public interfaces from that module:
`gmk-expand'
This GNU Guile function takes a single string as an argument. The
string is expanded by `make' using normal expansion rules. The
result of the expansion is converted into a string and provided to
GNU Guile as the result of the function.
`gmk-eval'
This function takes a single string as an argument. The string is
evaluated by `make' as if it were a makefile. This is the same
capability available via the `eval' function (*note Eval
Function::). The result of the `gmk-eval' function is always the
empty string.
`gmk-var'
This function takes a single string as an argument. The string is
interpreted as the name of a `make' variable, which is then
expanded. The result of the expansion is converted into a string
and provided as the result of the function in GNU Guile.
8.13.3 Example Using Guile in `make'
------------------------------------
Here is a very simple example using GNU Guile to manage writing to a
file. This set of Guile code simply opens a file, then allows writing
strings to it (one string per line), then closes it again. Note that
because we cannot store complex values such as Guile ports in `make'
variables, we'll keep the port as a global variable in the Guile
interpreter.
This code defines the Guile functions:
define GUILEIO
;; A simple Guile IO library for GNU make
(define MKPORT #f)
(define (mkopen name mode)
(set! MKPORT (open-file name mode))
#f)
(define (mkwrite s)
(display s MKPORT)
(newline MKPORT)
#f)
(define (mkclose)
(close-port MKPORT)
#f)
endef
# Internalize the Guile IO functions
$(guile $(GUILEIO))
Now you can use these Guile functions to create files. Suppose you
need to operate on a very large list, which cannot fit on the command
line, but the utility you're using accepts the list as input as well:
prog: $(PREREQS)
@$(guile (mkopen "tmp.out" "w")) \
$(foreach X,$^,$(guile (mkwrite "$(X)"))) \
$(guile (mkclose))
$(LINK) < tmp.out
[-- Attachment #3: gmk-default.scm --]
[-- Type: text/x-scheme, Size: 1900 bytes --]
;; Contents of the (gnu make) Guile module
;; Copyright (C) 2011 Free Software Foundation, Inc.
;; This file is part of GNU Make.
;;
;; GNU Make 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 of the License, or (at your option)
;; any later version.
;;
;; GNU Make 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 (to-string-maybe x)
(cond
;; In GNU make, "false" is the empty string
((or (not x)
(unspecified? x)
(null? x)
(and (string? x) (string-null? x)))
#f)
;; We want something not false... not sure about this
((eq? x #t) "t")
;; Basics
((or (symbol? x) (number? x))
(object->string x))
((char? x)
(string x))
;; Printable string (no special characters)
((and (string? x)
(eq? (string-length (string-delete x char-set:printing)) 0))
x)
;; No idea: fail
(else (error "Unknown object:" x))))
(define (obj-to-str x)
(let ((acc '()))
(define (walk x)
(cond ((pair? x) (walk (car x)) (walk (cdr x)))
((to-string-maybe x) => (lambda (s) (set! acc (cons s acc))))))
(walk x)
(string-join (reverse! acc))))
;; eval (GNU make eval) the input string S
(define (gmk-eval s)
(gmk-expand (format #f "$(eval ~a)" (obj-to-str s))))
;; Return the value of the GNU make variable V
(define (gmk-var v)
(gmk-expand (format #f "$(~a)" (obj-to-str v))))
;; Export the public interfaces
(export gmk-expand gmk-eval gmk-var)
[-- Attachment #4: guile.c --]
[-- Type: text/x-csrc, Size: 3120 bytes --]
/* GNU Guile interface for GNU Make.
Copyright (C) 2011 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make 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 of the License, or (at your option) any later
version.
GNU Make 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/>. */
#include "make.h"
#ifndef HAVE_GUILE
/* Without Guile we just call the real main() directly. */
void
guile_boot (void (*func)(int, char **, char **),
int argc, char **argv, char **envp)
{
(*func) (argc, argv, envp);
}
#else
#include "debug.h"
#include "dep.h"
#include "variable.h"
#include <libguile.h>
static SCM make_mod = SCM_EOL;
static SCM obj_to_str = SCM_EOL;
/* Convert an SCM object into a string. */
static char *
cvt_scm_to_str (SCM obj)
{
return scm_to_locale_string (scm_call_1 (obj_to_str, obj));
}
/* Perform the GNU make expansion function. */
static SCM
guile_expand_wrapper (SCM obj)
{
char *str = cvt_scm_to_str (obj);
SCM ret;
char *res;
DB (DB_BASIC, (_("guile: Expanding '%s'\n"), str));
res = allocated_variable_expand (str);
ret = scm_from_locale_string (res);
free (str);
free (res);
return ret;
}
/* Invoked by scm_c_define_module(), in the context of the GNU make module. */
static void
guile_define_module (void *data UNUSED)
{
/* Ingest the predefined Guile module for GNU make. */
#include "gmk-default.h"
/* Register a subr for GNU make's eval capability. */
scm_c_define_gsubr ("gmk-expand", 1, 0, 0, guile_expand_wrapper);
/* Define the rest of the module. */
scm_c_eval_string (GUILE_module_defn);
}
/* Initialize the GNU make Guile module. */
static void
guile_init ()
{
/* Define the module. */
make_mod = scm_c_define_module ("gnu make", guile_define_module, NULL);
/* Get a reference to the object-to-string translator, for later. */
obj_to_str = scm_variable_ref (scm_c_module_lookup (make_mod, "obj-to-str"));
/* Import the GNU make module exports into the generic space. */
scm_c_eval_string ("(use-modules (gnu make))");
}
static void (*real_main)(int, char **, char **);
/* Initialize Guile, then run the real GNU make main. */
static void
guile_boot_internal (void *data, int argc, char **argv)
{
guile_init ();
(*real_main) (argc, argv, data);
}
/* ----- Public interface ----- */
void
guile_boot (void (*func)(int, char **, char **),
int argc, char **argv, char **envp)
{
real_main = func;
scm_boot_guile (argc, argv, guile_boot_internal, envp);
/* Never returns. */
}
/* This is the make interface for passing programs to Guile. */
char *
guile_eval_string (char *str)
{
return cvt_scm_to_str (scm_c_eval_string (str));
}
#endif
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: Guile support in GNU make
2012-01-14 19:55 Guile support in GNU make Paul Smith
@ 2012-01-15 8:51 ` Thien-Thi Nguyen
2012-01-15 12:33 ` Thien-Thi Nguyen
2012-01-15 16:12 ` Paul Smith
0 siblings, 2 replies; 19+ messages in thread
From: Thien-Thi Nguyen @ 2012-01-15 8:51 UTC (permalink / raw)
To: psmith; +Cc: guile-user
() Paul Smith <psmith@gnu.org>
() Sat, 14 Jan 2012 14:55:05 -0500
Any suggestions [...] will be welcome
I looked at the doc file and have these suggestions:
- In Scheme, it is customary to say "procedure" instead of "function".
I suggest 8.13.2 Interfaces from Guile to `make' explicitly state that
(for those unfamiliar w/ Scheme), and then liberally specify "function"
for Make functions and "procedure" for Scheme procedures.
- The ‘#t => t’ distinguishes the symbol t from others, which feels wrong.
I suggest #t => ""; #f => error.
- Give more details for ‘other => error’. Since this feature is new,
there will be many debugging opportunities :-D, so the better you
define this condition, the easier it will be for users to use, and
for you to get feedback for further iteration.
That's all. Looking forward to playing w/ this feature!
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: Guile support in GNU make
2012-01-15 8:51 ` Thien-Thi Nguyen
@ 2012-01-15 12:33 ` Thien-Thi Nguyen
2012-01-15 16:12 ` Paul Smith
1 sibling, 0 replies; 19+ messages in thread
From: Thien-Thi Nguyen @ 2012-01-15 12:33 UTC (permalink / raw)
To: psmith; +Cc: guile-user
Oh yeah, i forgot: I think Make vars should not be
accessed by a Scheme string, but rather a symbol:
(define (gmk-var v)
(or (symbol? v) (error "not a symbol:" v))
(gmk-expand (format #f "$(~a)" (obj-to-str v))))
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: Guile support in GNU make
2012-01-15 8:51 ` Thien-Thi Nguyen
2012-01-15 12:33 ` Thien-Thi Nguyen
@ 2012-01-15 16:12 ` Paul Smith
2012-01-15 20:11 ` Thien-Thi Nguyen
2012-01-15 22:02 ` Ludovic Courtès
1 sibling, 2 replies; 19+ messages in thread
From: Paul Smith @ 2012-01-15 16:12 UTC (permalink / raw)
To: Thien-Thi Nguyen; +Cc: guile-user
On Sun, 2012-01-15 at 09:51 +0100, Thien-Thi Nguyen wrote:
> - In Scheme, it is customary to say "procedure" instead of "function".
> I suggest 8.13.2 Interfaces from Guile to `make' explicitly state that
> (for those unfamiliar w/ Scheme), and then liberally specify "function"
> for Make functions and "procedure" for Scheme procedures.
Excellent, thank you. That will definitely make things more clear.
> - The ‘#t => t’ distinguishes the symbol t from others, which feels wrong.
> I suggest #t => ""; #f => error.
Hm. The problem with this is that we can't easily use Guile booleans in
GNU make. For example, the syntax for make's $(if ...) function is:
$(if <condition>,<then>[,<else>])
The <condition> is expanded as a makefile expression and if it's empty
it's considered false. If it's non-empty it's considered true.
Suppose we wanted to write a Guile condition here, something like:
$(guile (access? "foo" R_OK))
Under the current behavior that can be used directly:
$(if $(guile (access? "foo" R_OK)),...)
If we change things as you suggest we must be sure that we NEVER provide
a result of #f to any procedure that is called by make's guile function
otherwise make will fail. In other words we'd have to do something like
this instead:
$(if $(guile (if (access? "foo" R_OK) true #t)),...)
Or maybe more understandable:
$(if $(guile (if (access? "foo" R_OK) true "")),...)
Of course we could write a procedure to do this conversion for us, but
isn't that just making extra work to do what we could define the
conversion to do natively? I understand the conversion of #t => "t" and
#f => "" is strange to think about, but I'm not sure the alternatives
are better.
> - Give more details for ‘other => error’. Since this feature is new,
> there will be many debugging opportunities :-D, so the better you
> define this condition, the easier it will be for users to use, and
> for you to get feedback for further iteration.
I agree with this 100%... unfortunately I really have no idea what
happens here or what facilities are available/appropriate for handling
errors or debugging Guile programs. I will need to investigate.
> Oh yeah, i forgot: I think Make vars should not be accessed by a
> Scheme string, but rather a symbol
Well, my concern about this is that in GNU make, anyway, we very often
use constructed variable names. I would assume that the same would be
true in Guile procedures, which means it will more be convenient to
store variable names in strings in Guile (it seems to me) so they can be
more easily manipulated. Of course you can always use symbol->string
etc. But is this worth it, to require the Guile user to always perform
this operation when we could do it automatically?
--
-------------------------------------------------------------------------------
Paul D. Smith <psmith@gnu.org> Find some GNU make tips at:
http://www.gnu.org http://make.mad-scientist.net
"Please remain calm...I may be mad, but I am a professional." --Mad Scientist
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: Guile support in GNU make
2012-01-15 16:12 ` Paul Smith
@ 2012-01-15 20:11 ` Thien-Thi Nguyen
2012-01-15 20:49 ` Paul Smith
2012-01-15 22:02 ` Ludovic Courtès
1 sibling, 1 reply; 19+ messages in thread
From: Thien-Thi Nguyen @ 2012-01-15 20:11 UTC (permalink / raw)
To: psmith; +Cc: guile-user
() Paul Smith <psmith@gnu.org>
() Sun, 15 Jan 2012 11:12:29 -0500
> - The ‘#t => t’ distinguishes the symbol t from others, which feels wrong.
> I suggest #t => ""; #f => error.
[desirability of #t => "t" and #f => ""]
Thanks. Now that i understand the motivation, i think the current
way is fine. You should move this excellent example into the docs.
> Oh yeah, i forgot: I think Make vars should not be accessed by a
> Scheme string, but rather a symbol
Well, my concern about this is that in GNU make, anyway, we very often
use constructed variable names. I would assume that the same would be
true in Guile procedures, which means it will more be convenient to
store variable names in strings in Guile (it seems to me) so they can be
more easily manipulated. Of course you can always use symbol->string
etc.
Guile has both ‘string-append’ and ‘symbol-append’ as well as the other
string-manipulation procedures, so the convenience argument is not so
convicing. But why XOR instead of OR? It's no big deal to...
But is this worth it, to require the Guile user to always perform
this operation when we could do it automatically?
...support either string or symbol argument. The current implementation,
i.e., ‘(format #f "$(~A)" X)’ will DTRT. All it needs is documentation.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: Guile support in GNU make
2012-01-15 20:11 ` Thien-Thi Nguyen
@ 2012-01-15 20:49 ` Paul Smith
0 siblings, 0 replies; 19+ messages in thread
From: Paul Smith @ 2012-01-15 20:49 UTC (permalink / raw)
To: Thien-Thi Nguyen; +Cc: guile-user
On Sun, 2012-01-15 at 21:11 +0100, Thien-Thi Nguyen wrote:
> [desirability of #t => "t" and #f => ""]
>
> Thanks. Now that i understand the motivation, i think the current
> way is fine. You should move this excellent example into the docs.
OK I'll try to find a realistic example to make this more clear.
> > Oh yeah, i forgot: I think Make vars should not be accessed by a
> > Scheme string, but rather a symbol
>
> Well, my concern about this is that in GNU make, anyway, we very often
> use constructed variable names. I would assume that the same would be
> true in Guile procedures, which means it will more be convenient to
> store variable names in strings in Guile (it seems to me) so they can be
> more easily manipulated. Of course you can always use symbol->string
> etc.
>
> Guile has both ‘string-append’ and ‘symbol-append’ as well as the other
> string-manipulation procedures, so the convenience argument is not so
> convicing. But why XOR instead of OR? It's no big deal to...
>
> But is this worth it, to require the Guile user to always perform
> this operation when we could do it automatically?
>
> ...support either string or symbol argument. The current implementation,
> i.e., ‘(format #f "$(~A)" X)’ will DTRT. All it needs is documentation.
Yes that's true. OK I'll update the documentation.
Thanks!
--
-------------------------------------------------------------------------------
Paul D. Smith <psmith@gnu.org> Find some GNU make tips at:
http://www.gnu.org http://make.mad-scientist.net
"Please remain calm...I may be mad, but I am a professional." --Mad Scientist
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: Guile support in GNU make
2012-01-15 16:12 ` Paul Smith
2012-01-15 20:11 ` Thien-Thi Nguyen
@ 2012-01-15 22:02 ` Ludovic Courtès
2012-01-16 14:07 ` Paul Smith
1 sibling, 1 reply; 19+ messages in thread
From: Ludovic Courtès @ 2012-01-15 22:02 UTC (permalink / raw)
To: guile-user
Hi Paul,
And thanks for the great news! :-)
Paul Smith <psmith@gnu.org> skribis:
> On Sun, 2012-01-15 at 09:51 +0100, Thien-Thi Nguyen wrote:
[...]
>> - The ‘#t => t’ distinguishes the symbol t from others, which feels wrong.
>> I suggest #t => ""; #f => error.
>
> Hm. The problem with this is that we can't easily use Guile booleans in
> GNU make. For example, the syntax for make's $(if ...) function is:
>
> $(if <condition>,<then>[,<else>])
>
> The <condition> is expanded as a makefile expression and if it's empty
> it's considered false. If it's non-empty it's considered true.
Would it be possible for Make to delay the conversion of SCMs to
strings, and in turn to differentiate between conditions as strings, and
conditions that are SCMs?
In the latter case, it could just apply scm_is_true to the condition.
Thanks,
Ludo’.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: Guile support in GNU make
2012-01-15 22:02 ` Ludovic Courtès
@ 2012-01-16 14:07 ` Paul Smith
2012-01-17 22:42 ` Ludovic Courtès
0 siblings, 1 reply; 19+ messages in thread
From: Paul Smith @ 2012-01-16 14:07 UTC (permalink / raw)
To: Ludovic Courtès; +Cc: guile-user
On Sun, 2012-01-15 at 23:02 +0100, Ludovic Courts wrote:
> And thanks for the great news! :-)
I promoted the feature to GNU make CVS (I know, still CVS!!) on
Savannah. I hope to generate a test dist file sometime this week. I'll
email when it's available if people want to take a look.
> Paul Smith <psmith@gnu.org> skribis:
> >> - The ‘#t => t’ distinguishes the symbol t from others, which feels wrong.
> >> I suggest #t => ""; #f => error.
> >
> > Hm. The problem with this is that we can't easily use Guile booleans in
> > GNU make. For example, the syntax for make's $(if ...) function is:
> >
> > $(if <condition>,<then>[,<else>])
> >
> > The <condition> is expanded as a makefile expression and if it's empty
> > it's considered false. If it's non-empty it's considered true.
>
> Would it be possible for Make to delay the conversion of SCMs to
> strings, and in turn to differentiate between conditions as strings, and
> conditions that are SCMs?
I don't think this is possible. Make has no "data types" at all. It
just manipulates strings--every operation in make is a string operation,
and the "results" of operations are just constructing new string buffers
by doing string manipulations, then passing that string to the next
function (or whatever).
There's just no facility anywhere internal to make to store or
manipulate a non-string item.
I suppose one option would be to have #f translate to the string "#f"
and change the definition in make of "false" to be "either the empty
string OR the string #f". Since "#" is a comment character in make it's
highly unlikely (although not impossible) someone would have that as a
valid value. However, this would be a lot of effort (finding all the
places in make that use the empty string as "false" and modifying them).
And I'm not sure it wouldn't cause other issues. I think, all in all,
it's better to leave it as-is unless someone can point out a real
problem with it (besides a general unpleasant aftertaste).
--
-------------------------------------------------------------------------------
Paul D. Smith <psmith@gnu.org> Find some GNU make tips at:
http://www.gnu.org http://make.mad-scientist.net
"Please remain calm...I may be mad, but I am a professional." --Mad Scientist
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: Guile support in GNU make
2012-01-16 14:07 ` Paul Smith
@ 2012-01-17 22:42 ` Ludovic Courtès
2012-01-17 23:26 ` Paul Smith
0 siblings, 1 reply; 19+ messages in thread
From: Ludovic Courtès @ 2012-01-17 22:42 UTC (permalink / raw)
To: psmith; +Cc: guile-user
[-- Attachment #1: Type: text/plain, Size: 730 bytes --]
Hi Paul,
Paul Smith <psmith@gnu.org> skribis:
> On Sun, 2012-01-15 at 23:02 +0100, Ludovic Courts wrote:
>> And thanks for the great news! :-)
>
> I promoted the feature to GNU make CVS (I know, still CVS!!) on
> Savannah. I hope to generate a test dist file sometime this week. I'll
> email when it's available if people want to take a look.
Excellent!
I just tried this:
--8<---------------cut here---------------start------------->8---
$(guile (display "hello, world\n"))
$(guile (pk (resolve-interface '(gnu make))))
--8<---------------cut here---------------end--------------->8---
And then “make -f ./the-file.mk”.
It works as intended ;-) but hits a segfault fixed with this patch:
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: text/x-patch, Size: 410 bytes --]
--- guile.c.~2.3.~ 2012-01-16 04:32:49.000000000 +0100
+++ guile.c 2012-01-17 23:35:53.000000000 +0100
@@ -92,9 +92,12 @@ func_guile (char *o, char **argv, const
if (argv[0] && argv[0][0] != '\0')
{
char *str = scm_with_guile (internal_guile_eval, argv[0]);
+ if (str != NULL)
+ {
o = variable_buffer_output (o, str, strlen (str));
free (str);
}
+ }
return o;
}
[-- Attachment #3: Type: text/plain, Size: 2171 bytes --]
Anyway, nice job! :-)
>> Paul Smith <psmith@gnu.org> skribis:
>> >> - The ‘#t => t’ distinguishes the symbol t from others, which feels wrong.
>> >> I suggest #t => ""; #f => error.
>> >
>> > Hm. The problem with this is that we can't easily use Guile booleans in
>> > GNU make. For example, the syntax for make's $(if ...) function is:
>> >
>> > $(if <condition>,<then>[,<else>])
>> >
>> > The <condition> is expanded as a makefile expression and if it's empty
>> > it's considered false. If it's non-empty it's considered true.
>>
>> Would it be possible for Make to delay the conversion of SCMs to
>> strings, and in turn to differentiate between conditions as strings, and
>> conditions that are SCMs?
>
> I don't think this is possible. Make has no "data types" at all. It
> just manipulates strings--every operation in make is a string operation,
> and the "results" of operations are just constructing new string buffers
> by doing string manipulations, then passing that string to the next
> function (or whatever).
>
> There's just no facility anywhere internal to make to store or
> manipulate a non-string item.
OK, I see.
> I suppose one option would be to have #f translate to the string "#f"
> and change the definition in make of "false" to be "either the empty
> string OR the string #f". Since "#" is a comment character in make it's
> highly unlikely (although not impossible) someone would have that as a
> valid value.
It is possible to write valid GNU Make code that generates strings
containing “#”?
> However, this would be a lot of effort (finding all the places in make
> that use the empty string as "false" and modifying them). And I'm not
> sure it wouldn't cause other issues. I think, all in all, it's better
> to leave it as-is unless someone can point out a real problem with it
> (besides a general unpleasant aftertaste).
Yeah.
These are different “value worlds” (as Jim Blandy says), and one of them
has a single data type, so this may be the best that can be done without
introducing other data types in the Make language.
Thanks!
Ludo’.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: Guile support in GNU make
2012-01-17 22:42 ` Ludovic Courtès
@ 2012-01-17 23:26 ` Paul Smith
2012-01-19 20:42 ` Ludovic Courtès
2012-01-19 22:14 ` Ludovic Courtès
0 siblings, 2 replies; 19+ messages in thread
From: Paul Smith @ 2012-01-17 23:26 UTC (permalink / raw)
To: Ludovic Courtès; +Cc: guile-user
On Tue, 2012-01-17 at 23:42 +0100, Ludovic Courts wrote:
> It works as intended ;-) but hits a segfault fixed with this patch:
Doh! I added a feature to make that allows you to define functions
separately (previously all functions had to be predefined in the static
table in functions.c) and moved the guile function code out of
function.c into guile.c for better encapsulation...
And introduced a bug. Sigh.
Thanks for the catch.
> > I suppose one option would be to have #f translate to the string "#f"
> > and change the definition in make of "false" to be "either the empty
> > string OR the string #f". Since "#" is a comment character in make it's
> > highly unlikely (although not impossible) someone would have that as a
> > valid value.
>
> It is possible to write valid GNU Make code that generates strings
> containing “#”?
Yes; make supports escaping comment characters:
~$ cat > /tmp/x1.mk
FOO = \#
all: ; @echo 'FOO = $(FOO)'
~$ make -f /tmp/x1.mk
FOO = #
But my suspicion is that people would rarely use it due to annoyance
factors.
Thanks for testing this!
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: Guile support in GNU make
2012-01-17 23:26 ` Paul Smith
@ 2012-01-19 20:42 ` Ludovic Courtès
2012-01-19 22:14 ` Ludovic Courtès
1 sibling, 0 replies; 19+ messages in thread
From: Ludovic Courtès @ 2012-01-19 20:42 UTC (permalink / raw)
To: psmith; +Cc: guile-user
Hi Paul,
I see Make’s configure.in reads this:
--8<---------------cut here---------------start------------->8---
# For some strange reason, at least on Ubuntu, each version of Guile
# comes with it's own PC file so we have to specify them as individual
# packages. Ugh.
AS_IF([test "x$with_guile" != xno],
[ PKG_CHECK_MODULES([GUILE], [guile-2.0], [have_guile=yes],
[PKG_CHECK_MODULES([GUILE], [guile-1.8], [have_guile=yes],
[PKG_CHECK_MODULES([GUILE], [guile-1.6], [have_guile=yes],
[have_guile=no])])])
])
--8<---------------cut here---------------end--------------->8---
But only Guile 2.0 and the latest 1.8 releases have a .pc file.
Thanks,
Ludo’.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: Guile support in GNU make
2012-01-17 23:26 ` Paul Smith
2012-01-19 20:42 ` Ludovic Courtès
@ 2012-01-19 22:14 ` Ludovic Courtès
1 sibling, 0 replies; 19+ messages in thread
From: Ludovic Courtès @ 2012-01-19 22:14 UTC (permalink / raw)
To: psmith; +Cc: guile-user, make-alpha
[-- Attachment #1: Type: text/plain, Size: 841 bytes --]
Hi Paul,
With all my enthusiasm (and repulsion for an ugly Guile 2.0 bug on SPARC
waiting to be fixed), I came up with the following patch to illustrate
an addition that could be worthwhile.
One can write stuff like:
--8<---------------cut here---------------start------------->8---
%.y: %.z
false
$(guile (pk (pattern-rules) #f))
$(guile (pk (map rule-targets (pattern-rules)) #f))
--8<---------------cut here---------------end--------------->8---
and it prints out:
--8<---------------cut here---------------start------------->8---
;;; ((#<rule cece60 ("%.y")>) #f)
;;; ((("%.y")) #f)
--8<---------------cut here---------------end--------------->8---
SMOBS for ‘dep’ and ‘commands’ could be added similarly, allowing for
nice makefile introspection and debugging.
WDYT?
Thanks,
Ludo’.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: the patch --]
[-- Type: text/x-patch, Size: 5225 bytes --]
Index: Makefile.am
===================================================================
RCS file: /sources/make/make/Makefile.am,v
retrieving revision 2.62
diff -u -r2.62 Makefile.am
--- Makefile.am 16 Jan 2012 02:29:20 -0000 2.62
+++ Makefile.am 19 Jan 2012 22:06:58 -0000
@@ -46,7 +46,12 @@
$(remote)
if HAVE_GUILE
+ BUILT_SOURCES = guile.x
make_SOURCES += guile.c
+
+.c.x:
+ $(GUILE_SNARF) -o $@ $< $(AM_CPPFLAGS) -I$(builddir) -I$(srcdir) \
+ $(GUILE_CFLAGS)
endif
EXTRA_make_SOURCES = vmsjobs.c remote-stub.c remote-cstms.c
Index: configure.in
===================================================================
RCS file: /sources/make/make/configure.in,v
retrieving revision 1.161
diff -u -r1.161 configure.in
--- configure.in 16 Jan 2012 02:29:22 -0000 1.161
+++ configure.in 19 Jan 2012 22:06:58 -0000
@@ -185,7 +185,8 @@
])
AS_IF([test "$have_guile" = yes],
- [AC_DEFINE([HAVE_GUILE], [1], [Embed GNU Guile support])])
+ [AC_PATH_PROG([GUILE_SNARF], [guile-snarf])
+ AC_DEFINE([HAVE_GUILE], [1], [Embed GNU Guile support])])
AM_CONDITIONAL([HAVE_GUILE], [test "$have_guile" = yes])
Index: guile.c
===================================================================
RCS file: /sources/make/make/guile.c,v
retrieving revision 2.4
diff -u -r2.4 guile.c
--- guile.c 18 Jan 2012 13:31:11 -0000 2.4
+++ guile.c 19 Jan 2012 22:06:58 -0000
@@ -14,13 +14,103 @@
You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
#include "make.h"
#include "debug.h"
#include "dep.h"
+#include "rule.h"
#include "variable.h"
#include <libguile.h>
+
+\f
+SCM_SMOB (dependency, "dependency", 0);
+
+SCM_SMOB (rule, "rule", 0);
+
+
+SCM gmk_rule_targets (SCM);
+
+SCM_SMOB_PRINT (rule, print_rule, obj, port, pstate)
+{
+ /* XXX: On Guile < 2.0, use `scm_from_locale_string'. */
+ scm_simple_format (port, scm_from_latin1_string ("#<rule ~a ~s>"),
+ scm_list_2 (scm_number_to_string
+ (scm_object_address (obj),
+ scm_from_int (16)),
+ gmk_rule_targets (obj)));
+ return 1;
+}
+
+/* Return the SMOB corresponding to RULE. */
+static SCM
+gmk_from_rule (struct rule *r)
+{
+ if (scm_is_false (r->smob))
+ /* Associate the new SMOB with R so that R only ever one associated SMOB,
+ which allows rules to be compared with `eq?'. */
+ SCM_NEWSMOB (r->smob, rule, r);
+
+ return r->smob;
+}
+
+/* Return the C rule struct corresponding to OBJ. */
+static struct rule *
+gmk_to_rule (SCM obj)
+{
+ SCM_ASSERT (SCM_SMOB_PREDICATE (rule, obj), obj, 0, "gmk_to_rule");
+
+ return (struct rule *) SCM_SMOB_DATA (obj);
+}
+
+SCM_DEFINE (gmk_rule_p, "rule?", 1, 0, 0,
+ (SCM obj),
+ "Return #t when @var{obj} is a rule.")
+#define FUNC_NAME s_gmk_rule_p
+{
+ return SCM_SMOB_PREDICATE (rule, obj);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (gmk_all_rules, "pattern-rules", 0, 0, 0,
+ (void),
+ "Return all the pattern rules of the current makefile.")
+#define FUNC_NAME s_gmk_all_rules
+{
+ SCM lst;
+ struct rule *r;
+
+ for (r = pattern_rules, lst = SCM_EOL;
+ r != NULL;
+ r = r->next)
+ lst = scm_cons (gmk_from_rule (r), lst);
+
+ return scm_reverse (lst);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (gmk_rule_targets, "rule-targets", 1, 0, 0,
+ (SCM obj),
+ "Return the list of targets of @var{rule}.")
+#define FUNC_NAME s_gmk_rule_targets
+{
+ int i;
+ SCM lst;
+ struct rule *r;
+
+ r = gmk_to_rule (obj);
+ for (i = 0, lst = SCM_EOL; i < r->num; i++)
+ lst = scm_cons (scm_from_locale_string (r->targets[i]), lst);
+
+ return scm_reverse (lst);
+}
+#undef FUNC_NAME
+
+\f
static SCM make_mod = SCM_EOL;
static SCM obj_to_str = SCM_EOL;
@@ -76,6 +166,8 @@
/* Import the GNU make module exports into the generic space. */
scm_c_eval_string ("(use-modules (gnu make))");
+#include "guile.x"
+
return NULL;
}
Index: rule.c
===================================================================
RCS file: /sources/make/make/rule.c,v
retrieving revision 1.55
diff -u -r1.55 rule.c
--- rule.c 16 Jan 2012 02:29:23 -0000 1.55
+++ rule.c 19 Jan 2012 22:06:58 -0000
@@ -458,6 +458,9 @@
r->targets = targets;
r->suffixes = target_percents;
r->lens = xmalloc (n * sizeof (unsigned int));
+#ifdef HAVE_GUILE
+ r->smob = SCM_BOOL_F;
+#endif
for (i = 0; i < n; ++i)
{
Index: rule.h
===================================================================
RCS file: /sources/make/make/rule.h,v
retrieving revision 1.19
diff -u -r1.19 rule.h
--- rule.h 16 Jan 2012 02:29:24 -0000 1.19
+++ rule.h 19 Jan 2012 22:06:58 -0000
@@ -17,6 +17,10 @@
this program. If not, see <http://www.gnu.org/licenses/>. */
+#ifdef HAVE_GUILE
+# include <libguile.h>
+#endif
+
/* Structure used for pattern (implicit) rules. */
struct rule
@@ -30,6 +34,9 @@
unsigned short num; /* Number of targets. */
char terminal; /* If terminal (double-colon). */
char in_use; /* If in use by a parent pattern_search. */
+#ifdef HAVE_GUILE
+ SCM smob; /* The corresponding SMOB or #f. */
+#endif
};
/* For calling install_pattern_rule. */
^ permalink raw reply [flat|nested] 19+ messages in thread
[parent not found: <1316557011.28907.237.camel@homebase>]
end of thread, other threads:[~2012-01-31 21:32 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-01-14 19:55 Guile support in GNU make Paul Smith
2012-01-15 8:51 ` Thien-Thi Nguyen
2012-01-15 12:33 ` Thien-Thi Nguyen
2012-01-15 16:12 ` Paul Smith
2012-01-15 20:11 ` Thien-Thi Nguyen
2012-01-15 20:49 ` Paul Smith
2012-01-15 22:02 ` Ludovic Courtès
2012-01-16 14:07 ` Paul Smith
2012-01-17 22:42 ` Ludovic Courtès
2012-01-17 23:26 ` Paul Smith
2012-01-19 20:42 ` Ludovic Courtès
2012-01-19 22:14 ` Ludovic Courtès
[not found] <1316557011.28907.237.camel@homebase>
[not found] ` <1326572016.3482.144.camel@homebase>
[not found] ` <20120122182923.GB3460@mini.zxlink>
2012-01-22 21:56 ` Paul Smith
2012-01-23 6:01 ` Thien-Thi Nguyen
2012-01-23 6:08 ` Thien-Thi Nguyen
2012-01-29 20:05 ` Paul Smith
2012-01-31 19:17 ` Kirill Smelkov
2012-01-31 21:32 ` Paul Smith
2012-01-25 23:45 ` Ludovic Courtès
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).