#!perl

use strict;
use warnings;

use SPVM::Global;
use SPVM::Builder::Util;
use SPVM::Builder::Exe;

# NEVER add compiler/linker options here; all flags must be managed in config files to prevent object file inconsistency.
SPVM::Builder::Util::getopt
  # spvm,spvmcc,spvmdeps common
  'h|help'          => \my $help,
  'v|version'       => \my $show_version,
  'I=s' => \my @spvm_include_dirs,
  'Mblib'            => \my $blib,
  
  # spvm,spvmcc common
  'B|build-dir=s'   => \my $build_dir,
  'w'               => \my $warning,
  'f|force'         => \my $force,
  
  # spvmcc only
  'q|quiet'   => \my $quiet,
  'o|output=s'        => \my $output_file,
  'no-config' => \my $allow_no_config_file,
  'm|mode=s' => \my $mode,
  'object-file=s' => \my @external_object_files,
;

if ($help) {
  print SPVM::Builder::Util::extract_usage;
  exit 0;
}
elsif ($show_version) {
  my $version_string = "spvmcc v$SPVM::VERSION";
  print "$version_string\n";
  exit 0;
}

my $script_name = shift;

unless (defined $script_name) {
  warn "<script_name> is required.\n\n";
  warn SPVM::Builder::Util::extract_usage;
  exit 255;
}

unless (defined $output_file) {
  warn "-o, --output option is required.\n\n";
  warn SPVM::Builder::Util::extract_usage;
  exit 255;
}

my $source = "";
eval { $source = SPVM::Builder::Util::slurp_binary($script_name); };

SPVM::Builder::Util::setup_spvm_command_environment($script_name, $source, $blib, \@spvm_include_dirs, $build_dir, $quiet, undef, $warning, $force);

my $build_exe = SPVM::Builder::Exe->new(
  script_name => $script_name,
  output_file => $output_file,
  mode => $mode,
  allow_no_config_file => $allow_no_config_file,
  external_object_files => \@external_object_files,
);

$build_exe->build_exe_file;

=encoding utf8

=head1 Name

spvmcc - Generating Excutable File

=head1 Description

The spvmcc command generates an executable file from SPVM classes.

=head1 Usage

  Usage: spvmcc [OPTIONS] SCRIPT_NAME
    
    spvmcc -o myapp myapp.spvm
    
    spvmcc -I lib -o myapp myapp.spvm
  
  Options:
    -h, --help                     Shows this message
    -v, --version                  Shows the version
    -I DIR                         Adds a include directory
    -Mblib                         Same as "-Mblib" in perl
    
    -B, --build-dir DIR            Build directory
    -w                             Enables warning flag
    -f|--force                     Compilations and links are forced
    
    -q, --quiet                    Stops diagnostic messages.
    -o, --output FILE              The output file name
    --no-config                    No configration file is ok
    -m, --mode MODE                Config mode

=head1 Details

=head2 spvmcc Command

  spvmcc [OPTIONS] SCRIPT_NAME

The C<spvmcc> command generates an executable file from SPVM classes.

I<OPTIONS> are L<options|/"Options">.

I<SCRIPT_NAME> is a script path that contains an SPVM script.
  
  # myapp.spvm
  use Fn;
  my $var = 1;
  say $var;

Anon class that contains a L<bootstrap method|SPVM::Document::Language::Class/"Bootstrap Method"> is allowed as an SPVM script.

  # myapp.spvm
  class {
    
    version "1.001";
    
    our $FOO : int;
    
    use Fn;
    
    static method main : void () {
      my $var = 1;
      say $var;
    }
  }

The base name of I<SCRIPT_NAME> must be a L<Script Base Name|spvm/"Script Base Name">. Otherwise an exception is thrown.

See L<Class Search Directories|SPVM::Document::Language::Class/"Class Search Directories"> about default class search directories.

See L<SPVM::Document::EnvironmentVariables> about available environment variables.

=head2 Config File for Executable File

A config file that corresponding to the script name must exist for an executable file except for the case that L<"--no-config"> is specified.

The config for an executable file is a L<SPVM::Builder::Config::Exe> object.

C<myapp.config>:

  use SPVM::Builder::Config::Exe;
  
  my $exe_config = SPVM::Builder::Config::Exe->new;
  
  $exe_config

=head2 Build Caching

High-reliability build caching using Ninja-compatible logs, command-line hashes, and file content SHA-1 to detect all changes perfectly.

See L<SPVM::Builder::Ninja>.

=head2 Resources

There are important points to be aware of when generating executable files. That is, L<resources|SPVM::Document::Resource> are not automatically compiled.

When you run an SPVM program with the L<spvm> command, the resources are contained within the shared library of each class. Therefore, there are no conflicts between resources.

However, in the case of executable files, there are resource conflicts. For this, the resources must be resolved manually in the configuration file.

  $config->use_resource('Resource::Zlib');

This is hard work, but given that the executable file must be compiled from source files and run on a variety of platforms, I think that solving it manually is a better way.

I have published a command that allows you to view the list of classes using resources and the resource settings.

See also L<--resource-info|spvmdeps/"--resource-info"> option in L<spvmdeps> command to dump resource information.

=head2 lib Directive

If the source code specified by I<SCRIPT_NAME> contains lib directives, The directories specified by lib directive is prepeneded to L<class search directories|SPVM::Document::Language::Class/"Class Search Directories">.
  
  #lib "$FindBin::Bin/lib"

This directories specified by lib directive is placed after the directories specified by L</"-I"> option.

=head1 Options

=head2 --help

See L<spvm/"--help">.

=head2 -h

  -h

See L<spvm/"-h">.

=head2 --version

See L<spvm/"--version">.

=head2 -v

  -v

See L<spvm/"-v">.

=head2 -I

  -I DIR

See L<spvm/"-I">.

=head2 -Mblib

  -Mblib

See L<spvm/"-Mblib">.

See L<spvm/"-B">.

=head2 --build-dir

  --build-dir DIR

See L<spvm/"--build-dir">.

=head2 -B

  -B DIR

=head2 -w

  -w

See L<spvm/"-w">.

=head2 -f

  -f

See L<spvm/"-f">.

=head2 --force

See L<spvm/"--force">.

=head2 --quiet

  --quiet

Stops diagnostic messages.

=head2 -q

  -q

Same as L</"--quiet">.

=head2 --output

  --output FILE

Specifies the output file path I<FILE>. This output file is an executable file.

=head2 -o

  -o FILE

Same as L</"--output">.

=head2 --no-config

If this option is specified and a config file does not exist, the C<spvmcc> command runs without finising the program.

=head2 --mode

  --mode MODE

Specifies the config mode I<MODE>.

See L<Config Mode|SPVM::Builder::Config/"Config Mode"> about config modes.

=head2 -m

  -m MODE

Same as L</"--mode">.

=head2 --object-file

  --object-file OBJECT_FILE

An additional object file I<OBJECT_FILE> passed to the linker.

This option can be repeated.

=head1 Copyright & License

Copyright 2023 Yuki Kimoto. All Rights Reserved.

MIT License.
