The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

Usage

  interface $class_name;

Details

Interface Methods

EOS } elsif ($resource) { $description = "The $class_name resource in SPVM is a resouce to do someting.";

    my $native = $self->native;
    my $new_method;
    if ($native eq 'c') {
      $new_method = 'new_gnu99';
    }
    elsif ($native eq 'c++') {
      $new_method = 'new_cpp';
    }
    
    my $native_module_ext;
    if (defined $native) {
      if ($native eq 'c') {
        $native_module_ext = 'c';
      }
      elsif ($native eq 'c++') {
        $native_module_ext = 'cpp';
      }
    }
    
    # extern C for C++
    my $extern_c_start;
    my $extern_c_end;
    if ($native eq 'c++') {
      $extern_c_start = qq(extern "C" {);
      $extern_c_end = "}";
    }
    else {
      $extern_c_start = '';
      $extern_c_end = '';
    }
    
    $main_doc  = <<"EOS";
=head1 Usage

MyClass.config:

  my \$config = SPVM::Builder::Config->$new_method(file => __FILE__);
  
  \$config->use_resource('$class_name');
  
  \$config;

MyClass.$native_module_ext:

  #include "spvm_native.h"
  #include "foo.h"
  
  $extern_c_start
  
  int32_t SPVM__MyClass__test(SPVM_ENV* env, SPVM_VALUE* stack) {
    
    // Use functions in foo.h
    
    return 0;
  }
  
  $extern_c_end
  

Details

Original Product

Original Product Version

Language

Language Specification

Required Libraries

Required Linker Flags

Required Resources

Header Files

Source Files

Compiler Flags

How to Create Resource

Donwload

Extracting Source Files

Extracting Header Files

EOS } else { $description = "The $class_name class in SPVM has methods to do someting."; $main_doc = <<"EOS"; =head1 Usage

  use $class_name;

Details

Inheritance

Interfaces

Enumerations

Fields

Class Methods

Instance Methods

EOS }

  my $version_decl = 'our $VERSION = "0.001";';
  
  my $only_lib_files = $self->only_lib_files;
  if ($only_lib_files) {
    $version_decl = '';
  }
  
  # Content
  my $perl_class_content = "";
  $perl_class_content = <<"EOS";
package SPVM::$class_name;

$version_decl

1;

Name

SPVM::$class_name - Short Description

Description

$description

$main_doc =head1 Repository

Author

$user_name $user_email

Copyright & License

Copyright (c) $year $user_name

MIT License

EOS

  # Generate file
  my $perl_class_rel_file = SPVM::Builder::Util::convert_class_name_to_rel_file($class_name, 'pm');
  $perl_class_rel_file =  $self->create_lib_rel_file($perl_class_rel_file);
  $self->generate_file($perl_class_rel_file, $perl_class_content);
}

sub generate_native_config_file { my ($self) = @_;

  my $class_name = $self->class_name;
  
  # C or C++
  my $native = $self->native;
  my $new_method;
  if ($native eq 'c') {
    $new_method = 'new_gnu99';
  }
  elsif ($native eq 'c++') {
    $new_method = 'new_cpp';
  }
  
  # User name
  my $user_name = $self->user_name;
  unless (defined $user_name) {
    $user_name = '[--user-name]'
  }
  
  # Year
  my $year = $self->_year;
  
  # Content
  my $native_config_content = <<"EOS";
# Copyright (c) $year $user_name
# MIT License

use strict; use warnings; use SPVM::Builder::Config;

my \$config = SPVM::Builder::Config->$new_method(file => __FILE__);

\$config; EOS

  # Generate file
  my $native_config_rel_file = SPVM::Builder::Util::convert_class_name_to_rel_file($class_name, 'config');
  $native_config_rel_file =  $self->create_lib_rel_file($native_config_rel_file);
  $self->generate_file($native_config_rel_file, $native_config_content);
}

