2019-03-26 23:51:51 +00:00
#!/usr/bin/env python
2017-04-18 00:16:57 +00:00
2019-03-26 23:51:51 +00:00
import os
import sys
2019-11-26 19:26:06 +00:00
import subprocess
if sys . version_info < ( 3 , ) :
def decode_utf8 ( x ) :
return x
else :
import codecs
def decode_utf8 ( x ) :
return codecs . utf_8_decode ( x ) [ 0 ]
2017-04-18 00:16:57 +00:00
2019-08-21 08:03:49 +00:00
# Workaround for MinGW. See:
# http://www.scons.org/wiki/LongCmdLinesOnWin32
if ( os . name == " nt " ) :
import subprocess
2019-12-15 22:13:19 +00:00
2019-08-21 08:03:49 +00:00
def mySubProcess ( cmdline , env ) :
#print "SPAWNED : " + cmdline
startupinfo = subprocess . STARTUPINFO ( )
startupinfo . dwFlags | = subprocess . STARTF_USESHOWWINDOW
proc = subprocess . Popen ( cmdline , stdin = subprocess . PIPE , stdout = subprocess . PIPE ,
stderr = subprocess . PIPE , startupinfo = startupinfo , shell = False , env = env )
data , err = proc . communicate ( )
rv = proc . wait ( )
if rv :
print ( " ===== " )
print ( err . decode ( " utf-8 " ) )
print ( " ===== " )
return rv
2019-12-15 22:13:19 +00:00
2019-08-21 08:03:49 +00:00
def mySpawn ( sh , escape , cmd , args , env ) :
2019-12-15 22:13:19 +00:00
2019-08-21 08:03:49 +00:00
newargs = ' ' . join ( args [ 1 : ] )
cmdline = cmd + " " + newargs
2019-12-15 22:13:19 +00:00
2019-08-21 08:03:49 +00:00
rv = 0
if len ( cmdline ) > 32000 and cmd . endswith ( " ar " ) :
cmdline = cmd + " " + args [ 1 ] + " " + args [ 2 ] + " "
for i in range ( 3 , len ( args ) ) :
rv = mySubProcess ( cmdline + args [ i ] , env )
if rv :
2019-12-15 22:13:19 +00:00
break
else :
2019-08-21 08:03:49 +00:00
rv = mySubProcess ( cmdline , env )
2019-12-15 22:13:19 +00:00
2019-08-21 08:03:49 +00:00
return rv
2018-02-22 22:16:25 +00:00
def add_sources ( sources , dir , extension ) :
2019-03-26 23:51:51 +00:00
for f in os . listdir ( dir ) :
if f . endswith ( ' . ' + extension ) :
sources . append ( dir + ' / ' + f )
2018-02-22 22:16:25 +00:00
2019-03-26 23:51:51 +00:00
# Try to detect the host platform automatically.
2018-08-16 14:14:35 +00:00
# This is used if no `platform` argument is passed
if sys . platform . startswith ( ' linux ' ) :
host_platform = ' linux '
elif sys . platform == ' darwin ' :
host_platform = ' osx '
2019-05-16 01:09:39 +00:00
elif sys . platform == ' win32 ' or sys . platform == ' msys ' :
2018-08-16 14:14:35 +00:00
host_platform = ' windows '
else :
2019-03-26 23:51:51 +00:00
raise ValueError (
' Could not detect platform automatically, please specify with '
' platform=<platform> '
)
2018-02-22 22:16:25 +00:00
2020-03-30 21:58:20 +00:00
env = Environment ( ENV = os . environ )
is64 = sys . maxsize > 2 * * 32
if (
env [ ' TARGET_ARCH ' ] == ' amd64 ' or
env [ ' TARGET_ARCH ' ] == ' emt64 ' or
env [ ' TARGET_ARCH ' ] == ' x86_64 ' or
env [ ' TARGET_ARCH ' ] == ' arm64-v8a '
) :
is64 = True
2018-08-16 14:14:35 +00:00
opts = Variables ( [ ] , ARGUMENTS )
2019-03-26 23:51:51 +00:00
opts . Add ( EnumVariable (
' platform ' ,
' Target platform ' ,
host_platform ,
2019-11-26 19:26:06 +00:00
allowed_values = ( ' linux ' , ' osx ' , ' windows ' , ' android ' , ' ios ' ) ,
2019-03-26 23:51:51 +00:00
ignorecase = 2
) )
opts . Add ( EnumVariable (
' bits ' ,
' Target platform bits ' ,
2020-03-30 21:58:20 +00:00
' 64 ' if is64 else ' 32 ' ,
( ' 32 ' , ' 64 ' )
2019-03-26 23:51:51 +00:00
) )
opts . Add ( BoolVariable (
' use_llvm ' ,
' Use the LLVM compiler - only effective when targeting Linux ' ,
False
) )
opts . Add ( BoolVariable (
' use_mingw ' ,
' Use the MinGW compiler instead of MSVC - only effective on Windows ' ,
False
) )
2018-08-16 14:14:35 +00:00
# Must be the same setting as used for cpp_bindings
2019-03-26 23:51:51 +00:00
opts . Add ( EnumVariable (
' target ' ,
' Compilation target ' ,
' debug ' ,
allowed_values = ( ' debug ' , ' release ' ) ,
ignorecase = 2
) )
opts . Add ( PathVariable (
' headers_dir ' ,
' Path to the directory containing Godot headers ' ,
' godot_headers ' ,
PathVariable . PathIsDir
) )
opts . Add ( PathVariable (
' custom_api_file ' ,
' Path to a custom JSON API file ' ,
None ,
PathVariable . PathIsFile
) )
opts . Add ( BoolVariable (
' generate_bindings ' ,
' Generate GDNative API bindings ' ,
False
) )
2019-08-05 20:13:23 +00:00
opts . Add ( EnumVariable (
2019-08-21 08:03:49 +00:00
' android_arch ' ,
' Target Android architecture ' ,
' armv7 ' ,
[ ' armv7 ' , ' arm64v8 ' , ' x86 ' , ' x86_64 ' ]
2019-08-05 20:13:23 +00:00
) )
2019-11-26 19:26:06 +00:00
opts . Add ( EnumVariable (
' ios_arch ' ,
' Target iOS architecture ' ,
' arm64 ' ,
[ ' armv7 ' , ' arm64 ' , ' x86_64 ' ]
) )
opts . Add (
' IPHONEPATH ' ,
' Path to iPhone toolchain ' ,
' /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain ' ,
)
2019-08-21 08:03:49 +00:00
opts . Add (
' android_api_level ' ,
' Target Android API level ' ,
' 18 ' if ARGUMENTS . get ( " android_arch " , ' armv7 ' ) in [ ' armv7 ' , ' x86 ' ] else ' 21 '
)
opts . Add (
' ANDROID_NDK_ROOT ' ,
' Path to your Android NDK installation. By default, uses ANDROID_NDK_ROOT from your defined environment variables. ' ,
os . environ . get ( " ANDROID_NDK_ROOT " , None )
)
2020-06-17 19:12:57 +00:00
opts . Add ( BoolVariable (
' generate_template_get_node ' ,
" Generate a template version of the Node class ' s get_node. " ,
2020-08-23 16:02:12 +00:00
True
2020-06-17 19:12:57 +00:00
) )
2017-04-18 00:16:57 +00:00
2018-08-16 14:14:35 +00:00
opts . Update ( env )
Help ( opts . GenerateHelpText ( env ) )
2017-04-18 00:16:57 +00:00
2019-03-26 23:51:51 +00:00
# This makes sure to keep the session environment variables on Windows.
# This way, you can run SCons in a Visual Studio 2017 prompt and it will find
# all the required tools
2019-08-21 08:03:49 +00:00
if host_platform == ' windows ' and env [ ' platform ' ] != ' android ' :
2018-10-25 16:35:33 +00:00
if env [ ' bits ' ] == ' 64 ' :
env = Environment ( TARGET_ARCH = ' amd64 ' )
elif env [ ' bits ' ] == ' 32 ' :
env = Environment ( TARGET_ARCH = ' x86 ' )
2019-03-26 23:51:51 +00:00
opts . Update ( env )
2018-02-22 22:16:25 +00:00
2018-08-16 14:14:35 +00:00
if env [ ' platform ' ] == ' linux ' :
if env [ ' use_llvm ' ] :
2018-02-25 16:03:55 +00:00
env [ ' CXX ' ] = ' clang++ '
2020-09-04 23:06:51 +00:00
env . Append ( CCFLAGS = [ ' -fPIC ' , ' -std=c++14 ' , ' -Wwrite-strings ' ] )
2019-08-05 20:13:23 +00:00
env . Append ( LINKFLAGS = [ " -Wl,-R, ' $$ORIGIN ' " ] )
if env [ ' target ' ] == ' debug ' :
2020-09-04 23:06:51 +00:00
env . Append ( CCFLAGS = [ ' -Og ' , ' -g ' ] )
2019-08-05 20:13:23 +00:00
elif env [ ' target ' ] == ' release ' :
env . Append ( CCFLAGS = [ ' -O3 ' ] )
if env [ ' bits ' ] == ' 64 ' :
env . Append ( CCFLAGS = [ ' -m64 ' ] )
env . Append ( LINKFLAGS = [ ' -m64 ' ] )
elif env [ ' bits ' ] == ' 32 ' :
env . Append ( CCFLAGS = [ ' -m32 ' ] )
env . Append ( LINKFLAGS = [ ' -m32 ' ] )
2018-08-16 14:14:35 +00:00
elif env [ ' platform ' ] == ' osx ' :
2019-03-26 23:51:51 +00:00
# Use Clang on macOS by default
env [ ' CXX ' ] = ' clang++ '
2018-08-16 14:14:35 +00:00
if env [ ' bits ' ] == ' 32 ' :
2019-03-26 23:51:51 +00:00
raise ValueError (
' Only 64-bit builds are supported for the macOS target. '
)
2018-08-16 14:14:35 +00:00
2020-09-04 23:06:51 +00:00
env . Append ( CCFLAGS = [ ' -std=c++14 ' , ' -arch ' , ' x86_64 ' ] )
2019-03-26 23:51:51 +00:00
env . Append ( LINKFLAGS = [
' -arch ' ,
' x86_64 ' ,
' -framework ' ,
' Cocoa ' ,
' -Wl,-undefined,dynamic_lookup ' ,
] )
2018-08-16 14:14:35 +00:00
if env [ ' target ' ] == ' debug ' :
2020-09-04 23:06:51 +00:00
env . Append ( CCFLAGS = [ ' -Og ' , ' -g ' ] )
2018-08-16 14:14:35 +00:00
elif env [ ' target ' ] == ' release ' :
env . Append ( CCFLAGS = [ ' -O3 ' ] )
2019-11-26 19:26:06 +00:00
elif env [ ' platform ' ] == ' ios ' :
if env [ ' ios_arch ' ] == ' x86_64 ' :
sdk_name = ' iphonesimulator '
env . Append ( CCFLAGS = [ ' -mios-simulator-version-min=10.0 ' ] )
else :
sdk_name = ' iphoneos '
env . Append ( CCFLAGS = [ ' -miphoneos-version-min=10.0 ' ] )
try :
sdk_path = decode_utf8 ( subprocess . check_output ( [ ' xcrun ' , ' --sdk ' , sdk_name , ' --show-sdk-path ' ] ) . strip ( ) )
except ( subprocess . CalledProcessError , OSError ) :
raise ValueError ( " Failed to find SDK path while running xcrun --sdk {} --show-sdk-path. " . format ( sdk_name ) )
compiler_path = env [ ' IPHONEPATH ' ] + ' /usr/bin/ '
env [ ' ENV ' ] [ ' PATH ' ] = env [ ' IPHONEPATH ' ] + " /Developer/usr/bin/: " + env [ ' ENV ' ] [ ' PATH ' ]
env [ ' CC ' ] = compiler_path + ' clang '
env [ ' CXX ' ] = compiler_path + ' clang++ '
env [ ' AR ' ] = compiler_path + ' ar '
env [ ' RANLIB ' ] = compiler_path + ' ranlib '
2020-09-04 23:06:51 +00:00
env . Append ( CCFLAGS = [ ' -std=c++14 ' , ' -arch ' , env [ ' ios_arch ' ] , ' -isysroot ' , sdk_path ] )
2019-11-26 19:26:06 +00:00
env . Append ( LINKFLAGS = [
' -arch ' ,
env [ ' ios_arch ' ] ,
' -framework ' ,
' Cocoa ' ,
' -Wl,-undefined,dynamic_lookup ' ,
' -isysroot ' , sdk_path ,
' -F ' + sdk_path
] )
if env [ ' target ' ] == ' debug ' :
2020-09-04 23:06:51 +00:00
env . Append ( CCFLAGS = [ ' -Og ' , ' -g ' ] )
2019-11-26 19:26:06 +00:00
elif env [ ' target ' ] == ' release ' :
env . Append ( CCFLAGS = [ ' -O3 ' ] )
2018-08-16 14:14:35 +00:00
elif env [ ' platform ' ] == ' windows ' :
if host_platform == ' windows ' and not env [ ' use_mingw ' ] :
# MSVC
env . Append ( LINKFLAGS = [ ' /WX ' ] )
if env [ ' target ' ] == ' debug ' :
2019-04-07 14:03:20 +00:00
env . Append ( CCFLAGS = [ ' /Z7 ' , ' /Od ' , ' /EHsc ' , ' /D_DEBUG ' , ' /MDd ' ] )
2018-08-16 14:14:35 +00:00
elif env [ ' target ' ] == ' release ' :
env . Append ( CCFLAGS = [ ' /O2 ' , ' /EHsc ' , ' /DNDEBUG ' , ' /MD ' ] )
2019-03-26 23:51:51 +00:00
2019-05-25 12:23:36 +00:00
elif host_platform == ' linux ' or host_platform == ' osx ' :
2019-03-26 23:51:51 +00:00
# Cross-compilation using MinGW
2018-08-16 14:14:35 +00:00
if env [ ' bits ' ] == ' 64 ' :
env [ ' CXX ' ] = ' x86_64-w64-mingw32-g++ '
2019-05-25 12:23:36 +00:00
env [ ' AR ' ] = " x86_64-w64-mingw32-ar "
env [ ' RANLIB ' ] = " x86_64-w64-mingw32-ranlib "
env [ ' LINK ' ] = " x86_64-w64-mingw32-g++ "
2018-08-16 14:14:35 +00:00
elif env [ ' bits ' ] == ' 32 ' :
env [ ' CXX ' ] = ' i686-w64-mingw32-g++ '
2019-05-25 12:23:36 +00:00
env [ ' AR ' ] = " i686-w64-mingw32-ar "
env [ ' RANLIB ' ] = " i686-w64-mingw32-ranlib "
env [ ' LINK ' ] = " i686-w64-mingw32-g++ "
2019-12-15 22:13:19 +00:00
elif host_platform == ' windows ' and env [ ' use_mingw ' ] :
env = env . Clone ( tools = [ ' mingw ' ] )
env [ " SPAWN " ] = mySpawn
2018-04-08 16:00:54 +00:00
2019-03-26 23:51:51 +00:00
# Native or cross-compilation using MinGW
2019-05-25 12:23:36 +00:00
if host_platform == ' linux ' or host_platform == ' osx ' or env [ ' use_mingw ' ] :
2020-09-04 23:06:51 +00:00
# These options are for a release build even using target=debug
env . Append ( CCFLAGS = [ ' -O3 ' , ' -std=c++14 ' , ' -Wwrite-strings ' ] )
2019-03-26 23:51:51 +00:00
env . Append ( LINKFLAGS = [
' --static ' ,
' -Wl,--no-undefined ' ,
' -static-libgcc ' ,
' -static-libstdc++ ' ,
] )
2020-09-04 23:06:51 +00:00
2019-08-21 08:03:49 +00:00
elif env [ ' platform ' ] == ' android ' :
if host_platform == ' windows ' :
env = env . Clone ( tools = [ ' mingw ' ] )
env [ " SPAWN " ] = mySpawn
2019-12-15 22:13:19 +00:00
2019-08-21 08:03:49 +00:00
# Verify NDK root
if not ' ANDROID_NDK_ROOT ' in env :
raise ValueError ( " To build for Android, ANDROID_NDK_ROOT must be defined. Please set ANDROID_NDK_ROOT to the root folder of your Android NDK installation. " )
2019-12-15 22:13:19 +00:00
2019-08-21 08:03:49 +00:00
# Validate API level
api_level = int ( env [ ' android_api_level ' ] )
if env [ ' android_arch ' ] in [ ' x86_64 ' , ' arm64v8 ' ] and api_level < 21 :
print ( " WARN: 64-bit Android architectures require an API level of at least 21; setting android_api_level=21 " )
env [ ' android_api_level ' ] = ' 21 '
api_level = 21
2019-12-15 22:13:19 +00:00
2019-08-21 08:03:49 +00:00
# Setup toolchain
toolchain = env [ ' ANDROID_NDK_ROOT ' ] + " /toolchains/llvm/prebuilt/ "
if host_platform == " windows " :
toolchain + = " windows "
import platform as pltfm
if pltfm . machine ( ) . endswith ( " 64 " ) :
toolchain + = " -x86_64 "
elif host_platform == " linux " :
toolchain + = " linux-x86_64 "
elif host_platform == " osx " :
toolchain + = " darwin-x86_64 "
env . PrependENVPath ( ' PATH ' , toolchain + " /bin " ) # This does nothing half of the time, but we'll put it here anyways
# Get architecture info
arch_info_table = {
" armv7 " : {
" march " : " armv7-a " , " target " : " armv7a-linux-androideabi " , " tool_path " : " arm-linux-androideabi " , " compiler_path " : " armv7a-linux-androideabi " ,
" ccflags " : [ ' -mfpu=neon ' ]
} ,
" arm64v8 " : {
" march " : " armv8-a " , " target " : " aarch64-linux-android " , " tool_path " : " aarch64-linux-android " , " compiler_path " : " aarch64-linux-android " ,
" ccflags " : [ ]
} ,
" x86 " : {
" march " : " i686 " , " target " : " i686-linux-android " , " tool_path " : " i686-linux-android " , " compiler_path " : " i686-linux-android " ,
" ccflags " : [ ' -mstackrealign ' ]
} ,
" x86_64 " : { " march " : " x86-64 " , " target " : " x86_64-linux-android " , " tool_path " : " x86_64-linux-android " , " compiler_path " : " x86_64-linux-android " ,
" ccflags " : [ ]
}
}
arch_info = arch_info_table [ env [ ' android_arch ' ] ]
# Setup tools
env [ ' CC ' ] = toolchain + " /bin/clang "
env [ ' CXX ' ] = toolchain + " /bin/clang++ "
env [ ' AR ' ] = toolchain + " /bin/ " + arch_info [ ' tool_path ' ] + " -ar "
env . Append ( CCFLAGS = [ ' --target= ' + arch_info [ ' target ' ] + env [ ' android_api_level ' ] , ' -march= ' + arch_info [ ' march ' ] , ' -fPIC ' ] ) #, '-fPIE', '-fno-addrsig', '-Oz'])
env . Append ( CCFLAGS = arch_info [ ' ccflags ' ] )
2019-03-26 23:51:51 +00:00
env . Append ( CPPPATH = [
' . ' ,
env [ ' headers_dir ' ] ,
' include ' ,
' include/gen ' ,
' include/core ' ,
] )
2018-02-11 14:50:01 +00:00
# Generate bindings?
json_api_file = ' '
2018-02-22 22:16:25 +00:00
2019-03-26 23:51:51 +00:00
if ' custom_api_file ' in env :
2018-11-25 21:13:15 +00:00
json_api_file = env [ ' custom_api_file ' ]
2018-05-16 00:05:41 +00:00
else :
2020-08-27 17:46:03 +00:00
json_api_file = os . path . join ( os . getcwd ( ) , env [ ' headers_dir ' ] , ' api.json ' )
2017-03-06 07:49:24 +00:00
2018-11-25 21:13:15 +00:00
if env [ ' generate_bindings ' ] :
2018-08-16 14:14:35 +00:00
# Actually create the bindings here
2017-07-23 15:53:50 +00:00
import binding_generator
2017-04-18 00:16:57 +00:00
2020-06-17 19:12:57 +00:00
binding_generator . generate_bindings ( json_api_file , env [ ' generate_template_get_node ' ] )
2017-03-06 07:49:24 +00:00
2019-03-26 23:51:51 +00:00
# Sources to compile
2018-02-22 22:16:25 +00:00
sources = [ ]
add_sources ( sources , ' src/core ' , ' cpp ' )
2018-02-11 14:50:01 +00:00
add_sources ( sources , ' src/gen ' , ' cpp ' )
2017-03-06 02:30:46 +00:00
2019-11-26 19:26:06 +00:00
arch_suffix = env [ ' bits ' ]
if env [ ' platform ' ] == ' android ' :
arch_suffix = env [ ' android_arch ' ]
if env [ ' platform ' ] == ' ios ' :
arch_suffix = env [ ' ios_arch ' ]
2018-08-16 14:14:35 +00:00
library = env . StaticLibrary (
2019-08-21 08:03:49 +00:00
target = ' bin/ ' + ' libgodot-cpp. {} . {} . {} {} ' . format (
2019-03-26 23:51:51 +00:00
env [ ' platform ' ] ,
env [ ' target ' ] ,
2019-11-26 19:26:06 +00:00
arch_suffix ,
2019-08-21 08:03:49 +00:00
env [ ' LIBSUFFIX ' ]
2019-03-26 23:51:51 +00:00
) , source = sources
2018-08-16 14:14:35 +00:00
)
2018-02-22 22:16:25 +00:00
Default ( library )