stbey has asked for the wisdom of the Perl Monks concerning the following question:

Dear Perl Monks,

what would be the best way to detect whether a working C compiler is available at build time of a module (i.e., in Makefile.PL)?

I would like to install a (faster) XS version of a module if that is the case, and a (slower) pure-Perl implementation if not.

Remember that C compilers are not always available on all systems. Sometimes they cost heavy extra money, or sometimes you have to work with what's there on a customer's or provider's server (where frequently installing a C compiler is not an option due to company policies).

Thank you!

UPDATE:

In the meantime, I've adopted a mixed approach, using an "Inline"-like search of the PATH (as fallback) and the "have_compiler" method (which actually compiles and links a test file) when "ExtUtils::CBuilder" is available.

Look here: http://cpansearch.perl.org/src/STBEY/Date-Calc-6.1/Makefile.PL

After that, I dropped this approach altogether and went for the usual "wrapper" approach - "Date::Calc" is now (v6.2) a wrapper which tries to load "Date::Calc::XS", and failing that, loads "Date::Calc::PP".

  • Comment on How to best detect availability of C compiler in Makefile.PL?

Replies are listed 'Best First'.
Re: How to best detect availability of C compiler in Makefile.PL?
by bingos (Vicar) on Oct 13, 2009 at 11:23 UTC

    Module::Install has the can_cc function you can use in your Makefile.PL

    use inc::Module::Install; if ( can_cc() ) { # do XS stuff } else { # do pure-perl stuff } # rest of Makefile.PL
Re: How to best detect availability of C compiler in Makefile.PL?
by cdarke (Prior) on Oct 13, 2009 at 10:22 UTC
    The only way I know of is to check $Config{cc} (Corion told me that one ages ago) then see if you can load it with system or qx (redirecting stderr). That ensures you are using the same compiler as perl, which can be an issue sometimes, particularly on Windows.
        eg, it could be 'ccache cc'

        FWIW, the C/Makefile.PL in Inline-0.45 seems to do a pretty good job of finding the C compiler (albeit rather kludgily).
        I don't think it detects 'ccache cc', however.
        Here's a C/Makefile.PL that should also detect 'ccache cc', though it has yet to be run by the intrepid cpan testers:
        use strict; use ExtUtils::MakeMaker; use Config; use File::Spec; my ($cc, $exe) = @Config{'cc', '_exe'}; $cc =~ s/\s+-.+$//; #remove possible trailing options my $comp = (split /\./, $cc)[0]; my $found = 0; my $delim = $Config::Config{path_sep}; if ($cc =~ m|/:\[|) { $found = -f "$comp$exe"; } # $Config{cc} might be something like '/some/place/cc' elsif ($cc =~ m|/|) { $found = -f "$comp$exe" || -l $cc; } # $Config{cc} might be something like 'ccache cc' elsif ($cc =~ m|ccache|) { my @cc = split /\s+/, $cc; $found = -f "$cc[0]$exe" || -l $cc[0]; if($found && $cc[1]) {$found = -f "$cc[1]$exe" || -l $cc[1]} } else { my $comp = (split /\./, $cc)[0]; for my $lib (split $delim, $ENV{PATH}) { $found = -f File::Spec->catfile($lib,"$comp$exe") and last; } } print <<END; Inline::C is packaged with Inline.pm because it is the most commonly u +sed Inline Language Support Module (ILSM). See also: Inline::ASM, ::Awk, ::BC, ::Basic, ::Befunge, ::CPP (C++), : +:CPR, ::Foo, ::Guile, ::Java, ::Octave, ::PERL, ::Python, ::Ruby, +::TT, ::Tcl and ::WebChat. Config.pm indicates that your version of Perl was built with this C co +mpiler: $cc END if ($found) { print <<END; I have located this compiler on your system: END } else { print <<END; I cannot locate this compiler on your system. You can install Inline.pm without installing Inline::C. But you'll need to install another Inline language module (like Inline::Java for instance) to actually make use of it. If the aforementioned C compiler really is on your system, please make + sure it can be found in the PATH and then try running this program again. O +r if you think I made an error searching for this compiler, simply answer ' +Y' to the next question. END # ' } my $answer = ''; my $default = $found ? "y" : "n"; while (1) { $answer = prompt ('Do you want to install Inline::C?', $default); last if $answer =~ /^(y|yes|n|no)$/i; } if ($answer =~ /^(y|yes)$/i) { WriteMakefile( NAME => 'Inline::C', clean => {FILES => '_Inline_test'}, ) } else { open MF, "> Makefile" or die "Can't open Makefile for output"; print MF <<'END'; all:: test:: clean:: END close MF; }
        Cheers,
        Rob