File: Makefile.PL

package info (click to toggle)
libjavascript-quickjs-perl 0.21-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 4,180 kB
  • sloc: ansic: 72,822; javascript: 7,743; perl: 1,065; makefile: 353; sh: 108
file content (332 lines) | stat: -rw-r--r-- 8,964 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
#!/usr/bin/env perl

use strict;
use warnings;

use ExtUtils::MakeMaker::CPANfile;

use Config;

use File::Temp;
use File::Slurper;
use File::Spec;
use File::Which;
use Cwd;

my $GMAKE_PATH = _find_gmake();

if (!$GMAKE_PATH) {
    die "GNU Make ($Config{'gmake'}) is required.\n";
}
elsif (!-x $GMAKE_PATH) {
    if ($!) {
        die "Failed to detect if GNU Make ($GMAKE_PATH) is executable: $!\n";
    }

    die "GNU Make ($GMAKE_PATH) is not executable.\n";
}

my $ATOMIC_ENV_KEY = 'JS_QUICKJS_LINK_LIBATOMIC';

my $PERL_QJS_MAKEFILE_PATH = File::Spec->catfile( Cwd::getcwd(), 'Makefile.quickjs');

my $libpath = File::Spec->catfile('quickjs', 'libquickjs.a');

# quickjs needs these; pre-5.20 perls didn’t include libpthread.
# Note that MSWin32, if given these, will try to compile them statically
# rather than dynamically, which breaks compilation.
#
my @libs = ($^O eq 'MSWin32') ? () : qw(-lm -ldl -lpthread);

if (_need_librt()) {
    push @libs, '-lrt';
}

_tweak_for_os();

if (!_stdatomic_h_exists()) {
    _avoid_stdatomic_h();
}

# QuickJS’s Makefile uses the mkdir CLI tool to create this directory.
# The problem is that it expects POSIX’s mkdir, which doesn’t match
# Windows’s. To avoid that problem we pre-create the directory now:
#
mkdir( File::Spec->catdir( qw(quickjs .obj) ) );

make_libquickjs_makefile();

# RaspiOS needs this; others may, too:
if (_should_link_libatomic()) {
    push @libs, '-latomic';
}

WriteMakefile(
    NAME              => 'JavaScript::QuickJS',
    VERSION_FROM      => 'lib/JavaScript/QuickJS.pm', # finds $VERSION
    ($] >= 5.005 ?     ## Add these new keywords supported since 5.005
      (ABSTRACT_FROM  => 'lib/JavaScript/QuickJS.pm', # retrieve abstract from module
       AUTHOR         => [
            'Felipe Gasper (FELIPE)',
        ],
      ) : ()
    ),
    INC               => '-Wall --std=c99 -I.',
    LICENSE           => "perl_5",

    PMLIBDIRS => ['lib'],

    LIBS => "@libs",

    OBJECT => join(
        q< >,
        '$(BASEEXT)$(OBJ_EXT)',
        $libpath,
    ),

    META_MERGE => {
        'meta-spec' => { version => 2 },
        resources => {
            repository => {
                type => 'git',
                url => 'git://github.com/FGasper/p5-JavaScript-QuickJS.git',
                web => 'https://github.com/FGasper/p5-JavaScript-QuickJS',
            },
            bugtracker => {
                web => 'https://github.com/FGasper/p5-JavaScript-QuickJS/issues',
            },
        },
    },
);

#----------------------------------------------------------------------

# CPAN offers Alien::gmake, but there’s a significant dependency tree
# involved there.
sub _find_gmake {
    my $gmake;

    if (my $make = File::Which::which($Config{'make'})) {
        my $out = `$make --version`;
        if ($out =~ m<gnu>i) {
            $gmake = $make;
        }
    }

    $gmake ||= File::Which::which($Config{'gmake'});

    return $gmake;
}

sub _tweak_for_os {
    my %bsd_fix = (
        Makefile => sub {
            return "CONFIG_DARWIN=y$/" . shift;
        },
    );

    my %edits = (
        freebsd => \%bsd_fix,
        openbsd => \%bsd_fix,
    );

    if (my $edits_h = $edits{$^O}) {
        my $touchfile_path = File::Spec->catfile('quickjs', 'js-qjs-tweaked');

        if (-e $touchfile_path) {
            print "QuickJS is already tweaked for $^O compatibility.$/";
        }
        else {
            print "Tweaking QuickJS for $^O compatibility …$/";

            for my $fname (keys %$edits_h) {
                my $path = "quickjs/$fname";

                my $content = File::Slurper::read_binary($path);

                my $out = $edits_h->{$fname}->($content);
                File::Slurper::write_binary($path, $out);
            }

            print "Done.$/";

            open my $fh, '>', $touchfile_path;
        }
    }
    else {
        print "No tweaks for this OS ($^O) are available. Hopefully none are needed!$/";
    }
}

# In CloudLinux 6, glibc is old enough to need -lrt. Test for that.
#
my $_cached_need_librt;
sub _need_librt {
    return $_cached_need_librt if defined $_cached_need_librt;

    print "Checking whether this system needs to link to librt …\n";

    my $ok = _does_this_compile(
        '#include <stdlib.h>',
        '#ifdef __GLIBC__',
        '#  if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 17)',
        '#      error "This system needs librt"',
        '#  endif',
        '#endif',
        'int main() { return 0; }',
    );

    print "\t… " . ($ok ? 'Guess not.' : 'Looks like it.') . "\n";

    return $_cached_need_librt = !$ok;
}

