IQ.Pilot Release Commit @ 0b96bd5

This commit is contained in:
IQ.Lvbs CI [bot]
2026-09-02 16:46:45 -05:00
parent 4fb3da761f
commit 7745f48100
162 changed files with 12835 additions and 9476 deletions

View File

@@ -1,97 +1,19 @@
import subprocess
import os
import shutil
import iqdbc
import sys
venv_site_packages = os.path.join(Dir("#").abspath, ".venv", "lib", "python3.12", "site-packages")
if os.path.isdir(venv_site_packages) and venv_site_packages not in sys.path:
sys.path.insert(0, venv_site_packages)
import imgui
import iqdbc
import libusb
from iqpilot.common.basedir import BASEDIR
Import('env', 'arch', 'common', 'messaging', 'visionipc', 'cereal', 'replay_lib', 'ffmpeg_libs')
# Detect Qt - skip build if not available
if arch == "Darwin":
try:
brew_prefix = subprocess.check_output(['brew', '--prefix'], encoding='utf8').strip()
has_qt = os.path.isdir(os.path.join(brew_prefix, "opt/qt@5"))
except (FileNotFoundError, subprocess.CalledProcessError):
has_qt = False
else:
has_qt = shutil.which('qmake') is not None
if not has_qt:
Return()
qt_env = env.Clone()
qt_modules = ["Widgets", "Gui", "Core"]
qt_libs = []
if arch == "Darwin":
qt_env['QTDIR'] = f"{brew_prefix}/opt/qt@5"
qt_dirs = [
os.path.join(qt_env['QTDIR'], "include"),
]
qt_dirs += [f"{qt_env['QTDIR']}/include/Qt{m}" for m in qt_modules]
qt_env["LINKFLAGS"] += ["-F" + os.path.join(qt_env['QTDIR'], "lib")]
qt_env["FRAMEWORKS"] += [f"Qt{m}" for m in qt_modules]
qt_env.AppendENVPath('PATH', os.path.join(qt_env['QTDIR'], "bin"))
else:
qt_install_prefix = subprocess.check_output(['qmake', '-query', 'QT_INSTALL_PREFIX'], encoding='utf8').strip()
qt_install_headers = subprocess.check_output(['qmake', '-query', 'QT_INSTALL_HEADERS'], encoding='utf8').strip()
qt_env['QTDIR'] = qt_install_prefix
qt_dirs = [
f"{qt_install_headers}",
]
qt_gui_path = os.path.join(qt_install_headers, "QtGui")
qt_gui_dirs = [d for d in os.listdir(qt_gui_path) if os.path.isdir(os.path.join(qt_gui_path, d))]
qt_dirs += [f"{qt_install_headers}/QtGui/{qt_gui_dirs[0]}/QtGui", ] if qt_gui_dirs else []
qt_dirs += [f"{qt_install_headers}/Qt{m}" for m in qt_modules]
qt_libs = [f"Qt5{m}" for m in qt_modules]
qt_env['QT3DIR'] = qt_env['QTDIR']
qt_env.Tool('qt3')
qt_env['CPPPATH'] += qt_dirs
qt_flags = [
"-D_REENTRANT",
"-DQT_NO_DEBUG",
"-DQT_WIDGETS_LIB",
"-DQT_GUI_LIB",
"-DQT_CORE_LIB",
"-DQT_MESSAGELOGCONTEXT",
]
qt_env['CXXFLAGS'] += qt_flags
qt_env['LIBPATH'] += ['#iqpilot/selfdrive/ui', ]
qt_env['LIBS'] = qt_libs
base_frameworks = qt_env['FRAMEWORKS']
base_libs = [common, messaging, cereal, visionipc, 'm', 'pthread'] + qt_env["LIBS"]
if arch == "Darwin":
base_frameworks += ['CoreFoundation', 'CoreVideo', 'CoreMedia', 'IOKit', 'Security', 'VideoToolbox']
cabana_env = qt_env.Clone()
cabana_env['CPPPATH'] += [libusb.INCLUDE_DIR]
cabana_env['LIBPATH'] += [libusb.LIB_DIR]
# IQ.Pilot patch: replay_lib fetches routes over libcurl and signs konn3kt JWTs with
# OpenSSL (tools/replay/api.cc), and visionipc references OpenCL — upstream gets all
# three transitively from its Python downloader / vendored wheels, we link them here.
cabana_libs = [cereal, messaging, visionipc, replay_lib] + ffmpeg_libs + \
['bz2', 'zstd', 'curl', 'ssl', 'crypto', 'usb-1.0'] + base_libs
if arch == "Darwin":
base_frameworks += ['OpenCL']
else:
cabana_libs += ['OpenCL']
opendbc_path = '-DOPENDBC_FILE_PATH=\'"%s"\'' % iqdbc.DBC_PATH
cabana_env['CXXFLAGS'] += [opendbc_path]
# embed the bootstrap icons SVG into the binary
def build_bootstrap_icons_src(target, source, env):
data = open(str(source[0]), 'rb').read()
with open(str(target[0]), 'w') as f:
@@ -100,48 +22,92 @@ def build_bootstrap_icons_src(target, source, env):
f.write('extern const size_t bootstrap_icons_svg_len;\n')
f.write('const unsigned char bootstrap_icons_svg[] = {\n')
for i in range(0, len(data), 32):
f.write(','.join(str(b) for b in data[i:i+32]) + ',\n')
f.write(','.join(str(b) for b in data[i:i + 32]) + ',\n')
f.write('};\n')
f.write('const size_t bootstrap_icons_svg_len = sizeof(bootstrap_icons_svg);\n')
return None
# IQ.Pilot patch: no comma-deps-bootstrap-icons wheel here; the SVG is checked in
# under third_party/bootstrap (see its pull.sh).
bootstrap_icons_src = cabana_env.Command('assets/bootstrap_icons.cc', '#iqpilot/third_party/bootstrap/bootstrap-icons.svg',
cabana_env.PrettyAction(build_bootstrap_icons_src, 'GEN'))
cabana_env = env.Clone()
cabana_env['CPPPATH'] += [imgui.INCLUDE_DIR, libusb.INCLUDE_DIR]
cabana_env['LIBPATH'] += [p for p in [imgui.MESA_DIR, libusb.LIB_DIR] if os.path.isdir(p)]
cabana_env['CXXFLAGS'] += [
opendbc_path,
"-DGLFW_INCLUDE_NONE",
'-DCABANA_FONTS_DIR=\'"%s"\'' % os.path.join(os.path.realpath(BASEDIR), "iqpilot", "selfdrive", "assets", "fonts"),
'-DBOOTSTRAP_ICONS_TTF=\'"%s"\'' % os.path.join(os.path.realpath(BASEDIR), "iqpilot", "tools", "jotpluggler", "assets", "bootstrap-icons.ttf"),
]
# build assets
assets = "assets/assets.cc"
cabana_env.Command(assets, "assets/assets.qrc", cabana_env.PrettyAction("rcc $SOURCES -o $TARGET", 'RCC'))
cabana_env.Depends(assets, Glob('/assets/*', exclude=[assets, "assets/assets.o"]))
bootstrap_icons_src = cabana_env.Command(
'ui/obj/bootstrap_icons.cc',
'#iqpilot/third_party/bootstrap/bootstrap-icons.svg',
cabana_env.PrettyAction(build_bootstrap_icons_src, 'GEN'),
)
cabana_srcs = ['mainwin.cc', 'streams/pandastream.cc', 'streams/devicestream.cc', 'streams/livestream.cc', 'streams/abstractstream.cc', 'streams/replaystream.cc', 'binaryview.cc', 'historylog.cc', 'videowidget.cc', 'signalview.cc',
'streams/routes.cc', 'dbc/dbc.cc', 'dbc/dbcfile.cc', 'dbc/dbcmanager.cc', 'dbc/dbcqt.cc',
'utils/export.cc', 'utils/util.cc', 'utils/elidedlabel.cc',
'chart/chartswidget.cc', 'chart/chart.cc', 'chart/signalselector.cc', 'chart/tiplabel.cc', 'chart/sparkline.cc',
'commands.cc', 'messageswidget.cc', 'streamselector.cc', 'settings.cc', 'panda.cc',
'cameraview.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc', 'tools/findsignal.cc', 'tools/routeinfo.cc']
core_srcs = [
'streams/pandastream.cc',
'streams/devicestream.cc',
'streams/livestream.cc',
'streams/abstractstream.cc',
'streams/replaystream.cc',
'dbc/dbc.cc',
'dbc/dbcfile.cc',
'dbc/dbcmanager.cc',
'utils/export.cc',
'utils/util.cc',
'utils/strings.cc',
'commands.cc',
'settings.cc',
'routes.cc',
'panda.cc',
]
if arch != "Darwin":
cabana_srcs += ['streams/socketcanstream.cc']
cabana_lib = cabana_env.Library("cabana_lib", cabana_srcs + [bootstrap_icons_src], LIBS=cabana_libs, FRAMEWORKS=base_frameworks)
cabana_env.Program('_cabana', ['cabana.cc', cabana_lib, assets], LIBS=cabana_libs, FRAMEWORKS=base_frameworks)
core_srcs += ['streams/socketcanstream.cc']
core_objects = [cabana_env.Object('ui/obj/' + src.replace('/', '_')[:-3], src) for src in core_srcs]
ui_objects = core_objects + [cabana_env.Object('ui/obj/bootstrap_icons', bootstrap_icons_src)]
ui_objects += cabana_env.Glob('ui/*.cc')
ui_objects += cabana_env.Glob('ui/widgets/*.cc')
ui_objects += cabana_env.Glob('ui/dialogs/*.cc')
ui_objects += cabana_env.Glob('ui/chart/*.cc')
ui_objects += cabana_env.Glob('ui/tools/*.cc')
cabana_libs = [
replay_lib,
common,
messaging,
visionipc,
cereal,
File(f"{imgui.LIB_DIR}/libimgui.a"),
File(f"{imgui.LIB_DIR}/libglfw3.a"),
] + ffmpeg_libs + ['bz2', 'zstd', 'curl', 'ssl', 'crypto', 'm', 'pthread', 'usb-1.0']
if arch == "Darwin":
cabana_env['FRAMEWORKS'] = ['OpenGL', 'OpenCL', 'Cocoa', 'IOKit', 'CoreFoundation', 'CoreVideo', 'CoreMedia', 'Security', 'VideoToolbox']
else:
cabana_libs += ['GL', 'OpenCL', 'dl']
cabana = cabana_env.Program('_cabana', ui_objects, LIBS=cabana_libs)
if GetOption('extras'):
# This target deliberately uses the base environment and links no Qt libraries.
# It prevents Qt dependencies from creeping back into the DBC core.
dbc_core_test_env = env.Clone()
dbc_core_test_env['CXXFLAGS'] += [opendbc_path]
dbc_core_test_objects = [
dbc_core_test_env.Object('tests/dbc_core_tests', 'tests/test_cabana.cc'),
dbc_core_test_env.Object('tests/dbc_core_model', 'dbc/dbc.cc'),
dbc_core_test_env.Object('tests/dbc_core_file', 'dbc/dbcfile.cc'),
dbc_core_test_env.Object('tests/dbc_core_manager', 'dbc/dbcmanager.cc'),
test_env = env.Clone()
test_env['CXXFLAGS'] += [opendbc_path]
test_objects = [
test_env.Object('tests/dbc_core_tests', 'tests/test_cabana.cc'),
test_env.Object('tests/dbc_core_model', 'dbc/dbc.cc'),
test_env.Object('tests/dbc_core_file', 'dbc/dbcfile.cc'),
test_env.Object('tests/dbc_core_manager', 'dbc/dbcmanager.cc'),
test_env.Object('tests/dbc_core_strings', 'utils/strings.cc'),
test_env.Object('tests/dbc_core_util', 'utils/util.cc'),
test_env.Object('tests/dbc_core_icons', bootstrap_icons_src),
test_env.Object('tests/dbc_core_routes', 'routes.cc'),
]
dbc_core_test_env.Program('tests/test_dbc_core', dbc_core_test_objects)
test_env.Program('tests/test_dbc_core', test_objects, LIBS=[replay_lib, common, 'curl', 'ssl', 'crypto'])
output_json_file = 'iqpilot/tools/cabana/dbc/car_fingerprint_to_dbc.json'
generate_dbc = cabana_env.Command('#' + output_json_file,
['dbc/generate_dbc_json.py'],
cabana_env.PrettyAction("python3 iqpilot/tools/cabana/dbc/generate_dbc_json.py --out " + output_json_file,
'GEN', logfile='${TARGET}.log'))
cabana_env.Depends(generate_dbc, ["#iqpilot/common", "#iqpilot/cereal"])
generate_dbc = cabana_env.Command(
'#' + output_json_file,
['dbc/generate_dbc_json.py'],
cabana_env.PrettyAction('"%s" iqpilot/tools/cabana/dbc/generate_dbc_json.py --out %s' % (sys.executable, output_json_file), 'GEN', logfile='${TARGET}.log'),
)
cabana_env.Depends(generate_dbc, ['#iqpilot/common', '#iqpilot/cereal', os.path.dirname(iqdbc.__file__)])
cabana_env.Depends(cabana, generate_dbc)