aboutsummaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/servo/build_commands.py58
-rw-r--r--python/servo/try_parser.py33
2 files changed, 76 insertions, 15 deletions
diff --git a/python/servo/build_commands.py b/python/servo/build_commands.py
index b21f89980c0..42988debf35 100644
--- a/python/servo/build_commands.py
+++ b/python/servo/build_commands.py
@@ -13,10 +13,11 @@ import os.path as path
import pathlib
import shutil
import stat
+import subprocess
import sys
from time import time
-from typing import Optional
+from typing import Optional, List
import notifypy
@@ -40,6 +41,32 @@ SUPPORTED_ASAN_TARGETS = ["aarch64-apple-darwin", "aarch64-unknown-linux-gnu",
"x86_64-apple-darwin", "x86_64-unknown-linux-gnu"]
+def get_rustc_llvm_version() -> Optional[List[int]]:
+ """Determine the LLVM version of `rustc` and return it as a List[major, minor, patch, ...]
+
+ In some cases we want to ensure that the LLVM version of rustc and clang match, e.g.
+ when using ASAN for both C/C++ and Rust code, we want to use the same ASAN implementation.
+ This function assumes that rustc points to the rust compiler we are interested in, which should
+ be valid in both rustup managed environment and on nix.
+ """
+ try:
+ result = subprocess.run(['rustc', '--version', '--verbose'], encoding='utf-8', capture_output=True)
+ result.check_returncode()
+ for line in result.stdout.splitlines():
+ line_lowercase = line.lower()
+ if line_lowercase.startswith("llvm version:"):
+ llvm_version = line_lowercase.strip("llvm version:")
+ llvm_version = llvm_version.strip()
+ version = llvm_version.split('.')
+ print(f"Info: rustc is using LLVM version {'.'.join(version)}")
+ return version
+ else:
+ print(f"Error: Couldn't find LLVM version in output of `rustc --version --verbose`: `{result.stdout}`")
+ except Exception as e:
+ print(f"Error: Failed to determine rustc version: {e}")
+ return None
+
+
@CommandProvider
class MachCommands(CommandBase):
@Command('build', description='Build Servo', category='build')
@@ -99,11 +126,30 @@ class MachCommands(CommandBase):
env["RUSTFLAGS"] = env.get("RUSTFLAGS", "") + " -Zsanitizer=address"
opts += ["-Zbuild-std"]
kwargs["target_override"] = target_triple
- # TODO: Investigate sanitizers in C/C++ code:
- # env.setdefault("CFLAGS", "")
- # env.setdefault("CXXFLAGS", "")
- # env["CFLAGS"] += " -fsanitize=address"
- # env["CXXFLAGS"] += " -fsanitize=address"
+
+ # Note: We want to use the same clang/LLVM version as rustc.
+ rustc_llvm_version = get_rustc_llvm_version()
+ if rustc_llvm_version is None:
+ raise RuntimeError("Unable to determine necessary clang version for ASAN support")
+ llvm_major: int = rustc_llvm_version[0]
+ target_clang = f"clang-{llvm_major}"
+ target_cxx = f"clang++-{llvm_major}"
+ if shutil.which(target_clang) is None or shutil.which(target_cxx) is None:
+ raise RuntimeError(f"--with-asan requires `{target_clang}` and `{target_cxx}` to be in PATH")
+ env.setdefault("TARGET_CC", target_clang)
+ env.setdefault("TARGET_CXX", target_cxx)
+ # TODO: We should also parse the LLVM version from the clang compiler we chose.
+ # It's unclear if the major version being the same is sufficient.
+
+ # We need to use `TARGET_CFLAGS`, since we don't want to compile host dependencies with ASAN,
+ # since that causes issues when building build-scripts / proc macros.
+ env.setdefault("TARGET_CFLAGS", "")
+ env.setdefault("TARGET_CXXFLAGS", "")
+ env["TARGET_CFLAGS"] += " -fsanitize=address"
+ env["TARGET_CXXFLAGS"] += " -fsanitize=address"
+ env["TARGET_LDFLAGS"] = "-static-libasan"
+ # By default build mozjs from source to enable ASAN with mozjs.
+ env.setdefault("MOZJS_FROM_SOURCE", "1")
# asan replaces system allocator with asan allocator
# we need to make sure that we do not replace it with jemalloc
diff --git a/python/servo/try_parser.py b/python/servo/try_parser.py
index 9a6b31693b0..0d78599c06f 100644
--- a/python/servo/try_parser.py
+++ b/python/servo/try_parser.py
@@ -39,11 +39,12 @@ class JobConfig(object):
unit_tests: bool = False
build_libservo: bool = False
bencher: bool = False
+ build_args: str = ""
wpt_args: str = ""
number_of_wpt_chunks: int = 20
# These are the fields that must match in between two JobConfigs for them to be able to be
# merged. If you modify any of the fields above, make sure to update this line as well.
- merge_compatibility_fields: ClassVar[List[str]] = ['workflow', 'profile', 'wpt_args']
+ merge_compatibility_fields: ClassVar[List[str]] = ['workflow', 'profile', 'wpt_args', 'build_args']
def merge(self, other: JobConfig) -> bool:
"""Try to merge another job with this job. Returns True if merging is successful
@@ -209,7 +210,8 @@ class TestParser(unittest.TestCase):
'build_libservo': False,
'workflow': 'linux',
'wpt': False,
- 'wpt_args': ''
+ 'wpt_args': '',
+ 'build_args': ''
}]
})
@@ -225,7 +227,8 @@ class TestParser(unittest.TestCase):
"unit_tests": True,
'build_libservo': False,
'bencher': True,
- "wpt_args": ""
+ "wpt_args": "",
+ 'build_args': ''
},
{
"name": "MacOS (Unit Tests)",
@@ -236,7 +239,8 @@ class TestParser(unittest.TestCase):
"unit_tests": True,
'build_libservo': False,
'bencher': False,
- "wpt_args": ""
+ "wpt_args": "",
+ 'build_args': ''
},
{
"name": "Windows (Unit Tests)",
@@ -247,7 +251,8 @@ class TestParser(unittest.TestCase):
"unit_tests": True,
'build_libservo': False,
'bencher': False,
- "wpt_args": ""
+ "wpt_args": "",
+ 'build_args': ''
},
{
"name": "Android",
@@ -258,7 +263,8 @@ class TestParser(unittest.TestCase):
"unit_tests": False,
'build_libservo': False,
'bencher': False,
- "wpt_args": ""
+ "wpt_args": "",
+ 'build_args': ''
},
{
"name": "OpenHarmony",
@@ -269,7 +275,8 @@ class TestParser(unittest.TestCase):
"unit_tests": False,
'build_libservo': False,
'bencher': False,
- "wpt_args": ""
+ "wpt_args": "",
+ 'build_args': ''
},
{
"name": "Lint",
@@ -280,7 +287,9 @@ class TestParser(unittest.TestCase):
"unit_tests": False,
'build_libservo': False,
'bencher': False,
- "wpt_args": ""}
+ "wpt_args": "",
+ 'build_args': ''
+ }
]})
def test_job_merging(self):
@@ -295,7 +304,8 @@ class TestParser(unittest.TestCase):
'build_libservo': False,
'workflow': 'linux',
'wpt': True,
- 'wpt_args': ''
+ 'wpt_args': '',
+ 'build_args': ''
}]
})
@@ -327,6 +337,11 @@ class TestParser(unittest.TestCase):
self.assertFalse(a.merge(b), "Should not merge jobs that run different WPT tests.")
self.assertEqual(a, JobConfig("Linux (Unit Tests)", Workflow.LINUX, unit_tests=True))
+ a = JobConfig("Linux (Unit Tests)", Workflow.LINUX, unit_tests=True)
+ b = JobConfig("Linux (Unit Tests)", Workflow.LINUX, unit_tests=True, build_args="--help")
+ self.assertFalse(a.merge(b), "Should not merge jobs with different build arguments.")
+ self.assertEqual(a, JobConfig("Linux (Unit Tests)", Workflow.LINUX, unit_tests=True))
+
def test_full(self):
self.assertDictEqual(json.loads(Config("full").to_json()),
json.loads(Config("").to_json()))