—package
Dist::Build::XS;
$Dist::Build::XS::VERSION
=
'0.019'
;
use
strict;
use
warnings;
sub
get_flags {
my
(
$raw
) =
@_
;
return
$raw
if
not
defined
(
$raw
) or
ref
(
$raw
);
return
[ shellwords(
$raw
) ]
}
sub
add_methods {
my
(
$self
,
$planner
,
%args
) =
@_
;
$planner
->add_delegate(
'add_xs'
,
sub
{
my
(
$planner
,
%args
) =
@_
;
my
$pureperl_only
=
$args
{pureperl_only} //
$planner
->pureperl_only;
die
"Can't build xs files under --pureperl-only\n"
if
$pureperl_only
;
$planner
=
$planner
->new_scope;
my
$config
=
$args
{config} //
$planner
->config;
$planner
->load_extension(
'ExtUtils::Builder::ParseXS'
, 0.016,
config
=>
$config
)
unless
$planner
->can(
'parse_xs'
);
$planner
->load_extension(
'ExtUtils::Builder::AutoDetect::C'
, 0.016,
config
=>
$config
)
unless
$planner
->can(
'compile'
);
my
$xs_base
=
$args
{xs_base} //
'lib'
;
my
(
$module_name
,
$xs_file
);
if
(
defined
$args
{module}) {
$module_name
=
$args
{module};
$xs_file
=
$args
{file} // catfile(
$xs_base
,
split
/::/,
$module_name
) .
'.xs'
;
}
elsif
(
defined
$args
{file}) {
$xs_file
=
$args
{file};
$module_name
=
$planner
->module_for_xs(
$xs_file
,
$xs_base
);
}
else
{
$module_name
=
$planner
->main_module;
$xs_file
= catfile(
$xs_base
,
split
/::/,
$module_name
) .
'.xs'
;
}
my
$module_version
=
$args
{version} //
$planner
->version;
my
$xs_dir
= dirname(
$xs_file
);
my
$c_file
=
$planner
->c_file_for_xs(
$xs_file
,
$xs_dir
);
$planner
->parse_xs(
$xs_file
,
$c_file
,
%args
,
module
=>
$module_name
);
my
$o_file
=
$planner
->obj_file(basename(
$c_file
,
'.c'
),
$xs_dir
);
my
%defines
= (
%{
$args
{defines} // {} },
VERSION
=>
qq/"$module_version"/
,
XS_VERSION
=>
qq/"$module_version"/
,
);
my
$compiler_flags
= get_flags(
$args
{extra_compiler_flags});
$planner
->compile(
$c_file
,
$o_file
,
type
=>
'loadable-object'
,
profile
=>
'@Perl'
,
defines
=> \
%defines
,
include_dirs
=> [ dirname(
$xs_file
), @{
$args
{include_dirs} // [] } ],
extra_args
=>
$compiler_flags
,
config
=>
$config
,
);
my
@objects
=
$o_file
;
for
my
$source
(@{
$args
{extra_sources} }) {
my
%options
=
ref
$source
? %{
$source
} : (
source
=>
$source
);
my
$dirname
= dirname(
$options
{source});
my
$object
=
$options
{object} //
$planner
->obj_file(basename(
$options
{source},
'.c'
),
$dirname
);
my
%defines
= (%{
$args
{defines} // {} }, %{
$options
{defines} // {} });
my
@include_dirs
= (@{
$args
{include_dirs} // [] }, @{
$options
{include_dirs} // [] });
my
@compiler_flags
= (@{
$compiler_flags
// [] }, @{
$options
{flags} // [] });
$planner
->compile(
$options
{source},
$object
,
type
=>
'loadable-object'
,
profile
=>
'@Perl'
,
defines
=> \
%defines
,
include_dirs
=> \
@include_dirs
,
extra_args
=> \
@compiler_flags
,
config
=>
$config
,
);
push
@objects
,
$object
;
}
push
@objects
, @{
$args
{extra_objects} }
if
$args
{extra_objects};
my
$lib_file
=
$planner
->extension_filename(
$module_name
);
$planner
->
link
(\
@objects
,
$lib_file
,
type
=>
'loadable-object'
,
profile
=>
'@Perl'
,
module_name
=>
$module_name
,
mkdir
=> 1,
extra_args
=> get_flags(
$args
{extra_linker_flags}),
library_dirs
=>
$args
{library_dirs},
libraries
=>
$args
{libraries},
config
=>
$config
,
);
$planner
->create_phony(
'dynamic'
,
$lib_file
);
return
$lib_file
;
});
$planner
->add_delegate(
'auto_xs'
,
sub
{
my
(
$planner
,
%args
) =
@_
;
my
$dir
=
delete
$args
{dir} //
'lib'
;
my
$xs_files
=
$planner
->create_pattern(
dir
=>
$dir
,
file
=>
'*.xs'
);
my
$so_files
=
$planner
->create_subst(
on
=>
$xs_files
,
subst
=>
sub
{
my
(
$source
) =
@_
;
$planner
->add_xs(
%args
,
xs_base
=>
$dir
,
module
=>
undef
,
file
=>
$source
,
);
},
);
return
;
});
}
1;
# ABSTRACT: An XS implementation for Dist::Build
__END__
=pod
=encoding UTF-8
=head1 NAME
Dist::Build::XS - An XS implementation for Dist::Build
=head1 VERSION
version 0.019
=head1 SYNOPSIS
# planner/xs.pl
load_extension('Dist::Build::XS');
add_xs(
module => 'Foo::Bar',
extra_sources => [ glob 'src/*.c' ],
libraries => [ 'foo' ],
);
=head1 DESCRIPTION
This module implements support for XS for Dist::Build.
=head1 METHODS
=head2 add_xs
This method takes the following named arguments, all optional:
=over 4
=item * module
The name of the module to be compiled. This defaults to C<$main_module> unless C<file> is given, in which case the name is derived from the path.
=item * version
The version of the module, defaulting to the dist version.
=item * file
The name of the XS file. By default it's derived from the C<$module_name>, e.g. C<lib/Foo/Bar.xs> for C<Foo::Bar>.
=item * defines
This hash contains defines for the C files. E.g. C<< { DEBUG => 1 } >>.
=item * include_dirs
A list of directories to add to the include path. For the xs file the directory it is in is automatically added to this list.
=item * extra_sources
A list of C files to compile with this module. Instead of just a name, entries can also be a hash with the following entries:
=over 4
=item * source
The name of the input file. Mandatory.
=item * object
The name of the object that will be compiled. Will be derive from the source name by default.
=item * include_dirs
An array containing additional include directories for this objects
=item * defines
A hash containing additional defines for this object.
=item * flags
An array containing additional flags for this compilation.
=back
=item * extra_objects
A list of object files to link with the module.
=item * extra_compiler_flags
Additional flags to feed to the compiler. This can either be an array or a (shell-quoted) string.
=item * extra_sources
Extra C files to compile with this module.
=item * library_dirs
Extra libraries to find libraries in.
=item * libraries
Libraries to link to.
=item * extra_linker_flags
Additional flags to feed to the compiler. This can either be an array or a (shell-quoted) string.
=back
=head2 auto_xs
This method is like C<add_xs>, except that instead of taking C<module> or C<file> named arguments, it takes a C<dir> argument (defaulting to C<'lib'>). It will search that directory for all XS files, and build them with the other arguments passed to this function.
=head1 EXTENSIONS
Various extensions exist that modify the behavior of C<add_xs>. Among these are:
=over 4
=item * L<Dist::Build::XS::Import|Dist::Build::XS::Import>
This adds an C<import> argument to imports include directories and compilation flags exported by other modules using L<Dist::Build::XS::Export|Dist::Build::XS::Export>.
=item * L<Dist::Build::XS::WriteConstants|Dist::Build::XS::WriteConstants>
This adds a C<write_constants> argument, integrating L<ExtUtils::Constant|ExtUtils::Constant>.
=item * L<Dist::Build::XS::Alien|Dist::Build::XS::Alien>
This adds an C<alien> argument to link to libraries using L<Alien::Base|Alien::Base>.
=item * L<Dist::Build::XS::PkgConfig|Dist::Build::XS::PkgConfig>
This adds a C<pkg_config> argument to link to libraries using C<pkg-config> files.
=back
=head1 AUTHOR
Leon Timmermans <fawaka@gmail.com>
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2024 by Leon Timmermans.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut