targets.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import os
  2. import subprocess
  3. import sys
  4. from SCons.Script import ARGUMENTS
  5. from SCons.Variables import *
  6. from SCons.Variables.BoolVariable import _text2bool
  7. # Helper methods
  8. def get_cmdline_bool(option, default):
  9. """We use `ARGUMENTS.get()` to check if options were manually overridden on the command line,
  10. and SCons' _text2bool helper to convert them to booleans, otherwise they're handled as strings.
  11. """
  12. cmdline_val = ARGUMENTS.get(option)
  13. if cmdline_val is not None:
  14. return _text2bool(cmdline_val)
  15. else:
  16. return default
  17. def using_clang(env):
  18. return "clang" in os.path.basename(env["CC"])
  19. def is_vanilla_clang(env):
  20. if not using_clang(env):
  21. return False
  22. try:
  23. version = subprocess.check_output([env.subst(env["CXX"]), "--version"]).strip().decode("utf-8")
  24. except (subprocess.CalledProcessError, OSError):
  25. print("Couldn't parse CXX environment variable to infer compiler version.")
  26. return False
  27. return not version.startswith("Apple")
  28. # Main tool definition
  29. def options(opts):
  30. opts.Add(
  31. EnumVariable(
  32. "optimize",
  33. "The desired optimization flags",
  34. "speed_trace",
  35. ("none", "custom", "debug", "speed", "speed_trace", "size"),
  36. )
  37. )
  38. opts.Add(BoolVariable("debug_symbols", "Build with debugging symbols", True))
  39. opts.Add(BoolVariable("dev_build", "Developer build with dev-only debugging code (DEV_ENABLED)", False))
  40. def exists(env):
  41. return True
  42. def generate(env):
  43. # Configuration of build targets:
  44. # - Editor or template
  45. # - Debug features (DEBUG_ENABLED code)
  46. # - Dev only code (DEV_ENABLED code)
  47. # - Optimization level
  48. # - Debug symbols for crash traces / debuggers
  49. # Keep this configuration in sync with SConstruct in upstream Godot.
  50. env.editor_build = env["target"] == "editor"
  51. env.dev_build = env["dev_build"]
  52. env.debug_features = env["target"] in ["editor", "template_debug"]
  53. if env.dev_build:
  54. opt_level = "none"
  55. elif env.debug_features:
  56. opt_level = "speed_trace"
  57. else: # Release
  58. opt_level = "speed"
  59. env["optimize"] = ARGUMENTS.get("optimize", opt_level)
  60. env["debug_symbols"] = get_cmdline_bool("debug_symbols", env.dev_build)
  61. if env.editor_build:
  62. env.Append(CPPDEFINES=["TOOLS_ENABLED"])
  63. if env.debug_features:
  64. # DEBUG_ENABLED enables debugging *features* and debug-only code, which is intended
  65. # to give *users* extra debugging information for their game development.
  66. env.Append(CPPDEFINES=["DEBUG_ENABLED"])
  67. # In upstream Godot this is added in typedefs.h when DEBUG_ENABLED is set.
  68. env.Append(CPPDEFINES=["DEBUG_METHODS_ENABLED"])
  69. if env.dev_build:
  70. # DEV_ENABLED enables *engine developer* code which should only be compiled for those
  71. # working on the engine itself.
  72. env.Append(CPPDEFINES=["DEV_ENABLED"])
  73. else:
  74. # Disable assert() for production targets (only used in thirdparty code).
  75. env.Append(CPPDEFINES=["NDEBUG"])
  76. # Set optimize and debug_symbols flags.
  77. # "custom" means do nothing and let users set their own optimization flags.
  78. if env.get("is_msvc", False):
  79. if env["debug_symbols"]:
  80. env.Append(CCFLAGS=["/Zi", "/FS"])
  81. env.Append(LINKFLAGS=["/DEBUG:FULL"])
  82. if env["optimize"] == "speed":
  83. env.Append(CCFLAGS=["/O2"])
  84. env.Append(LINKFLAGS=["/OPT:REF"])
  85. elif env["optimize"] == "speed_trace":
  86. env.Append(CCFLAGS=["/O2"])
  87. env.Append(LINKFLAGS=["/OPT:REF", "/OPT:NOICF"])
  88. elif env["optimize"] == "size":
  89. env.Append(CCFLAGS=["/O1"])
  90. env.Append(LINKFLAGS=["/OPT:REF"])
  91. elif env["optimize"] == "debug" or env["optimize"] == "none":
  92. env.Append(CCFLAGS=["/Od"])
  93. else:
  94. if env["debug_symbols"]:
  95. # Adding dwarf-4 explicitly makes stacktraces work with clang builds,
  96. # otherwise addr2line doesn't understand them.
  97. env.Append(CCFLAGS=["-gdwarf-4"])
  98. if env.dev_build:
  99. env.Append(CCFLAGS=["-g3"])
  100. else:
  101. env.Append(CCFLAGS=["-g2"])
  102. else:
  103. if using_clang(env) and not is_vanilla_clang(env):
  104. # Apple Clang, its linker doesn't like -s.
  105. env.Append(LINKFLAGS=["-Wl,-S", "-Wl,-x", "-Wl,-dead_strip"])
  106. else:
  107. env.Append(LINKFLAGS=["-s"])
  108. if env["optimize"] == "speed":
  109. env.Append(CCFLAGS=["-O3"])
  110. # `-O2` is friendlier to debuggers than `-O3`, leading to better crash backtraces.
  111. elif env["optimize"] == "speed_trace":
  112. env.Append(CCFLAGS=["-O2"])
  113. elif env["optimize"] == "size":
  114. env.Append(CCFLAGS=["-Os"])
  115. elif env["optimize"] == "debug":
  116. env.Append(CCFLAGS=["-Og"])
  117. elif env["optimize"] == "none":
  118. env.Append(CCFLAGS=["-O0"])