1Alien::Build::Manual::AUlsieernACuotnhtorri(b3u)ted PerlAlDioecnu:m:eBnutialtdi:o:nManual::AlienAuthor(3)
2
3
4

NAME

6       Alien::Build::Manual::AlienAuthor - Alien author documentation
7

VERSION

9       version 1.93
10

SYNOPSIS

12        perldoc Alien::Build::Manual::AlienAuthor
13

DESCRIPTION

15       This document is intended to teach Alien authors how to build their own
16       Alien distribution using Alien::Build and Alien::Base.  Such an Alien
17       distribution consists of three essential parts:
18
19       An alienfile
20           This is a recipe for how to 1) detect an already installed version
21           of the library or tool you are alienizing 2) download and build the
22           library or tool that you are alienizing and 3) gather the
23           configuration settings necessary for the use of that library or
24           tool.
25
26       An installer "Makefile.PL" or "Build.PL" or a "dist.ini" if you are
27       using Dist::Zilla
28           This is a thin layer between your alienfile recipe, and the Perl
29           installer (either ExtUtils::MakeMaker or Module::Build.
30
31       A Perl class (.pm file) that inherits from Alien::Base
32           For most Aliens this does not need to be customized at all, since
33           Alien::Base usually does what you need.
34
35       For example if you were alienizing a library called libfoo, you might
36       have these files:
37
38        Alien-Libfoo-1.00/Makefile.PL
39        Alien-Libfoo-1.00/alienfile
40        Alien-Libfoo-1.00/lib/Alien/Libfoo.pm
41
42       This document will focus mainly on instructing you how to construct an
43       alienfile, but we will also briefly cover making a simple "Makefile.PL"
44       or "dist.ini" to go along with it.  We will also touch on when you
45       might want to extend your subclass to add non-standard functionality.
46
47   Using commands
48       Most software libraries and tools will come with instructions for how
49       to install them in the form of commands that you are intended to type
50       into a shell manually.  The easiest way to automate those instructions
51       is to just put the commands in your alienfile.  For example, lets
52       suppose that libfoo is built using autoconf and provides a "pkg-config"
53       ".pc" file.
54
55       We will also later discuss plugins.  For common build systems like
56       autoconf or CMake, it is usually better to use the appropriate plugin
57       because they will handle corner cases better than a simple set of
58       commands.  We're going to take a look at commands first because it's
59       easier to understand the different phases with commands.
60
61       (Aside, autoconf is a series of tools and macros used to configure
62       (usually) a C or C++ library or tool by generating any number of
63       Makefiles.  It is the C equivalent to ExtUtils::MakeMaker, if you will.
64       Basically, if your library or tool instructions start with
65       './configure' it is most likely an autoconf based library or tool).
66
67       (Aside2, "pkg-config" is a standard-ish way to provide the compiler and
68       linker flags needed for compiling and linking against the library.  If
69       your tool installs a ".pc" file, usually in "$PREFIX/lib/pkgconfig"
70       then, your tool uses "pkg-config").
71
72       Here is the alienfile that you might have:
73
74        use alienfile;
75
76        probe [ 'pkg-config --exists libfoo' ];
77
78        share {
79
80          start_url 'http://www.libfoo.org/src/libfoo-1.00.tar.gz';
81
82          download [ 'wget %{.meta.start_url}' ];
83
84          extract [ 'tar zxf %{.install.download}' ];
85
86          build [
87            [ './configure --prefix=%{.install.prefix} --disable-shared' ],
88            [ '%{make}' ],
89            [ '%{make} install' ],
90          ];
91
92        };
93
94        gather [
95          [ 'pkg-config --modversion libfoo', \'%{.runtime.version}' ],
96          [ 'pkg-config --cflags     libfoo', \'%{.runtime.cflags}'  ],
97          [ 'pkg-config --libs       libfoo', \'%{.runtime.libs}'    ],
98        ];
99
100       There is a lot going on here, so lets decode it a little bit.  An
101       alienfile is just some Perl with some alien specific sugar.  The first
102       line
103
104        use alienfile;
105
106       imports the sugar into the alienfile.  It also is a flag for the reader
107       to see that this is an alienfile and not some other kind of Perl
108       script.
109
110       The second line is the probe directive:
111
112        probe [ 'pkg-config --exists libfoo' ];
113
114       is used to see if the library is already installed on the target
115       system.  If "pkg-config" is in the path, and if libfoo is installed,
116       this should exit with a success (0) and tell Alien::Build to use the
117       system library.  If either "pkg-config" in the PATH, or if libfoo is
118       not installed, then it will exist with non-success (!= 0) and tells
119       Alien::Build to download and build from source.
120
121       You can provide as many probe directives as you want.  This is useful
122       if there are different ways to probe for the system.  Alien::Build will
123       stop on the first successfully found system library found.  Say our
124       library libfoo comes with a ".pc" file for use with "pkg-config" and
125       also provides a "foo-config" program to find the same values.  You
126       could then specify this in your alienfile
127
128        probe [ 'pkg-config --exists libfoo' ];
129        probe [ 'foo-config --version' ];
130
131       Other directives can be specified multiple times if there are different
132       methods that can be tried for the various steps.
133
134       Sometimes it is easier to probe for a library from Perl rather than
135       with a command.  For that you can use a code reference.  For example,
136       another way to call "pkg-config" would be from Perl:
137
138        probe sub {
139          my($build) = @_;  # $build is the Alien::Build instance.
140          system 'pkg-config --exists libfoo';
141          $? == 0 ? 'system' : 'share';
142        };
143
144       The Perl code should return 'system' if the library is installed, and
145       'share' if not.  (Other directives should return a true value on
146       success, and a false value).  You can also throw an exception with
147       "die" to indicate a failure.
148
149       The next part of the alienfile is the "share" block, which is used to
150       group the directives which are used to download and install the library
151       or tool in the event that it is not already installed.
152
153        share {
154          start_url 'http://www.libfoo.org/src/libfoo-1.00.tar.gz';
155          download [ 'wget %{.meta.start_url}' ];
156          extract [ 'tar zxf %{.install.download}' ];
157          build [
158            [ './configure --prefix=%{.install.prefix} --disable-shared' ],
159            [ '%{make}' ],
160            [ '%{make} install' ],
161          ];
162        };
163
164       The start_url specifies where to find the package that you are
165       alienizing.  It should be either a tarball (or zip file, or what have
166       you) or an HTML index.  The download directive as you might imagine
167       specifies how to download  the library or tool.  The extract directive
168       specifies how to extract the archive once it is downloaded.  In the
169       extract step, you can use the variable "%{.install.download}" as a
170       placeholder for the archive that was downloaded in the download step.
171       This is also accessible if you use a code reference from the
172       Alien::Build instance:
173
174        share {
175          ...
176          requires 'Archive::Extract';
177          extract sub {
178            my($build) = @_;
179            my $tarball = $build->install_prop->{download};
180            my $ae = Archive::Extract->new( archive => $tarball );
181            $ae->extract;
182            1;
183          }
184          ...
185        };
186
187       The build directive specifies how to build the library or tool once it
188       has been downloaded and extracted.  Note the special variable
189       "%{.install.prefix}" is the location where the library should be
190       installed.  "%{make}" is a helper which will be replaced by the
191       appropriate "make", which may be called something different on some
192       platforms (on Windows for example, it frequently may be called "nmake"
193       or "dmake").
194
195       The final part of the alienfile has a gather directive which specifies
196       how to get the details on how to compile and link against the library.
197       For this, once again we use the "pkg-config" command:
198
199        gather [
200          [ 'pkg-config --modversion libfoo', \'%{.runtime.version}' ],
201          [ 'pkg-config --cflags     libfoo', \'%{.runtime.cflags}'  ],
202          [ 'pkg-config --libs       libfoo', \'%{.runtime.libs}'    ],
203        ];
204
205       The scalar reference as the final item in the command list tells
206       Alien::Build that the output from the command should be stored in the
207       given variable.  The runtime variables are the ones that will be
208       available to "Alien::Libfoo" once it is installed.  (Install
209       properties, which are the ones that we have seen up till now are thrown
210       away once the Alien distribution is installed.
211
212       You can also provide a "sys" block for directives that should be used
213       when a system install is detected.  Normally you only need to do this
214       if the gather step is different between share and system installs.  For
215       example, the above is equivalent to:
216
217        build {
218          ...
219          gather [
220            [ 'pkg-config --modversion libfoo', \'%{.runtime.version}' ],
221            [ 'pkg-config --cflags     libfoo', \'%{.runtime.cflags}'  ],
222            [ 'pkg-config --libs       libfoo', \'%{.runtime.libs}'    ],
223          ];
224        };
225
226        sys {
227          gather [
228            [ 'pkg-config --modversion libfoo', \'%{.runtime.version}' ],
229            [ 'pkg-config --cflags     libfoo', \'%{.runtime.cflags}'  ],
230            [ 'pkg-config --libs       libfoo', \'%{.runtime.libs}'    ],
231          ];
232        };
233
234       (Aside3, the reason it is called "sys" and not "system" is so that it
235       does not conflict with the built in "system" function)!
236
237   Using plugins
238       The first example is a good way of showing the full manual path that
239       you can choose, but there is a lot of repetition, if you are doing many
240       Aliens that use autoconf and "pkg-config" (which are quite common.
241       alienfile allows you to use plugins.  See Alien::Build::Plugin for a
242       list of some of the plugin categories.
243
244       For now, I will just show you how to write the alienfile for libfoo
245       above using Alien::Build::Plugin::Build::Autoconf,
246       Alien::Build::Plugin::PkgConfig::Negotiate,
247       Alien::Build::Plugin::Download::Negotiate, and
248       Alien::Build::Plugin::Extract::Negotiate
249
250        use alienfile;
251
252        plugin 'PkgConfig' => (
253          pkg_name => 'libfoo',
254        );
255
256        share {
257          start_url 'http://www.libfoo.org/src';
258          plugin 'Download' => (
259            filter => qr/^libfoo-[0-9\.]+\.tar\.gz$/,
260            version => qr/^libfoo-([0-9\.]+)\.tar\.gz$/,
261          );
262          plugin 'Extract' => 'tar.gz';
263          plugin 'Build::Autoconf';
264          build [
265            '%{configure} --disable-shared',
266            '%{make}',
267            '%{make} install',
268          ];
269        };
270
271       The first plugin that we use is the "pkg-config" negotiation plugin.  A
272       negotiation plugin is one which doesn't do the actual work but selects
273       the best one from a set of plugins depending on your platform and
274       environment.  (In the case of
275       Alien::Build::Plugin::PkgConfig::Negotiate, it may choose to use
276       command line tools, a pure Perl implementation (PkgConfig), or
277       libpkgconf, depending on what is available).  When using negotiation
278       plugins you may omit the "::Negotiate" suffix.  So as you can see using
279       the plugin here is an advantage because it is more reliable that just
280       specifying a command which may not be installed!
281
282       Next we use the download negotiation plugin.  This is also better than
283       the version above, because again, "wget" my not be installed on the
284       target system.  Also you can specify a URL which will be scanned for
285       links, and use the most recent version.
286
287       We use the Extract negotiation plugin to use either command line tools,
288       or Perl libraries to extract from the archive once it is downloaded.
289
290       Finally we use the Autoconf plugin
291       (Alien::Build::Plugin::Build::Autoconf).  This is a lot more
292       sophisticated and reliable than in the previous example, for a number
293       of reasons.  This version will even work on Windows assuming the
294       library or tool you are alienizing supports that platform!
295
296       Strictly speaking the build directive is not necessary, because the
297       autoconf plugin provides a default which is reasonable.  The only
298       reason that you would want to include it is if you need to provide
299       additional flags to the configure step.
300
301        share {
302          ...
303          build [
304            '%{configure} --enable-bar --enable-baz --disable-shared',
305            '%{make}',
306            '%{make} install',
307          ];
308        };
309
310   Verifying and debugging your alienfile
311       You could feed your alienfile directly into Alien::Build, or
312       Alien::Build::MM, but it is sometimes useful to test your alienfile
313       using the "af" command (it does not come with Alien::Build, you need to
314       install App::af).  By default "af" will use the "alienfile" in the
315       current directory (just as "make" uses the "Makefile" in the current
316       directory; just like "make" you can use the "-f" option to specify a
317       different alienfile).
318
319       You can test your alienfile in dry run mode:
320
321        % af install --dry-run
322        Alien::Build::Plugin::Core::Legacy> adding legacy hash to config
323        Alien::Build::Plugin::Core::Gather> mkdir -p /tmp/I2YXRyxb0r/_alien
324        ---
325        cflags: ''
326        cflags_static: ''
327        install_type: system
328        legacy:
329          finished_installing: 1
330          install_type: system
331          name: libfoo
332          original_prefix: /tmp/7RtAusykNN
333          version: 1.2.3
334        libs: '-lfoo '
335        libs_static: '-lfoo '
336        prefix: /tmp/7RtAusykNN
337        version: 1.2.3
338
339       You can use the "--type" option to force a share install (download and
340       build from source):
341
342        % af install --type=share --dry-run
343        Alien::Build::Plugin::Core::Download> decoding html
344        Alien::Build::Plugin::Core::Download> candidate *https://www.libfoo.org/download/libfoo-1.2.4.tar.gz
345        Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.2.3.tar.gz
346        Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.2.2.tar.gz
347        Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.2.1.tar.gz
348        Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.2.0.tar.gz
349        Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.1.9.tar.gz
350        Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.1.8.tar.gz
351        Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.1.7.tar.gz
352        Alien::Build::Plugin::Core::Download> candidate  ...
353        Alien::Build::Plugin::Core::Download> setting version based on archive to 1.2.4
354        Alien::Build::Plugin::Core::Download> downloaded libfoo-1.2.4.tar.gz
355        Alien::Build::CommandSequence> + ./configure --prefix=/tmp/P22WEXj80r --with-pic --disable-shared
356        ... snip ...
357        Alien::Build::Plugin::Core::Gather> mkdir -p /tmp/WsoLAQ889w/_alien
358        ---
359        cflags: ''
360        cflags_static: ''
361        install_type: share
362        legacy:
363          finished_installing: 1
364          install_type: share
365          original_prefix: /tmp/P22WEXj80r
366          version: 1.2.4
367        libs: '-L/tmp/P22WEXj80r/lib -lfoo '
368        libs_static: '-L/tmp/P22WEXj80r/lib -lfoo '
369        prefix: /tmp/P22WEXj80r
370        version: 1.2.4
371
372       You can also use the "--before" and "--after" options to take a peek at
373       what the build environment looks like at different stages as well,
374       which can sometimes be useful:
375
376        % af install --dry-run --type=share --before build bash
377        Alien::Build::Plugin::Core::Download> decoding html
378        Alien::Build::Plugin::Core::Download> candidate *https://www.libfoo.org/download/libfoo-1.2.4.tar.gz
379        Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.2.3.tar.gz
380        Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.2.2.tar.gz
381        Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.2.1.tar.gz
382        Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.2.0.tar.gz
383        Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.1.9.tar.gz
384        Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.1.8.tar.gz
385        Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.1.7.tar.gz
386        Alien::Build::Plugin::Core::Download> candidate  ...
387        Alien::Build::Plugin::Core::Download> setting version based on archive to 1.2.4
388        Alien::Build::Plugin::Core::Download> downloaded libfoo-1.2.4.tar.gz
389        App::af::install>  [ before build ] + bash
390        /tmp/fbVPu4LRTs/build_5AVn/libfoo-1.2.4$ ls
391        CHANGES Makefile autoconf.ac lib
392        /tmp/fbVPu4LRTs/build_5AVn/libfoo-1.2.4$
393
394       There are a lot of other useful things that you can do with the "af"
395       command.  See af for details.
396
397   Integrating with MakeMaker
398       Once you have a working alienfile you can write your "Makefile.PL".
399
400        use ExtUtils::MakeMaker;
401        use Alien::Build::MM;
402
403        my $abmm = Alien::Build::MM->new;
404
405        WriteMakefile($abmm->mm_args(
406          ABSTRACT           => 'Discover or download and install libfoo',
407          DISTNAME           => 'Alien-Libfoo',
408          NAME               => 'Alien::Libfoo',
409          VERSION_FROM       => 'lib/Alien/Libfoo.pm',
410          CONFIGURE_REQUIRES => {
411            'Alien::Build::MM' => 0,
412          },
413          BUILD_REQUIRES => {
414            'Alien::Build::MM' => 0,
415          },
416          PREREQ_PM => {
417            'Alien::Base' => 0,
418          },
419          # If you are going to write the recommended
420          # tests you will will want these:
421          TEST_REQUIRES => {
422            'Test::Alien' => 0,
423            'Test2::V0'   => 0,
424          },
425        ));
426
427        sub MY::postamble {
428          $abmm->mm_postamble;
429        }
430
431       The "lib/Alien/Libfoo.pm" that goes along with it is very simple:
432
433        package Alien::Libfoo;
434
435        use strict;
436        use warnings;
437        use base qw( Alien::Base );
438
439        1;
440
441       You are done and can install it normally:
442
443        % perl Makefile.PL
444        % make
445        % make test
446        % make install
447
448   Integrating with Module::Build
449       Please don't!  Okay if you have to there is Alien::Build::MB.
450
451   Non standard configuration
452       Alien::Base support most of the things that your Alien will need, like
453       compiler flags (cflags), linker flags (libs) and binary directory
454       (bin_dir).  Your library or tool may have other configuration items
455       which are not supported by default.  You can store the values in the
456       alienfile into the runtime properties:
457
458        gather [
459          # standard:
460          [ 'foo-config --version libfoo', \'%{.runtime.version}' ],
461          [ 'foo-config --cflags  libfoo', \'%{.runtime.cflags}'  ],
462          [ 'foo-config --libs    libfoo', \'%{.runtime.libs}'    ],
463          # non-standard
464          [ 'foo-config --bar-baz libfoo', \'%{.runtime.bar_baz}' ],
465        ];
466
467       then you can expose them in your Alien::Base subclass:
468
469        package Alien::Libfoo;
470
471        use strict;
472        use warnings;
473        use base qw( Alien::Base );
474
475        sub bar_baz {
476          my($self) = @_;
477          $self->runtime_prop->{bar_baz},
478        };
479
480        1;
481
482   Testing
483       (optional, but highly recommended)
484
485       You should write a test using Test::Alien to make sure that your alien
486       will work with any XS modules that are going to use it:
487
488        use Test2::V0;
489        use Test::Alien;
490        use Alien::Libfoo;
491
492        alien_ok 'Alien::Libfoo';
493
494        xs_ok { local $/; <DATA> }, with_subtest {
495          is Foo::something(), 1, 'Foo::something() returns 1';
496        };
497
498        done_testing;
499
500        __DATA__
501        #include "EXTERN.h"
502        #include "perl.h"
503        #include "XSUB.h"
504        #include <foo.h>
505
506        MODULE = Foo PACKAGE = Foo
507
508        int something()
509
510       You can also use Test::Alien to test tools instead of libraries:
511
512        use Test2::V0;
513        use Test::Alien;
514        use Alien::Libfoo;
515
516        alien_ok 'Alien::Libfoo';
517        run_ok(['foo', '--version'])
518          ->exit_is(0);
519
520        done_testing;
521
522       You can also write tests specifically for FFI::Platypus, if your alien
523       is going to be used to write FFI bindings.  (the test below is the FFI
524       equivalent to the XS example above).
525
526        use Test2::V0;
527        use Test::Alien;
528        use Alien::Libfoo;
529
530        alien_ok 'Alien::Libfoo';
531        ffi_ok { symbols => [ 'something' ] }, with_subtest {
532          # $ffi is an instance of FFI::Platypus with the lib
533          # set appropriately.
534          my($ffi) = @_;
535          my $something = $ffi->function( something => [] => 'int' );
536          is $something->call(), 1, 'Foo::something() returns 1';
537        };
538
539       If you do use "ffi_ok" you want to make sure that your alien reliably
540       produces dynamic libraries.  If it isn't consistent (if for example
541       some platforms tend not to provide or build dynamic libraries), you can
542       check that "dynamic_libs" doesn't return an empty list.
543
544        ...
545        alien_ok 'Alien::Libfoo';
546        SKIP: {
547          skip "This test requires a dynamic library"
548            unless Alien::Libfoo->dynamic_libs;
549          ffi_ok { symbols [ 'something' ] }, with_subtest {
550            ...
551          };
552        }
553
554       More details on testing Alien modules can be found in the Test::Alien
555       documentation.
556
557       You can also run the tests that come with the package that you are
558       alienizing, by using a "test" block in your alienfile.  Keep in mind
559       that some packages use testing tools or have other prerequisites that
560       will not be available on your users machines when they attempt to
561       install your alien.  So you do not want to blindly add a test block
562       without checking what the prereqs are.  For Autoconf style packages you
563       typically test a package using the "make check" command:
564
565        use alienfile;
566
567        plugin 'PkgConfig' => 'libfoo';
568
569        share {
570          ... # standard build steps.
571          test [ '%{make} check' ];
572        };
573
574   Dist::Zilla
575       (optional, mildly recommended)
576
577       You can also use the Alien::Build Dist::Zilla plugin
578       Dist::Zilla::Plugin::AlienBuild:
579
580        name    = Alien-Libfoo
581        author  = E. Xavier Ample <example@cpan.org>
582        license = Perl_5
583        copyright_holder = E. Xavier Ample <example@cpan.org>
584        copyright_year   = 2017
585        version = 0.01
586
587        [@Basic]
588        [AlienBuild]
589
590       The plugin takes care of a lot of details like making sure that the
591       correct minimum versions of Alien::Build and Alien::Base are used.  See
592       the plugin documentation for additional details.
593
594   Using your Alien
595       Once you have installed you can use your Alien.  See
596       Alien::Build::Manual::AlienUser for guidance on that.
597

AUTHOR

599       Author: Graham Ollis <plicease@cpan.org>
600
601       Contributors:
602
603       Diab Jerius (DJERIUS)
604
605       Roy Storey (KIWIROY)
606
607       Ilya Pavlov
608
609       David Mertens (run4flat)
610
611       Mark Nunberg (mordy, mnunberg)
612
613       Christian Walde (Mithaldu)
614
615       Brian Wightman (MidLifeXis)
616
617       Zaki Mughal (zmughal)
618
619       mohawk (mohawk2, ETJ)
620
621       Vikas N Kumar (vikasnkumar)
622
623       Flavio Poletti (polettix)
624
625       Salvador Fandiño (salva)
626
627       Gianni Ceccarelli (dakkar)
628
629       Pavel Shaydo (zwon, trinitum)
630
631       Kang-min Liu (劉康民, gugod)
632
633       Nicholas Shipp (nshp)
634
635       Juan Julián Merelo Guervós (JJ)
636
637       Joel Berger (JBERGER)
638
639       Petr Pisar (ppisar)
640
641       Lance Wicks (LANCEW)
642
643       Ahmad Fatoum (a3f, ATHREEF)
644
645       José Joaquín Atria (JJATRIA)
646
647       Duke Leto (LETO)
648
649       Shoichi Kaji (SKAJI)
650
651       Shawn Laffan (SLAFFAN)
652
653       Paul Evans (leonerd, PEVANS)
654
656       This software is copyright (c) 2011-2019 by Graham Ollis.
657
658       This is free software; you can redistribute it and/or modify it under
659       the same terms as the Perl 5 programming language system itself.
660
661
662
663perl v5.30.1                      2019-12-1A0lien::Build::Manual::AlienAuthor(3)
Impressum