2016-10-17 08:50:25 +02:00
#!/usr/bin/env python
2017-09-24 22:40:15 +02:00
EnsureSConsVersion ( 0 , 98 , 1 )
2014-02-10 02:10:30 +01:00
2019-02-10 15:22:31 +01:00
# System
2014-02-10 02:10:30 +01:00
import glob
2019-02-10 15:22:31 +01:00
import os
2019-12-19 10:03:11 +01:00
import pickle
2014-02-10 02:10:30 +01:00
import sys
2020-05-28 15:48:19 +02:00
from collections import OrderedDict
2019-02-10 15:22:31 +01:00
# Local
2014-02-10 02:10:30 +01:00
import methods
2018-03-17 23:23:55 +01:00
import gles_builders
from platform_methods import run_in_subprocess
2014-03-07 20:20:06 +01:00
2014-02-10 02:10:30 +01:00
# scan possible build platforms
2016-10-30 18:57:40 +01:00
platform_list = [ ] # list of platforms
platform_opts = { } # options for each platform
platform_flags = { } # flags for each platform
2014-02-10 02:10:30 +01:00
2016-10-30 18:57:40 +01:00
active_platforms = [ ]
active_platform_ids = [ ]
platform_exporters = [ ]
2017-11-16 01:33:48 +01:00
platform_apis = [ ]
2014-02-10 02:10:30 +01:00
2018-08-28 20:40:51 +02:00
for x in sorted ( glob . glob ( " platform/* " ) ) :
2016-10-30 18:57:40 +01:00
if ( not os . path . isdir ( x ) or not os . path . exists ( x + " /detect.py " ) ) :
2016-10-30 18:44:57 +01:00
continue
2016-10-30 18:57:40 +01:00
tmppath = " ./ " + x
2016-10-30 18:44:57 +01:00
2019-02-10 15:22:31 +01:00
sys . path . insert ( 0 , tmppath )
2016-10-30 18:44:57 +01:00
import detect
2016-10-30 18:57:40 +01:00
if ( os . path . exists ( x + " /export/export.cpp " ) ) :
2016-10-30 18:44:57 +01:00
platform_exporters . append ( x [ 9 : ] )
2017-11-16 01:33:48 +01:00
if ( os . path . exists ( x + " /api/api.cpp " ) ) :
platform_apis . append ( x [ 9 : ] )
2016-10-30 18:44:57 +01:00
if ( detect . is_active ( ) ) :
2016-10-30 18:57:40 +01:00
active_platforms . append ( detect . get_name ( ) )
2016-11-01 00:24:30 +01:00
active_platform_ids . append ( x )
2016-10-30 18:44:57 +01:00
if ( detect . can_build ( ) ) :
2016-10-30 18:57:40 +01:00
x = x . replace ( " platform/ " , " " ) # rest of world
x = x . replace ( " platform \\ " , " " ) # win32
platform_list + = [ x ]
platform_opts [ x ] = detect . get_opts ( )
platform_flags [ x ] = detect . get_flags ( )
2016-10-30 18:44:57 +01:00
sys . path . remove ( tmppath )
sys . modules . pop ( ' detect ' )
2014-02-10 02:10:30 +01:00
2016-10-30 18:57:40 +01:00
methods . save_active_platforms ( active_platforms , active_platform_ids )
2014-02-10 02:10:30 +01:00
2016-10-30 18:57:40 +01:00
custom_tools = [ ' default ' ]
2014-02-10 02:10:30 +01:00
2016-10-09 21:23:27 +02:00
platform_arg = ARGUMENTS . get ( " platform " , ARGUMENTS . get ( " p " , False ) )
2015-07-24 02:04:50 +02:00
2018-03-21 15:51:44 +01:00
if os . name == " nt " and ( platform_arg == " android " or ARGUMENTS . get ( " use_mingw " , False ) ) :
custom_tools = [ ' mingw ' ]
elif platform_arg == ' javascript ' :
# Use generic POSIX build toolchain for Emscripten.
custom_tools = [ ' cc ' , ' c++ ' , ' ar ' , ' link ' , ' textfile ' , ' zip ' ]
2014-02-10 02:10:30 +01:00
2016-11-01 00:24:30 +01:00
env_base = Environment ( tools = custom_tools )
2016-10-17 21:04:13 +02:00
if ' TERM ' in os . environ :
2016-10-30 18:44:57 +01:00
env_base [ ' ENV ' ] [ ' TERM ' ] = os . environ [ ' TERM ' ]
2016-06-06 13:45:45 +02:00
env_base . AppendENVPath ( ' PATH ' , os . getenv ( ' PATH ' ) )
env_base . AppendENVPath ( ' PKG_CONFIG_PATH ' , os . getenv ( ' PKG_CONFIG_PATH ' ) )
2016-10-30 18:57:40 +01:00
env_base . disabled_modules = [ ]
env_base . use_ptrcall = False
2017-11-02 03:12:28 +01:00
env_base . module_version_string = " "
2018-03-02 20:51:29 +01:00
env_base . msvc = False
2016-10-30 18:57:40 +01:00
2014-02-10 02:10:30 +01:00
env_base . __class__ . disable_module = methods . disable_module
2017-11-02 03:12:28 +01:00
env_base . __class__ . add_module_version_string = methods . add_module_version_string
2014-02-10 02:10:30 +01:00
env_base . __class__ . add_source_files = methods . add_source_files
2016-01-25 04:21:04 +01:00
env_base . __class__ . use_windows_spawn_fix = methods . use_windows_spawn_fix
2016-10-30 17:04:07 +01:00
env_base . __class__ . split_lib = methods . split_lib
2014-02-10 02:10:30 +01:00
2017-11-28 21:27:57 +01:00
env_base . __class__ . add_shared_library = methods . add_shared_library
env_base . __class__ . add_library = methods . add_library
env_base . __class__ . add_program = methods . add_program
2018-06-21 06:33:25 +02:00
env_base . __class__ . CommandNoCache = methods . CommandNoCache
2018-09-28 13:29:52 +02:00
env_base . __class__ . disable_warnings = methods . disable_warnings
2017-11-28 21:27:57 +01:00
2016-10-30 18:57:40 +01:00
env_base [ " x86_libtheora_opt_gcc " ] = False
env_base [ " x86_libtheora_opt_vc " ] = False
2015-11-25 04:28:03 +01:00
2019-12-19 10:03:11 +01:00
# avoid issues when building with different versions of python out of the same directory
env_base . SConsignFile ( " .sconsign {0} .dblite " . format ( pickle . HIGHEST_PROTOCOL ) )
2016-11-03 00:23:55 +01:00
# Build options
2014-02-10 02:10:30 +01:00
customs = [ ' custom.py ' ]
profile = ARGUMENTS . get ( " profile " , False )
if profile :
2016-10-30 18:44:57 +01:00
if os . path . isfile ( profile ) :
customs . append ( profile )
2016-10-30 18:57:40 +01:00
elif os . path . isfile ( profile + " .py " ) :
customs . append ( profile + " .py " )
2014-02-10 02:10:30 +01:00
2016-10-30 18:57:40 +01:00
opts = Variables ( customs , ARGUMENTS )
2016-11-03 00:23:55 +01:00
# Target build options
2018-06-07 20:46:32 +02:00
opts . Add ( ' arch ' , " Platform-dependent architecture (arm/arm64/x86/x64/mips/...) " , ' ' )
2018-03-01 17:02:19 +01:00
opts . Add ( EnumVariable ( ' bits ' , " Target platform bits " , ' default ' , ( ' default ' , ' 32 ' , ' 64 ' ) ) )
2016-11-03 00:23:55 +01:00
opts . Add ( ' p ' , " Platform (alias for ' platform ' ) " , ' ' )
2017-09-25 05:06:45 +02:00
opts . Add ( ' platform ' , " Target platform ( %s ) " % ( ' | ' . join ( platform_list ) , ) , ' ' )
opts . Add ( EnumVariable ( ' target ' , " Compilation target " , ' debug ' , ( ' debug ' , ' release_debug ' , ' release ' ) ) )
2018-07-21 22:26:14 +02:00
opts . Add ( EnumVariable ( ' optimize ' , " Optimization type " , ' speed ' , ( ' speed ' , ' size ' ) ) )
2018-06-07 20:46:32 +02:00
opts . Add ( BoolVariable ( ' tools ' , " Build the tools (a.k.a. the Godot editor) " , True ) )
opts . Add ( BoolVariable ( ' use_lto ' , ' Use link-time optimization ' , False ) )
2019-02-26 01:46:24 +01:00
opts . Add ( BoolVariable ( ' use_precise_math_checks ' , ' Math checks use very precise epsilon (useful to debug the engine) ' , False ) )
2016-11-03 00:23:55 +01:00
# Components
2017-09-25 06:04:49 +02:00
opts . Add ( BoolVariable ( ' deprecated ' , " Enable deprecated features " , True ) )
2018-06-07 20:46:32 +02:00
opts . Add ( BoolVariable ( ' gdscript ' , " Enable GDScript support " , True ) )
opts . Add ( BoolVariable ( ' minizip ' , " Enable ZIP archive support using minizip " , True ) )
opts . Add ( BoolVariable ( ' xaudio2 ' , " Enable the XAudio2 audio driver " , False ) )
2020-04-04 13:46:15 +02:00
opts . Add ( " custom_modules " , " A list of comma-separated directory paths containing custom modules to build. " , " " )
2016-11-03 00:23:55 +01:00
# Advanced options
2017-09-25 06:04:49 +02:00
opts . Add ( BoolVariable ( ' verbose ' , " Enable verbose output for the compilation " , False ) )
2018-06-07 20:46:32 +02:00
opts . Add ( BoolVariable ( ' progress ' , " Show a progress indicator during compilation " , True ) )
2018-10-03 13:38:09 +02:00
opts . Add ( EnumVariable ( ' warnings ' , " Set the level of warnings emitted during compilation " , ' all ' , ( ' extra ' , ' all ' , ' moderate ' , ' no ' ) ) )
opts . Add ( BoolVariable ( ' werror ' , " Treat compiler warnings as errors. Depends on the level of warnings set with ' warnings ' " , False ) )
2019-06-15 15:19:58 +02:00
opts . Add ( BoolVariable ( ' dev ' , " If yes, alias for verbose=yes warnings=extra werror=yes " , False ) )
2018-10-03 13:38:09 +02:00
opts . Add ( ' extra_suffix ' , " Custom extra suffix added to the base filename of all generated binary files " , ' ' )
opts . Add ( BoolVariable ( ' vsproj ' , " Generate a Visual Studio solution " , False ) )
2018-06-07 20:46:32 +02:00
opts . Add ( EnumVariable ( ' macports_clang ' , " Build using Clang from MacPorts " , ' no ' , ( ' no ' , ' 5.0 ' , ' devel ' ) ) )
2019-12-09 19:22:08 +01:00
opts . Add ( BoolVariable ( ' split_libmodules ' , " Split intermediate libmodules.a in smaller chunks to prevent exceeding linker command line size (forced to True when using MinGW) " , False ) )
2018-10-03 13:38:09 +02:00
opts . Add ( BoolVariable ( ' disable_3d ' , " Disable 3D nodes for a smaller executable " , False ) )
2018-12-21 03:21:10 +01:00
opts . Add ( BoolVariable ( ' disable_advanced_gui ' , " Disable advanced GUI nodes and behaviors " , False ) )
2018-06-07 10:41:11 +02:00
opts . Add ( BoolVariable ( ' no_editor_splash ' , " Don ' t use the custom splash screen for the editor " , False ) )
2018-09-15 14:45:54 +02:00
opts . Add ( ' system_certs_path ' , " Use this path as SSL certificates default for editor (for package maintainers) " , ' ' )
2016-11-03 00:23:55 +01:00
# Thirdparty libraries
2020-03-06 13:31:52 +01:00
#opts.Add(BoolVariable('builtin_assimp', "Use the built-in Assimp library", True))
2018-06-07 20:46:32 +02:00
opts . Add ( BoolVariable ( ' builtin_bullet ' , " Use the built-in Bullet library " , True ) )
2018-09-14 16:02:04 +02:00
opts . Add ( BoolVariable ( ' builtin_certs ' , " Bundle default SSL certificates to be used if you don ' t specify an override in the project settings " , True ) )
2018-06-07 20:46:32 +02:00
opts . Add ( BoolVariable ( ' builtin_enet ' , " Use the built-in ENet library " , True ) )
opts . Add ( BoolVariable ( ' builtin_freetype ' , " Use the built-in FreeType library " , True ) )
opts . Add ( BoolVariable ( ' builtin_libogg ' , " Use the built-in libogg library " , True ) )
opts . Add ( BoolVariable ( ' builtin_libpng ' , " Use the built-in libpng library " , True ) )
opts . Add ( BoolVariable ( ' builtin_libtheora ' , " Use the built-in libtheora library " , True ) )
opts . Add ( BoolVariable ( ' builtin_libvorbis ' , " Use the built-in libvorbis library " , True ) )
opts . Add ( BoolVariable ( ' builtin_libvpx ' , " Use the built-in libvpx library " , True ) )
opts . Add ( BoolVariable ( ' builtin_libwebp ' , " Use the built-in libwebp library " , True ) )
2019-07-01 18:14:26 +02:00
opts . Add ( BoolVariable ( ' builtin_wslay ' , " Use the built-in wslay library " , True ) )
2018-06-07 20:46:32 +02:00
opts . Add ( BoolVariable ( ' builtin_mbedtls ' , " Use the built-in mbedTLS library " , True ) )
opts . Add ( BoolVariable ( ' builtin_miniupnpc ' , " Use the built-in miniupnpc library " , True ) )
opts . Add ( BoolVariable ( ' builtin_opus ' , " Use the built-in Opus library " , True ) )
2019-05-26 23:59:14 +02:00
opts . Add ( BoolVariable ( ' builtin_pcre2 ' , " Use the built-in PCRE2 library " , True ) )
2019-11-20 08:54:52 +01:00
opts . Add ( BoolVariable ( ' builtin_pcre2_with_jit ' , " Use JIT compiler for the built-in PCRE2 library " , True ) )
2018-06-07 20:46:32 +02:00
opts . Add ( BoolVariable ( ' builtin_recast ' , " Use the built-in Recast library " , True ) )
opts . Add ( BoolVariable ( ' builtin_squish ' , " Use the built-in squish library " , True ) )
2018-09-29 14:46:26 +02:00
opts . Add ( BoolVariable ( ' builtin_xatlas ' , " Use the built-in xatlas library " , True ) )
2018-06-07 20:46:32 +02:00
opts . Add ( BoolVariable ( ' builtin_zlib ' , " Use the built-in zlib library " , True ) )
opts . Add ( BoolVariable ( ' builtin_zstd ' , " Use the built-in Zstd library " , True ) )
2016-11-03 00:23:55 +01:00
2018-01-05 20:37:18 +01:00
# Compilation environment setup
2016-11-03 00:23:55 +01:00
opts . Add ( " CXX " , " C++ compiler " )
opts . Add ( " CC " , " C compiler " )
2018-01-05 20:37:18 +01:00
opts . Add ( " LINK " , " Linker " )
opts . Add ( " CCFLAGS " , " Custom flags for both the C and C++ compilers " )
2016-11-01 00:24:30 +01:00
opts . Add ( " CFLAGS " , " Custom flags for the C compiler " )
2019-04-24 16:49:12 +02:00
opts . Add ( " CXXFLAGS " , " Custom flags for the C++ compiler " )
2016-11-01 00:24:30 +01:00
opts . Add ( " LINKFLAGS " , " Custom flags for the linker " )
2016-11-03 00:23:55 +01:00
2014-02-10 02:10:30 +01:00
# add platform specific options
for k in platform_opts . keys ( ) :
2016-10-30 18:44:57 +01:00
opt_list = platform_opts [ k ]
for o in opt_list :
2017-09-25 05:06:45 +02:00
opts . Add ( o )
2014-02-10 02:10:30 +01:00
2020-04-04 13:46:15 +02:00
# Detect modules.
2020-05-28 15:48:19 +02:00
modules_detected = OrderedDict ( )
2020-04-04 13:46:15 +02:00
module_search_paths = [ " modules " ] # Built-in path.
if ARGUMENTS . get ( " custom_modules " ) :
paths = ARGUMENTS . get ( " custom_modules " ) . split ( " , " )
for p in paths :
try :
module_search_paths . append ( methods . convert_custom_modules_path ( p ) )
except ValueError as e :
print ( e )
sys . exit ( 255 )
for path in module_search_paths :
# Note: custom modules can override built-in ones.
modules_detected . update ( methods . detect_modules ( path ) )
include_path = os . path . dirname ( path )
if include_path :
env_base . Prepend ( CPPPATH = [ include_path ] )
# Add module options
for name , path in modules_detected . items ( ) :
enabled = True
sys . path . insert ( 0 , path )
2017-10-03 00:01:15 +02:00
import config
2020-04-04 13:46:15 +02:00
try :
enabled = config . is_enabled ( )
except AttributeError :
pass
sys . path . remove ( path )
sys . modules . pop ( " config " )
opts . Add ( BoolVariable ( " module_ " + name + " _enabled " , " Enable module ' %s ' " % ( name , ) , enabled ) )
methods . write_modules ( modules_detected )
2014-02-10 02:10:30 +01:00
2016-10-30 18:57:40 +01:00
opts . Update ( env_base ) # update environment
Help ( opts . GenerateHelpText ( env_base ) ) # generate help
2014-02-10 02:10:30 +01:00
# add default include paths
2019-10-09 16:11:04 +02:00
env_base . Prepend ( CPPPATH = [ ' # ' ] )
2014-12-27 17:42:37 +01:00
# configure ENV for platform
2016-10-30 18:57:40 +01:00
env_base . platform_exporters = platform_exporters
2017-11-16 01:33:48 +01:00
env_base . platform_apis = platform_apis
2014-02-10 02:10:30 +01:00
2019-02-26 01:46:24 +01:00
if ( env_base [ " use_precise_math_checks " ] ) :
env_base . Append ( CPPDEFINES = [ ' PRECISE_MATH_CHECKS ' ] )
2016-10-30 18:57:40 +01:00
if ( env_base [ ' target ' ] == ' debug ' ) :
2018-10-02 18:53:53 +02:00
env_base . Append ( CPPDEFINES = [ ' DEBUG_MEMORY_ALLOC ' , ' DISABLE_FORCED_INLINE ' ] )
2014-02-10 02:10:30 +01:00
2019-02-10 15:08:16 +01:00
# The two options below speed up incremental builds, but reduce the certainty that all files
# will properly be rebuilt. As such, we only enable them for debug (dev) builds, not release.
# To decide whether to rebuild a file, use the MD5 sum only if the timestamp has changed.
# http://scons.org/doc/production/HTML/scons-user/ch06.html#idm139837621851792
env_base . Decider ( ' MD5-timestamp ' )
# Use cached implicit dependencies by default. Can be overridden by specifying `--implicit-deps-changed` in the command line.
# http://scons.org/doc/production/HTML/scons-user/ch06s04.html
env_base . SetOption ( ' implicit_cache ' , 1 )
2017-12-16 20:11:13 +01:00
if ( env_base [ ' no_editor_splash ' ] ) :
2018-03-02 20:51:29 +01:00
env_base . Append ( CPPDEFINES = [ ' NO_EDITOR_SPLASH ' ] )
2017-12-16 20:11:13 +01:00
2017-09-25 06:04:49 +02:00
if not env_base [ ' deprecated ' ] :
2018-03-02 20:51:29 +01:00
env_base . Append ( CPPDEFINES = [ ' DISABLE_DEPRECATED ' ] )
2016-06-28 18:10:15 +02:00
2014-02-10 02:10:30 +01:00
env_base . platforms = { }
2016-10-30 18:57:40 +01:00
selected_platform = " "
2014-02-10 02:10:30 +01:00
2014-10-07 06:31:49 +02:00
if env_base [ ' platform ' ] != " " :
2016-10-30 18:57:40 +01:00
selected_platform = env_base [ ' platform ' ]
2014-10-07 06:31:49 +02:00
elif env_base [ ' p ' ] != " " :
2016-10-30 18:57:40 +01:00
selected_platform = env_base [ ' p ' ]
env_base [ " platform " ] = selected_platform
2019-05-26 19:05:31 +02:00
else :
# Missing `platform` argument, try to detect platform automatically
if sys . platform . startswith ( ' linux ' ) :
2019-05-27 13:42:52 +02:00
selected_platform = ' x11 '
2019-05-26 19:05:31 +02:00
elif sys . platform == ' darwin ' :
selected_platform = ' osx '
elif sys . platform == ' win32 ' :
selected_platform = ' windows '
else :
print ( " Could not detect platform automatically. Supported platforms: " )
for x in platform_list :
print ( " \t " + x )
print ( " \n Please run SCons again and select a valid platform: platform=<string> " )
2019-05-27 13:42:52 +02:00
2019-05-26 19:05:31 +02:00
if selected_platform != " " :
print ( " Automatically detected platform: " + selected_platform )
env_base [ " platform " ] = selected_platform
2014-10-07 06:31:49 +02:00
if selected_platform in platform_list :
2019-02-10 15:22:31 +01:00
tmppath = " ./platform/ " + selected_platform
sys . path . insert ( 0 , tmppath )
2016-10-30 18:44:57 +01:00
import detect
if " create " in dir ( detect ) :
env = detect . create ( env_base )
else :
env = env_base . Clone ( )
2017-10-03 00:01:15 +02:00
2020-05-18 13:58:27 +02:00
# Compilation DB requires SCons 3.1.1+.
from SCons import __version__ as scons_raw_version
2019-11-02 15:21:21 +01:00
2020-05-18 13:58:27 +02:00
scons_ver = env . _get_major_minor_revision ( scons_raw_version )
if scons_ver > = ( 3 , 1 , 1 ) :
env . Tool ( " compilation_db " , toolpath = [ " misc/scons " ] )
env . Alias ( " compiledb " , env . CompilationDatabase ( " compile_commands.json " ) )
2019-11-02 15:21:21 +01:00
2017-09-25 06:04:49 +02:00
if env [ ' dev ' ] :
env [ ' verbose ' ] = True
2019-06-15 15:19:58 +02:00
env [ ' warnings ' ] = " extra "
env [ ' werror ' ] = True
2016-10-30 18:44:57 +01:00
2017-09-25 06:04:49 +02:00
if env [ ' vsproj ' ] :
2016-10-30 18:44:57 +01:00
env . vs_incs = [ ]
env . vs_srcs = [ ]
2016-10-30 18:57:40 +01:00
def AddToVSProject ( sources ) :
2016-10-30 18:44:57 +01:00
for x in sources :
if type ( x ) == type ( " " ) :
fname = env . File ( x ) . path
else :
fname = env . File ( x ) [ 0 ] . path
2016-10-30 18:57:40 +01:00
pieces = fname . split ( " . " )
if len ( pieces ) > 0 :
2016-10-30 18:44:57 +01:00
basename = pieces [ 0 ]
2016-10-30 18:57:40 +01:00
basename = basename . replace ( ' \\ \\ ' , ' / ' )
2017-11-16 16:37:02 +01:00
if os . path . isfile ( basename + " .h " ) :
env . vs_incs = env . vs_incs + [ basename + " .h " ]
2018-01-19 04:13:48 +01:00
elif os . path . isfile ( basename + " .hpp " ) :
env . vs_incs = env . vs_incs + [ basename + " .hpp " ]
2017-11-16 16:37:02 +01:00
if os . path . isfile ( basename + " .c " ) :
env . vs_srcs = env . vs_srcs + [ basename + " .c " ]
elif os . path . isfile ( basename + " .cpp " ) :
env . vs_srcs = env . vs_srcs + [ basename + " .cpp " ]
2016-10-30 18:44:57 +01:00
env . AddToVSProject = AddToVSProject
2016-10-30 18:57:40 +01:00
env . extra_suffix = " "
2016-10-30 18:44:57 +01:00
2016-10-30 18:57:40 +01:00
if env [ " extra_suffix " ] != ' ' :
env . extra_suffix + = ' . ' + env [ " extra_suffix " ]
2016-10-30 18:44:57 +01:00
2020-02-20 11:09:20 +01:00
# Environment flags
2016-10-30 18:44:57 +01:00
CCFLAGS = env . get ( ' CCFLAGS ' , ' ' )
env [ ' CCFLAGS ' ] = ' '
2017-08-26 18:53:49 +02:00
env . Append ( CCFLAGS = str ( CCFLAGS ) . split ( ) )
2016-10-30 18:44:57 +01:00
CFLAGS = env . get ( ' CFLAGS ' , ' ' )
env [ ' CFLAGS ' ] = ' '
2017-08-26 18:53:49 +02:00
env . Append ( CFLAGS = str ( CFLAGS ) . split ( ) )
2014-02-22 13:34:40 +01:00
2019-04-24 16:49:12 +02:00
CXXFLAGS = env . get ( ' CXXFLAGS ' , ' ' )
env [ ' CXXFLAGS ' ] = ' '
env . Append ( CXXFLAGS = str ( CXXFLAGS ) . split ( ) )
2016-10-30 18:44:57 +01:00
LINKFLAGS = env . get ( ' LINKFLAGS ' , ' ' )
env [ ' LINKFLAGS ' ] = ' '
2017-08-26 18:53:49 +02:00
env . Append ( LINKFLAGS = str ( LINKFLAGS ) . split ( ) )
2016-10-30 18:44:57 +01:00
2020-02-20 11:09:20 +01:00
# Platform specific flags
2016-10-30 18:44:57 +01:00
flag_list = platform_flags [ selected_platform ]
for f in flag_list :
2016-10-30 18:57:40 +01:00
if not ( f [ 0 ] in ARGUMENTS ) : # allow command line to override platform flags
2016-10-30 18:44:57 +01:00
env [ f [ 0 ] ] = f [ 1 ]
2020-02-20 11:09:20 +01:00
# Must happen after the flags definition, so that they can be used by platform detect
2016-10-30 18:44:57 +01:00
detect . configure ( env )
2015-08-24 01:54:13 +02:00
2020-02-20 11:09:20 +01:00
# Set our C and C++ standard requirements.
# Prepending to make it possible to override
# This needs to come after `configure`, otherwise we don't have env.msvc.
2019-07-22 16:57:24 +02:00
if not env . msvc :
2020-02-20 11:09:20 +01:00
# Specifying GNU extensions support explicitly, which are supported by
# both GCC and Clang. This mirrors GCC and Clang's current default
# compile flags if no -std is specified.
env . Prepend ( CFLAGS = [ ' -std=gnu11 ' ] )
env . Prepend ( CXXFLAGS = [ ' -std=gnu++14 ' ] )
else :
# MSVC doesn't have clear C standard support, /std only covers C++.
# We apply it to CCFLAGS (both C and C++ code) in case it impacts C features.
env . Prepend ( CCFLAGS = [ ' /std:c++14 ' ] )
2019-07-22 16:57:24 +02:00
2018-10-03 13:38:09 +02:00
# Configure compiler warnings
2018-03-02 20:51:29 +01:00
if env . msvc :
2018-10-03 17:27:22 +02:00
# Truncations, narrowing conversions, signed/unsigned comparisons...
disable_nonessential_warnings = [ ' /wd4267 ' , ' /wd4244 ' , ' /wd4305 ' , ' /wd4018 ' , ' /wd4800 ' ]
2017-05-26 22:22:13 +02:00
if ( env [ " warnings " ] == ' extra ' ) :
env . Append ( CCFLAGS = [ ' /Wall ' ] ) # Implies /W4
2018-10-02 14:37:31 +02:00
elif ( env [ " warnings " ] == ' all ' ) :
2017-05-26 22:22:13 +02:00
env . Append ( CCFLAGS = [ ' /W3 ' ] + disable_nonessential_warnings )
elif ( env [ " warnings " ] == ' moderate ' ) :
env . Append ( CCFLAGS = [ ' /W2 ' ] + disable_nonessential_warnings )
else : # 'no'
2017-03-25 08:36:00 +01:00
env . Append ( CCFLAGS = [ ' /w ' ] )
2017-11-21 19:06:43 +01:00
# Set exception handling model to avoid warnings caused by Windows system headers.
env . Append ( CCFLAGS = [ ' /EHsc ' ] )
2018-10-03 13:38:09 +02:00
if ( env [ " werror " ] ) :
env . Append ( CCFLAGS = [ ' /WX ' ] )
2019-05-15 19:33:21 +02:00
# Force to use Unicode encoding
env . Append ( MSVC_FLAGS = [ ' /utf8 ' ] )
2017-05-26 22:22:13 +02:00
else : # Rest of the world
2020-02-26 13:23:37 +01:00
version = methods . get_compiler_version ( env ) or [ - 1 , - 1 ]
2019-02-12 21:10:08 +01:00
shadow_local_warning = [ ]
2019-02-22 15:54:05 +01:00
all_plus_warnings = [ ' -Wwrite-strings ' ]
2019-02-12 21:10:08 +01:00
2019-04-05 12:51:15 +02:00
if methods . using_gcc ( env ) :
2020-02-26 13:23:37 +01:00
if version [ 0 ] > = 7 :
2019-02-12 21:10:08 +01:00
shadow_local_warning = [ ' -Wshadow-local ' ]
2019-04-05 14:06:16 +02:00
2017-05-26 22:22:13 +02:00
if ( env [ " warnings " ] == ' extra ' ) :
2019-04-05 14:06:16 +02:00
# Note: enable -Wimplicit-fallthrough for Clang (already part of -Wextra for GCC)
# once we switch to C++11 or later (necessary for our FALLTHROUGH macro).
2019-04-24 16:49:12 +02:00
env . Append ( CCFLAGS = [ ' -Wall ' , ' -Wextra ' , ' -Wno-unused-parameter ' ]
2019-04-02 21:15:02 +02:00
+ all_plus_warnings + shadow_local_warning )
2019-04-24 16:49:12 +02:00
env . Append ( CXXFLAGS = [ ' -Wctor-dtor-privacy ' , ' -Wnon-virtual-dtor ' ] )
2019-04-05 12:51:15 +02:00
if methods . using_gcc ( env ) :
2019-06-20 11:11:44 +02:00
env . Append ( CCFLAGS = [ ' -Walloc-zero ' ,
2019-06-15 15:19:58 +02:00
' -Wduplicated-branches ' , ' -Wduplicated-cond ' ,
' -Wstringop-overflow=4 ' , ' -Wlogical-op ' ] )
2019-04-24 16:49:12 +02:00
env . Append ( CXXFLAGS = [ ' -Wnoexcept ' , ' -Wplacement-new=1 ' ] )
2020-02-26 13:23:37 +01:00
if version [ 0 ] > = 9 :
2019-04-24 16:49:12 +02:00
env . Append ( CCFLAGS = [ ' -Wattribute-alias=2 ' ] )
2018-10-02 14:37:31 +02:00
elif ( env [ " warnings " ] == ' all ' ) :
2019-02-21 20:57:39 +01:00
env . Append ( CCFLAGS = [ ' -Wall ' ] + shadow_local_warning )
2017-05-26 22:22:13 +02:00
elif ( env [ " warnings " ] == ' moderate ' ) :
2019-02-21 20:57:39 +01:00
env . Append ( CCFLAGS = [ ' -Wall ' , ' -Wno-unused ' ] + shadow_local_warning )
2017-05-26 22:22:13 +02:00
else : # 'no'
2017-03-25 08:36:00 +01:00
env . Append ( CCFLAGS = [ ' -w ' ] )
2018-10-03 13:38:09 +02:00
if ( env [ " werror " ] ) :
env . Append ( CCFLAGS = [ ' -Werror ' ] )
else : # always enable those errors
env . Append ( CCFLAGS = [ ' -Werror=return-type ' ] )
2014-10-07 06:31:49 +02:00
2018-10-25 15:59:26 +02:00
if ( hasattr ( detect , ' get_program_suffix ' ) ) :
suffix = " . " + detect . get_program_suffix ( )
else :
suffix = " . " + selected_platform
2014-10-07 06:31:49 +02:00
2016-10-30 18:57:40 +01:00
if ( env [ " target " ] == " release " ) :
2017-09-25 06:04:49 +02:00
if env [ " tools " ] :
2016-10-30 18:44:57 +01:00
print ( " Tools can only be built with targets ' debug ' and ' release_debug ' . " )
sys . exit ( 255 )
2016-10-30 18:57:40 +01:00
suffix + = " .opt "
2018-03-02 20:51:29 +01:00
env . Append ( CPPDEFINES = [ ' NDEBUG ' ] )
2016-10-30 18:44:57 +01:00
2016-10-30 18:57:40 +01:00
elif ( env [ " target " ] == " release_debug " ) :
2017-09-25 06:04:49 +02:00
if env [ " tools " ] :
2016-10-30 18:57:40 +01:00
suffix + = " .opt.tools "
2016-10-30 18:44:57 +01:00
else :
2016-10-30 18:57:40 +01:00
suffix + = " .opt.debug "
2016-10-30 18:44:57 +01:00
else :
2017-09-25 06:04:49 +02:00
if env [ " tools " ] :
2016-10-30 18:57:40 +01:00
suffix + = " .tools "
2016-10-30 18:44:57 +01:00
else :
2016-10-30 18:57:40 +01:00
suffix + = " .debug "
2016-10-30 18:44:57 +01:00
if env [ " arch " ] != " " :
2016-10-30 18:57:40 +01:00
suffix + = " . " + env [ " arch " ]
elif ( env [ " bits " ] == " 32 " ) :
suffix + = " .32 "
elif ( env [ " bits " ] == " 64 " ) :
suffix + = " .64 "
suffix + = env . extra_suffix
2019-02-10 15:22:31 +01:00
sys . path . remove ( tmppath )
2016-10-30 18:44:57 +01:00
sys . modules . pop ( ' detect ' )
2020-05-28 15:48:19 +02:00
modules_enabled = OrderedDict ( )
2019-06-28 22:42:26 +02:00
env . module_icons_paths = [ ]
2017-11-15 20:16:51 +01:00
env . doc_class_path = { }
2016-10-30 18:44:57 +01:00
2020-05-28 15:48:19 +02:00
for name , path in modules_detected . items ( ) :
2020-04-04 13:46:15 +02:00
if not env [ " module_ " + name + " _enabled " ] :
2016-10-30 18:44:57 +01:00
continue
2020-04-04 13:46:15 +02:00
sys . path . insert ( 0 , path )
env . current_module = name
2016-10-30 18:44:57 +01:00
import config
2018-05-30 19:11:33 +02:00
# can_build changed number of arguments between 3.0 (1) and 3.1 (2),
# so try both to preserve compatibility for 3.0 modules
can_build = False
try :
can_build = config . can_build ( env , selected_platform )
except TypeError :
print ( " Warning: module ' %s ' uses a deprecated `can_build` "
" signature in its config.py file, it should be "
" `can_build(env, platform)`. " % x )
can_build = config . can_build ( selected_platform )
if ( can_build ) :
2016-10-30 18:44:57 +01:00
config . configure ( env )
2019-06-28 22:42:26 +02:00
# Get doc classes paths (if present)
2017-09-14 14:34:53 +02:00
try :
2019-06-28 22:42:26 +02:00
doc_classes = config . get_doc_classes ( )
doc_path = config . get_doc_path ( )
for c in doc_classes :
2020-04-04 13:46:15 +02:00
env . doc_class_path [ c ] = path + " / " + doc_path
2017-09-14 14:34:53 +02:00
except :
pass
2019-06-28 22:42:26 +02:00
# Get icon paths (if present)
try :
icons_path = config . get_icons_path ( )
2020-04-04 13:46:15 +02:00
env . module_icons_paths . append ( path + " / " + icons_path )
2019-06-28 22:42:26 +02:00
except :
# Default path for module icons
2020-04-04 13:46:15 +02:00
env . module_icons_paths . append ( path + " / " + " icons " )
modules_enabled [ name ] = path
sys . path . remove ( path )
sys . modules . pop ( " config " )
2017-09-12 22:42:36 +02:00
2020-04-04 13:46:15 +02:00
env . module_list = modules_enabled
2016-10-30 18:44:57 +01:00
2017-11-02 03:12:28 +01:00
methods . update_version ( env . module_version_string )
2017-12-21 18:51:57 +01:00
env [ " PROGSUFFIX " ] = suffix + env . module_version_string + env [ " PROGSUFFIX " ]
2017-11-02 03:12:28 +01:00
env [ " OBJSUFFIX " ] = suffix + env [ " OBJSUFFIX " ]
2018-07-23 14:38:30 +02:00
# (SH)LIBSUFFIX will be used for our own built libraries
# LIBSUFFIXES contains LIBSUFFIX and SHLIBSUFFIX by default,
# so we need to append the default suffixes to keep the ability
2018-11-17 18:04:08 +01:00
# to link against thirdparty libraries (.a, .so, .lib, etc.).
if os . name == " nt " :
# On Windows, only static libraries and import libraries can be
# statically linked - both using .lib extension
env [ " LIBSUFFIXES " ] + = [ env [ " LIBSUFFIX " ] ]
else :
env [ " LIBSUFFIXES " ] + = [ env [ " LIBSUFFIX " ] , env [ " SHLIBSUFFIX " ] ]
2017-11-02 03:12:28 +01:00
env [ " LIBSUFFIX " ] = suffix + env [ " LIBSUFFIX " ]
env [ " SHLIBSUFFIX " ] = suffix + env [ " SHLIBSUFFIX " ]
2016-10-30 18:44:57 +01:00
if ( env . use_ptrcall ) :
2018-03-02 20:51:29 +01:00
env . Append ( CPPDEFINES = [ ' PTRCALL_ENABLED ' ] )
2017-09-25 06:04:49 +02:00
if env [ ' tools ' ] :
2018-03-02 20:51:29 +01:00
env . Append ( CPPDEFINES = [ ' TOOLS_ENABLED ' ] )
2017-09-25 06:04:49 +02:00
if env [ ' disable_3d ' ] :
2018-07-21 23:17:03 +02:00
if env [ ' tools ' ] :
print ( " Build option ' disable_3d=yes ' cannot be used with ' tools=yes ' (editor), only with ' tools=no ' (export template). " )
sys . exit ( 255 )
else :
env . Append ( CPPDEFINES = [ ' _3D_DISABLED ' ] )
2017-09-25 06:04:49 +02:00
if env [ ' gdscript ' ] :
2018-03-02 20:51:29 +01:00
env . Append ( CPPDEFINES = [ ' GDSCRIPT_ENABLED ' ] )
2017-09-25 06:04:49 +02:00
if env [ ' disable_advanced_gui ' ] :
2018-07-21 23:17:03 +02:00
if env [ ' tools ' ] :
print ( " Build option ' disable_advanced_gui=yes ' cannot be used with ' tools=yes ' (editor), only with ' tools=no ' (export template). " )
sys . exit ( 255 )
else :
env . Append ( CPPDEFINES = [ ' ADVANCED_GUI_DISABLED ' ] )
2017-09-25 06:04:49 +02:00
if env [ ' minizip ' ] :
2018-03-02 20:51:29 +01:00
env . Append ( CPPDEFINES = [ ' MINIZIP_ENABLED ' ] )
2016-10-30 18:44:57 +01:00
2019-08-11 19:07:59 +02:00
editor_module_list = [ ' regex ' ]
for x in editor_module_list :
if not env [ ' module_ ' + x + ' _enabled ' ] :
if env [ ' tools ' ] :
print ( " Build option ' module_ " + x + " _enabled=no ' cannot be used with ' tools=yes ' (editor), only with ' tools=no ' (export template). " )
sys . exit ( 255 )
2017-09-25 06:04:49 +02:00
if not env [ ' verbose ' ] :
2016-10-30 18:57:40 +01:00
methods . no_verbose ( sys , env )
2017-01-08 14:08:18 +01:00
2017-12-26 20:36:18 +01:00
if ( not env [ " platform " ] == " server " ) : # FIXME: detect GLES3
2018-03-17 23:23:55 +01:00
env . Append ( BUILDERS = { ' GLES3_GLSL ' : env . Builder ( action = run_in_subprocess ( gles_builders . build_gles3_headers ) , suffix = ' glsl.gen.h ' , src_suffix = ' .glsl ' ) } )
env . Append ( BUILDERS = { ' GLES2_GLSL ' : env . Builder ( action = run_in_subprocess ( gles_builders . build_gles2_headers ) , suffix = ' glsl.gen.h ' , src_suffix = ' .glsl ' ) } )
2016-10-30 18:44:57 +01:00
2017-11-26 02:47:54 +01:00
scons_cache_path = os . environ . get ( " SCONS_CACHE " )
if scons_cache_path != None :
CacheDir ( scons_cache_path )
print ( " Scons cache enabled... (path: ' " + scons_cache_path + " ' ) " )
2016-10-30 18:44:57 +01:00
Export ( ' env ' )
2016-10-30 18:57:40 +01:00
# build subdirs, the build order is dependent on link order.
2016-10-30 18:44:57 +01:00
SConscript ( " core/SCsub " )
SConscript ( " servers/SCsub " )
SConscript ( " scene/SCsub " )
2017-03-05 14:21:25 +01:00
SConscript ( " editor/SCsub " )
2016-10-30 18:44:57 +01:00
SConscript ( " drivers/SCsub " )
2017-11-16 01:33:48 +01:00
SConscript ( " platform/SCsub " )
2016-10-30 18:44:57 +01:00
SConscript ( " modules/SCsub " )
SConscript ( " main/SCsub " )
2016-11-01 00:24:30 +01:00
SConscript ( " platform/ " + selected_platform + " /SCsub " ) # build selected platform
2016-10-30 18:44:57 +01:00
# Microsoft Visual Studio Project Generation
2017-09-25 06:04:49 +02:00
if env [ ' vsproj ' ] :
2017-10-01 17:08:21 +02:00
env [ ' CPPPATH ' ] = [ Dir ( path ) for path in env [ ' CPPPATH ' ] ]
2017-08-28 17:17:26 +02:00
methods . generate_vs_project ( env , GetOption ( " num_jobs " ) )
2017-11-18 18:09:18 +01:00
methods . generate_cpp_hint_file ( " cpp.hint " )
2014-10-07 06:31:49 +02:00
2017-09-12 17:00:14 +02:00
# Check for the existence of headers
conf = Configure ( env )
if ( " check_c_headers " in env ) :
for header in env [ " check_c_headers " ] :
if ( conf . CheckCHeader ( header [ 0 ] ) ) :
2018-03-02 20:51:29 +01:00
env . AppendUnique ( CPPDEFINES = [ header [ 1 ] ] )
2017-09-12 17:00:14 +02:00
2019-05-26 19:05:31 +02:00
elif selected_platform != " " :
2019-07-17 11:25:57 +02:00
if selected_platform == " list " :
print ( " The following platforms are available: \n " )
else :
print ( ' Invalid target platform " ' + selected_platform + ' " . ' )
print ( " The following platforms were detected: \n " )
2014-02-10 02:10:30 +01:00
2016-10-30 18:44:57 +01:00
for x in platform_list :
2016-10-30 18:57:40 +01:00
print ( " \t " + x )
2019-07-17 11:25:57 +02:00
2019-05-26 19:05:31 +02:00
print ( " \n Please run SCons again and select a valid platform: platform=<string> " )
2017-07-08 11:39:07 +02:00
2019-07-17 11:25:57 +02:00
if selected_platform == " list " :
# Exit early to suppress the rest of the built-in SCons messages
sys . exit ( 0 )
else :
sys . exit ( 255 )
2018-03-14 14:42:43 +01:00
# The following only makes sense when the env is defined, and assumes it is
if ' env ' in locals ( ) :
screen = sys . stdout
# Progress reporting is not available in non-TTY environments since it
# messes with the output (for example, when writing to a file)
show_progress = ( env [ ' progress ' ] and sys . stdout . isatty ( ) )
node_count = 0
node_count_max = 0
node_count_interval = 1
2017-08-03 16:53:16 +02:00
node_count_fname = str ( env . Dir ( ' # ' ) ) + ' /.scons_node_count '
2018-03-14 14:42:43 +01:00
import time , math
class cache_progress :
# The default is 1 GB cache and 12 hours half life
def __init__ ( self , path = None , limit = 1073741824 , half_life = 43200 ) :
self . path = path
self . limit = limit
self . exponent_scale = math . log ( 2 ) / half_life
if env [ ' verbose ' ] and path != None :
screen . write ( ' Current cache limit is ' + self . convert_size ( limit ) + ' (used: ' + self . convert_size ( self . get_size ( path ) ) + ' ) \n ' )
self . delete ( self . file_list ( ) )
def __call__ ( self , node , * args , * * kw ) :
global node_count , node_count_max , node_count_interval , node_count_fname , show_progress
if show_progress :
# Print the progress percentage
node_count + = node_count_interval
if ( node_count_max > 0 and node_count < = node_count_max ) :
screen . write ( ' \r [ %3d %% ] ' % ( node_count * 100 / node_count_max ) )
screen . flush ( )
elif ( node_count_max > 0 and node_count > node_count_max ) :
screen . write ( ' \r [100 % ] ' )
screen . flush ( )
else :
screen . write ( ' \r [Initial build] ' )
screen . flush ( )
def delete ( self , files ) :
if len ( files ) == 0 :
return
if env [ ' verbose ' ] :
# Utter something
screen . write ( ' \r Purging %d %s from cache... \n ' % ( len ( files ) , len ( files ) > 1 and ' files ' or ' file ' ) )
[ os . remove ( f ) for f in files ]
def file_list ( self ) :
2018-10-27 01:18:15 +02:00
if self . path is None :
2018-03-14 14:42:43 +01:00
# Nothing to do
return [ ]
# Gather a list of (filename, (size, atime)) within the
# cache directory
file_stat = [ ( x , os . stat ( x ) [ 6 : 8 ] ) for x in glob . glob ( os . path . join ( self . path , ' * ' , ' * ' ) ) ]
if file_stat == [ ] :
# Nothing to do
return [ ]
# Weight the cache files by size (assumed to be roughly
# proportional to the recompilation time) times an exponential
# decay since the ctime, and return a list with the entries
# (filename, size, weight).
current_time = time . time ( )
file_stat = [ ( x [ 0 ] , x [ 1 ] [ 0 ] , ( current_time - x [ 1 ] [ 1 ] ) ) for x in file_stat ]
2019-05-19 12:34:40 +02:00
# Sort by the most recently accessed files (most sensible to keep) first
2018-03-14 14:42:43 +01:00
file_stat . sort ( key = lambda x : x [ 2 ] )
# Search for the first entry where the storage limit is
# reached
sum , mark = 0 , None
for i , x in enumerate ( file_stat ) :
sum + = x [ 1 ]
if sum > self . limit :
mark = i
break
2018-10-27 01:18:15 +02:00
if mark is None :
2018-03-14 14:42:43 +01:00
return [ ]
2017-11-27 14:39:05 +01:00
else :
2018-03-14 14:42:43 +01:00
return [ x [ 0 ] for x in file_stat [ mark : ] ]
def convert_size ( self , size_bytes ) :
if size_bytes == 0 :
return " 0 bytes "
size_name = ( " bytes " , " KB " , " MB " , " GB " , " TB " , " PB " , " EB " , " ZB " , " YB " )
i = int ( math . floor ( math . log ( size_bytes , 1024 ) ) )
p = math . pow ( 1024 , i )
s = round ( size_bytes / p , 2 )
return " %s %s " % ( int ( s ) if i == 0 else s , size_name [ i ] )
def get_size ( self , start_path = ' . ' ) :
total_size = 0
for dirpath , dirnames , filenames in os . walk ( start_path ) :
for f in filenames :
fp = os . path . join ( dirpath , f )
total_size + = os . path . getsize ( fp )
return total_size
def progress_finish ( target , source , env ) :
global node_count , progressor
with open ( node_count_fname , ' w ' ) as f :
f . write ( ' %d \n ' % node_count )
progressor . delete ( progressor . file_list ( ) )
try :
with open ( node_count_fname ) as f :
node_count_max = int ( f . readline ( ) )
except :
pass
cache_directory = os . environ . get ( " SCONS_CACHE " )
# Simple cache pruning, attached to SCons' progress callback. Trim the
# cache directory to a size not larger than cache_limit.
cache_limit = float ( os . getenv ( " SCONS_CACHE_LIMIT " , 1024 ) ) * 1024 * 1024
progressor = cache_progress ( cache_directory , cache_limit )
Progress ( progressor , interval = node_count_interval )
progress_finish_command = Command ( ' progress_finish ' , [ ] , progress_finish )
AlwaysBuild ( progress_finish_command )