Build with LTO automatically (#691)
Add a new mode to "automatically" build with LTO.
Specifically when the most recent commit in emscripten-releases modifies the
emscripten-version.txt file, build with LTO.
The use-lto flag can be set to "auto" for this behavior, or true or false.
diff --git a/src/build.py b/src/build.py
index bf4a8aa..cb8ca9c 100755
--- a/src/build.py
+++ b/src/build.py
@@ -48,6 +48,7 @@
CMAKE_TOOLCHAIN_FILE = 'Wasi.cmake'
EMSCRIPTEN_CONFIG_UPSTREAM = 'emscripten_config_upstream'
+EMSCRIPTEN_VERSION_FILE = 'emscripten-version.txt'
# Avoid flakes: use cached repositories to avoid relying on external network.
GIT_MIRROR_BASE = 'https://chromium.googlesource.com/'
@@ -271,6 +272,19 @@
GCC_REVISION = 'b6125c702850488ac3bfb1079ae5c9db89989406'
GCC_CLONE_DEPTH = 1000
+g_should_use_lto = None
+
+
+def ShouldUseLTO():
+ if options.use_lto == 'auto':
+ # Avoid shelling out to git (via RevisionModifiesFile) more than once.
+ global g_should_use_lto
+ if g_should_use_lto is None:
+ g_should_use_lto = RevisionModifiesFile(
+ GetSrcDir(EMSCRIPTEN_VERSION_FILE))
+ return g_should_use_lto
+ return options.use_lto == 'true'
+
def CopyBinaryToArchive(binary, prefix=''):
"""All binaries are archived in the same tar file."""
@@ -524,6 +538,18 @@
print()
+def RevisionModifiesFile(f):
+ # TODO: There's probably some nice single-command way to do this.
+ if not os.path.isfile(f):
+ return False
+ cwd = os.path.dirname(f)
+ head_rev = proc.check_output(['git', 'rev-parse', 'HEAD'], cwd=cwd).strip()
+ last_rev = proc.check_output(
+ ['git', 'rev-list', '-n1', 'HEAD', f], cwd=cwd).strip()
+ print('Last rev modifying %s is %s, HEAD is %s' % (f, last_rev, head_rev))
+ return head_rev == last_rev
+
+
def ChromiumFetchSync(name, work_dir, git_repo,
checkout=RemoteBranch('master')):
"""Some Chromium projects want to use gclient for clone and
@@ -887,7 +913,7 @@
buildbot.Step('LLVM')
Mkdir(build_dir)
cc_env = BuildEnv(build_dir, bin_subdir=True)
- build_dylib = 'ON' if not IsWindows() and not options.use_lto else 'OFF'
+ build_dylib = 'ON' if not IsWindows() and not ShouldUseLTO() else 'OFF'
command = CMakeCommandNative([
GetLLVMSrcDir('llvm'),
'-DCMAKE_CXX_FLAGS=-Wno-nonportable-include-path',
@@ -914,7 +940,7 @@
command.append('-DLLVM_ENABLE_LLD=ON')
ninja_targets = ('all', 'install')
- if options.use_lto:
+ if ShouldUseLTO():
targets = ['clang', 'lld', 'llvm-ar', 'llvm-addr2line', 'llvm-cxxfilt',
'llvm-dwarfdump', 'llvm-dwp', 'llvm-nm', 'llvm-objcopy',
'llvm-objdump', 'llvm-ranlib', 'llvm-readobj', 'llvm-size',
@@ -1082,7 +1108,7 @@
cmake_command = CMakeCommandNative([GetSrcDir('binaryen')], build_dir)
cmake_command.append('-DBYN_INSTALL_TOOLS_ONLY=ON')
- if options.use_lto:
+ if ShouldUseLTO():
cmake_command.append('-DBUILD_STATIC_LIB=ON')
cmake_command.append('-DBYN_ENABLE_LTO=ON')
@@ -1123,6 +1149,13 @@
native = 'google-closure-compiler-linux'
proc.check_call(['npm', 'install', native], cwd=em_install_dir)
+ version_file = GetSrcDir(EMSCRIPTEN_VERSION_FILE)
+ if os.path.isfile(version_file):
+ with open(version_file) as f:
+ print('Copying emscripten version file (version %s)' %
+ f.read().strip())
+ shutil.copy2(version_file, em_install_dir)
+
def Emscripten():
InstallEmscripten()
@@ -1439,7 +1472,7 @@
# When using LTO we always want a clean build (the previous
# build was non-LTO)
- if self.incremental_build_dir and options.use_lto:
+ if self.incremental_build_dir and ShouldUseLTO():
RemoveIfBot(self.incremental_build_dir)
try:
self.runnable(*self.args, **self.kwargs)
@@ -1452,7 +1485,7 @@
finally:
# When using LTO we want to always clean up afterward,
# (the next build will be non-LTO).
- if self.incremental_build_dir and options.use_lto:
+ if self.incremental_build_dir and ShouldUseLTO():
RemoveIfBot(self.incremental_build_dir)
@@ -1848,7 +1881,8 @@
'--clobber', dest='clobber', default=False, action='store_true',
help="Delete working directories, forcing a clean build")
parser.add_argument(
- '--use-lto', dest='use_lto', default=False, action='store_true',
+ '--use-lto', dest='use_lto', default=False, action='store',
+ choices=['true', 'false', 'auto'],
help='Use extra optimization for host binaries')
return parser.parse_args()
@@ -1938,7 +1972,7 @@
if not options.use_sysroot:
host_toolchains.SetUseSysroot(False)
- if options.use_lto and IsMac():
+ if ShouldUseLTO() and IsMac():
# The prebuilt clang on mac doesn't include libLTO, so use the SDK
host_toolchains.SetForceHostClang(False)