mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-06-08 11:25:51 +08:00
* Reapply "modeld: split warp" (#38085)
This reverts commit d489dd8909.
* don't time make_random_inputs
* depend on chunk targets
* also depend on compile_modeld's dependencies
299 lines
8.7 KiB
Python
299 lines
8.7 KiB
Python
import os
|
|
import subprocess
|
|
import sys
|
|
import sysconfig
|
|
import platform
|
|
import shlex
|
|
import importlib
|
|
import numpy as np
|
|
|
|
import SCons.Errors
|
|
from SCons.Defaults import _stripixes
|
|
|
|
TICI = os.path.isfile('/TICI')
|
|
|
|
SCons.Warnings.warningAsException(True)
|
|
|
|
Decider('MD5-timestamp')
|
|
|
|
SetOption('num_jobs', max(1, int(os.cpu_count()/(1 if "CI" in os.environ else 2))))
|
|
|
|
AddOption('--ccflags', action='store', type='string', default='', help='pass arbitrary flags over the command line')
|
|
AddOption('--verbose', action='store_true', default=False, help='show full build commands')
|
|
release = not os.path.exists(File('#.gitattributes').abspath) # file absent on release branch, see release_files.py
|
|
AddOption('--minimal',
|
|
action='store_false',
|
|
dest='extras',
|
|
default=(not TICI and not release),
|
|
help='the minimum build to run openpilot. no tests, tools, etc.')
|
|
|
|
# Detect platform
|
|
arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip()
|
|
if platform.system() == "Darwin":
|
|
arch = "Darwin"
|
|
elif arch == "aarch64" and TICI:
|
|
arch = "larch64"
|
|
assert arch in [
|
|
"larch64", # linux tici arm64
|
|
"aarch64", # linux pc arm64
|
|
"x86_64", # linux pc x64
|
|
"Darwin", # macOS arm64 (x86 not supported)
|
|
]
|
|
|
|
pkg_names = ['acados', 'bzip2', 'capnproto', 'catch2', 'eigen', 'ffmpeg', 'json11', 'libjpeg', 'libyuv', 'ncurses', 'zeromq', 'zstd']
|
|
pkgs = [importlib.import_module(name) for name in pkg_names]
|
|
acados = pkgs[pkg_names.index('acados')]
|
|
acados_include_dirs = [
|
|
acados.INCLUDE_DIR,
|
|
os.path.join(acados.INCLUDE_DIR, "blasfeo", "include"),
|
|
os.path.join(acados.INCLUDE_DIR, "hpipm", "include"),
|
|
]
|
|
|
|
|
|
# ***** enforce a whitelist of system libraries *****
|
|
# this prevents silently relying on a 3rd party package,
|
|
# e.g. apt-installed libusb. all libraries should either
|
|
# be distributed with all Linux distros and macOS, or
|
|
# vendored in commaai/dependencies.
|
|
allowed_system_libs = {
|
|
"EGL", "GLESv2", "GL",
|
|
"Qt5Charts", "Qt5Core", "Qt5Gui", "Qt5Widgets",
|
|
"dl", "drm", "gbm", "m", "pthread",
|
|
}
|
|
|
|
def _resolve_lib(env, name):
|
|
for d in env.Flatten(env.get('LIBPATH', [])):
|
|
p = Dir(str(d)).abspath
|
|
for ext in ('.a', '.so', '.dylib'):
|
|
f = File(os.path.join(p, f'lib{name}{ext}'))
|
|
if f.exists() or f.has_builder():
|
|
return name
|
|
if name in allowed_system_libs:
|
|
return name
|
|
raise SCons.Errors.UserError(f"Unexpected non-vendored library '{name}'")
|
|
|
|
def _libflags(target, source, env, for_signature):
|
|
libs = []
|
|
lp = env.subst('$LIBLITERALPREFIX')
|
|
for lib in env.Flatten(env.get('LIBS', [])):
|
|
if isinstance(lib, str):
|
|
if os.sep in lib or lib.startswith('#'):
|
|
libs.append(File(lib))
|
|
elif lib.startswith('-') or (lp and lib.startswith(lp)):
|
|
libs.append(lib)
|
|
else:
|
|
libs.append(_resolve_lib(env, lib))
|
|
else:
|
|
libs.append(lib)
|
|
return _stripixes(env['LIBLINKPREFIX'], libs, env['LIBLINKSUFFIX'],
|
|
env['LIBPREFIXES'], env['LIBSUFFIXES'], env, env['LIBLITERALPREFIX'])
|
|
|
|
env = Environment(
|
|
ENV={
|
|
"PATH": os.environ['PATH'],
|
|
"PYTHONPATH": Dir("#").abspath,
|
|
"ACADOS_SOURCE_DIR": acados.DIR,
|
|
"ACADOS_PYTHON_INTERFACE_PATH": acados.TEMPLATE_DIR,
|
|
"TERA_PATH": acados.TERA_PATH
|
|
},
|
|
CCFLAGS=[
|
|
"-g",
|
|
"-fPIC",
|
|
"-O2",
|
|
"-Wunused",
|
|
"-Werror",
|
|
"-Wshadow" if arch in ("Darwin", "larch64") else "-Wshadow=local",
|
|
"-Wno-unknown-warning-option",
|
|
"-Wno-inconsistent-missing-override",
|
|
"-Wno-c99-designator",
|
|
"-Wno-reorder-init-list",
|
|
"-Wno-vla-cxx-extension",
|
|
],
|
|
CFLAGS=["-std=gnu11"],
|
|
CXXFLAGS=["-std=c++1z"],
|
|
CPPPATH=[
|
|
"#",
|
|
"#msgq",
|
|
acados_include_dirs,
|
|
[x.INCLUDE_DIR for x in pkgs],
|
|
],
|
|
LIBPATH=[
|
|
"#common",
|
|
"#msgq_repo",
|
|
"#selfdrive/pandad",
|
|
"#rednose/helpers",
|
|
[x.LIB_DIR for x in pkgs],
|
|
],
|
|
RPATH=[],
|
|
CYTHONCFILESUFFIX=".cpp",
|
|
COMPILATIONDB_USE_ABSPATH=True,
|
|
REDNOSE_ROOT="#",
|
|
tools=["default", "cython", "compilation_db", "rednose_filter"],
|
|
toolpath=["#site_scons/site_tools", "#rednose_repo/site_scons/site_tools"],
|
|
)
|
|
if arch != "larch64":
|
|
env['_LIBFLAGS'] = _libflags
|
|
|
|
# Arch-specific flags and paths
|
|
if arch == "larch64":
|
|
env["CC"] = "clang"
|
|
env["CXX"] = "clang++"
|
|
env.Append(LIBPATH=[
|
|
"/usr/lib/aarch64-linux-gnu",
|
|
])
|
|
arch_flags = ["-D__TICI__", "-mcpu=cortex-a57"]
|
|
env.Append(CCFLAGS=arch_flags)
|
|
env.Append(CXXFLAGS=arch_flags)
|
|
elif arch == "Darwin":
|
|
env.Append(LIBPATH=[
|
|
"/System/Library/Frameworks/OpenGL.framework/Libraries",
|
|
])
|
|
env.Append(CCFLAGS=["-DGL_SILENCE_DEPRECATION"])
|
|
env.Append(CXXFLAGS=["-DGL_SILENCE_DEPRECATION"])
|
|
|
|
_extra_cc = shlex.split(GetOption('ccflags') or '')
|
|
if _extra_cc:
|
|
env.Append(CCFLAGS=_extra_cc)
|
|
|
|
# no --as-needed on mac linker
|
|
if arch != "Darwin":
|
|
env.Append(LINKFLAGS=["-Wl,--as-needed", "-Wl,--no-undefined"])
|
|
|
|
# Shorter build output: show brief descriptions instead of full commands.
|
|
# Full command lines are still printed on failure by scons.
|
|
if not GetOption('verbose'):
|
|
for action, short in (
|
|
("CC", "CC"),
|
|
("CXX", "CXX"),
|
|
("LINK", "LINK"),
|
|
("SHCC", "CC"),
|
|
("SHCXX", "CXX"),
|
|
("SHLINK", "LINK"),
|
|
("AR", "AR"),
|
|
("RANLIB", "RANLIB"),
|
|
("AS", "AS"),
|
|
):
|
|
env[f"{action}COMSTR"] = f" [{short}] $TARGET"
|
|
|
|
# ********** Cython build environment **********
|
|
envCython = env.Clone()
|
|
envCython["CPPPATH"] += [sysconfig.get_paths()['include'], np.get_include()]
|
|
envCython["CCFLAGS"] += ["-Wno-#warnings", "-Wno-cpp", "-Wno-shadow", "-Wno-deprecated-declarations"]
|
|
envCython["CCFLAGS"].remove("-Werror")
|
|
|
|
envCython["LIBS"] = []
|
|
if arch == "Darwin":
|
|
envCython["LINKFLAGS"] = env["LINKFLAGS"] + ["-bundle", "-undefined", "dynamic_lookup"]
|
|
else:
|
|
envCython["LINKFLAGS"] = ["-pthread", "-shared"]
|
|
|
|
np_version = SCons.Script.Value(np.__version__)
|
|
Export('envCython', 'np_version')
|
|
|
|
Export('env', 'arch', 'acados')
|
|
|
|
# Setup cache dir
|
|
cache_dir = '/data/scons_cache' if arch == "larch64" else '/tmp/scons_cache'
|
|
cache_size_limit = 4e9 if "CI" in os.environ else 2e9
|
|
CacheDir(cache_dir)
|
|
Clean(["."], cache_dir)
|
|
|
|
def prune_cache_dir(target=None, source=None, env=None):
|
|
cache_files = sorted((os.path.join(root, f) for root, _, files in os.walk(cache_dir) for f in files), key=os.path.getmtime)
|
|
cache_size = sum(os.path.getsize(f) for f in cache_files)
|
|
for f in cache_files:
|
|
if cache_size < cache_size_limit:
|
|
break
|
|
cache_size -= os.path.getsize(f)
|
|
os.unlink(f)
|
|
|
|
# ********** start building stuff **********
|
|
|
|
# Build common module
|
|
SConscript(['common/SConscript'])
|
|
Import('_common')
|
|
common = [_common, 'json11', 'zmq']
|
|
Export('common')
|
|
|
|
# Build messaging (cereal + msgq + socketmaster + their dependencies)
|
|
# Enable swaglog include in submodules
|
|
env_swaglog = env.Clone()
|
|
env_swaglog['CXXFLAGS'].append('-DSWAGLOG="\\"common/swaglog.h\\""')
|
|
SConscript(['msgq_repo/SConscript'], exports={'env': env_swaglog})
|
|
|
|
SConscript(['cereal/SConscript'])
|
|
|
|
Import('socketmaster', 'msgq')
|
|
messaging = [socketmaster, msgq, 'capnp', 'kj',]
|
|
Export('messaging')
|
|
|
|
|
|
# Build other submodules
|
|
SConscript(['panda/SConscript'])
|
|
|
|
# Build rednose library
|
|
SConscript(['rednose/SConscript'])
|
|
|
|
# Build system services
|
|
SConscript([
|
|
'system/loggerd/SConscript',
|
|
])
|
|
|
|
if arch == "larch64":
|
|
SConscript(['system/camerad/SConscript'])
|
|
|
|
# Build selfdrive
|
|
SConscript([
|
|
'selfdrive/pandad/SConscript',
|
|
'selfdrive/controls/lib/lateral_mpc_lib/SConscript',
|
|
'selfdrive/controls/lib/longitudinal_mpc_lib/SConscript',
|
|
'selfdrive/locationd/SConscript',
|
|
'selfdrive/modeld/SConscript',
|
|
'selfdrive/ui/SConscript',
|
|
])
|
|
|
|
# Build desktop-only tools
|
|
if GetOption('extras') and arch != "larch64":
|
|
SConscript([
|
|
'tools/replay/SConscript',
|
|
'tools/cabana/SConscript',
|
|
'tools/jotpluggler/SConscript',
|
|
])
|
|
|
|
|
|
env.CompilationDatabase('compile_commands.json')
|
|
|
|
# progress output
|
|
def count_scons_nodes(nodes):
|
|
seen = set()
|
|
stack = list(nodes)
|
|
|
|
while stack:
|
|
node = stack.pop().disambiguate()
|
|
if node in seen:
|
|
continue
|
|
seen.add(node)
|
|
executor = node.get_executor()
|
|
if executor is not None:
|
|
stack += executor.get_all_prerequisites() + executor.get_all_children()
|
|
|
|
return len(seen)
|
|
|
|
progress_interval = 5
|
|
progress_count = 0
|
|
progress_total = max(1, count_scons_nodes(env.arg2nodes(BUILD_TARGETS or [Dir('.')], env.fs.Entry)))
|
|
|
|
def progress_function(node):
|
|
global progress_count
|
|
if progress_count >= progress_total:
|
|
return
|
|
progress_count = min(progress_count + progress_interval, progress_total)
|
|
progress = round(100. * progress_count / progress_total, 1)
|
|
sys.stderr.write("\rBuilding: %5.1f%%" % progress if sys.stderr.isatty() else "progress: %.1f\n" % progress)
|
|
if progress == 100. and sys.stderr.isatty():
|
|
sys.stderr.write("\n")
|
|
sys.stderr.flush()
|
|
|
|
Progress(progress_function, interval=progress_interval)
|
|
AddPostAction(BUILD_TARGETS or [Dir('.')], prune_cache_dir)
|