2023-08-29 03:15:16 +00:00
import hashlib
import json
import os
import re
import shutil
2023-09-17 17:05:13 +00:00
from . checksum import dirsum
2023-08-29 03:15:16 +00:00
from . log import *
from . utils import yeetdir
2023-09-28 02:20:33 +00:00
from . version import orca_version , install_dir
2023-08-29 03:15:16 +00:00
def attach_source_commands ( subparsers ) :
source_cmd = subparsers . add_parser ( " source " , help = " Commands for helping compile the Orca source code into your project. " )
2023-09-16 20:46:00 +00:00
source_sub = source_cmd . add_subparsers ( required = True , title = " commands " )
2023-08-29 03:15:16 +00:00
cflags_cmd = source_sub . add_parser ( " cflags " , help = " Get help setting up a C or C++ compiler to compile the Orca source. " )
2023-09-28 02:20:33 +00:00
cflags_cmd . add_argument ( " srcdir " , nargs = " ? " , default = path_in_install ( " src " ) , help = " the directory containing the Orca source code (defaults to system installation) " )
2023-08-29 03:15:16 +00:00
cflags_cmd . set_defaults ( func = shellish ( cflags ) )
vendor_cmd = source_sub . add_parser ( " vendor " , help = " Copy the Orca source code into your project. " )
vendor_cmd . add_argument ( " dir " , type = str , help = " the directory into which the Orca source code will be copied " )
vendor_cmd . set_defaults ( func = shellish ( vendor ) )
2023-09-28 02:20:33 +00:00
def path_in_install ( path ) :
return os . path . join ( install_dir ( ) , path )
2023-08-29 03:15:16 +00:00
def vendor ( args ) :
# Verify that we are ok to vendor into the requested dir.
if os . path . exists ( args . dir ) :
try :
with open ( vendor_file_path ( args . dir ) , " r " ) as f :
vendor_info = json . load ( f )
version = vendor_info [ " version " ]
print ( f " Orca version { version } is currently installed in that directory. " )
if vendor_checksum ( args . dir ) != vendor_info [ " checksum " ] :
log_error ( f " The contents of your vendor directory have been modified. This command will exit to avoid overwriting any local changes. To proceed, manually delete { args . dir } and try again. " )
exit ( 1 )
except FileNotFoundError :
if len ( os . listdir ( args . dir ) ) > 0 :
log_error ( f " The requested directory already exists and does not appear to contain Orca source code. To avoid deleting anything important, please either provide the correct path or manually empty { args . dir } first. " )
exit ( 1 )
yeetdir ( args . dir )
2023-09-28 02:20:33 +00:00
vendor_src = os . path . join ( args . dir , " src " )
vendor_runtime = os . path . join ( args . dir , " build " , " bin " )
vendor_resources = os . path . join ( args . dir , " resources " )
shutil . copytree ( path_in_install ( " src " ) , vendor_src )
shutil . copytree ( path_in_install ( " build/bin " ) , vendor_runtime )
shutil . copytree ( path_in_install ( " resources " ) , vendor_resources )
2023-08-29 03:15:16 +00:00
with open ( vendor_file_path ( args . dir ) , " w " ) as f :
json . dump ( {
" version " : orca_version ( ) ,
" checksum " : vendor_checksum ( args . dir ) ,
} , f , indent = 2 )
2023-09-28 02:20:33 +00:00
2023-08-29 03:15:16 +00:00
print ( f " Version { orca_version ( ) } of the Orca source code has been copied to { args . dir } . " )
def vendor_file_path ( vendor_dir ) :
return os . path . join ( vendor_dir , " .orcavendor " )
def vendor_checksum ( dir ) :
2023-09-17 17:05:13 +00:00
return dirsum ( dir , excluded_extensions = [ " orcavendor " ] )
2023-08-29 03:15:16 +00:00
def cflags ( args ) :
if not os . path . exists ( os . path . join ( args . srcdir , " orca.h " ) ) :
log_error ( f " The provided path does not seem to contain the Orca source code: { args . srcdir } " )
exit ( 1 )
def path_contains ( a , b ) :
a_abs = os . path . abspath ( a )
b_abs = os . path . abspath ( b )
return os . path . commonpath ( [ a_abs , b_abs ] ) == a_abs
def nicepath ( path ) :
path_abs = os . path . abspath ( path )
if path_contains ( os . getcwd ( ) , path_abs ) :
return os . path . relpath ( path_abs )
else :
return path_abs
include = nicepath ( args . srcdir )
orcac = nicepath ( os . path . join ( args . srcdir , " orca.c " ) )
extinclude = nicepath ( os . path . join ( args . srcdir , " ext " ) )
sysinclude = nicepath ( os . path . join ( args . srcdir , " libc-shim/include " ) )
libcsource = nicepath ( os . path . join ( args . srcdir , " libc-shim/src/*.c " ) )
print ( " To compile Orca as part of your C or C++ project, you must: " )
print ( f " > Put the following directory on your SYSTEM include search path: " )
print ( f " { sysinclude } " )
print ( f " > Put the following directories on your include search path: " )
print ( f " { include } " )
print ( f " { extinclude } " )
print ( f " > Compile the following file as a single translation unit: " )
print ( f " { orcac } " )
print ( f " > Compile the following files as separate translation units: " )
print ( f " { libcsource } " )
print ( )
print ( " The following clang flags are also required: " )
print ( " > --target=wasm32 (to compile to wasm) " )
print ( " > --no-standard-libraries (to use only our libc shim) " )
print ( " > -mbulk-memory (to enable memset/memcpy intrinsics, which are required) " )
print ( " > -D__ORCA__ (to signal that the Orca source code is being compiled to run on Orca itself) " )
print ( " > -Wl,--no-entry (to prevent wasm-ld from looking for a _start symbol) " )
print ( " > -Wl,--export-dynamic (to expose your module ' s functions to Orca) " )
print ( )
print ( " And the following clang flags are recommended: " )
print ( " > -g -O2 (to compile with optimizations and debug info) " )
print ( )
print ( " Complete clang example: " )
print ( )
2023-09-16 20:14:19 +00:00
print ( f " clang --target=wasm32 --no-standard-libraries -mbulk-memory -g -O2 -D__ORCA__ -Wl,--no-entry -Wl,--export-dynamic -isystem \" { sysinclude } \" -I \" { include } \" -I \" { extinclude } \" \" { orcac } \" \" { libcsource } \" your-main.c " )
2023-08-29 03:15:16 +00:00
print ( )
if not path_contains ( os . getcwd ( ) , args . srcdir ) :
print ( " If these paths look crazy to you, consider vendoring the source code into your " )
print ( " project using `orca source vendor`. " )
print ( )