Affix

 view release on metacpan or  search on metacpan

lib/Affix/Wrap.pm  view on Meta::CPAN

                my $sig = $unique_types{$name}->affix_type;
                push @batch_lines, "    typedef $name => $sig;" if $sig && $sig ne "$name()";
            }
            my $batch_str = @batch_lines ? join( "\n", @batch_lines ) . "\n" : "";

            # Perl Module Construction
            # Safely quote $lib: escape \ and ] within q[...] delimiters
            my $_lib = '';
            if ( defined $lib ) {
                my $safe_lib = $lib;
                $safe_lib =~ s/\\/\\\\/g;
                $safe_lib =~ s/\]/\\]/g;
                $_lib = "my \$lib = q[$safe_lib];";
            }
            my $out = <<~"PERL";
            package $pkg {
                use v5.40;
                use Affix qw[:all];
                #
                $_lib
            PERL
            for my $name (@fwd) {
                $out .= "    typedef '$name';\n";
            }
            $out .= $batch_str;
            $out .= "\n    #\n";
            for my $node (@nodes) {
                $out .= "    " . $node->perl_constants . "\n" if $node isa Affix::Wrap::Enum;
            }
            $out .= "\n    #\n";
            for my $node (@nodes) {
                my $code = $node->affix_type;
                if ( $code && ( $node isa Affix::Wrap::Function || $node isa Affix::Wrap::Variable || $node isa Affix::Wrap::Macro ) ) {
                    $out .= "    $code;\n";
                }
            }
            $out .= "};\n1;\n";
        }

        method generate( $lib, $pkg, $file ) {
            my ( $code, $nodes ) = $self->_generate_code( $lib, $pkg );
            Path::Tiny::path($file)->spew_utf8($code);
        }

        method wrap ( $lib, $pkg //= [caller]->[0] ) {
            my ( $code, $nodes ) = $self->_generate_code( $lib, $pkg );
            eval $code;
            if ($@) {
                Carp::croak("Affix::Wrap wrap() compilation failed: $@\n\nCode:\n$code");
            }
            return grep { $_ isa Affix::Wrap::Function || $_ isa Affix::Wrap::Variable || $_ isa Affix::Wrap::Macro } @$nodes;
        }

        method list_symbols ($lib_path) {
            my $abs = path($lib_path)->absolute->stringify;
            return [] unless -e $abs;
            my @symbols;
            my ( $out, $err, $exit );

            # llvm-nm
            # We use --extern-only to find the public API
            ( $out, $err, $exit ) = capture { system( 'llvm-nm', '--extern-only', '--defined-only', $abs ) };
            if ( $exit == 0 && $out ) {
                for ( split /\n/, $out ) {
                    if (/ [TRG] (?:_)?(\w+)$/) { push @symbols, $1; }
                }
            }

            # objdump for Strawberry Perl
            if ( !@symbols ) {
                ( $out, $err, $exit ) = capture { system( 'objdump', '-p', $abs ) };
                if ( $exit == 0 && $out ) {

                    # objdump -p displays the "Export Address Table"
                    # We look for the lines following the table header
                    my $in_exports = 0;
                    for ( split /\n/, $out ) {
                        if (/^\[Ordinal\/Name Pointer\] Table$/) { $in_exports = 1; next; }
                        if ($in_exports) {
                            last if /^\s*$/;    # End of table

                            # Format:[   0] lsquic_engine_new
                            if (/\[\s*\d+\]\s+(\w+)/) { push @symbols, $1; }
                        }
                    }
                }
            }

            # dumpbin for MSVC
            if ( !@symbols ) {
                ( $out, $err, $exit ) = capture { system( 'dumpbin', '/EXPORTS', $abs ) };
                if ( $exit == 0 && $out ) {
                    my $in_exports = 0;
                    for ( split /\n/, $out ) {
                        if (/ordinal\s+hint\s+RVA\s+name/) { $in_exports = 1; next; }
                        if ($in_exports) {

                            # Format: 1    0 00001234 lsquic_engine_new
                            if (/^\s+\d+\s+[A-F0-9]+\s+[A-F0-9]+\s+(\w+)/) { push @symbols, $1; }
                        }
                    }
                }
            }
            @symbols = sort @symbols;
            if ( !@symbols ) {
                warn "[!] list_symbols: No symbols found in $abs using llvm-nm, objdump, or dumpbin.\n";
            }
            return \@symbols;
        }
    }
}
1;
__END__
Copyright (C) Sanko Robinson.

This library is free software; you can redistribute it and/or modify it under
the terms found in the Artistic License 2. Other copyrights, terms, and
conditions may apply to data transmitted through this module.



( run in 1.340 second using v1.01-cache-2.11-cpan-5c0b1e786e0 )