sub generate_native_class_file { my ($self) = @_;

  my $class_name = $self->class_name;
  
  # extern C for C++
  my $native = $self->native;
  my $extern_c_start;
  my $extern_c_end;
  if ($native eq 'c++') {
    $extern_c_start = qq(extern "C" {);
    $extern_c_end = "}";
  }
  else {
    $extern_c_start = '';
    $extern_c_end = '';
  }

  # Generate file
  my $native_module_ext;
  if (defined $native) {
    if ($native eq 'c') {
      $native_module_ext = 'c';
    }
    elsif ($native eq 'c++') {
      $native_module_ext = 'cpp';
    }
  }
  
  # Content
  my $native_class_name = $class_name;
  $native_class_name =~ s/::/__/g;
  my $native_class_file = $class_name;
  $native_class_file =~ s/::/\//g;
  $native_class_file .= ".$native_module_ext";

  # User name
  my $user_name = $self->user_name;
  unless (defined $user_name) {
    $user_name = '[--user-name]'
  }
  
  # Year
  my $year = $self->_year;
  
  my $native_class_content = <<"EOS";
// Copyright (c) $year $user_name
// MIT License

#include "spvm_native.h"

$extern_c_start

static const char* FILE_NAME = "$native_class_file";

int32_t SPVM__${native_class_name}__foo(SPVM_ENV* env, SPVM_VALUE* stack) {

  return 0;
}

$extern_c_end EOS

  my $native_class_rel_file = SPVM::Builder::Util::convert_class_name_to_rel_file($class_name, $native_module_ext);
  $native_class_rel_file =  $self->create_lib_rel_file($native_class_rel_file);
  $self->generate_file($native_class_rel_file, $native_class_content);
}

sub generate_gitkeep_file_for_native_module_include_dir { my ($self) = @_;

  my $class_name = $self->class_name;
  
  # Generate file
  my $gitkeep_rel_file_for_native_module_include_dir = SPVM::Builder::Util::convert_class_name_to_rel_file($class_name, 'native');
  $gitkeep_rel_file_for_native_module_include_dir .= '/include/.gitkeep';
  $gitkeep_rel_file_for_native_module_include_dir =  $self->create_lib_rel_file($gitkeep_rel_file_for_native_module_include_dir);
  $self->generate_file($gitkeep_rel_file_for_native_module_include_dir, '');
}

sub generate_gitkeep_file_for_native_module_src_dir { my ($self) = @_;

  my $class_name = $self->class_name;
  
  # Generate file
  my $gitkeep_rel_file_for_native_module_include_dir = SPVM::Builder::Util::convert_class_name_to_rel_file($class_name, 'native');
  $gitkeep_rel_file_for_native_module_include_dir .= '/src/.gitkeep';
  $gitkeep_rel_file_for_native_module_include_dir =  $self->create_lib_rel_file($gitkeep_rel_file_for_native_module_include_dir);
  $self->generate_file($gitkeep_rel_file_for_native_module_include_dir, '');
}

sub generate_gitignore_file { my ($self) = @_;

  my $gitignore_content = <<'EOS';
/blib/*
/Makefile
/Makefile.old
/MYMETA.yml
/MYMETA.json
/pm_to_blib
/SPVM-*
.spvm_build
core.*
core
*.bak
*.BAK
*.tmp
*.o
*.bs
EOS
  
  # Generate file
  my $gitignore_rel_file = '.gitignore';
  $self->generate_file($gitignore_rel_file, $gitignore_content);
}

sub generate_gitattributes_file { my ($self) = @_;

  my $gitattributes_content = <<'EOS';
*.spvm text eol=lf
EOS
  
  # Generate file
  my $gitattributes_rel_file = '.gitattributes';
  $self->generate_file($gitattributes_rel_file, $gitattributes_content);
}

sub generate_manifest_skip_file { my ($self) = @_;

  # Content
  my $manifest_skip_content = <<'EOS';
(^|\/)blib/
(^|\/)Makefile$
(^|\/)Makefile.old$
(^|\/)MYMETA.yml$
(^|\/)MYMETA.json$
(^|\/)pm_to_blib$
(^|\/).spvm_build/
(^|\/)t/.spvm_build/
(^|\/)SPVM-
(^|\/)core\.
(^|\/)core$
(^|\/)\.git/
\.bak$
\.tmp$
\.tmp/
\.BAK$
\.o$
\.bs$
EOS

  # Generate file
  my $manifest_skip_rel_file = 'MANIFEST.SKIP';
  $self->generate_file($manifest_skip_rel_file, $manifest_skip_content);
}

sub generate_changes_file { my ($self) = @_;

  # Year
  my $today_tp = Time::Piece::localtime;
  my $today = $today_tp->strftime('%Y-%m-%d');
  
  # Content
  my $changes_content = <<"EOS";
0.001 $today
  [Changes]
    * First release.
  

EOS

  # Generate file
  my $changes_rel_file = 'Changes';
  $self->generate_file($changes_rel_file, $changes_content);
}

sub generate_readme_markdown_file { my ($self) = @_;

  my $class_name = $self->class_name;
  
  # Content
  my $readme_markdown_content = <<"EOS";
# SPVM::$class_name

<a href="https://metacpan.org/pod/SPVM::$class_name">SPVM::$class_name</a>

EOS

  # Generate file
  my $readme_markdown_rel_file = 'README.md';
  $self->generate_file($readme_markdown_rel_file, $readme_markdown_content);
}

sub generate_makefile_pl_file { my ($self) = @_;

  my $class_name = $self->class_name;
  
  # Resource
  my $resource = $self->resource;
  
  # Native make rule
  my $make_rule_native = $self->native && !$resource ? "\$make_rule .= SPVM::Builder::Util::API::create_make_rule_native('$class_name');" : '';
  
  # Precompile make rule
  my $make_rule_precompile = $self->precompile && !$resource ? "\$make_rule .= SPVM::Builder::Util::API::create_make_rule_precompile('$class_name');" : '';

  my $perl_class_rel_file = SPVM::Builder::Util::convert_class_name_to_rel_file($class_name, 'pm');
  $perl_class_rel_file =  $self->create_lib_rel_file($perl_class_rel_file);

  my $spvm_class_rel_file = SPVM::Builder::Util::convert_class_name_to_rel_file($class_name, 'spvm');
  $spvm_class_rel_file =  $self->create_lib_rel_file($spvm_class_rel_file);
  
  # User name
  my $user_name = $self->user_name;
  unless (defined $user_name) {
    $user_name = '[--user-name]'
  }
  
  # User email
  my $user_email = $self->user_email;
  unless (defined $user_email) {
    $user_email = '[--user-email]'
  }
  
  # "Makefile.PL" content
  my $makefile_pl_content = <<"EOS";
use 5.008_007;
use ExtUtils::MakeMaker;
use strict;
use warnings;
use Config;
use Getopt::Long 'GetOptions';

GetOptions( 'meta' => \\my \$meta, 'no-build-spvm-modules' => \\my \$no_build_spvm_modules, );

if (\$meta) { \$no_build_spvm_modules = 1; }

unless (\$meta) { # Do something such as environment check. }

my \%configure_and_runtime_requires = ('SPVM' => '$SPVM::VERSION'); WriteMakefile( NAME => 'SPVM::$class_name', VERSION_FROM => '$perl_class_rel_file', LICENSE => 'mit', (\$] >= 5.005 ? (ABSTRACT_FROM => '$perl_class_rel_file', AUTHOR => '$user_name<$user_email>') : ()), test => {TESTS => 't/*.t t/*/*.t t/*/*/*.t'}, clean => {FILES => ['.spvm_build', 't/.spvm_build']}, META_MERGE => { 'meta-spec' => { version => 2 }, resources => { repository => { type => 'git', url => '', web => '', }, }, no_index => { directory => [], } }, NORECURS => 1, CONFIGURE_REQUIRES => { \%configure_and_runtime_requires, }, PREREQ_PM => { \%configure_and_runtime_requires, }, TEST_REQUIRES => {

  },
);

