Alien-OpenMP

 view release on metacpan or  search on metacpan

README  view on Meta::CPAN

NAME
    Alien::OpenMP - Encapsulate system info for OpenMP

SYNOPSIS
        use Alien::OpenMP;
        say Alien::OpenMP->cflags;       # e.g. '-fopenmp' if gcc
        say Alien::OpenMP->lddlflags;    # e.g. '-fopenmp' if gcc
        say Alien::OpenMP->auto_include; # e.g. '#include <omp.h>' if gcc

DESCRIPTION
    This module encapsulates the knowledge required to compile OpenMP
    programs $Config{ccname}. "C", "Fortran", and "C++" programs annotated
    with declarative OpenMP pragmas will still compile if the compiler (and
    linker if this is a separate process) is not passed the appropriate flag
    to enable OpenMP support. This is because all pragmas are hidden behind
    full line comments (with the addition of OpenMP specific "sentinels", as
    they are called).

    All compilers require OpenMP to be explicitly activated during
    compilation; for example, GCC's implementation, "GOMP", is invoked by
    the "-fopenmp" flag.

    Most major compilers support OpenMP, including: GCC, Intel, IBM,
    Portland Group, NAG, and those compilers created using LLVM. GCC's
    OpenMP implementation, "GOMP", is available in all modern versions.
    Unfortunately, while OpenMP is a well supported standard; compilers are
    not required to use the same commandline switch to activate support. All
    compilers that support OpenMP use slightly different ways of invoking
    it.

  Compilers Supported by this module

README  view on Meta::CPAN

    to build "perl". Since the vast majority of "perl"s are building using
    "gcc", initial support is targeting it. However, like "perl", many other
    compilers may be used.

    Adding support for a new compiler should be straightforward; please
    section on contributing, below.

  Contributing
    The biggest need is to support additional compilers. OpenMP is a well
    established standard across compilers, but there is no guarantee that
    all compilers will use the same flags, library names, or header files.
    It should also be easy to contribute a patch to add this information,
    which is effectively its purpose. At the very least, please create an
    issue at the official issue tracker to request this support, and be sure
    to include the relevant information. Chances are the maintainers of this
    module do not have access to an unsupported compiler.

METHODS
    "cflags"
       Returns flag used by a supported compiler to enable OpenMP. If not
       support, an empty string is provided since by definition all OpenMP
       programs must compile because OpenMP pragmas are annotations hidden
       behind source code comments.

       Example, GCC uses, "-fopenmp".

    "lddlflags"
       Returns the flag used by the linker to enable OpenMP. This is usually
       the same as what is returned by "cflags".

       Example, GCC uses, "-fopenmp", for this as well.

    "Inline"
       Used in support of Inline::C's "with" method (inherited from Inline).
       This method is not called directly, but used when compiling OpenMP
       programs with "Inline::C":

           use Alien::OpenMP; use Inline (
               C           => 'DATA',
               with        => qw/Alien::OpenMP/,
           );

       The nice, compact form above replaces this mess:

           use Alien::OpenMP; use Inline (
               C             => 'DATA',
               ccflagsex     => Alien::OpenMP->cflags(),
               lddlflags     => join( q{ }, $Config::Config{lddlflags}, Alien::OpenMP::lddlflags() ),
               auto_include => Alien::OpenMP->auto_include(),
           );

       It also means that the standard *include* for OpenMP is not required
       in the "C" code, i.e., "#include <omp.h>".

AUTHOR
    OODLER 577 <oodler@cpan.org>

COPYRIGHT AND LICENSE

alienfile  view on Meta::CPAN

    requires 'Path::Tiny'  => '0.053';
  }
  if (!Alien::OpenMP::configure->is_known) {
    Alien::OpenMP::configure->unsupported(__PACKAGE__);
    exit;
  }
};

plugin 'Probe::CBuilder' => (
  lang         => 'C',
  cflags       => Alien::OpenMP::configure->cflags,
  libs         => Alien::OpenMP::configure->libs,
  options      => {quiet => 0},
  program      => join("\n" => <DATA>),
);

