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