-
Notifications
You must be signed in to change notification settings - Fork 924
configury: revamp the OPAL_CHECK_PACKAGE macro #4823
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
configury: revamp the OPAL_CHECK_PACKAGE macro #4823
Conversation
Refs #4722 @jsquyres this is a very early stage prototype. long story short, we now have
if both
can you please share your thoughts on this new macro ? the code itself is very lightly tested so do not worry too much about it at this stage. |
4c1b304
to
f49caf3
Compare
:bot:aws:retest |
f49caf3
to
e290767
Compare
@ggouaillardet From what I can tell, this doesn't solve the problem we've been talking about on #4818 where one version of the package is installed in a standard location, and the user specifies a different version installed in a custom location. No matter how you set CPPFLAGS or LDFLAGS, the autoconf macros AC_CHECK_HEADER and AC_SEARCH_LIB will still pickup the version in the standard location and return success. I've tried every trick I can find to get around that issue, with no success. Finally posted a question on StackOverflow to see if anyone has an idea. Bottom line so far: all you really can do is check for file and library existence in this scenario. What is weird is that if you get the foo_CPPFLAGS and foo_LDFLAGS set correctly, then the component does get linked to the right version of the package! You just can't get autoconf to respect it when doing the checks. |
e290767
to
a07d454
Compare
@rhc54 I am not sure we read each other correctly. The issue in #4818, is that if I might have chosen my words poorly previously, and what I really meant by
is Open MPI passes CPPFLAGS and LDFLAGS directly to It is of course possible to parse |
@ggouaillardet I don't believe the following is true:
From my testing, AC_CHECK_HEADER and AC_SEARCH_LIB always include the standard locations, regardless of the CPPFLAGS and LDFLAGS that are passed. I have been unable to prevent them from doing so. |
@rhc54 miscommunication again, and I can take the blame for that one
What I really meant is that when |
Understood - but it still won't work The problem is that AC_CHECK_HEADER will see the header in the std location, and that is what will be checked - not the one in your DIR/include location. Ditto for AC_SEARCH_LIB. The documentation implies this behavior as it states that the purpose of these functions is to find an instance of the search condition, not a specific instance of it. For example, when explaining AC_SEARCH_LIB:
So the goal of these search routines is to look around the system at the std locations and any locations given by FLAGS until they find the first instance where the search is satisfied. Once that happens, they return "found" and are done. We have been "getting lucky" all these years because:
What I suggest is that we only use AC_CHECK_HEADERS and AC_SEARCH_LIBS when we are looking for something in the std locations. Otherwise, we should look for existence of the actual file/library (not just the directory). If we want to check the library for a given function, we can do that using |
@rhc54 here are my observations on OS X, with from
bottom line
based on my observations (e.g. |
Well, I respectfully disagree with your conclusion. I think you are getting fooled by a false positive. Think about it for a bit and you'll begin to understand why. AC_CHECK_HEADERS and AC_SEARCH_LIBS both use compile tests to check for existence - you can see that in the output you posted. Now consider how a compiler works. If you pass a CPPFLAGS value to a compiler, it looks in that location plus the standard locations for any include file. If it didn't do that, we'd all go nuts chasing down all the stuff like So your test for zlib.h would have passed just as well if you had given a totally bogus path for The only way to ensure you only check the given location is to avoid compile-based tests. |
Figured I'd try to clarify a bit more and then surrender 😄 My basic point I'm trying to make here is: once you have manually checked for existence and readability of the header file, running AC_CHECK_HEADERS doesn't do anything for us. It will always succeed if the header exists in a std location, regardless of what we pass for CPPFLAGS, so why waste the time running it? The same is true for AC_SEARCH_LIBS - if the library we are looking for is in a std location (and the function is in that version), then AC_SEARCH_LIBS will always succeed, regardless of what we pass for LDFLAGS. The only thing the macro does for you is check that the specified function is a public symbol in at least one of the versions of the library in a combination of the std location plus the given LDFLAGS - it doesn't tell you that the version of the library in your specified location was the one that provided it. So if we are given a non-std location, we might as well just test for existence and be done - unless we have some reason to believe that the specified package is not installed in a std location. I suppose we could run the macros without any FLAGS and see if we get a positive response - if we do, then just do the existence check on the given location. I'm not sure what that adds, hence my proposal to just check for existence and then trust the user. HTH |
FWIW: only one reply so far to the StackOverflow issue - they suggested looking at boost for an example where the desired behavior appeared to be achieved. However, looking at their code:
So they first have to verify existence for the same reason we do. In their case, they run The StackOverflow ticket is here: https://stackoverflow.com/questions/48829078/autoconf-check-a-specific-library I'll keep tracking it in case someone pipes up with a better answer, but I'm beginning to believe there is no really good solution. It seems to me that the only real thing we can do is check for existence to catch a typo, and then trust the user. |
add the OPAL_DEFINE_PACKAGE helper that define --with-FOO=DIR --with-FOO-cppflags=FLAGS --with-FOO-ldflags=FLAGS --with-FOO-libdir=DIR (deprecated) OPAL_CHECK_PACKAGE2(prefix, header, library, function, extra-libraries, package, [action-if-found], [action-if-not-found], includes) is much easier to use and handle most of the work under the hood. Signed-off-by: Gilles Gouaillardet <gilles@rist.or.jp>
a07d454
to
6b3dce2
Compare
I think you're both right. Ralph's right, the AC_CHECK_HEADERS doesn't tell us precisely what we want to know (same with AC_SEARCH_LIBS), in that if the header's in the standard location and the user specifies --with--includes, the user can get fooled. Giles is right that we should be calling both AC_CHECK_HEADERS and AC_SEARCH_LIBS at least once on every file to sanity check that they should compile. Our current system of calling multiple times doesn't work the way we want, but we should still check that the header can compile. There are cases where this isn't true, such as only supporting 64 bit compiles when OMPI is being built with -m32. I haven't had a chance to look at this patch in depth; will do so today. |
I actually agree on the From the references provided so far (and that I could find myself), it appears that all you really can do is:
You can check for a specific function using This seems to be a pretty common problem, and the above solution appears to be where everyone winds up - often after lots of agonizing |
@rhc54, yeah, sorry, I meant AC_CHECK_LIB, not AC_SEARCH_LIBS. One should at least sanity check that something exists, although there's not more than that we can do. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have strong objections to the half-change. We should either update all the CHECK_PACKAGE calls or none at all. I haven't had time to do this patch not because opal_check_package was hard to write, but because updating all the configure.m4 files was going to take some time. But it's the right thing to do.
Also, we shouldn't add opal_check_package2, but should re-define opal_check_package to do what we want, otherwise, we'll have two behaviors and nobody wins.
config/opal_check_package2.m4
Outdated
@@ -0,0 +1,237 @@ | |||
dnl -*- shell-script -*- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
either -- autoconf -- or nothing, please
config/opal_check_package2.m4
Outdated
# so this sucks, but there's no way to get through the progression | ||
# of header includes without killing off the cache variable and trying | ||
# again... | ||
unset opal_Header |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we shouldn't need this code with the (proper) change to only checking the header / library location once.
config/opal_check_package2.m4
Outdated
# again... | ||
unset opal_Header | ||
|
||
# get rid of the trailing slash(es) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
config/opal_check_package2.m4
Outdated
AC_CHECK_HEADERS([$2], [opal_check_package_header_happy="yes"], []) | ||
AS_IF([test "$opal_check_package_header_happy" = "no"], | ||
[# no go on the as is - reset the cache and try again | ||
unset opal_Header])], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove
config/opal_check_package2.m4
Outdated
AC_CHECK_HEADERS([$2], [opal_check_package_header_happy="yes"], [], [$6])]) | ||
|
||
AS_IF([test "$opal_check_package_header_happy" = "yes"], [$4], [$5]) | ||
unset opal_check_package_header_happy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove
config/opal_check_package2.m4
Outdated
dnl additonal -l arguments to link successfully, list them here. | ||
dnl * dir_prefix: if the header/library is located in a non-standard | ||
dnl location (e.g., /opt/foo as opposed to /usr), list it here | ||
dnl * libdir_prefix: if the library is not under $dir_prefix/lib or |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doesn't match prototype.
config/opal_check_package2.m4
Outdated
dnl * action_if_found: if both the header and library are found and | ||
dnl usable, execute action_if_found | ||
dnl * action_if_not_found: otherwise, execute action_if_not_found | ||
dnl * extra_includes: if including header_filename requires additional |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't match name of argument in function above. Also, why on a new function is this after the action_if_found / action_if_not_found, which are traditionally the last two arguments?
config/opal_check_package2.m4
Outdated
opal_check_package_$1_orig_LDFLAGS="$$1_LDFLAGS" | ||
opal_check_package_$1_orig_LIBS="$$1_LIBS" | ||
|
||
AS_IF([test "$with_$6" != "no"], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code would be a lot simpler if you defined a variable foobar=$with_$6 and used that in all the tests instead of constantly doing the m4 expansion thing.
config/opal_check_package2.m4
Outdated
opal_check_package_$1_orig_LIBS="$$1_LIBS" | ||
|
||
AS_IF([test "$with_$6" != "no"], | ||
[AS_IF([test -n "$with_$6_cppflags" || test -z "$with_$6" || test "$with_$6" = "yes"], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure why this is here. It's literally the union of all options != no.
config/opal_setup_zlib.m4
Outdated
AC_DEFINE_UNQUOTED([OPAL_HAVE_ZLIB], [$opal_zlib_support], | ||
[Whether or not we have zlib support]) | ||
OPAL_VAR_SCOPE_POP | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not remove the whole line?
@bwbarret thanks for the review ! I agree that at the end there should be only one I will make the requested changes from now. |
Signed-off-by: Gilles Gouaillardet <gilles@rist.or.jp>
@bwbarrett I pushed a new commit that should address your review, plus some more revamp. |
@ggouaillardet I thought we were going to revise the lib section to avoid use of |
I will update the PR, thanks ! |
only use AC_SEARCH_LIBS when --with-FOO[=yes] if --with-FOO-ldflags=LDFLAGS or --with-FOO=DIR is used, then use AC_CHECK_LIB if --with-FOO=DIR is used, the macro is only tried if 'ls DIR/lib[64]/liblib.*' returns more than one file. This is not yet bulletproof since - if DIR/lib/libLIB.xyz is a match, the linker will not use that and will try lib in the default path instead. - if DIR/lib/libLIB.so has the wrong bitness/arch, the linker will ignore it and try lib in the default path instead Signed-off-by: Gilles Gouaillardet <gilles@rist.or.jp>
@rhc54 i updated the PR based on your latest message. |
what happened to the code that removed trailing '/'? I think we really need it, and no point in us putting it everywhere. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We seem to still not be on the same page; we're supposed to be ripping out a lot of the complicated code we still have in here progressing through search libraries.
AC_ARG_WITH([$1], [AC_HELP_STRING([--with-$1=DIR], [$2])]) | ||
AC_ARG_WITH([$1-cppflags], [AC_HELP_STRING([--with-$1-cppflags=FLAGS], [$3])]) | ||
AC_ARG_WITH([$1-ldflags], [AC_HELP_STRING([--with-$1-ldflags=FLAGS], [$4])]) | ||
AC_ARG_WITH([$1-libdir], [AC_HELP_STRING([--with-$1-libdir=DIR], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to split OPAL_DECLARE_PACKAGE and OPAL_DECLARE_PACKAGE_DEPRECATED, with only _DEPRECATED adding --with-$1-libdir. Otherwise, we end up adding a deprecated argument for new components, which is weird.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fair point, I will update this.
dnl [action-if-found], [action-if-not-found]) | ||
dnl -------------------------------------------------------------------- | ||
AC_DEFUN([_OPAL_CHECK_PACKAGE2_HEADER], [ | ||
AS_VAR_PUSHDEF([opal_With], [with_$1]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This capitalization kind of makes me ragey. Why the semi-CamelCase, with underscores?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
opal_Lib
and opal_Header
have been around for a while, but I get your point and will update this too.
AC_CHECK_HEADERS([$3], [$5], [$6], [$4])], | ||
[AS_IF([test -z "$opal_With" || test "$opal_With" = "yes"], | ||
[AC_CHECK_HEADERS([$3], [$5], [$6], [$4])], | ||
[AS_IF([test -r "$opal_With/$3"], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We agreed we were getting rid of this, didn't we? We were only going to check with_dir/include if with_cppflags wasn't set. There should only need to be a single call to AC_CHECK_HEADERS in this function, with a simple set if if statements to set CPPFLAGS as needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current code does not check DIR
nor DIR/include
if --with-FOO-cppflags
is set, did I get that part wrong ?
Also, the current code fails if --with-FOO-cppflags
is not used and nor DIR/header.h
nor DIR/include/header.h
exists. If we move to a single AC_CHECK_HEADERS
invokation, handling this bozo case might be a bit convoluted. I am open to suggestions though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ggouaillardet I think the use of the test -n
option is what confused here - I honestly don't think we have used that variation elsewhere. Nothing wrong with it - just something I had to look up (and ask about), and still trip over until I get used to it.
The code looks generally correct to me. If they provide the cppflags option, then we just use it. If not, then we check std locations if opal_with is empty or "yes", then DIR, and then DIR/include. The only thing I believe we might change is to reduce the complexity a bit.
I believe what @bwbarrett was getting at is that you could use all those AS_IF's to simply set a local cppflags value, and then set CPPFLAGS and have a single call to AC_CHECK_HEADERS
at the end. Would significantly simplify the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test -n didn't confuse me. I was saying that the code structure is way more complicated than it needs to be. It should be something like:
AS_IF([test -n "$with_FOO_cppflags"], [CPPFLAGS=$with_FOO_cppflags],
AS_IF([test -n "$with_FOO" != "yes"], [CPPFLAGS=$with_foo/include])])
AC_CHECK_HEADERS([....])
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rhc54 @bwbarrett my question was how to elegantly handle the case in which --with-FOO-cppflags
is not set and --with-FOO=DIR
is used and nor DIR/foo.h
nor DIR/include/foo.h
exist.
Ideally, it would fail without aborting nor invoking AC_CHECK_HEADERS
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that ensuring DIR/include/foo.h (and remember, we're NOT checking for DIR/foo.h) is important. If you feel strongly that it is for the case of --with-dir, I'd do something like:
if test -n "$with_FOO_cppflags" ; then
add_CPPFLAGS="$with_FOO_cppflags"
elif test "$with_FOO" != "yes"; then
if test ! -r "$with_FOO/include/$header_file"; then
AC_MSG_ERROR([Didn't find expected header <blah> in <blah>.])
fi
add_CPPFLAGS="-I$with_FOO/include"
fi
CPPFLAGS=$CPPFLAGS $add_CPPFLAGS
AC_CHECK_HEADERS
Again, this all got so complicated it had a billion unintended side effects. Our whole goal is to get back to simple, even if we miss some corner cases in testing; we can define what we do, how it doesn't do what the user may want, but that the important part is IT'S DEFINED.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huh??? Part of this whole thing was to ensure that we do check for DIR/foo.h, and then for DIR/include/foo.h, as that is where multiple vendors install by default. I don't understand why that is objectionable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, that's terrible. --with-FOO should never add DIR/foo.h. The whole point of this change is to add --with-FOO-cppflags so that if the header was in an odd spot, customers could add the right CPPFLAGS to get what they need. DIR/foo.h adds a really dangerous -I flag in all but some corner-case situations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I give up - this has morphed into something that doesn't appear to meet my needs at all. I'll just hardcode what I need into the .m4's where I need it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bwbarett One motivation for the change is to allow users to install their include files in a non standard location (in this case, it was /usr/include/pmix
instead of /usr/include
), so we cannot assume we only need to append /include
to DIR
and look for headers there.
That being said, and since --with-FOO-cppflags
and --with-FOO-ldflags
are new options, the new macro will have to differ between master
and the release branches for a while. As far as I am concerned, I would be fine testing for DIR/foo.h
only in the release branches, and master
not testing it (since --with-FOO-cppflags
can be used to achieve the same goal).
@rhc54 is this acceptable for you ?
# so this sucks, but there's no way to get through the progression | ||
# of search libs without killing off the cache variable and trying | ||
# again... | ||
unset opal_Lib |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
again, we were going to get rid of all this...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am puzzled. do we want to check DIR/lib64
when there is stuff in DIR/lib
but AC_CHECK_LIB
fails ? If yes, I am afraid we do need something like that, though we should update opal_Lib
(or whatever its new name will be) since we moved from AC_SEARCH_LIBS
to AC_CHECK_LIB
. Makes sense ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ggouaillardet I believe what @bwbarrett is saying is that we agreed not to run AC_CHECK_LIB
at all if they provided a location, either in the ldflags option or in a non-default setting of the "with" option. Reason is that you'll get a false positive if the lib in the std location passes the test, even if the lib in the specified location fails. So the best you can do is check for existence in lib and lib64, and if found, then set LDFLAGS and move on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, what @rhc54 said.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rhc54 @bwbarrett let me put it this way.
If an end user configure --with-FOO=DIR
and in the worst case scenario, you'd rather have configure success (and make
might either crash because DIR/lib/libfoo.so
is missing the required symbol, or silently use the libraries in the default location because DIR/lib/libfoo.so
has the wrong bitness or the linker only accepts static library that is not there) than, silently use a working library in the default location instead or DIR/lib[64]
.
I fully understand there is not a perfect solution here.
If this is what we want, they I will make the changes, even if I believe this would be a regression (e.g. make
fails and we could have trapped that in configure
but we chose not to try).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you missed the point. Your configure logic is going to succeed anyway because AC_CHECK_LIB
is going to do exactly what you just described - it is a compile test, and so the compiler is going to walk thru all those options and find a working library somewhere, but not necessarily the one you specified. Setting LDFLAGS
does not limit the compiler to looking at just that directory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AC_CHECK_LIB is a link test. If --with-foo=DIR (or --with-foo-ldflags) found a library, that's the library it found. That library has the function that's important, in a way that's linkable (has the right size, bitness, static vs. dynamic, etc.). There's still a versioning problem and if callers are sensitive to a particular version, then they probably need extra tests in the higher level check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rhc54 I fully understand AC_CHECK_LIB
might lead to false positives if libfoo.so
in DIR/lib
is not usable. (And if it is usable, then this is the one that will be used, not the one in /usr/lib64
).
13 days ago, you wrote
I thought we were going to revise the lib section to avoid use of AC_SEARCH_LIB and use AC_CHECK_LIB instead, and only after checking for existence of the specified lib in the target location?
and yesterday
I believe what @bwbarrett is saying is that we agreed not to run AC_CHECK_LIB at all if they provided a location, either in the ldflags option or in a non-default setting of the "with" option.
The only point in my previous comment was if we simply do not run AC_CHECK_LIB
at all, then we not only keep the same false positives (and there is virtually nothing we can do about that), but we also miss some false negatives (e.g. configure
successes, but make
will fail).
And once again, if both of you (@rhc54 and @bwbarrett ) still agree Open MPI should not run AC_CHECK_LIB
at all (when --with-FOO-ldflags=LDFLAGS
or --with-FOO=DIR
is used), then I will implement this change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have given up - my head has been spun around on this so many times, I've lost count. You guys do whatever you want.
@rhc54 do we really need to remove the trailing slash(es) ? Developers should not add these in Open MPI, and so far, the policy was that end users get what they ask for. So if they |
Yeah, we really do need to remove those trailing slash(es). Even some of our testers (e.g., IBM Jenkins in the PMIx repo) use them. So please do restore it. |
Can one of the admins verify this patch? |
The IBM CI (PGI) build failed! Please review the log, linked below. Gist: https://gist.github.com/6ff06c812a7c60275cda1d3030ec6ad3 |
I'm not sure why the IBM tester ran on this PR yesterday. I'm going to close this PR, because we're in the process of rewriting opal_check_package to use pkg-config and friends and this will become less and less relevant as we do that. |
add the OPAL_DEFINE_PACKAGE helper that define
--with-FOO=DIR
--with-FOO-cppflags=FLAGS
--with-FOO-ldflags=FLAGS
--with-FOO-libdir=DIR (deprecated)
OPAL_CHECK_PACKAGE2(prefix,
header,
library,
function,
extra-libraries,
package,
[action-if-found], [action-if-not-found],
includes)
is much easier to use and handle most of the work under the hood.
Signed-off-by: Gilles Gouaillardet gilles@rist.or.jp