https://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112018-06-04T03:17:42ZRuby Issue Tracking SystemRuby master - Bug #14816: Extension build failure on a system with musl libchttps://bugs.ruby-lang.org/issues/14816?journal_id=723612018-06-04T03:17:42Zshyouhei (Shyouhei Urabe)shyouhei@ruby-lang.org
<ul></ul><p>akamch (Anatoly Kamchatnov) wrote:</p>
<blockquote>
<p>isinf() and isnan() are defined as macros in musl: <a href="https://git.musl-libc.org/cgit/musl/tree/include/math.h" class="external">https://git.musl-libc.org/cgit/musl/tree/include/math.h</a></p>
</blockquote>
<p>Yes, and the corresponding missing.h lines are this:</p>
<pre><code class="c syntaxhl" data-language="c"><span class="cp">#ifndef isnan
# ifndef HAVE_ISNAN
</span><span class="n">RUBY_EXTERN</span> <span class="kt">int</span> <span class="nf">isnan</span><span class="p">(</span><span class="kt">double</span><span class="p">);</span>
<span class="cp"># endif
#endif
</span></code></pre>
<p>So the conflicting function <em>is</em> actually guarded by #ifdef. I guess this is not our fault?</p> Ruby master - Bug #14816: Extension build failure on a system with musl libchttps://bugs.ruby-lang.org/issues/14816?journal_id=723752018-06-04T11:37:21Zakamch (Anatoly Kamchatnov)akamch@gmail.com
<ul></ul><blockquote>
<p>I guess this is not our fault?</p>
</blockquote>
<p>Not entirely. Most likely it's nobody's fault but you can always blame autoconf :) Alpine's author thinks that "the configure script does not detect isnan/isinf as macros, call ruby devs". Autoconf's doc says</p>
<pre><code>isinf
isnan
The C99 standard says that isinf and isnan are macros. On some systems just macros are available (e.g., HP-UX and Solaris 10), on some systems both macros and functions (e.g., glibc 2.3.2), and on some systems only functions (e.g., IRIX 6 and Solaris 9). In some cases these functions are declared in nonstandard headers like <sunmath.h> and defined in non-default libraries like -lm or -lsunmath.
The C99 isinf and isnan macros work correctly with long double arguments, but pre-C99 systems that use functions typically assume double arguments. On such a system, isinf incorrectly returns true for a finite long double argument that is outside the range of double.
The best workaround for these issues is to use gnulib modules isinf and isnan (see Gnulib). But a lighter weight solution involves code like the following.
#include <math.h>
#ifndef isnan
# define isnan(x) \
(sizeof (x) == sizeof (long double) ? isnan_ld (x) \
: sizeof (x) == sizeof (double) ? isnan_d (x) \
: isnan_f (x))
static inline int isnan_f (float x) { return x != x; }
static inline int isnan_d (double x) { return x != x; }
static inline int isnan_ld (long double x) { return x != x; }
#endif
#ifndef isinf
# define isinf(x) \
(sizeof (x) == sizeof (long double) ? isinf_ld (x) \
: sizeof (x) == sizeof (double) ? isinf_d (x) \
: isinf_f (x))
static inline int isinf_f (float x)
{ return !isnan (x) && isnan (x - x); }
static inline int isinf_d (double x)
{ return !isnan (x) && isnan (x - x); }
static inline int isinf_ld (long double x)
{ return !isnan (x) && isnan (x - x); }
#endif
</code></pre>
<p><a href="https://www.gnu.org/software/autoconf/manual/autoconf.html#Function-Portability" class="external">https://www.gnu.org/software/autoconf/manual/autoconf.html#Function-Portability</a></p>
<p>Looks like musl is not unlike HP-UX and Solaris 10 in that regard. The question is where one should fix this: some header or ruby routines around extconf.rb, gem in question, anywhere else? That I don't know, but the first option still seems plausible to me.</p> Ruby master - Bug #14816: Extension build failure on a system with musl libchttps://bugs.ruby-lang.org/issues/14816?journal_id=723762018-06-04T18:32:27Zshevegen (Robert A. Heiler)shevegen@gmail.com
<ul></ul><p>I think ngoto is knowing quite a bit about Solaris so perhaps if he has<br>
time he could comment.</p>
<p>I also understand you wanting to use Ruby even on exotic combinations<br>
like musl + void. The original rack author also uses void. :)</p> Ruby master - Bug #14816: Extension build failure on a system with musl libchttps://bugs.ruby-lang.org/issues/14816?journal_id=723772018-06-04T19:06:55Zakamch (Anatoly Kamchatnov)akamch@gmail.com
<ul></ul><blockquote>
<p>I also understand you wanting to use Ruby even on exotic combinations like musl + void.</p>
</blockquote>
<p>Indeed, yet one can also easily envision many a failed build of Ruby codebases inside the musl-only Alpine-based Docker containers. Void is almost irrelevant here.</p>
<blockquote>
<p>The original rack author also uses void. :)</p>
</blockquote>
<p>And does hell of a job maintaining that fine distribution.</p> Ruby master - Bug #14816: Extension build failure on a system with musl libchttps://bugs.ruby-lang.org/issues/14816?journal_id=723822018-06-04T23:58:46Zshyouhei (Shyouhei Urabe)shyouhei@ruby-lang.org
<ul></ul><p>akamch (Anatoly Kamchatnov) wrote:</p>
<blockquote>
<blockquote>
<p>I guess this is not our fault?</p>
</blockquote>
<p>Not entirely. Most likely it's nobody's fault but you can always blame autoconf</p>
</blockquote>
<p>Highly skeptical. Can you build ruby from source and show us your config.log then?</p>
<p>Like I showed before the <code>RUBY_EXTERN int isnan(double);</code> line is effective only if (1) isnan is <em>not</em> a macro, and (2) isnan is <em>not</em> provided as a function. "The best workaround" that the autoconf says does not work on your system because in case it would, ours must also.</p> Ruby master - Bug #14816: Extension build failure on a system with musl libchttps://bugs.ruby-lang.org/issues/14816?journal_id=723832018-06-05T00:21:40Zshyouhei (Shyouhei Urabe)shyouhei@ruby-lang.org
<ul></ul><p>Let me directly point out what is actually to be blamed:</p>
<p>akamch (Anatoly Kamchatnov) wrote:</p>
<blockquote>
<p>In file included from /usr/include/c++/7.3/math.h:36:0,<br>
from /home/rev/.rbenv/versions/2.6.0-preview2/include/ruby-2.6.0/ruby/missing.h:23,<br>
from /home/rev/.rbenv/versions/2.6.0-preview2/include/ruby-2.6.0/ruby/defines.h:153,<br>
from /home/rev/.rbenv/versions/2.6.0-preview2/include/ruby-2.6.0/ruby/ruby.h:29,<br>
from /home/rev/.rbenv/versions/2.6.0-preview2/include/ruby-2.6.0/ruby.h:33,<br>
from unf.cc:3:<br>
/usr/include/c++/7.3/cmath:626:3: note: previous declaration 'constexpr bool std::isnan(double)'<br>
isnan(double __x)<br>
^~~~~</p>
</blockquote>
<p>This is wrong. Your C++ header file <em>does</em> define a function named isnan. You have to include C's one (the one you referred) instead.</p> Ruby master - Bug #14816: Extension build failure on a system with musl libchttps://bugs.ruby-lang.org/issues/14816?journal_id=723862018-06-05T01:53:55Zshyouhei (Shyouhei Urabe)shyouhei@ruby-lang.org
<ul></ul><p>Proposed workaround, not tested though.</p>
<pre><code class="patch syntaxhl" data-language="patch"><span class="p">From 01839b509c1bb914337124ac3d1f644b05ef90d8 Mon Sep 17 00:00:00 2001
From: "Urabe, Shyouhei" <shyouhei@ruby-lang.org>
Date: Tue, 5 Jun 2018 10:26:06 +0900
Subject: [PATCH] C++11 is so bad it introduces a nightmare.
</span><span class="err">
</span><span class="p">TL;DR see https://developers.redhat.com/blog/2016/02/29/why-cstdlib-is-more-complicated-than-you-might-think/
</span><span class="err">
</span> - `isnan` is something relatively new. We need to provide one for
those systems without it. However:
- X/Open defines `int isnan(double)`. Note the `int`.
- C99 defines `isnan(x)` to be a macro.
- C++11 nukes them all, undefines all the "masking macro"s, and
define its own `bool isnan(double)`. Note the `bool`.
- In C++, `int isnan(double)` and `bool isnan(double)` are
incompatible.
- So the mess.
<span class="err">
</span><span class="p">Signed-off-by: Urabe, Shyouhei <shyouhei@ruby-lang.org>
---
</span> include/ruby/missing.h | 6 ++++++
1 file changed, 6 insertions(+)
<span class="err">
</span><span class="gh">diff --git a/include/ruby/missing.h b/include/ruby/missing.h
index dc3fd502b5..8df917498e 100644
</span><span class="gd">--- a/include/ruby/missing.h
</span><span class="gi">+++ b/include/ruby/missing.h
</span><span class="p">@@ -168,6 +168,8 @@</span> RUBY_EXTERN const union bytesequence4_or_float rb_nan;
# include <ieeefp.h>
# endif
# define isinf(x) (!finite(x) && !isnan(x))
<span class="gi">+# elsif __cplusplus >= 201103L
+# include <cmath> // it must include constexpr bool isinf(double);
</span> # else
RUBY_EXTERN int isinf(double);
# endif
<span class="p">@@ -176,7 +178,11 @@</span> RUBY_EXTERN int isinf(double);
#ifndef isnan
# ifndef HAVE_ISNAN
<span class="gi">+# if __cplusplus >= 201103L
+# include <cmath> // it must include constexpr bool isnan(double);
+# else
</span> RUBY_EXTERN int isnan(double);
<span class="gi">+# endif
</span> # endif
#endif
<span class="gd">--
</span><span class="p">2.17.1
</span><span class="err">
</span></code></pre> Ruby master - Bug #14816: Extension build failure on a system with musl libchttps://bugs.ruby-lang.org/issues/14816?journal_id=723892018-06-05T05:00:50Zakamch (Anatoly Kamchatnov)akamch@gmail.com
<ul></ul><p>shyouhei (Shyouhei Urabe) wrote:</p>
<blockquote>
<p>Let me directly point out what is actually to be blamed</p>
</blockquote>
<p>Works best for me! Thank you very much for getting to the root of the problem, there's much to reflect upon.</p>
<p>The patch does away with the isnan error, but the other one still remains:</p>
<pre><code>compiling unf.cc
cc1plus: warning: command line option '-Wimplicit-int' is valid for C/ObjC but not for C++
cc1plus: warning: command line option '-Wdeclaration-after-statement' is valid for C/ObjC but not for C++
cc1plus: warning: command line option '-Wimplicit-function-declaration' is valid for C/ObjC but not for C++
In file included from /home/rev/.rbenv/versions/2.6.0-preview2/include/ruby-2.6.0/ruby/defines.h:153:0,
from /home/rev/.rbenv/versions/2.6.0-preview2/include/ruby-2.6.0/ruby/ruby.h:29,
from /home/rev/.rbenv/versions/2.6.0-preview2/include/ruby-2.6.0/ruby.h:33,
from unf.cc:3:
/home/rev/.rbenv/versions/2.6.0-preview2/include/ruby-2.6.0/ruby/missing.h:174:29: error: 'int isinf(double)' conflicts with a previous declaration
RUBY_EXTERN int isinf(double);
^
In file included from /usr/include/c++/7.3/math.h:36:0,
from /home/rev/.rbenv/versions/2.6.0-preview2/include/ruby-2.6.0/ruby/missing.h:23,
from /home/rev/.rbenv/versions/2.6.0-preview2/include/ruby-2.6.0/ruby/defines.h:153,
from /home/rev/.rbenv/versions/2.6.0-preview2/include/ruby-2.6.0/ruby/ruby.h:29,
from /home/rev/.rbenv/versions/2.6.0-preview2/include/ruby-2.6.0/ruby.h:33,
from unf.cc:3:
/usr/include/c++/7.3/cmath:599:3: note: previous declaration 'constexpr bool std::isinf(double)'
isinf(double __x)
^~~~~
cc1plus: warning: unrecognized command line option '-Wno-cast-function-type'
cc1plus: warning: unrecognized command line option '-Wno-self-assign'
cc1plus: warning: unrecognized command line option '-Wno-constant-logical-operand'
cc1plus: warning: unrecognized command line option '-Wno-parentheses-equality'
make: *** [Makefile:211: unf.o] Error 1
make failed, exit code 2
</code></pre> Ruby master - Bug #14816: Extension build failure on a system with musl libchttps://bugs.ruby-lang.org/issues/14816?journal_id=723912018-06-05T06:16:35Zshyouhei (Shyouhei Urabe)shyouhei@ruby-lang.org
<ul></ul><p>akamch (Anatoly Kamchatnov) wrote:</p>
<blockquote>
<p>The patch does away with the isnan error, but the other one still remains:</p>
</blockquote>
<p>Ah sorry. Embarrassing typo :(. Try applying this patch over the previous one.</p>
<pre><code class="patch syntaxhl" data-language="patch"><span class="gh">diff --git a/include/ruby/missing.h b/include/ruby/missing.h
index 8df917498e..2d3852c131 100644
</span><span class="gd">--- a/include/ruby/missing.h
</span><span class="gi">+++ b/include/ruby/missing.h
</span><span class="p">@@ -168,7 +168,7 @@</span> RUBY_EXTERN const union bytesequence4_or_float rb_nan;
# include <ieeefp.h>
# endif
# define isinf(x) (!finite(x) && !isnan(x))
<span class="gd">-# elsif __cplusplus >= 201103L
</span><span class="gi">+# elif __cplusplus >= 201103L
</span> # include <cmath> // it must include constexpr bool isinf(double);
# else
RUBY_EXTERN int isinf(double);
</code></pre> Ruby master - Bug #14816: Extension build failure on a system with musl libchttps://bugs.ruby-lang.org/issues/14816?journal_id=723942018-06-05T06:27:36Zakamch (Anatoly Kamchatnov)akamch@gmail.com
<ul></ul><p>Works great, many thanks, Shyouhei!</p>
<p>The wider question on what could/should have been done to avoid these ifdef dances is definitely not Ruby's to answer.</p> Ruby master - Bug #14816: Extension build failure on a system with musl libchttps://bugs.ruby-lang.org/issues/14816?journal_id=723972018-06-05T06:51:02Zshyouhei (Shyouhei Urabe)shyouhei@ruby-lang.org
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Closed</i></li></ul><p>Applied in changeset trunk|r63571.</p>
<hr>
<p><code>int isnan(double)</code> is a POSIXism</p>
<ul>
<li>
<code>isnan</code> is something relatively new. We need to provide one for<br>
those systems without it. However:</li>
<li>X/Open defines <code>int isnan(double)</code>. Note the <code>int</code>.</li>
<li>C99 defines <code>isnan(x)</code> to be a macro.</li>
<li>C++11 nukes them all, undefines all the "masking macro"s, and<br>
defines its own <code>bool isnan(double)</code>. Note the <code>bool</code>.</li>
<li>In C++, <code>int isnan(double)</code> and <code>bool isnan(double)</code> are<br>
incompatible.</li>
<li>So the mess.</li>
</ul>
<p>[Bug <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Extension build failure on a system with musl libc (Closed)" href="https://bugs.ruby-lang.org/issues/14816">#14816</a>]<a href="/issues/14816">[ruby-core:87364]</a><br>
further reading: <a href="https://developers.redhat.com/blog/2016/02/29/why-cstdlib-is-more-complicated-than-you-might-think/" class="external">https://developers.redhat.com/blog/2016/02/29/why-cstdlib-is-more-complicated-than-you-might-think/</a></p> Ruby master - Bug #14816: Extension build failure on a system with musl libchttps://bugs.ruby-lang.org/issues/14816?journal_id=723982018-06-05T06:52:42Zshyouhei (Shyouhei Urabe)shyouhei@ruby-lang.org
<ul><li><strong>Backport</strong> changed from <i>2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN</i> to <i>2.3: REQUIRED, 2.4: REQUIRED, 2.5: REQUIRED</i></li></ul> Ruby master - Bug #14816: Extension build failure on a system with musl libchttps://bugs.ruby-lang.org/issues/14816?journal_id=732202018-07-30T13:57:38Zusa (Usaku NAKAMURA)usa@garbagecollect.jp
<ul><li><strong>Backport</strong> changed from <i>2.3: REQUIRED, 2.4: REQUIRED, 2.5: REQUIRED</i> to <i>2.3: REQUIRED, 2.4: DONE, 2.5: REQUIRED</i></li></ul><p>ruby_2_4 r64126 merged revision(s) 63571,63572.</p> Ruby master - Bug #14816: Extension build failure on a system with musl libchttps://bugs.ruby-lang.org/issues/14816?journal_id=735862018-08-18T04:18:38Znagachika (Tomoyuki Chikanaga)nagachika00@gmail.com
<ul><li><strong>Backport</strong> changed from <i>2.3: REQUIRED, 2.4: DONE, 2.5: REQUIRED</i> to <i>2.3: REQUIRED, 2.4: DONE, 2.5: DONE</i></li></ul><p>ruby_2_5 r64434 merged revision(s) 63571,63572.</p>