after probe => sub {
  # only reached on success AFAICT
  my $build = shift;
  $build->install_prop->{'alien_openmp_compiler_has_openmp'} = 1;
  $build->runtime_prop->{auto_include}                       = Alien::OpenMP::configure->auto_include;

lib/Alien/OpenMP.pm  view on Meta::CPAN

package Alien::OpenMP;

use parent 'Alien::Base';
use Config ();
use Alien::OpenMP::configure ();

our $VERSION = '0.003006';

# "public" Alien::Base method implementations

# we can reuse cflags for gcc/gomp; hopefully this will
# remain the case for all supported compilers
sub lddlflags { shift->libs }

# Inline related methods

sub Inline {
  my ($self, $lang) = @_;
  my $params = $self->SUPER::Inline($lang);
  $params->{CCFLAGSEX} = delete $params->{INC};
  return {
    %$params,
    LDDLFLAGS     => join( q{ }, $Config::Config{lddlflags}, $self->lddlflags() ),
    AUTO_INCLUDE  => $self->runtime_prop->{auto_include},
  };
}

1;

__END__

=head1 NAME

Alien::OpenMP - Encapsulate system info for OpenMP

=head1 SYNOPSIS

    use Alien::OpenMP;
    say Alien::OpenMP->cflags;       # e.g. '-fopenmp' if gcc
    say Alien::OpenMP->lddlflags;    # e.g. '-fopenmp' if gcc
    say Alien::OpenMP->auto_include; # e.g. '#include <omp.h>' if gcc

=head1 DESCRIPTION

This module encapsulates the knowledge required to compile OpenMP programs
C<$Config{ccname}>. C<C>, C<Fortran>, and C<C++> programs annotated
with declarative OpenMP pragmas will still compile if the compiler (and
linker if this is a separate process) is not passed the appropriate flag
to enable OpenMP support. This is because all pragmas are hidden behind
full line comments (with the addition of OpenMP specific C<sentinels>,
as they are called).

All compilers require OpenMP to be explicitly activated during compilation;
for example, GCC's implementation, C<GOMP>, is invoked by the C<-fopenmp>
flag.

Most major compilers support OpenMP, including: GCC, Intel, IBM,
Portland Group, NAG, and those compilers created using LLVM. GCC's OpenMP
implementation, C<GOMP>, is available in all modern versions. Unfortunately,
while OpenMP is a well supported standard; compilers are not required to
use the same commandline switch to activate support. All compilers that
support OpenMP use slightly different ways of invoking it.

=head2 Compilers Supported by this module

lib/Alien/OpenMP.pm  view on Meta::CPAN

C<gcc>, initial support is targeting it. However, like C<perl>, many
other compilers may be used.

Adding support for a new compiler should be straightforward; please
section on contributing, below.

=head2 Contributing

The biggest need is to support additional compilers. OpenMP is a well
established standard across compilers, but there is no guarantee that
all compilers will use the same flags, library names, or header files. It
should also be easy to contribute a patch to add this information, which
is effectively its purpose. At the very least, please create an issue
at the official issue tracker to request this support, and be sure to
include the relevant information. Chances are the maintainers of this
module do not have access to an unsupported compiler.

=head1 METHODS

=over 3

=item C<cflags>

Returns flag used by a supported compiler to enable OpenMP. If not support,
an empty string is provided since by definition all OpenMP programs
must compile because OpenMP pragmas are annotations hidden behind source
code comments.

Example, GCC uses, C<-fopenmp>.

=item C<lddlflags>

Returns the flag used by the linker to enable OpenMP. This is usually
the same as what is returned by C<cflags>.

Example, GCC uses, C<-fopenmp>, for this as well.

=item C<Inline>

Used in support of L<Inline::C>'s C<with> method (inherited from
L<Inline>). This method is not called directly, but used when compiling
OpenMP programs with C<Inline::C>:

    use Alien::OpenMP; use Inline (
        C           => 'DATA',
        with        => qw/Alien::OpenMP/,
    );

The nice, compact form above replaces this mess:

    use Alien::OpenMP; use Inline (
        C             => 'DATA',
        ccflagsex     => Alien::OpenMP->cflags(),
        lddlflags     => join( q{ }, $Config::Config{lddlflags}, Alien::OpenMP::lddlflags() ),
        auto_include => Alien::OpenMP->auto_include(),
    );

It also means that the standard I<include> for OpenMP is not required in
the C<C> code, i.e., C<< #include <omp.h> >>.

=back

=head1 AUTHOR

lib/Alien/OpenMP/configure.pm  view on Meta::CPAN

use strict;
use warnings;
use Config;

our $CCNAME = $ENV{CC} || $Config::Config{ccname};
our $OS     = $^O;

