{"id":514,"date":"2015-03-05T14:46:31","date_gmt":"2015-03-05T22:46:31","guid":{"rendered":"http:\/\/porkrind.org\/missives\/?p=514"},"modified":"2015-03-05T14:48:42","modified_gmt":"2015-03-05T22:48:42","slug":"perl-module-xs-configuration-is-hard","status":"publish","type":"post","link":"https:\/\/porkrind.org\/missives\/perl-module-xs-configuration-is-hard\/","title":{"rendered":"Perl Module XS configuration is hard"},"content":{"rendered":"<p>I wrote <a href=\"http:\/\/search.cpan.org\/dist\/Time-Monotonic\/\">a simple little Perl Module<\/a> recently, and it reminded me how frustrating it is to get it all working.<\/p>\n<p>I&#8217;m not even talking about the <code>.xs<\/code> preprocessor (xsubpp)\u2014that&#8217;s weird, but it&#8217;s fairly straightforward. Most contingencies are accounted for and you can make it do whatever you want, and in my case, the results were <a href=\"https:\/\/github.com\/caldwell\/Time-Monotonic\/blob\/88baaad41557ffc5a61a780b4a1c6f6d942e137f\/Monotonic.xs\">pretty minimal and beautiful in their own way<\/a>. No, I&#8217;m talking about actually building it and making it compile in a cross platform way.<\/p>\n<p>If you&#8217;re used to standard unix C source releases, you know you can just run <code>.\/configure<\/code> and then <code>make<\/code> and it&#8217;ll (probably) just work. Behind the scenes <code>configure<\/code> is madness, but the principle it works on (feature detection by actually compiling things) is sound. My module is an interface to <a href=\"https:\/\/github.com\/ThomasHabets\/monotonic_clock\">a small third party library<\/a>. I can&#8217;t count on the library being installed on the machine already, so I want to statically link against it. It includes a configure script for unix machines and some windows source that isn&#8217;t covered by <code>.\/configure<\/code>.<\/p>\n<p>In Perl, there are two different ways to build your module: <code>ExtUtils::MakeMaker<\/code> and <code>Module::Build<\/code>. For pure Perl modules, I will only use <code>Module::Build<\/code>, as <code>ExtUtils::MakeMaker<\/code> seems too hairy. But for an XS module, I&#8217;m not sure. <code>ExtUtils::MakeMaker<\/code> looked fairly configurable so <a href=\"https:\/\/github.com\/caldwell\/Time-Monotonic\/blob\/88baaad41557ffc5a61a780b4a1c6f6d942e137f\/Makefile.PL\">I try that first<\/a>. It works very well for compiling XS Unix stuff, but because it builds a Makefile and lets you just drop your own rules in, it encouraged me to just call my library&#8217;s <code>.\/configure<\/code> and then <code>make<\/code> in its directory:<\/p>\n<pre><code class=\"language-perl\">use ExtUtils::MakeMaker;\n\nWriteMakefile(\n    # ... boilerplate stuff stripped for brevity...\n\n    INC               =&gt; '-I.\/monotonic_clock\/include',\n    MYEXTLIB          =&gt; 'monotonic_clock\/.libs\/libmonotonic_clock.a'\n);\n\nsub MY::postamble {\n'\n$(MYEXTLIB): monotonic_clock\/configure\n    cd monotonic_clock &amp;&amp; CFLAGS=\"$(CCFLAGS)\" .\/configure &amp;&amp; $(MAKE) all\nmonotonic_clock\/configure: monotonic_clock\/configure.ac\n    cd monotonic_clock &amp;&amp; .\/bootstrap.sh\n'\n}\n<\/code><\/pre>\n<p>This of course worked just fine on my Mac.<\/p>\n<p><a href=\"http:\/\/matrix.cpantesters.org\/?dist=Time-Monotonic%200.9.0\">But it utterly failed everywhere else<\/a>. Ugh, there&#8217;s hardly any green there! Ok, so I focused on the Unix failures first\u2014I know this, I should be able to get stuff working. Turns out Linux wants <code>-fPIC<\/code> on the library&#8217;s code because I&#8217;m statically linking against it and it will end up in my modules shared library &#8220;.so&#8221; file. Ok, so I can <a href=\"https:\/\/github.com\/caldwell\/Time-Monotonic\/commit\/894c32bbae2ccefd932485cbe4dc5db6c47d10e8\">just unilaterally add <code>-fPIC<\/code><\/a>:<\/p>\n<pre><code class=\"language-perl\">sub MY::postamble {\n'\n$(MYEXTLIB): monotonic_clock\/configure Makefile.PL\n    cd monotonic_clock &amp;&amp; CFLAGS=\"$(CCFLAGS) -fPIC\" .\/configure &amp;&amp; $(MAKE) all\nmonotonic_clock\/configure: monotonic_clock\/configure.ac\n    cd monotonic_clock &amp;&amp; .\/bootstrap.sh\n'\n}\n<\/code><\/pre>\n<p>That works on clang on the Mac and gcc on Linux. I actually tested on my Debian machine. Everything should be great now!<\/p>\n<p><a href=\"http:\/\/matrix.cpantesters.org\/?dist=Time-Monotonic%200.9.1\">Nope<\/a>. Half the Linuxes are still failing, some of the Macs too, and I haven&#8217;t even addresses Windows yet. I discover that <code>-fPIC<\/code> happens to be defined by <code>ExtUtils::MakeMaker<\/code> on the appropriate platforms in the <code>CCCDLFLAGS<\/code> make variable, <a href=\"https:\/\/github.com\/caldwell\/Time-Monotonic\/commit\/eeb6e66fa66fd21990a59234f3855583abf80b45#diff-5d3ba18294715d9415e9e732852bfec6\">and switch to it<\/a> thinking this should solve the remaining Unix problems.<\/p>\n<p>Then I start thinking about Windows. I boot up my Windows 8 VM where I have Strawberry Perl installed and try out my module. It fails utterly. I forgot\u2014you can&#8217;t just call <code>.\/configure<\/code> in windows! Plus my library doesn&#8217;t even handle Windows in its configure script. I start thinking about writing my own Makefile rules to build it so I can drop the configure script completely. But I don&#8217;t like it. I&#8217;m going to need to detect which back-end the library should be using. I basically have to recreate what configure does, but in a Makefile. And I don&#8217;t know how much shell I can use in my rules and still work on Windows, meaning the detection is going to be a huge issue.<\/p>\n<p>So I decide to <a href=\"https:\/\/github.com\/caldwell\/Time-Monotonic\/commit\/e83419ac0fb46ac7d019ac66fa426abf2b54e36b#diff-07acf2723d76bb34afc399ca65b12f32\">drop <code>ExtUtils::MakeMaker<\/code> and use <code>Module::Build<\/code> instead<\/a>. It&#8217;s actually pretty straightforward:<\/p>\n<pre><code class=\"language-perl\">use strict;\nuse warnings FATAL =&gt; 'all';\nuse Module::Build;\n\nmy $builder = Module::Build-&gt;new(\n    # ... boilerplate stuff stripped for brevity...\n\n    extra_compiler_flags =&gt; '-DHAVE_GETTIMEOFDAY', # We're going to assume everyone is at least that modern\n    include_dirs =&gt; 'monotonic_clock\/include',\n    c_source     =&gt; ['monotonic_clock\/src\/monotonic_common.c'],\n);\n\n# Add the appropriate platform-specific backend.\n#\n# This isn't as good as the configure script that comes with\n# monotonic_clock, since it actually tests for the feature instead of\n# assuming that non-darwin unixes support POSIX clock_gettime. On the other\n# hand, this handles windows.\npush(@{$builder-&gt;c_source},\n     $^O                 eq 'darwin'  ? 'monotonic_clock\/src\/monotonic_mach.c' :\n     $builder-&gt;os_type() eq 'Windows' ? 'monotonic_clock\/src\/monotonic_win32.c' :\n     $builder-&gt;os_type() eq 'Unix'    ? 'monotonic_clock\/src\/monotonic_clock.c' :\n                                        'monotonic_clock\/src\/monotonic_generic.c');\n\n$builder-&gt;create_build_script();\n<\/code><\/pre>\n<p>I figure out that I can abuse the <code>c_source<\/code> configuration option. It&#8217;s supposed to be a directory where the source code lives and they search it recursively for &#8220;*.c&#8221; files. But it turns out if I pass a C file to it instead of a directory, the recursive search finds that one C file! So now I can add specific C files for the particular platforms. I now have something that compiles on my Mac, my Debian machine, and my Windows VM. Hooray! That covers everything. Finally!<\/p>\n<p><a href=\"http:\/\/matrix.cpantesters.org\/?dist=Time-Monotonic%20v0.9.2\">Sigh<\/a>. That&#8217;s worse than my last Makefile.PL based version! What&#8217;s going on? Ok, my <code>c_source<\/code> hack is biting me. I noticed that it was helpfully adding <code>-I<\/code> options for the sources directory to the compiler, but since I was passing in actual files to <code>c_source<\/code> I was getting compiler lines like <code>-Imonotonic_clock\/src\/monotonic_clock.c<\/code>. This was a warning on my Debian gcc and on Windows gcc, but my Mac&#8217;s clang just ignored it with no message at all. So I blew it off. Well, it turns out other compilers are more strict.<\/p>\n<p>So I start poking around the <code>Module::Build<\/code> source code. I discover that the <code>c_source<\/code> is adding to an internal <code>include_dirs<\/code> list. So I <a href=\"https:\/\/github.com\/caldwell\/Time-Monotonic\/commit\/f163e030836be89a6d8f8afaefef10de92614a29\">override the compile function to strip .c files out of the <code>include_dirs<\/code> list.<\/a>:<\/p>\n<pre><code class=\"language-perl\"># This hacks around the fact that we are using c_source to store files, when Module::Build expects directories.\nmy $custom = Module::Build-&gt;subclass(\n    class =&gt; 'My::Builder',\n    code  =&gt; &lt;&lt;'CUSTOM_CODE');\nsub compile_c {\n  my ($self, $file, %args) = @_;\n  # Adding to c_source adds to include_dirs, too. Since we're adding files, remove them.\n  @{$self-&gt;include_dirs} = grep { !\/.c$\/ } @{$self-&gt;include_dirs};\n  $self-&gt;SUPER::compile_c($file, %args);\n}\nCUSTOM_CODE\n<\/code><\/pre>\n<p>It seems really hacky (I hate having to write Perl code in a string) and a bit fragile (I sure hope they don&#8217;t change the API in a new version) but it actually works! I publish that and wait to see my wall of green.<\/p>\n<p><a href=\"http:\/\/matrix.cpantesters.org\/?dist=Time-Monotonic%20v0.9.3\">I don&#8217;t get to see it yet<\/a>. This is baffling to me. The worst part is the <a href=\"http:\/\/www.cpantesters.org\/cpan\/report\/b8012060-c330-11e4-88d1-f1207db652c0\">test reports themselves<\/a>. They aren&#8217;t showing me the build process, and they don&#8217;t try to identify the Linux distro, leaving me to intuit it from the versions of various things. It looks like one of the failing distros is Debian Wheezy (aka the current &#8220;stable&#8221;). So I as a last ditch effort use &#8220;debootstrap&#8221; to build a minimal install that I can chroot into. I try compiling and I can actually reproduce the error. This is phenomenal because I don&#8217;t have to guess any more.<\/p>\n<p>After poking around for a while I discover that in older glibcs, the <code>clock_gettime<\/code> function that my library uses requires <code>librt<\/code> and therefore a <code>-lrt<\/code> option to the linker. Ok. But I don&#8217;t want to add that unilaterally\u2014I got bit by that earlier in this process. I&#8217;m also frustrated that my backend detection code is just hardwired to <code>Module::Build<\/code>s <code>os_type()<\/code> function. Do I really know that old FreeBSDs support <code>clock_gettime<\/code>? No, I don&#8217;t, and I don&#8217;t want to figure it out. I think back wistfully to <code>.\/configure<\/code>\u2014it just detects stuff by compiling it and seeing if it works. That&#8217;s really what I want\u2014it&#8217;s the only way to know for sure without researching and testing on every. single. platform.<\/p>\n<p>And then it hits me, I guess <em>I<\/em> could do that. <code>Module::Build<\/code> uses <code>ExtUtils::CBuilder<\/code> internally, and so I can too. It turns out to actually <a href=\"https:\/\/github.com\/caldwell\/Time-Monotonic\/commit\/5302512a5bc707b88a7803b92228c48ea6ec7544\">not be that bad<\/a>. The longest part of the code is redirecting <code>stdout<\/code> and <code>stderr<\/code> so you don&#8217;t see a bunch of compilation errors while it&#8217;s figuring things out:<\/p>\n<pre><code class=\"language-perl\"># autoconf style feature tester. Can't believe someone hasn't written this yet...\nuse ExtUtils::CBuilder;\nmy $cb = ExtUtils::CBuilder-&gt;new(quiet=&gt;1);\n\nsub test_function_lib {\n    my ($function, $lib) = @_;\n    my $source = 'conf_test.c';\n    open my $conf_test, '&gt;', $source or return;\n    print $conf_test &lt;&lt;\"C_CODE\";\nint main() {\n    int $function();\n    return $function();\n}\nC_CODE\n    close $conf_test;\n\n    my $conf_log='conf_test.log';\n    my @saved_fhs = eval {\n        open(my $oldout, \"&gt;&amp;\", *STDOUT) or return;\n        open(my $olderr, \"&gt;&amp;\", *STDERR) or return;\n        open(STDOUT, '&gt;&gt;', $conf_log) or return;\n        open(STDERR, \"&gt;&gt;\", $conf_log) or return;\n        ($oldout, $olderr)\n    };\n\n    my $worked = eval {\n        my $obj = $cb-&gt;compile(source=&gt;$source);\n        my @junk = $cb-&gt;link_executable(objects =&gt; $obj, extra_linker_flags=&gt;$lib);\n        unlink $_ for (@junk, $obj, $source, $conf_log);\n        return 1;\n    };\n\n    if (@saved_fhs) {\n        open(STDOUT, \"&gt;&amp;\", $saved_fhs[0]) or return;\n        open(STDERR, \"&gt;&amp;\", $saved_fhs[1]) or return;\n        close($_) for (@saved_fhs);\n    }\n\n    $worked\n}\n<\/code><\/pre>\n<p>Using it is pretty easy:<\/p>\n<pre><code class=\"language-perl\">my $have_gettimeofday = test_function_lib(\"gettimeofday\", \"\");\nmy $need_librt = test_function_lib(\"clock_gettime\", \"-lrt\");\n<\/code><\/pre>\n<p>The one annoyance is that the feature detection doesn&#8217;t completely work on Windows. The technique I used (stolen unabashedly from autoconf) just declares the function with the wrong arguments and return value and tries to link with it. This works in general because C doesn&#8217;t encode the arguments or return values into the symbol name. Except Windows apparently does with its API functions: my feature detector detects <code>gettimeofday()<\/code> just fine, but not <code>QueryPerformanceCounter()<\/code>. If I declare <code>QueryPerformanceCounter()<\/code> properly then Windows links with it, otherwise I get an undefined symbol error. I don&#8217;t care enough to properly research Windows&#8217;s ABI, so I decided to just check <code>$^O<\/code>, assuming that all Windows will work. A quick check of the <a href=\"https:\/\/technet.microsoft.com\/en-us\/evalcenter\/ms644904%28v=vs.85%29\">Windows documentation<\/a> reveals that it&#8217;s has been supported since Windows 2000 and that&#8217;s good enough for me.<\/p>\n<p>I upload to CPAN and <a href=\"http:\/\/matrix.cpantesters.org\/?dist=Time-Monotonic%20v0.9.4\"><em>finally<\/em> see that green I&#8217;ve been looking for<\/a>.<\/p>\n<p>But it makes me wonder, why did <em>I<\/em> have to write this? It&#8217;s 2015, has nobody ever needed to build their Perl XS module differently for different platforms? I know I can&#8217;t be the first, but I had a really hard time finding any documentation or discussion about it. I didn&#8217;t see anything on CPAN that looked like it might solve my problems. Should this be a feature in <code>Module::Build<\/code>? I&#8217;ve only written two XS modules in my life, but both times I needed different sources on different platforms. Does anyone want to point me to something that does this well, or failing that, build off this idea and make something neat? I would love it, certainly.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I wrote a simple little Perl Module recently, and it reminded me how frustrating it is to get it all working. I&#8217;m not even talking about the .xs preprocessor (xsubpp)\u2014that&#8217;s weird, but it&#8217;s fairly straightforward. Most contingencies are accounted for and you can make it do whatever you want, and in my case, the results &hellip; <a href=\"https:\/\/porkrind.org\/missives\/perl-module-xs-configuration-is-hard\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Perl Module XS configuration is hard<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-514","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/posts\/514","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/comments?post=514"}],"version-history":[{"count":13,"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/posts\/514\/revisions"}],"predecessor-version":[{"id":527,"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/posts\/514\/revisions\/527"}],"wp:attachment":[{"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/media?parent=514"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/categories?post=514"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/tags?post=514"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}