sub MY::postamble {

  my \$make_rule = '';
  
  unless (\$no_build_spvm_modules) {
    require SPVM::Builder::Util::API;
    
    local \@INC = ('lib', \@INC);
    
    $make_rule_native
    $make_rule_precompile
  }
  
  return \$make_rule;
}

1; EOS

  # Generate file
  my $makefile_pl_rel_file = 'Makefile.PL';
  $self->generate_file($makefile_pl_rel_file, $makefile_pl_content);
}

sub generate_basic_test_file { my ($self) = @_;

  my $class_name = $self->class_name;
  
  my $spvm_class_rel_file = SPVM::Builder::Util::convert_class_name_to_rel_file($class_name, 'spvm');
  $spvm_class_rel_file =  $self->create_lib_rel_file($spvm_class_rel_file);
  
  # Content
  my $basic_test_content = <<"EOS";
use Test::More;

use strict; use warnings; use FindBin; use lib "\$FindBin::Bin/lib"; BEGIN { \$ENV{SPVM_BUILD_DIR} = "\$FindBin::Bin/.spvm_build"; }

use SPVM 'TestCase::$class_name';

use SPVM '$class_name'; use SPVM::$class_name; use SPVM 'Fn';

my \$api = SPVM::api();

my \$start_memory_blocks_count = \$api->get_memory_blocks_count;

ok(SPVM::TestCase::$class_name->test);

# Version check { my \$version_string = SPVM::Fn->get_version_string("$class_name"); is(\$SPVM::${class_name}::VERSION, \$version_string); }

my \$end_memory_blocks_count = \$api->get_memory_blocks_count; is(\$end_memory_blocks_count, \$start_memory_blocks_count);

done_testing; EOS

  # Generate file
  my $basic_test_rel_file = 't/basic.t';
  $self->generate_file($basic_test_rel_file, $basic_test_content);
}