my $checked   = 0;
my $supported = {
    gcc => {
        cflags        => ['-fopenmp'],
        libs          => ['-fopenmp'],
        auto_include  => join qq{\n}, ('#include <omp.h>'),
    },
    clang => {
        cflags        => [ '-Xclang', '-fopenmp' ],
        libs          => ['-lomp'],                 # this could be -Xpreprocessor
        auto_include  => join qq{\n}, ('#include <omp.h>'),
    },
};

sub auto_include {
  shift->_update_supported;
  return $supported->{$CCNAME}{auto_include} || q{};
}

sub cflags {
  shift->_update_supported;
  return join ' ', @{$supported->{$OS}{cflags} || $supported->{$CCNAME}{cflags} || []};
}

sub is_known {
  shift->_update_supported;
  return !!(exists($supported->{$OS}) || exists($supported->{$CCNAME}));
}

sub lddlflags { __PACKAGE__->libs }

sub libs {
  shift->_update_supported;
  return join ' ', @{$supported->{$OS}{libs} || $supported->{$CCNAME}{libs} || []};
}

sub unsupported {
  my ($self, $build) = (shift, shift);

  # build an array of messages

lib/Alien/OpenMP/configure.pm  view on Meta::CPAN

# test support only
sub _reset { $checked = 0; }

sub _update_supported {
  return if $checked;
  if ($OS eq 'darwin') {
    require File::Which;
    require Path::Tiny;

    # The issue here is that ccname=gcc and cc=cc as an interface to clang
    $supported->{darwin} = {cflags => ['-Xclang', '-fopenmp'], libs => ['-lomp'],};
    if (my $mp = File::Which::which('port')) {

      # macports /opt/local/bin/port
      my $mp_prefix = Path::Tiny->new($mp)->parent->parent;
      push @{$supported->{darwin}{cflags}}, "-I$mp_prefix/include/libomp";
      unshift @{$supported->{darwin}{libs}}, "-L$mp_prefix/lib/libomp";
    }
    else {
      # homebrew has the headers and library in /usr/local
      push @{$supported->{darwin}{cflags}}, "-I/usr/local/include";
      unshift @{$supported->{darwin}{libs}}, "-L/usr/local/lib";
    }
  }
  $checked++;
}

1;

=encoding utf8

lib/Alien/OpenMP/configure.pm  view on Meta::CPAN


  # alienfile
  use Alien::OpenMP::configure;

  if (!Alien::OpenMP::configure->is_known) {
    Alien::OpenMP::configure->unsupported(__PACKAGE__);
    exit;
  }

  plugin 'Probe::CBuilder' => (
    cflags  => Alien::OpenMP::configure->cflags,
    libs    => Alien::OpenMP::configure->libs,
    ...
  );

=head1 DESCRIPTION

L<Alien::OpenMP::configure> is storage for the compiler flags required for multiple compilers on multiple systems and
an attempt to intelligently support them.

This module is designed to be used by the L<Alien::OpenMP::configure> authors and contributors, rather than end users.

=head1 METHODS

L<Alien::OpenMP::configure> implements the following methods.

=head2 cflags

Obtain the compiler flags for the compiler and architecture suitable for passing as C<cflags> to
L<Alien::Build::Plugin::Probe::CBuilder>.

=head2 is_known

Return a Boolean to indicate whether the compiler is known to this module.

=head2 lddlflags

A synonym for L</"libs">.

=head2 libs

Obtain the compiler flags for the compiler and architecture suitable for passing as C<libs> to
L<Alien::Build::Plugin::Probe::CBuilder>.

=head2 unsupported

Report using L<Alien::Build::Log> or L<warn|https://metacpan.org/pod/perlfunc#warn-LIST> that the compiler/architecture
combination is unsupported and provide minimal notes on any solutions. There is little to no guarding of the actual
state of support in this function.

=cut

t/01-basic.t  view on Meta::CPAN

use Test::More;
use Test::Alien;
use Alien::OpenMP;

subtest 'syntax and interface' => sub {
  alien_ok 'Alien::OpenMP', 'public interface check for Alien::Base'; 
  is +Alien::OpenMP->install_type, 'system', 'no share install is possible';
};

subtest 'has options' => sub {
  like +Alien::OpenMP->cflags,    qr{-fopenmp},           q{Found expected OpenMP compiler switch for gcc/clang.};
  like +Alien::OpenMP->lddlflags, qr{(?:-lomp|-fopenmp)}, q{Found expected OpenMP linker switch for gcc/clang.};
};

done_testing;

t/03-configure.t  view on Meta::CPAN

subtest 'CC environment variable' => sub {
  local $Alien::OpenMP::configure::OS = 'linux';
  Alien::OpenMP::configure->_reset;
  is $Alien::OpenMP::configure::CCNAME, 'xyz-cc', 'esoteric compiler name';
  ok !Alien::OpenMP::configure->is_known, q{not known};
};

subtest 'gcc' => sub {
  local $Alien::OpenMP::configure::CCNAME = 'gcc';
  local $Alien::OpenMP::configure::OS     = 'linux';
  my $omp_flag = q{-fopenmp};
  Alien::OpenMP::configure->_reset;
  is +Alien::OpenMP::configure->is_known,  1, q{known};
  is +Alien::OpenMP::configure->cflags,    $omp_flag, q{Found expected OpenMP compiler switch for gcc.};
  is +Alien::OpenMP::configure->lddlflags, $omp_flag, q{Found expected OpenMP linker switch for gcc.};
};

subtest 'darwin clang/gcc homebrew' => sub {
  local $Alien::OpenMP::configure::CCNAME = 'gcc';
  local $Alien::OpenMP::configure::OS     = 'darwin';
  local $ENV{PATH}                        = "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin";
  Alien::OpenMP::configure->_reset;
  is +Alien::OpenMP::configure->is_known, 1,                    q{known};
  like +Alien::OpenMP::configure->cflags, qr{-Xclang -fopenmp}, q{Found expected OpenMP compiler switch for gcc/clang.};
  like +Alien::OpenMP::configure->lddlflags, qr{-lomp},         q{Found expected OpenMP linker switch for gcc/clang.};
  like +Alien::OpenMP::configure->cflags,    qr{-I/usr/local/include}, q{Found path to include headers};
};

subtest 'darwin clang/gcc macports' => sub {
  plan skip_all => 'Mocking does not work on MSWin32'
    if $^O eq 'MSWin32';
  local $Alien::OpenMP::configure::CCNAME = 'gcc';
  local $Alien::OpenMP::configure::OS     = 'darwin';
  local $ENV{PATH}                        = "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin";

  # create a mock port executable
  my $tempdir = Path::Tiny->tempdir();
  my $port    = $tempdir->child('bin', 'port');
  $port->parent->mkpath;
  $port->spew("#!/bin/bash");
  $port->chmod(0755);
  $ENV{PATH} .= ":$tempdir/bin";
  Alien::OpenMP::configure->_reset;
  is +Alien::OpenMP::configure->is_known, 1,                    q{known};
  like +Alien::OpenMP::configure->cflags, qr{-Xclang -fopenmp}, q{Found expected OpenMP compiler switch for gcc/clang.};
  like +Alien::OpenMP::configure->lddlflags, qr{-lomp},         q{Found expected OpenMP linker switch for gcc/clang.};
  like +Alien::OpenMP::configure->cflags,    qr{-I$tempdir/include/libomp}, q{Found path to include headers};
  like +Alien::OpenMP::configure->libs,      qr{-L$tempdir/lib/libomp},     q{Found path to library};
};

subtest 'unknown and therefore unsupported' => sub {
  local $Alien::OpenMP::configure::CCNAME = q{unsupported xyz};
  local $Alien::OpenMP::configure::OS     = q{foobar-os};
  Alien::OpenMP::configure->_reset;

  ok !Alien::OpenMP::configure->is_known, 'not known AKA unsupported';
  is +Alien::OpenMP::configure->cflags, q{}, 'empty string';
  is +Alien::OpenMP::configure->libs,   q{}, 'empty string';

  my ($stdout, $stderr, @result) = capture { Alien::OpenMP::configure->unsupported; 1 };
  is_deeply \@result, [1], 'no errors';
  like $stdout, qr{^OS Unsupported},                                         'Message for ExtUtils::MakeMaker';
  like $stderr, qr{This version of unsupported xyz does not support OpenMP}, 'unsupported compiler name';
};

subtest 'darwin, missing dependencies' => sub {
  local $Alien::OpenMP::configure::CCNAME = q{clang};



( run in 0.607 second using v1.01-cache-2.11-cpan-94b05bcf43c )