carla/Configure.py

961 lines
30 KiB
Python
Raw Normal View History

2023-10-28 07:21:01 +08:00
from concurrent.futures import ProcessPoolExecutor, as_completed
from argparse import ArgumentParser
from pathlib import Path
2023-11-15 03:48:24 +08:00
import subprocess, tarfile, zipfile, requests, psutil, shutil, glob, json, sys, os
FORCE_SEQUENTIAL = False
2023-11-18 06:18:00 +08:00
CARLA_VERSION_MAJOR = 0
CARLA_VERSION_MINOR = 9
CARLA_VERSION_PATCH = 14
CARLA_VERSION_STRING = f'{CARLA_VERSION_MAJOR}.{CARLA_VERSION_MINOR}.{CARLA_VERSION_PATCH}'
# Basic paths
WORKSPACE_PATH = Path(__file__).parent.resolve()
LIBCARLA_ROOT_PATH = WORKSPACE_PATH / 'LibCarla'
PYTHON_API_PATH = WORKSPACE_PATH / 'PythonAPI'
EXAMPLES_PATH = WORKSPACE_PATH / 'Examples'
BUILD_PATH = WORKSPACE_PATH / 'Build'
LIBCARLA_INSTALL_PATH = BUILD_PATH
DEPENDENCIES_PATH = BUILD_PATH / 'Dependencies'
DIST_PATH = WORKSPACE_PATH / 'Dist'
UTIL_PATH = WORKSPACE_PATH / 'Util'
DOCKER_UTILS_PATH = UTIL_PATH / 'DockerUtils'
BUILD_TOOLS_PATH = UTIL_PATH / 'BuildTools'
# UE plugin
CARLA_UE_PATH = WORKSPACE_PATH / 'Unreal' / 'CarlaUE4'
CARLA_UE_PLUGIN_ROOT_PATH = CARLA_UE_PATH / 'Plugins'
CARLA_UE_PLUGIN_PATH = CARLA_UE_PLUGIN_ROOT_PATH / 'Carla'
CARLA_UE_PLUGIN_DEPENDENCIES_PATH = CARLA_UE_PLUGIN_ROOT_PATH / 'CarlaDependencies'
# PythonAPI
PYTHON_API_SOURCE_PATH = PYTHON_API_PATH / 'carla'
# LibCarla
LIBCARLA_BUILD_PATH = BUILD_PATH
LIBCARLA_TEST_CONTENT_PATH = BUILD_PATH / 'test-content'
# Misc
TEST_RESULTS_PATH = BUILD_PATH / 'test-results'
LIBSTDCPP_TOOLCHAIN_PATH = BUILD_PATH / 'LibStdCppToolChain.cmake'
LIBCPP_TOOLCHAIN_PATH = BUILD_PATH / 'LibCppToolChain.cmake'
EXE_EXT = '.exe' if os.name == 'nt' else ''
LIB_EXT = '.lib' if os.name == 'nt' else '.a'
OBJ_EXT = '.obj' if os.name == 'nt' else '.o'
SHELL_EXT = '.bat' if os.name == 'nt' else ''
# Unreal Engine
UE_WORKSPACE_PATH = Path(os.getenv('UE4_ROOT', ''))
if not UE_WORKSPACE_PATH.exists():
print('Could not find Unreal Engine workspace. Please set the environment variable UE4_ROOT as specified in the docs.')
exit(-1)
# Omniverse
NV_OMNIVERSE_PLUGIN_PATH = UE_WORKSPACE_PATH / 'Engine' / 'Plugins' / 'Marketplace' / 'NVIDIA' / 'Omniverse'
NV_OMNIVERSE_PATCH_PATH = UTIL_PATH / 'Patches' / 'omniverse_4.26'
# Script settings
DEFAULT_PARALLELISM = psutil.cpu_count(logical = True)
CMAKE_GENERATOR = 'Ninja'
# Script types
class Download:
def __init__(self, url):
self.url = url
class GitRepository:
def __init__(self, url, tag : str = None):
self.url = url
self.tag = tag
class Dependency:
def __init__(
self,
name : str,
*sources):
self.name = name
self.sources = [ e for e in sources ]
assert all(type(e) is Download or type(e) is GitRepository for e in self.sources)
class Task:
def __init__(
self,
name : str,
in_edges : list,
body,
*args):
self.name = name
self.body = body
self.args = args
self.in_edges = in_edges
self.out_edges = [] # Filled right before task graph execution.
def CreateSubprocessTask(name : str, in_edges : list, command : list):
return Task(name, in_edges, LaunchSubprocessImmediate, command)
def CreateCMakeConfigureDefault(
name : str,
in_edges : list,
source_path : Path,
build_path : Path,
2023-11-18 06:18:00 +08:00
*args,
install_path : Path = None):
cmd = [
'cmake',
'-G', CMAKE_GENERATOR,
'-S', source_path,
'-B', build_path,
2023-11-22 00:32:55 +08:00
'-DCMAKE_C_COMPILER=' + C_COMPILER,
'-DCMAKE_CXX_COMPILER=' + CPP_COMPILER,
'-DCMAKE_BUILD_TYPE=Release',
2023-11-18 06:18:00 +08:00
'-DCMAKE_CXX_FLAGS_RELEASE="/MD"',
]
2023-11-18 06:18:00 +08:00
if install_path != None:
cmd.append('-DCMAKE_INSTALL_PREFIX=' + str(install_path))
cmd.extend([ *args ])
cmd.append(source_path)
return Task.CreateSubprocessTask(name, in_edges, cmd)
def CreateCMakeBuildDefault(
name : str,
in_edges : list,
build_path : Path,
*args):
cmd = [ 'cmake', '--build', build_path ]
cmd.extend([ *args ])
return Task.CreateSubprocessTask(name, in_edges, cmd)
def CreateCMakeInstallDefault(
name : str,
in_edges : list,
build_path : Path,
install_path : Path,
*args):
cmd = [ 'cmake', '--install', build_path, '--prefix', install_path ]
cmd.extend([ *args ])
return Task.CreateSubprocessTask(name, in_edges, cmd)
def Run(self):
self.body(*self.args)
class TaskGraph:
def __init__(self, parallelism : int = None):
self.sequential = FORCE_SEQUENTIAL
self.pool = ProcessPoolExecutor(parallelism)
self.futures = []
self.tasks = []
self.sources = []
self.task_map = {}
def Reset(self):
self.futures = []
self.tasks = []
self.sources = []
self.task_map = {}
def Add(self, task):
self.tasks.append(task)
if len(task.in_edges) == 0:
self.sources.append(task.name)
self.task_map[task.name] = self.tasks[-1]
2023-11-22 00:32:55 +08:00
def Validate(self):
return True
2023-11-18 06:18:00 +08:00
def Execute(self, sequential : bool = False):
2023-11-22 00:32:55 +08:00
assert self.Validate()
2023-11-18 06:18:00 +08:00
prior_sequential = self.sequential
try:
self.sequential = sequential
2023-11-22 00:32:55 +08:00
done = {}
todo = self.sources
while len(done) != self.tasks:
for e in todo:
if not self.sequential:
self.futures.append(self.pool.submit(task.Run))
else:
task.Run()
2023-11-18 06:18:00 +08:00
for e in self.tasks:
for in_edge in e.in_edges:
self.task_map[in_edge].out_edges.append(e)
for e in self.sources:
task = self.task_map.get(e, None)
assert task != None and type(task) is Task
2023-11-22 00:32:55 +08:00
Log(f'Running "{task.name}".')
if not self.sequential:
2023-11-22 00:32:55 +08:00
return [ e.result() for e in as_completed(self.futures) ]
2023-11-18 06:18:00 +08:00
finally:
self.sequential = prior_sequential
self.Reset()
class Context:
def __init__(self, args, parallelism):
self.task_graph = TaskGraph(parallelism)
self.args = args
pass
# Constants:
DEFAULT_DEPENDENCIES = [
Dependency(
'boost',
Download('https://boostorg.jfrog.io/artifactory/main/release/1.83.0/source/boost_1_83_0.zip'),
Download('https://carla-releases.s3.eu-west-3.amazonaws.com/Backup/boost_1_83_0.zip')),
Dependency(
'eigen',
GitRepository('https://gitlab.com/libeigen/eigen.git', tag = '3.4.0')),
Dependency(
'libpng',
GitRepository('https://github.com/glennrp/libpng.git', tag = 'v1.6.40')),
Dependency(
'proj',
GitRepository('https://github.com/OSGeo/PROJ.git', tag = '9.3.0'),
Download('https://download.osgeo.org/proj/proj-9.3.0.tar.gz')),
Dependency(
'gtest',
GitRepository('https://github.com/google/googletest.git', tag = 'v1.14.0')),
Dependency(
'zlib',
2023-11-18 06:18:00 +08:00
GitRepository('https://github.com/madler/zlib.git'),
Download('https://zlib.net/current/zlib.tar.gz')),
Dependency(
'xercesc',
GitRepository('https://github.com/apache/xerces-c.git', tag = 'v3.2.4'),
Download('https://archive.apache.org/dist/xerces/c/3/sources/xerces-c-3.2.3.zip'),
Download('https://carla-releases.s3.eu-west-3.amazonaws.com/Backup/xerces-c-3.2.3.zip')),
Dependency(
'sqlite',
Download('https://www.sqlite.org/2021/sqlite-amalgamation-3340100.zip')),
Dependency(
'rpclib',
GitRepository('https://github.com/rpclib/rpclib.git', tag = 'v2.3.0')),
Dependency(
'recast',
GitRepository('https://github.com/recastnavigation/recastnavigation.git', tag = 'v1.6.0')),
]
2023-11-18 06:18:00 +08:00
CHRONO_DEPENDENCIES = [
Dependency(
'chrono',
GitRepository('https://github.com/projectchrono/chrono.git', tag = '8.0.0'))
]
OSM_WORLD_RENDERER_DEPENDENCIES = [
Dependency(
'libosmscout',
GitRepository('https://github.com/Framstag/libosmscout.git')),
Dependency(
'lunasvg',
GitRepository('https://github.com/sammycage/lunasvg.git')),
]
OSM2ODR_DEPENDENCIES = [
Dependency(
'sumo',
2023-11-18 06:18:00 +08:00
GitRepository('https://github.com/carla-simulator/sumo.git', tag = 'carla_osm2odr')),
]
2023-11-18 06:18:00 +08:00
DEPENDENCY_MAP = {
**{ e.name : e for e in DEFAULT_DEPENDENCIES },
**{ e.name : e for e in CHRONO_DEPENDENCIES },
**{ e.name : e for e in OSM_WORLD_RENDERER_DEPENDENCIES },
**{ e.name : e for e in OSM2ODR_DEPENDENCIES }
}
def FindExecutable(candidates : list):
for e in candidates:
ec = subprocess.call(
[ 'where' if os.name == 'nt' else 'whereis', e ],
2023-11-16 02:50:59 +08:00
stdout = subprocess.PIPE,
stderr = subprocess.PIPE,
shell = True)
if ec == 0:
return e
return None
2023-11-22 00:32:55 +08:00
C_COMPILER = FindExecutable([
'clang-cl',
'cl'
] if os.name == 'nt' else [
'clang',
'gcc'
])
2023-11-22 00:32:55 +08:00
CPP_COMPILER = FindExecutable([
'clang-cl',
'cl'
] if os.name == 'nt' else [
'clang++',
'g++'
])
2023-11-22 00:32:55 +08:00
LINKER = FindExecutable([
'llvm-link',
'link'
] if os.name == 'nt' else [
'lld',
'ld'
])
2023-11-22 00:32:55 +08:00
LIB = FindExecutable([
'llvm-lib',
'lib',
'llvm-ar'
] if os.name == 'nt' else [
'llvm-ar',
'ar'
])
2023-10-28 07:21:01 +08:00
# Dependency paths
BOOST_TOOLSET = 'msvc-14.2'
BOOST_TOOLSET_SHORT = 'vc142'
BOOST_SOURCE_PATH = DEPENDENCIES_PATH / 'boost-source'
BOOST_BUILD_PATH = DEPENDENCIES_PATH / 'boost-build'
BOOST_INSTALL_PATH = DEPENDENCIES_PATH / 'boost-install'
BOOST_INCLUDE_PATH = BOOST_INSTALL_PATH / 'include'
BOOST_LIBRARY_PATH = BOOST_INSTALL_PATH / 'lib'
BOOST_B2_PATH = BOOST_SOURCE_PATH / f'b2{EXE_EXT}'
EIGEN_SOURCE_PATH = DEPENDENCIES_PATH / 'eigen-source'
EIGEN_BUILD_PATH = DEPENDENCIES_PATH / 'eigen-build'
EIGEN_INSTALL_PATH = DEPENDENCIES_PATH / 'eigen-install'
2023-11-18 06:18:00 +08:00
EIGEN_INCLUDE_PATH = EIGEN_INSTALL_PATH / 'include'
CHRONO_SOURCE_PATH = DEPENDENCIES_PATH / 'chrono-source'
CHRONO_BUILD_PATH = DEPENDENCIES_PATH / 'chrono-build'
CHRONO_INSTALL_PATH = DEPENDENCIES_PATH / 'chrono-install'
2023-11-22 00:32:55 +08:00
CHRONO_INCLUDE_PATH = CHRONO_INSTALL_PATH / 'include'
CHRONO_LIBRARY_PATH = CHRONO_INSTALL_PATH / 'lib'
GTEST_SOURCE_PATH = DEPENDENCIES_PATH / 'gtest-source'
GTEST_BUILD_PATH = DEPENDENCIES_PATH / 'gtest-build'
GTEST_INSTALL_PATH = DEPENDENCIES_PATH / 'gtest-install'
2023-11-18 06:18:00 +08:00
GTEST_INCLUDE_PATH = GTEST_INSTALL_PATH / 'include'
2023-11-22 00:32:55 +08:00
GTEST_LIBRARY_PATH = GTEST_INSTALL_PATH / 'lib'
ZLIB_SOURCE_PATH = DEPENDENCIES_PATH / 'zlib-source'
ZLIB_BUILD_PATH = DEPENDENCIES_PATH / 'zlib-build'
ZLIB_INSTALL_PATH = DEPENDENCIES_PATH / 'zlib-install'
2023-11-18 06:18:00 +08:00
ZLIB_INCLUDE_PATH = ZLIB_INSTALL_PATH / 'include'
2023-11-22 00:32:55 +08:00
ZLIB_LIBRARY_PATH = ZLIB_INSTALL_PATH / 'lib'
ZLIB_LIB_PATH = ZLIB_LIBRARY_PATH / f'zlib{LIB_EXT}'
LIBPNG_SOURCE_PATH = DEPENDENCIES_PATH / 'libpng-source'
LIBPNG_BUILD_PATH = DEPENDENCIES_PATH / 'libpng-build'
LIBPNG_INSTALL_PATH = DEPENDENCIES_PATH / 'libpng-install'
2023-11-18 06:18:00 +08:00
LIBPNG_INCLUDE_PATH = LIBPNG_INSTALL_PATH / 'include'
2023-11-22 00:32:55 +08:00
LIBPNG_LIBRARY_PATH = LIBPNG_INSTALL_PATH / 'lib'
SQLITE_SOURCE_PATH = DEPENDENCIES_PATH / 'sqlite-source'
SQLITE_BUILD_PATH = DEPENDENCIES_PATH / 'sqlite-build'
2023-11-22 00:32:55 +08:00
SQLITE_LIBRARY_PATH = SQLITE_BUILD_PATH
2023-11-18 06:18:00 +08:00
SQLITE_INCLUDE_PATH = SQLITE_SOURCE_PATH
2023-11-22 00:32:55 +08:00
SQLITE_LIB_PATH = SQLITE_BUILD_PATH / f'sqlite{LIB_EXT}'
SQLITE_EXE_PATH = SQLITE_BUILD_PATH / f'sqlite{EXE_EXT}'
PROJ_SOURCE_PATH = DEPENDENCIES_PATH / 'proj-source'
PROJ_BUILD_PATH = DEPENDENCIES_PATH / 'proj-build'
PROJ_INSTALL_PATH = DEPENDENCIES_PATH / 'proj-install'
2023-11-18 06:18:00 +08:00
PROJ_INCLUDE_PATH = PROJ_INSTALL_PATH / 'include'
2023-11-22 00:32:55 +08:00
PROJ_LIBRARY_PATH = PROJ_INSTALL_PATH / 'lib'
RECAST_SOURCE_PATH = DEPENDENCIES_PATH / 'recast-source'
RECAST_BUILD_PATH = DEPENDENCIES_PATH / 'recast-build'
RECAST_INSTALL_PATH = DEPENDENCIES_PATH / 'recast-install'
2023-11-18 06:18:00 +08:00
RECAST_INCLUDE_PATH = RECAST_INSTALL_PATH / 'include'
2023-11-22 00:32:55 +08:00
RECAST_LIBRARY_PATH = RECAST_INSTALL_PATH / 'lib'
RPCLIB_SOURCE_PATH = DEPENDENCIES_PATH / 'rpclib-source'
RPCLIB_BUILD_PATH = DEPENDENCIES_PATH / 'rpclib-build'
RPCLIB_INSTALL_PATH = DEPENDENCIES_PATH / 'rpclib-install'
2023-11-18 06:18:00 +08:00
RPCLIB_INCLUDE_PATH = RPCLIB_INSTALL_PATH / 'include'
2023-11-22 00:32:55 +08:00
RPCLIB_LIBRARY_PATH = RPCLIB_INSTALL_PATH / 'lib'
XERCESC_SOURCE_PATH = DEPENDENCIES_PATH / 'xercesc-source'
XERCESC_BUILD_PATH = DEPENDENCIES_PATH / 'xercesc-build'
XERCESC_INSTALL_PATH = DEPENDENCIES_PATH / 'xercesc-install'
2023-11-22 00:32:55 +08:00
XERCESC_LIBRARY_PATH = XERCESC_INSTALL_PATH / 'lib'
2023-11-18 06:18:00 +08:00
XERCESC_INCLUDE_PATH = XERCESC_INSTALL_PATH / 'include'
LIBOSMSCOUT_SOURCE_PATH = DEPENDENCIES_PATH / 'libosmscout-source'
LIBOSMSCOUT_BUILD_PATH = DEPENDENCIES_PATH / 'libosmscout-build'
LIBOSMSCOUT_INSTALL_PATH = DEPENDENCIES_PATH / 'libosmscout-install'
2023-11-18 06:18:00 +08:00
LIBOSMSCOUT_INCLUDE_PATH = LIBOSMSCOUT_INSTALL_PATH / 'include'
2023-11-22 00:32:55 +08:00
LIBOSMSCOUT_LIBRARY_PATH = LIBOSMSCOUT_INSTALL_PATH / 'lib'
LUNASVG_SOURCE_PATH = DEPENDENCIES_PATH / 'lunasvg-source'
LUNASVG_BUILD_PATH = DEPENDENCIES_PATH / 'lunasvg-build'
LUNASVG_INSTALL_PATH = DEPENDENCIES_PATH / 'lunasvg-install'
2023-11-18 06:18:00 +08:00
LUNASVG_INCLUDE_PATH = LUNASVG_INSTALL_PATH / 'include'
2023-11-22 00:32:55 +08:00
LUNASVG_LIBRARY_PATH = LUNASVG_INSTALL_PATH / 'lib'
SUMO_SOURCE_PATH = DEPENDENCIES_PATH / 'sumo-source'
SUMO_BUILD_PATH = DEPENDENCIES_PATH / 'sumo-build'
SUMO_INSTALL_PATH = DEPENDENCIES_PATH / 'sumo-install'
2023-11-18 06:18:00 +08:00
SUMO_INCLUDE_PATH = SUMO_INSTALL_PATH / 'include'
2023-11-22 00:32:55 +08:00
SUMO_LIBRARY_PATH = SUMO_INSTALL_PATH / 'lib'
2023-11-15 03:48:24 +08:00
2023-11-22 00:32:55 +08:00
HOUDINI_URL = 'https://github.com/sideeffects/HoudiniEngineForUnreal.git'
HOUDINI_PLUGIN_PATH = CARLA_UE_PLUGIN_ROOT_PATH / 'HoudiniEngine'
HOUDINI_COMMIT_HASH = '55b6a16cdf274389687fce3019b33e3b6e92a914'
HOUDINI_PATCH_PATH = UTIL_PATH / 'Patches' / 'houdini_patch.txt'
2023-11-22 00:32:55 +08:00
READTHEDOCS_URL_SUFFIX = 'how_to_build_on_windows/\n' if os.name == "nt" else 'build_linux/\n'
ERROR_MESSAGE = (
'\n'
'Ok, an error ocurred, don\'t panic!\n'
'We have different platforms where you can find some help:\n'
'\n'
'- Make sure you have read the documentation:\n'
2023-11-22 00:32:55 +08:00
f' https://carla.readthedocs.io/en/latest/{READTHEDOCS_URL_SUFFIX}'
'\n'
'- If the problem persists, submit an issue on our GitHub page:\n'
' https://github.com/carla-simulator/carla/issues\n'
'\n'
'- Or just use our Discord server!\n'
' We\'ll be glad to help you there:\n'
' https://discord.gg/42KJdRj\n'
)
2023-11-15 03:48:24 +08:00
def Log(message):
message = str(message)
message += '\n'
print(message, end='')
def LaunchSubprocess(
cmd : list,
display_output : bool = False,
working_directory : Path = None):
if display_output or FORCE_SEQUENTIAL:
2023-11-15 03:48:24 +08:00
return subprocess.run(cmd, cwd = working_directory)
else:
return subprocess.run(
cmd,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE,
cwd = working_directory)
def LaunchSubprocessImmediate(
cmd : list,
2023-11-17 08:11:53 +08:00
display_output : bool = False,
working_directory : Path = None):
sp = LaunchSubprocess(cmd, display_output, working_directory)
try:
sp.check_returncode()
except:
stdout = sp.stdout.decode() if sp.stdout else ''
stderr = sp.stderr.decode() if sp.stderr else ''
error_message = (
f'Failed to run task {cmd}.\n'
f' stdout:\n'
f' {stdout}\n'
f' stderr:\n'
f' {stderr}\n'
)
print(error_message)
2023-11-15 03:48:24 +08:00
def UpdateGitRepository(path : Path, url : str, branch : str = None):
if path.exists():
LaunchSubprocessImmediate([
2023-11-15 03:48:24 +08:00
'git',
'-C', str(path),
'pull'
])
2023-11-15 03:48:24 +08:00
else:
cmd = [
'git',
'-C', str(path.parent),
'clone',
'--depth', '1', '--single-branch'
]
if branch != None:
cmd.append('-b')
cmd.append(branch)
cmd.append(url)
cmd.append(path.stem)
LaunchSubprocessImmediate(cmd)
2023-11-15 03:48:24 +08:00
def DownloadDependency(name : str, path : Path, url : str):
# Download:
try:
temp_path = Path(str(path) + '.tmp')
with requests.Session() as session:
with session.get(url, stream = True) as result:
result.raise_for_status()
with open(temp_path, 'wb') as file:
shutil.copyfileobj(result.raw, file)
except Exception as err:
Log(f'Failed to download dependency "{name}": {err}')
# Extract:
try:
extract_path = path.with_name(path.name + '-temp')
if url.endswith('.tar.gz'):
archive_path = temp_path.with_suffix('.tar.gz')
temp_path.rename(archive_path)
with tarfile.open(archive_path) as file:
file.extractall(extract_path)
elif url.endswith('.zip'):
archive_path = temp_path.with_suffix('.zip')
temp_path.rename(archive_path)
zipfile.ZipFile(archive_path).extractall(extract_path)
# Peel unnecessary outer directory:
entries = [ file for file in extract_path.iterdir() ]
if len(entries) == 1 and entries[0].is_dir():
Path(entries[0]).rename(path)
if extract_path.exists():
extract_path.rmdir()
2023-11-15 03:48:24 +08:00
else:
extract_path.rename(path)
except Exception as err:
Log(f'Failed to extract dependency "{name}": {err}')
2023-10-28 07:21:01 +08:00
def UpdateDependency(dep : Dependency):
name = dep.name
Log(f'Updating {name}.')
download_path = DEPENDENCIES_PATH / f'{name}-source'
for source in dep.sources:
2023-11-15 03:48:24 +08:00
try:
if type(source) is GitRepository:
branch = source.tag
UpdateGitRepository(download_path, source.url, branch)
elif type(source) is Download:
2023-11-15 03:48:24 +08:00
if download_path.exists():
Log(f'Dependency "{name}" already present. Delete "{download_path}" if you wish for it to be downloaded again.')
else:
DownloadDependency(name, download_path, source.url)
2023-11-15 03:48:24 +08:00
return
finally:
pass
Log(f'Failed to update dependency "{name}".')
assert False
def BuildLibCarlaMain(c : Context):
c.task_graph.Add(Task.CreateCMakeConfigureDefault('configure-libcarla', [], WORKSPACE_PATH, BUILD_PATH,
f'-DBUILD_LIBCARLA_SERVER={"ON" if c.args.build_libcarla_server else "OFF"}',
f'-DBUILD_LIBCARLA_CLIENT={"ON" if c.args.build_libcarla_client else "OFF"}',
f'-DBUILD_OSM_WORLD_RENDERER={"ON" if c.args.build_osm_world_renderer else "OFF"}',
2023-11-17 08:11:53 +08:00
f'-DLIBCARLA_PYTORCH={"ON" if c.args.build_libcarla_pytorch else "OFF"}'))
2023-11-22 00:32:55 +08:00
c.task_graph.Add(Task.CreateCMakeBuildDefault('build-libcarla', [ 'configure-libcarla' ], BUILD_PATH))
2023-11-17 08:11:53 +08:00
c.task_graph.Add(Task.CreateCMakeInstallDefault('install-libcarla', [ 'build-libcarla' ], BUILD_PATH, LIBCARLA_INSTALL_PATH))
2023-11-22 00:32:55 +08:00
def BuildCarlaUECore():
2023-11-15 03:48:24 +08:00
if os.name == 'nt':
LaunchSubprocessImmediate([
UE_WORKSPACE_PATH / 'Engine' / 'Build' / 'BatchFiles' / 'Build.bat',
2023-11-15 03:48:24 +08:00
'CarlaUE4', 'Win64', 'Development', '-WaitMutex', '-FromMsBuild',
CARLA_UE_PATH / 'CarlaUE4.uproject'
])
2023-11-15 03:48:24 +08:00
else:
pass
2023-10-28 07:21:01 +08:00
def BuildCarlaUEMain(c : Context):
Log('Building Carla Unreal Engine Editor')
# c.args.enable_carsim
# c.args.enable_chrono
# c.args.enable_unity
if c.args.enable_omniverse:
c.task_graph.Add(Task('install-nv_omniverse', [], InstallNVIDIAOmniverse))
2023-11-22 00:32:55 +08:00
c.task_graph.Add(Task('build-carla_ue', [], BuildCarlaUECore))
2023-11-22 00:32:55 +08:00
def BuildPythonAPICore():
2023-11-21 00:59:13 +08:00
setup_content = ''
with open(PYTHON_API_SOURCE_PATH / 'setup.py.txt', 'r') as file:
setup_content = file.read()
setup_content = setup_content.format_map(globals())
if os.name == 'nt':
setup_content = setup_content.replace(os.sep, '/')
with open(PYTHON_API_SOURCE_PATH / 'setup.py', 'w') as file:
file.write(setup_content)
LaunchSubprocessImmediate([
sys.executable,
PYTHON_API_SOURCE_PATH / 'setup.py',
'bdist_egg',
'bdist_wheel'
], working_directory = PYTHON_API_SOURCE_PATH)
2023-10-28 07:21:01 +08:00
2023-11-22 00:32:55 +08:00
def BuildPythonAPIMain(c : Context):
c.task_graph.Add(Task('build-python-api', [ 'install-libcarla' ], BuildPythonAPICore))
def SetupUnrealEngine(c : Context):
Log('Setting up Unreal Engine.')
2023-10-28 07:21:01 +08:00
2023-11-15 03:48:24 +08:00
def InstallNVIDIAOmniverse():
filename = 'USDCarlaInterface'
header = f'{filename}.h'
source = f'{filename}.cpp'
omniverse_usd_path = NV_OMNIVERSE_PLUGIN_PATH / 'Source' / 'OmniverseUSD'
2023-11-15 03:48:24 +08:00
files = [
[ omniverse_usd_path / 'Public' / header, NV_OMNIVERSE_PATCH_PATH / header ],
[ omniverse_usd_path / 'Private' / source, NV_OMNIVERSE_PATCH_PATH / source ],
2023-11-15 03:48:24 +08:00
]
for src, dst in files:
shutil.copyfile(src, dst)
2023-10-28 07:21:01 +08:00
def UpdateDependencies(c : Context):
unique_dependencies = set(DEFAULT_DEPENDENCIES)
if c.args.build_osm_world_renderer:
unique_dependencies.update(OSM_WORLD_RENDERER_DEPENDENCIES)
if c.args.build_osm2odr:
unique_dependencies.update(OSM2ODR_DEPENDENCIES)
2023-11-18 06:18:00 +08:00
if c.args.enable_chrono:
unique_dependencies.update(CHRONO_DEPENDENCIES)
for dep in unique_dependencies:
name = dep.name
c.task_graph.Add(Task(f'update-{name}', [], UpdateDependency, dep))
c.task_graph.Execute()
2023-11-15 03:48:24 +08:00
def ConfigureBoost():
if BOOST_B2_PATH.exists():
2023-11-15 03:48:24 +08:00
return
LaunchSubprocessImmediate(
[ BOOST_SOURCE_PATH / f'bootstrap{SHELL_EXT}' ],
working_directory = BOOST_SOURCE_PATH)
2023-11-15 03:48:24 +08:00
def BuildAndInstallBoost():
2023-11-21 00:59:13 +08:00
if BOOST_INSTALL_PATH.exists():
2023-11-22 00:32:55 +08:00
Log(f'Currently we test for whether "{BOOST_INSTALL_PATH}" exists to detect whether recompilation of boost. If a rebuild is needed, delete it.')
2023-11-21 00:59:13 +08:00
return
LaunchSubprocessImmediate([
BOOST_B2_PATH,
f'-j{DEFAULT_PARALLELISM}',
'architecture=x86',
'address-model=64',
f'toolset={BOOST_TOOLSET}',
2023-11-15 03:48:24 +08:00
'variant=release',
'link=static',
'runtime-link=shared',
'threading=multi',
'--layout=system',
'--with-system',
'--with-filesystem',
'--with-python',
'--with-date_time',
f'--build-dir={BOOST_BUILD_PATH}',
f'--prefix={BOOST_INSTALL_PATH}',
f'--libdir={BOOST_LIBRARY_PATH}',
f'--includedir={BOOST_INCLUDE_PATH}',
2023-11-15 03:48:24 +08:00
'install'
2023-11-17 04:02:53 +08:00
], working_directory = BOOST_SOURCE_PATH)
2023-11-15 03:48:24 +08:00
def BuildSQLite():
SQLITE_BUILD_PATH.mkdir(exist_ok = True)
sqlite_sources = glob.glob(f'{SQLITE_SOURCE_PATH}/**/*.c', recursive = True)
2023-11-22 00:32:55 +08:00
if os.name == 'nt' and 'clang' in C_COMPILER:
if not SQLITE_EXE_PATH.exists():
cmd = [ C_COMPILER, f'-fuse-ld={LINKER}', '-march=native', '/O2', '/MD', '/EHsc' ]
cmd.extend(sqlite_sources)
cmd.append('-o')
2023-11-22 00:32:55 +08:00
cmd.append(SQLITE_EXE_PATH)
LaunchSubprocessImmediate(cmd)
2023-11-22 00:32:55 +08:00
if not SQLITE_LIB_PATH.exists():
cmd = [ C_COMPILER, f'-fuse-ld={LIB}', '-march=native', '/O2', '/MD', '/EHsc' ]
cmd.extend(sqlite_sources)
cmd.append('-o')
2023-11-22 00:32:55 +08:00
cmd.append(SQLITE_LIB_PATH)
LaunchSubprocessImmediate(cmd)
2023-11-15 03:48:24 +08:00
else:
pass
def FindXercesC():
return glob.glob(f'{XERCESC_INSTALL_PATH}/**/xerces-c*{LIB_EXT}', recursive=True)[0]
def BuildDependencies(c : Context):
# Configure:
2023-11-15 03:48:24 +08:00
2023-11-22 00:32:55 +08:00
c.task_graph.Add(Task('build-sqlite',
[],
BuildSQLite))
c.task_graph.Add(Task('configure-boost',
[],
ConfigureBoost))
2023-11-15 03:48:24 +08:00
c.task_graph.Add(Task.CreateCMakeConfigureDefault(
'configure-zlib',
[],
ZLIB_SOURCE_PATH,
2023-11-18 06:18:00 +08:00
ZLIB_BUILD_PATH,
install_path = ZLIB_INSTALL_PATH)) # ZLib determines where to install during configure.
c.task_graph.Add(Task.CreateCMakeConfigureDefault(
'configure-gtest',
[],
GTEST_SOURCE_PATH,
GTEST_BUILD_PATH))
c.task_graph.Add(Task.CreateCMakeConfigureDefault(
'configure-libpng',
[],
LIBPNG_SOURCE_PATH,
LIBPNG_BUILD_PATH,
'-DPNG_TESTS=OFF',
'-DPNG_TOOLS=OFF',
'-DPNG_BUILD_ZLIB=ON',
2023-11-18 06:18:00 +08:00
f'-DZLIB_INCLUDE_DIRS={ZLIB_INCLUDE_PATH}',
2023-11-22 00:32:55 +08:00
f'-DZLIB_LIBRARIES={ZLIB_LIB_PATH}'))
c.task_graph.Add(Task.CreateCMakeConfigureDefault(
'configure-proj',
[],
PROJ_SOURCE_PATH,
PROJ_BUILD_PATH,
f'-DSQLITE3_INCLUDE_DIR={SQLITE_SOURCE_PATH}',
2023-11-22 00:32:55 +08:00
f'-DSQLITE3_LIBRARY={SQLITE_LIB_PATH}',
f'-DEXE_SQLITE3={SQLITE_EXE_PATH}',
2023-11-15 03:48:24 +08:00
'-DWIN32_LEAN_AND_MEAN=1',
'-DVC_EXTRALEAN=1',
'-DNOMINMAX=1',
'-DENABLE_TIFF=OFF',
'-DENABLE_CURL=OFF',
'-DBUILD_SHARED_LIBS=OFF',
'-DBUILD_PROJSYNC=OFF',
'-DBUILD_PROJINFO=OFF',
'-DBUILD_CCT=OFF',
'-DBUILD_CS2CS=OFF',
'-DBUILD_GEOD=OFF',
'-DBUILD_GIE=OFF',
'-DBUILD_PROJ=OFF',
'-DBUILD_TESTING=OFF'))
2023-11-15 03:48:24 +08:00
c.task_graph.Add(Task.CreateCMakeConfigureDefault(
'configure-recast',
[],
RECAST_SOURCE_PATH,
RECAST_BUILD_PATH,
2023-11-15 03:48:24 +08:00
'-DRECASTNAVIGATION_DEMO=OFF',
'-DRECASTNAVIGATION_TESTS=OFF',
'-DRECASTNAVIGATION_EXAMPLES=OFF'))
2023-11-15 03:48:24 +08:00
c.task_graph.Add(Task.CreateCMakeConfigureDefault(
'configure-rpclib',
[],
RPCLIB_SOURCE_PATH,
RPCLIB_BUILD_PATH,
2023-11-15 03:48:24 +08:00
'-DRPCLIB_BUILD_TESTS=OFF',
'-DRPCLIB_GENERATE_COMPDB=OFF',
'-DRPCLIB_BUILD_EXAMPLES=OFF',
'-DRPCLIB_ENABLE_LOGGING=OFF',
'-DRPCLIB_ENABLE_COVERAGE=OFF',
'-DRPCLIB_MSVC_STATIC_RUNTIME=OFF'))
c.task_graph.Add(Task.CreateCMakeConfigureDefault(
'configure-xercesc',
[],
XERCESC_SOURCE_PATH,
XERCESC_BUILD_PATH))
if c.args.build_osm_world_renderer:
c.task_graph.Add(Task.CreateCMakeConfigureDefault(
'configure-libosmscout',
[],
LIBOSMSCOUT_SOURCE_PATH,
LIBOSMSCOUT_BUILD_PATH,
'-DOSMSCOUT_BUILD_TOOL_STYLEEDITOR=OFF',
'-DOSMSCOUT_BUILD_TOOL_OSMSCOUT2=OFF',
'-DOSMSCOUT_BUILD_TESTS=OFF',
'-DOSMSCOUT_BUILD_CLIENT_QT=OFF',
'-DOSMSCOUT_BUILD_DEMOS=OFF'))
c.task_graph.Add(Task.CreateCMakeConfigureDefault(
'configure-lunasvg',
[],
LUNASVG_SOURCE_PATH,
LUNASVG_BUILD_PATH))
if c.args.build_osm2odr:
c.task_graph.Add(Task.CreateCMakeConfigureDefault(
'configure-sumo',
[],
SUMO_SOURCE_PATH,
SUMO_BUILD_PATH,
2023-11-18 06:18:00 +08:00
f'-DZLIB_INCLUDE_DIR={ZLIB_INCLUDE_PATH}',
f'-DZLIB_LIBRARY={ZLIB_LIBRARY_PATH}',
f'-DPROJ_INCLUDE_DIR={PROJ_INSTALL_PATH}/include',
f'-DPROJ_LIBRARY={PROJ_INSTALL_PATH}/lib/proj{LIB_EXT}',
f'-DXercesC_INCLUDE_DIR={XERCESC_INSTALL_PATH}/include',
2023-11-18 06:18:00 +08:00
f'-DXercesC_LIBRARY={FindXercesC()}',
'-DSUMO_LIBRARIES=OFF',
# '-DPROFILING=OFF',
# '-DPPROF=OFF',
# '-DCOVERAGE=OFF',
# '-DSUMO_UTILS=OFF',
# '-DFMI=OFF',
# '-DNETEDIT=OFF',
# '-DENABLE_JAVA_BINDINGS=OFF',
# '-DENABLE_CS_BINDINGS=OFF',
# '-DCCACHE_SUPPORT=OFF',
))
if c.args.enable_chrono:
c.task_graph.Add(Task.CreateCMakeConfigureDefault(
'configure-chrono',
[],
CHRONO_SOURCE_PATH,
CHRONO_BUILD_PATH,
f'-DEIGEN3_INCLUDE_DIR={EIGEN_SOURCE_PATH}',
'-DENABLE_MODULE_VEHICLE=ON'))
2023-11-18 06:18:00 +08:00
c.task_graph.Execute()
# Build:
2023-11-17 04:02:53 +08:00
c.task_graph.Add(Task('build-boost', [], BuildAndInstallBoost))
c.task_graph.Add(Task.CreateCMakeBuildDefault('build-zlib', [], ZLIB_BUILD_PATH))
c.task_graph.Add(Task.CreateCMakeBuildDefault('build-gtest', [], GTEST_BUILD_PATH))
c.task_graph.Add(Task.CreateCMakeBuildDefault('build-libpng', [], LIBPNG_BUILD_PATH))
c.task_graph.Add(Task.CreateCMakeBuildDefault('build-proj', [], PROJ_BUILD_PATH))
c.task_graph.Add(Task.CreateCMakeBuildDefault('build-recast', [], RECAST_BUILD_PATH))
c.task_graph.Add(Task.CreateCMakeBuildDefault('build-rpclib', [], RPCLIB_BUILD_PATH))
c.task_graph.Add(Task.CreateCMakeBuildDefault('build-xercesc', [], XERCESC_BUILD_PATH))
if c.args.build_osm_world_renderer:
2023-11-17 04:02:53 +08:00
c.task_graph.Add(Task.CreateCMakeBuildDefault('build-lunasvg', [], LUNASVG_BUILD_PATH))
c.task_graph.Add(Task.CreateCMakeBuildDefault('build-libosmscout', [], LIBOSMSCOUT_BUILD_PATH))
if c.args.build_osm2odr:
2023-11-17 04:02:53 +08:00
c.task_graph.Add(Task.CreateCMakeBuildDefault('build-sumo', [], SUMO_BUILD_PATH))
if c.args.enable_chrono:
2023-11-17 04:02:53 +08:00
c.task_graph.Add(Task.CreateCMakeBuildDefault('build-chrono', [], CHRONO_BUILD_PATH))
2023-11-18 06:18:00 +08:00
c.task_graph.Execute(True)
# Install:
2023-11-18 06:18:00 +08:00
c.task_graph.Add(Task.CreateCMakeInstallDefault('install-zlib', [], ZLIB_BUILD_PATH, ZLIB_INSTALL_PATH))
2023-11-17 04:02:53 +08:00
c.task_graph.Add(Task.CreateCMakeInstallDefault('install-gtest', [], GTEST_BUILD_PATH, GTEST_INSTALL_PATH))
c.task_graph.Add(Task.CreateCMakeInstallDefault('install-libpng', [], LIBPNG_BUILD_PATH, LIBPNG_INSTALL_PATH))
c.task_graph.Add(Task.CreateCMakeInstallDefault('install-proj', [], PROJ_BUILD_PATH, PROJ_INSTALL_PATH))
c.task_graph.Add(Task.CreateCMakeInstallDefault('install-recast', [], RECAST_BUILD_PATH, RECAST_INSTALL_PATH))
c.task_graph.Add(Task.CreateCMakeInstallDefault('install-rpclib', [], RPCLIB_BUILD_PATH, RPCLIB_INSTALL_PATH))
c.task_graph.Add(Task.CreateCMakeInstallDefault('install-xercesc', [], XERCESC_BUILD_PATH, XERCESC_INSTALL_PATH))
if c.args.build_osm_world_renderer:
2023-11-17 04:02:53 +08:00
c.task_graph.Add(Task.CreateCMakeInstallDefault('install-lunasvg', [], LUNASVG_BUILD_PATH, LUNASVG_INSTALL_PATH))
c.task_graph.Add(Task.CreateCMakeInstallDefault('install-libosmscout', [], LIBOSMSCOUT_BUILD_PATH, LIBOSMSCOUT_INSTALL_PATH))
if c.args.build_osm2odr:
2023-11-17 04:02:53 +08:00
c.task_graph.Add(Task.CreateCMakeInstallDefault('install-sumo', [], SUMO_BUILD_PATH, SUMO_INSTALL_PATH))
if c.args.enable_chrono:
2023-11-17 04:02:53 +08:00
c.task_graph.Add(Task.CreateCMakeInstallDefault('install-chrono', [], CHRONO_BUILD_PATH, CHRONO_INSTALL_PATH))
c.task_graph.Execute()
2023-11-15 03:48:24 +08:00
def ParseCommandLine():
arg_parser = ArgumentParser(description = __doc__)
BUILD_LIBCARLA_CLIENT_OVERRIDE = True
BUILD_LIBCARLA_SERVER_OVERRIDE = True
2023-11-17 08:11:53 +08:00
BUILD_LIBCARLA_PYTORCH_OVERRIDE = True
BUILD_PYTHON_API_OVERRIDE = True
2023-11-17 08:11:53 +08:00
BUILD_CARLA_UE_OVERRIDE = False
UPDATE_DEPENDENCIES_OVERRIDE = True
BUILD_DEPENDENCIES_OVERRIDE = True
2023-11-18 06:18:00 +08:00
BUILD_OSM2ODR_OVERRIDE = True
BUILD_OSM_WORLD_RENDERER_OVERRIDE = False
BUILD_PACKAGE_OVERRIDE = True
CLEAN_OVERRIDE = False
2023-11-15 03:48:24 +08:00
arg_parser.add_argument(
'-build-libcarla-client',
2023-11-15 03:48:24 +08:00
action='store_true',
default = BUILD_LIBCARLA_CLIENT_OVERRIDE,
help = 'Whether to build LibCarla Client.')
arg_parser.add_argument(
'-build-libcarla-server',
action='store_true',
default = BUILD_LIBCARLA_SERVER_OVERRIDE,
help = 'Whether to build LibCarla Server.')
2023-11-17 08:11:53 +08:00
arg_parser.add_argument(
'-build-libcarla-pytorch',
action='store_true',
default = BUILD_LIBCARLA_PYTORCH_OVERRIDE,
help = 'Whether to build LibCarla-PyTorch.')
2023-11-15 03:48:24 +08:00
arg_parser.add_argument(
'-build-python-api',
action='store_true',
default = BUILD_PYTHON_API_OVERRIDE,
help = 'Whether to build the CARLA Python API.')
2023-11-15 03:48:24 +08:00
arg_parser.add_argument(
'-build-carla-unreal',
2023-11-15 03:48:24 +08:00
action='store_true',
default = BUILD_CARLA_UE_OVERRIDE,
help = 'Build to build the Unreal Engine Carla backend.')
2023-11-15 03:48:24 +08:00
arg_parser.add_argument(
'-update-dependencies',
action='store_true',
default = UPDATE_DEPENDENCIES_OVERRIDE,
2023-11-15 03:48:24 +08:00
help = 'Whether to update the CARLA dependencies.')
arg_parser.add_argument(
'-build-dependencies',
action='store_true',
default = BUILD_DEPENDENCIES_OVERRIDE,
2023-11-15 03:48:24 +08:00
help = 'Whether to build the CARLA dependencies.')
arg_parser.add_argument(
'-build-osm-world-renderer',
action='store_true',
default = BUILD_OSM_WORLD_RENDERER_OVERRIDE,
help = 'Whether to build OSM World Renderer.')
2023-11-15 03:48:24 +08:00
arg_parser.add_argument(
'-build-osm2odr',
action='store_true',
default = BUILD_OSM2ODR_OVERRIDE,
help = 'Whether to build OSM2ODR.')
2023-11-15 03:48:24 +08:00
arg_parser.add_argument(
'-package',
action='store_true',
default = BUILD_PACKAGE_OVERRIDE,
help = 'Whether to package Carla.')
2023-11-15 03:48:24 +08:00
arg_parser.add_argument(
'-clean',
action='store_true',
default = CLEAN_OVERRIDE,
2023-11-15 03:48:24 +08:00
help = 'Clean build files.')
2023-11-18 06:18:00 +08:00
arg_parser.add_argument(
'-enable-rss',
action='store_true',
help = 'Whether to enable "RSS".')
2023-11-15 03:48:24 +08:00
arg_parser.add_argument(
'-enable-carsim',
2023-11-15 03:48:24 +08:00
action='store_true',
help = 'Whether to enable plugin "CarSim".')
arg_parser.add_argument(
'-enable-chrono',
2023-11-15 03:48:24 +08:00
action='store_true',
help = 'Whether to enable plugin "Chrono".')
arg_parser.add_argument(
'-enable-unity',
2023-11-15 03:48:24 +08:00
action='store_true',
help = 'Whether to enable plugin "Unity".')
arg_parser.add_argument(
'-enable-omniverse',
2023-11-15 03:48:24 +08:00
action='store_true',
help = 'Whether to enable plugin "NVIDIA Omniverse".')
return arg_parser.parse_args()
2023-10-28 07:21:01 +08:00
2023-11-15 03:48:24 +08:00
def Main():
Log('Started.')
BUILD_PATH.mkdir(exist_ok = True)
DEPENDENCIES_PATH.mkdir(exist_ok = True)
2023-11-15 03:48:24 +08:00
arg = ParseCommandLine()
c = Context(arg, DEFAULT_PARALLELISM)
2023-11-15 03:48:24 +08:00
if arg.clean:
try:
shutil.rmtree(BUILD_PATH)
2023-11-15 03:48:24 +08:00
finally:
Log(f'Failed to remove {BUILD_PATH}.')
2023-11-15 03:48:24 +08:00
exit(-1)
if arg.update_dependencies or True:
UpdateDependencies(c)
for ext in [ '*.tmp', '*.zip', '*.tar.gz' ]:
for e in DEPENDENCIES_PATH.glob(ext):
2023-11-15 03:48:24 +08:00
e.unlink(missing_ok = True)
if arg.build_dependencies or True:
BuildDependencies(c)
BuildLibCarlaMain(c)
2023-11-15 03:48:24 +08:00
if arg.build_python_api:
BuildPythonAPIMain(c)
if arg.build_carla_unreal:
2023-11-15 03:48:24 +08:00
BuildCarlaUEMain(c)
2023-11-17 08:11:53 +08:00
c.task_graph.Execute()
2023-11-15 03:48:24 +08:00
Log('Done.')
2023-10-28 07:21:01 +08:00
if __name__ == '__main__':
2023-11-15 03:48:24 +08:00
try:
Main()
except Exception as err:
Log(err)
Log(ERROR_MESSAGE)
2023-11-15 03:48:24 +08:00
exit(-1)