sub generate_license_file { my ($self) = @_;

  my $class_name = $self->class_name;
  
  # User name
  my $user_name = $self->user_name;
  unless (defined $user_name) {
    $user_name = '[--user-name]'
  }
  
  # Year
  my $year = $self->_year;
  
  # Content
  my $license_content = <<"EOS";
MIT License

Copyright (c) $year $user_name

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. EOS

  # Generate file
  my $license_rel_file = 'LICENSE';
  $self->generate_file($license_rel_file, $license_content);
}

sub generate_basic_test_spvm_class_file { my ($self) = @_;

  my $class_name = $self->class_name;
  
  # Resource
  my $resource = $self->resource;
  
  # Content
  my $basic_test_spvm_class_content;
  
  if ($resource) {
    $basic_test_spvm_class_content = <<"EOS";
class TestCase::$class_name {
  native static method test : int ();
}
EOS
  }
  else {
    $basic_test_spvm_class_content = <<"EOS";
class TestCase::$class_name {
  use $class_name;
  static method test : int () {
    
    return 1;
  }
}
EOS
  }
  
  # Generate file
  my $basic_test_spvm_class_rel_file = SPVM::Builder::Util::convert_class_name_to_rel_file("TestCase::$class_name", 'spvm');
  $basic_test_spvm_class_rel_file = "t/lib/$basic_test_spvm_class_rel_file";
  $self->generate_file($basic_test_spvm_class_rel_file, $basic_test_spvm_class_content);
}

sub generate_basic_test_native_config_file { my ($self) = @_;

  my $class_name = $self->class_name;
  
  # Resource
  my $resource = $self->resource;

  # C or C++
  my $native = $self->native;
  my $new_method;
  if ($native eq 'c') {
    $new_method = 'new_gnu99';
  }
  elsif ($native eq 'c++') {
    $new_method = 'new_cpp';
  }
  
  # Content
  my $basic_test_native_config_content = <<"EOS";
use strict;
use warnings;

my \$config = SPVM::Builder::Config->$new_method(file => __FILE__);

\$config->use_resource('$class_name');

\$config; EOS

  # Generate file
  my $basic_test_native_config_rel_file = SPVM::Builder::Util::convert_class_name_to_rel_file("TestCase::$class_name", 'config');
  $basic_test_native_config_rel_file = "t/lib/$basic_test_native_config_rel_file";
  $self->generate_file($basic_test_native_config_rel_file, $basic_test_native_config_content);
}