sub _does_this_compile {
    my (@lines_of_c) = @_;

    my $dir = File::Temp::tempdir( CLEANUP => 1 );

    my $path = File::Spec->catfile( $dir, 'test.c' );

    {
        open my $fh, '>', $path or die "open($dir/test.c): $!";
        syswrite $fh, join("\n", @lines_of_c, q<>);
    }

    return 0 == system $Config{'cc'}, $path;
}

sub _should_link_libatomic {
    -e $PERL_QJS_MAKEFILE_PATH or die "Need quickjs makefile!";

    my $env_value = $ENV{$ATOMIC_ENV_KEY};

    if (defined $env_value) {
        if ($env_value) {
            if ($env_value ne '1') {
                die "Set $ATOMIC_ENV_KEY to 1 or a falsy value.\n";
            }

            print "You’ve forcibly enabled linking against libatomic.\n";
            return 1;
        }
        else {
            print "You’ve forcibly disabled linking against libatomic.\n";
            return 0;
        }
    }

    print "Does QuickJS need -latomic? (compiling core object file) …\n";

    my $rel_objpath = File::Spec->catfile( qw( .obj quickjs.nolto.o ) );
    my $objpath = File::Spec->catfile( 'quickjs', $rel_objpath );

    my $needs_libatomic;

    eval {
        system $GMAKE_PATH, '-C', 'quickjs', '-f', $PERL_QJS_MAKEFILE_PATH, $rel_objpath;
        die if $?;
        my $objbin = File::Slurper::read_binary($objpath);

        $needs_libatomic = -1 != index($objbin, '__atomic_fetch_sub_');
    };

    if ($@) {
        print "\tFailed to detect (assuming no): $@";
    }
    else {
        print "\t… " . ($needs_libatomic ? 'Looks like it.' : 'Guess not.') . "\n";
    }

    return $needs_libatomic;
}

sub _stdatomic_h_exists {
    my $dir = File::Temp::tempdir( CLEANUP => 1 );
    open my $fh, '>', "$dir/test.c";
    syswrite $fh, join(
        "\n",
        '#include <stdatomic.h>',
        'int main() { return 0; }',
    );

    print "Checking whether stdatomic.h exists …\n";

    my $ok = !system $Config{'cc'}, "$dir/test.c";

    print "\t… " . ($ok ? 'Looks like it.' : 'Guess not.') . "\n";

    return $ok;
}

sub _avoid_stdatomic_h {
    print "Tweaking QuickJS to avoid use of stdatomic.h …\n";

    my $qjs_c_path = File::Spec->catfile( qw( quickjs quickjs.c ) );

    my $quickjs_c = File::Slurper::read_binary($qjs_c_path);

    $quickjs_c =~ s<^#define\s+CONFIG_ATOMICS></* no atomics - J::QJS */>m or do {
        warn "Did no replace for quickjs.c?\n";
    };
    File::Slurper::write_binary($qjs_c_path, $quickjs_c);

    my $qjs_libc_path = File::Spec->catfile( qw( quickjs quickjs-libc.c ) );
    my $quickjs_libc_c = File::Slurper::read_binary($qjs_libc_path);

    $quickjs_libc_c =~ s<^#define\s+USE_WORKER></* no atomics - J::QJS */>m or do {
        warn "Did no replace for quickjs-libc.c?\n";
    };
    File::Slurper::write_binary($qjs_libc_path, $quickjs_libc_c);
}

sub make_libquickjs_makefile {
    my $mfpath = File::Spec->catfile('quickjs', 'Makefile');

    open my $rfh, '<', $mfpath or die "open Makefile: $!";
    my $make = do { local $/; <$rfh> };

    # QuickJS builds by default without position-independent code, which
    # means the resulting static library is only suitable for executables.
    # We need position-independent code so we can compile QuickJS into a
    # shared library.
    #
    substr($make, 0, 0, "CFLAGS+=-fPIC $ENV{CPPFLAGS}\n");

    # In systems old enough to need -lrt (e.g., CloudLinux 6),
    # assume we need these other omissions as well:
    #
    if (_need_librt()) {
        $make =~ s<^(.*no-format-truncation)><#$1 -- J::QJS>m or do {
            warn "No no-format-truncation to hide?\n";
        };

        $make =~ s<^(CONFIG_LTO)><#$1 -- J::QJS>m or do {
            warn "No CONFIG_LTO to hide?\n";
        };
    }

    open my $fh, '>', $PERL_QJS_MAKEFILE_PATH or die "open($PERL_QJS_MAKEFILE_PATH): $!";
    syswrite $fh, $make or die "write custom quickjs make: $!";
    print "Created `$PERL_QJS_MAKEFILE_PATH`$/";
}

# ----------------------------------------------------------------------
package MY;

use Config;

sub postamble {

    # QuickJS requires GNU make.
    my $make = ($^O =~ m<bsd>i) ? $GMAKE_PATH : '$(MAKE)';

    # The leading “+” is to ensure that parallel builds work properly.
    return <<"MAKE_FRAG"

$libpath:
\t+$make -C quickjs -f '$PERL_QJS_MAKEFILE_PATH' libquickjs.a
MAKE_FRAG
}

1;