Digest libraries are built incorrectly due to ambiguous location of "extconf.h"
This is essentially the same issue as bug #3231, "Digest Does Not Build", which has reappeared for me on CentOS 6.5 using gcc 4.4.7.
The attached patch changes the generated Makefiles so they explicitly specify the location of
extconf.h as each module's own source-code folder. This removes the ambiguity at compile time of which copy of the file should be included, the module's or its parent's, and allows the digest classes to build correctly regardless of the how the compiler prioritizes the folders in its search path. It causes no additional test failures (on my system, at least) so I believe this change is safe.
Here's the background:
Building the latest version of Ruby, either 2.1.1p76 or the head revision in Subversion, on CentOS 6.5 (x86; gcc 4.4.7) with OpenSSL headers installed succeeds but the digest classes are unusable, producing error messages at runtime like
/usr/local/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:55:in `require': /usr/local/lib/ruby/2.2.0/i686-linux/digest/md5.so: undefined symbol: rb_Digest_MD5_Init - /usr/local/lib/ruby/2.2.0/i686-linux/digest/md5.so (LoadError) from /usr/local/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:55:in `require' from test-digest-classes.rb:1:in `<main>'
The reason is modules under
ext/digest rely on generated
extconf.h files to indicate OpenSSL headers are available. However, at compile time files with this name are available in the module's own directory and the parent's, both of which are in the compiler's search path (as other header files in the parent directory are needed). For whatever reason the compiler is insisting on using the
extconf.h in the parent directory which causes each module to be misconfigured.
The result is that Ruby's own digest-algorithm implementations are not built, as the build system correctly identifies them as unnecessary, but due to the
extconf.h collision the source code assumes they are in use and therefore prepends "
rb_Digest_" to several function names. These become unresolved symbols when the system attempts to load the library.
The key to the solution is that if
extconf.h in a module's parent folder is temporarily renamed, the module will build fine and be usable. There does not appear to be any standard way of specifying to the compiler which copy it ought to use without specifying the file's full path, which is what this patch accomplishes.
#1 [ruby-core:61628] Updated by Nobuyoshi Nakada over 2 years ago
- Status changed from Open to Feedback
-I. option should be placed the top of
Why is the file in the parent directory used?
At least, your patch is wrong at the point that
extconf.h won't be generated in
$(srcdir) but in the cwd.
And what happens if name of the header is changed?
diff --git a/ext/digest/md5/extconf.rb b/ext/digest/md5/extconf.rb index 5a57fd3..f086cce 100644 --- a/ext/digest/md5/extconf.rb +++ b/ext/digest/md5/extconf.rb @@ -25,4 +25,5 @@ have_header("sys/cdefs.h") $preload = %w[digest] +create_header("./extconf.h") create_makefile("digest/md5")