sub generate_basic_test_native_class_file { my ($self) = @_;

  my $class_name = $self->class_name;
  
  # Resource
  my $resource = $self->resource;

  # extern C for C++
  my $native = $self->native;
  my $extern_c_start;
  my $extern_c_end;
  if ($native eq 'c++') {
    $extern_c_start = qq(extern "C" {);
    $extern_c_end = "}";
  }
  else {
    $extern_c_start = '';
    $extern_c_end = '';
  }
  
  # Content
  my $native_class_name = $class_name;
  $native_class_name =~ s/::/__/g;
  my $basic_test_native_class_content = <<"EOS";
#include "spvm_native.h"

$extern_c_start

int32_t SPVM__TestCase__${native_class_name}__test(SPVM_ENV* env, SPVM_VALUE* stack) {

  stack[0].ival = 1;
  
  return 0;
}

$extern_c_end EOS

  # Generate file
  my $native_module_ext;
  if (defined $native) {
    if ($native eq 'c') {
      $native_module_ext = 'c';
    }
    elsif ($native eq 'c++') {
      $native_module_ext = 'cpp';
    }
  }
  my $basic_test_native_class_rel_file = SPVM::Builder::Util::convert_class_name_to_rel_file("TestCase::$class_name", $native_module_ext);
  $basic_test_native_class_rel_file = "t/lib/$basic_test_native_class_rel_file";
  $self->generate_file($basic_test_native_class_rel_file, $basic_test_native_class_content);
}

sub generate_dist { my ($self) = @_;

  my $class_name = $self->class_name;
  
  unless (length $class_name) {
    confess("The class name must be specified");
  }
  
  if ($class_name =~ /-/) {
    confess("The class name cannnot contain \"-\"");
  }
  
  my $native = $self->native;
  my $interface = $self->interface;
  my $resource = $self->resource;
  
  if ($interface && $resource) {
    die "The --interface option and the --resource option cannot be specified at the same time"
  }
  
  my $class_name_rel_file = $class_name;
  $class_name_rel_file =~ s|::|/|g;
  
  # Generate output directory
  my $output_dir = $self->output_dir;
  $self->generate_dir($output_dir);
  
  # Generate SPVM class file
  $self->generate_spvm_class_file;
  
  # Generate Perl class file
  my $no_pm_file = $self->no_pm_file;
  unless ($no_pm_file) {
    $self->generate_perl_class_file;
  }
  
  if ($native) {
    # Generate native config file
    $self->generate_native_config_file;
    
    # Generate native class file
    unless ($resource) {
      $self->generate_native_class_file;
    }
    
    # Generate ".gitkeep" file for native class include directory
    $self->generate_gitkeep_file_for_native_module_include_dir;
    
    # Generate ".gitkeep" file for native class src directory
    $self->generate_gitkeep_file_for_native_module_src_dir;
  }
  
  my $only_lib_files = $self->only_lib_files;
  unless ($only_lib_files) {
    # Generate .gitignore file
    $self->generate_gitignore_file;
    
    # Generate .gitattributes file
    $self->generate_gitattributes_file;
    
    # Generate MANIFEST.SKIP file
    $self->generate_manifest_skip_file;
    
    # Generate Changes file
    $self->generate_changes_file;
    
    # Generate README.md file
    $self->generate_readme_markdown_file;
    
    # Generate Makefile.PL file
    $self->generate_makefile_pl_file;
    
    # Generate t/basic.t file
    $self->generate_basic_test_file;

    # Generate basic test SPVM class file
    $self->generate_basic_test_spvm_class_file;

    # Generate license file
    $self->generate_license_file;
    
    if ($resource) {
      # Generate basic test native class file
      $self->generate_basic_test_native_class_file;

      # Generate basic test native config file
      $self->generate_basic_test_native_config_file;
    }
  }
}

sub _year { my ($self) = @_;

  # Year
  my $today_tp = Time::Piece::localtime;
  my $year = $today_tp->year;
  
  return $year;
}

1;

Name

SPVM::Dist - Generating SPVM Distrubution

Description

The SPVM::Dist class has methods to generate an SPVM Distrubution.

Usage

  my $dist = SPVM::Dist->new(
    class_name => 'Math',
  );
  
  $dist->generate_dist;

Copyright & License

Copyright (c) 2023 Yuki Kimoto

MIT License