2 # This Source Code Form is subject to the terms of the Mozilla Public
3 # License, v. 2.0. If a copy of the MPL was not distributed with this
4 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 # Only necessary for flake8 to be happy...
20 from contextlib
import contextmanager
21 from shutil
import which
26 "x86_64-unknown-linux-gnu": ("Linux", "x86_64"),
27 "x86_64-pc-windows-msvc": ("Windows", "AMD64"),
28 "x86_64-apple-darwin": ("Darwin", "x86_64"),
29 "aarch64-apple-darwin": ("Darwin", "arm64"),
33 def is_llvm_toolchain(cc
, cxx
):
34 return "clang" in cc
and "clang" in cxx
38 print(" ".join(args
), file=sys
.stderr
, flush
=True)
39 if args
[0] == "cmake":
40 # CMake `message(STATUS)` messages, as appearing in failed source code
41 # compiles, appear on stdout, so we only capture that.
42 p
= subprocess
.Popen(args
, stdout
=subprocess
.PIPE
)
46 sys
.stdout
.write(line
.decode())
49 if r
!= 0 and os
.environ
.get("UPLOAD_DIR"):
50 cmake_output_re
= re
.compile(b
'See also "(.*/CMakeOutput.log)"')
51 cmake_error_re
= re
.compile(b
'See also "(.*/CMakeError.log)"')
53 def find_first_match(re
):
59 output_match
= find_first_match(cmake_output_re
)
60 error_match
= find_first_match(cmake_error_re
)
62 upload_dir
= os
.environ
["UPLOAD_DIR"].encode("utf-8")
63 if output_match
or error_match
:
66 shutil
.copy2(output_match
.group(1), upload_dir
)
68 shutil
.copy2(error_match
.group(1), upload_dir
)
70 r
= subprocess
.call(args
)
74 def run_in(path
, args
):
82 print('cd "%s"' % path
, file=sys
.stderr
)
87 print('cd "%s"' % d
, file=sys
.stderr
)
91 def patch(patch
, srcdir
):
92 patch
= os
.path
.realpath(patch
)
93 check_run(["patch", "-d", srcdir
, "-p1", "-i", patch
, "--fuzz=0", "-s"])
96 def import_clang_tidy(source_dir
, build_clang_tidy_alpha
, build_clang_tidy_external
):
97 clang_plugin_path
= os
.path
.join(os
.path
.dirname(sys
.argv
[0]), "..", "clang-plugin")
98 clang_tidy_path
= os
.path
.join(source_dir
, "clang-tools-extra/clang-tidy")
99 sys
.path
.append(clang_plugin_path
)
100 from import_mozilla_checks
import do_import
103 "alpha": build_clang_tidy_alpha
,
104 "external": build_clang_tidy_external
,
106 do_import(clang_plugin_path
, clang_tidy_path
, import_options
)
109 def build_package(package_build_dir
, cmake_args
):
110 if not os
.path
.exists(package_build_dir
):
111 os
.mkdir(package_build_dir
)
112 # If CMake has already been run, it may have been run with different
113 # arguments, so we need to re-run it. Make sure the cached copy of the
114 # previous CMake run is cleared before running it again.
115 if os
.path
.exists(package_build_dir
+ "/CMakeCache.txt"):
116 os
.remove(package_build_dir
+ "/CMakeCache.txt")
117 if os
.path
.exists(package_build_dir
+ "/CMakeFiles"):
118 shutil
.rmtree(package_build_dir
+ "/CMakeFiles")
120 run_in(package_build_dir
, ["cmake"] + cmake_args
)
121 run_in(package_build_dir
, ["ninja", "install", "-v"])
125 def updated_env(env
):
126 old_env
= os
.environ
.copy()
127 os
.environ
.update(env
)
130 os
.environ
.update(old_env
)
133 def build_tar_package(name
, base
, directory
):
134 name
= os
.path
.realpath(name
)
135 print("tarring {} from {}/{}".format(name
, base
, directory
), file=sys
.stderr
)
136 assert name
.endswith(".tar.zst")
138 cctx
= zstandard
.ZstdCompressor()
139 with
open(name
, "wb") as f
, cctx
.stream_writer(f
) as z
:
140 with tarfile
.open(mode
="w|", fileobj
=z
) as tf
:
149 if e
.errno
!= errno
.EEXIST
or not os
.path
.isdir(path
):
154 if os
.path
.isdir(path
):
163 def install_import_library(build_dir
, clang_dir
):
165 os
.path
.join(build_dir
, "lib", "clang.lib"), os
.path
.join(clang_dir
, "lib")
169 def is_darwin(target
):
170 return "-apple-darwin" in target
173 def is_linux(target
):
174 return "-linux-gnu" in target
177 def is_windows(target
):
178 return "-windows-msvc" in target
181 def is_cross_compile(target
):
182 return SUPPORTED_TARGETS
[target
] != (platform
.system(), platform
.machine())
199 is_final_stage
=False,
202 if not os
.path
.exists(stage_dir
):
205 build_dir
= stage_dir
+ "/build"
206 inst_dir
= stage_dir
+ "/" + package_name
208 # cmake doesn't deal well with backslashes in paths.
209 def slashify_path(path
):
210 return path
.replace("\\", "/")
212 def cmake_base_args(cc
, cxx
, asm
, ar
, ranlib
, ldflags
, inst_dir
):
213 machine_targets
= targets
if is_final_stage
and targets
else "X86"
217 "-DCMAKE_C_COMPILER=%s" % slashify_path(cc
[0]),
218 "-DCMAKE_CXX_COMPILER=%s" % slashify_path(cxx
[0]),
219 "-DCMAKE_ASM_COMPILER=%s" % slashify_path(asm
[0]),
220 "-DCMAKE_AR=%s" % slashify_path(ar
),
221 "-DCMAKE_C_FLAGS_INIT=%s" % " ".join(cc
[1:]),
222 "-DCMAKE_CXX_FLAGS_INIT=%s" % " ".join(cxx
[1:]),
223 "-DCMAKE_ASM_FLAGS_INIT=%s" % " ".join(asm
[1:]),
224 "-DCMAKE_EXE_LINKER_FLAGS_INIT=%s" % " ".join(ldflags
),
225 "-DCMAKE_SHARED_LINKER_FLAGS_INIT=%s" % " ".join(ldflags
),
226 "-DCMAKE_BUILD_TYPE=%s" % build_type
,
227 "-DCMAKE_INSTALL_PREFIX=%s" % inst_dir
,
228 "-DLLVM_TARGETS_TO_BUILD=%s" % machine_targets
,
229 "-DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=OFF",
230 "-DLLVM_ENABLE_ASSERTIONS=%s" % ("ON" if assertions
else "OFF"),
231 "-DLLVM_ENABLE_BINDINGS=OFF",
232 "-DLLVM_ENABLE_CURL=OFF",
233 "-DLLVM_INCLUDE_TESTS=OFF",
235 if is_llvm_toolchain(cc
[0], cxx
[0]):
236 cmake_args
+= ["-DLLVM_ENABLE_LLD=ON"]
237 elif is_windows(target
) and is_cross_compile(target
):
239 "Cannot cross-compile for Windows with a compiler that is not clang"
242 if "TASK_ID" in os
.environ
:
244 "-DCLANG_REPOSITORY_STRING=taskcluster-%s" % os
.environ
["TASK_ID"],
246 projects
= ["clang", "lld"]
248 projects
.append("clang-tools-extra")
250 cmake_args
.append("-DLLVM_TOOL_LLI_BUILD=OFF")
252 cmake_args
.append("-DLLVM_ENABLE_PROJECTS=%s" % ";".join(projects
))
255 cmake_args
+= ["-DLLVM_ENABLE_LIBXML2=FORCE_ON"]
256 if is_linux(target
) and is_final_stage
:
257 sysroot
= os
.path
.join(os
.environ
.get("MOZ_FETCHES_DIR", ""), "sysroot")
258 if os
.path
.exists(sysroot
):
259 cmake_args
+= ["-DLLVM_BINUTILS_INCDIR=/usr/include"]
260 cmake_args
+= ["-DCMAKE_SYSROOT=%s" % sysroot
]
261 # Work around the LLVM build system not building the i386 compiler-rt
262 # because it doesn't allow to use a sysroot for that during the cmake
264 cmake_args
+= ["-DCAN_TARGET_i386=1"]
265 cmake_args
+= ["-DLLVM_ENABLE_TERMINFO=OFF"]
266 if is_windows(target
):
267 cmake_args
.insert(-1, "-DLLVM_EXPORT_SYMBOLS_FOR_PLUGINS=ON")
268 cmake_args
.insert(-1, "-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded")
269 if is_cross_compile(target
):
271 f
"-DCMAKE_TOOLCHAIN_FILE={src_dir}/cmake/platforms/WinMsvc.cmake",
272 f
"-DLLVM_NATIVE_TOOLCHAIN={os.path.dirname(os.path.dirname(cc[0]))}",
273 f
"-DHOST_ARCH={target[: -len('-pc-windows-msvc')]}",
274 f
"-DLLVM_WINSYSROOT={os.environ['VSINSTALLDIR']}",
275 "-DLLVM_DISABLE_ASSEMBLY_FILES=ON",
278 fetches
= os
.environ
["MOZ_FETCHES_DIR"]
280 "-DLIBXML2_DEFINITIONS=-DLIBXML_STATIC",
281 f
"-DLIBXML2_INCLUDE_DIR={fetches}/libxml2/include/libxml2",
282 f
"-DLIBXML2_LIBRARIES={fetches}/libxml2/lib/libxml2s.lib",
285 # libllvm as a shared library is not supported on Windows
286 cmake_args
+= ["-DLLVM_LINK_LLVM_DYLIB=ON"]
287 if ranlib
is not None:
288 cmake_args
+= ["-DCMAKE_RANLIB=%s" % slashify_path(ranlib
)]
289 if is_darwin(target
) and is_cross_compile(target
):
290 arch
= "arm64" if target
.startswith("aarch64") else "x86_64"
292 "-DCMAKE_SYSTEM_NAME=Darwin",
293 "-DCMAKE_SYSTEM_VERSION=%s" % os
.environ
["MACOSX_DEPLOYMENT_TARGET"],
294 "-DCMAKE_OSX_SYSROOT=%s" % slashify_path(os
.getenv("CROSS_SYSROOT")),
295 "-DCMAKE_FIND_ROOT_PATH=%s" % slashify_path(os
.getenv("CROSS_SYSROOT")),
296 "-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER",
297 "-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY",
298 "-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY",
299 "-DCMAKE_MACOSX_RPATH=ON",
300 "-DCMAKE_OSX_ARCHITECTURES=%s" % arch
,
301 "-DDARWIN_osx_ARCHS=%s" % arch
,
302 "-DDARWIN_osx_SYSROOT=%s" % slashify_path(os
.getenv("CROSS_SYSROOT")),
303 "-DLLVM_DEFAULT_TARGET_TRIPLE=%s" % target
,
304 "-DCMAKE_C_COMPILER_TARGET=%s" % target
,
305 "-DCMAKE_CXX_COMPILER_TARGET=%s" % target
,
306 "-DCMAKE_ASM_COMPILER_TARGET=%s" % target
,
310 "-DDARWIN_osx_BUILTIN_ARCHS=arm64",
312 # Starting in LLVM 11 (which requires SDK 10.12) the build tries to
313 # detect the SDK version by calling xcrun. Cross-compiles don't have
314 # an xcrun, so we have to set the version explicitly.
316 "-DDARWIN_macosx_OVERRIDE_SDK_VERSION=%s"
317 % os
.environ
["MACOSX_DEPLOYMENT_TARGET"],
321 # Per https://releases.llvm.org/10.0.0/docs/HowToBuildWithPGO.html
323 "-DLLVM_BUILD_INSTRUMENTED=IR",
324 "-DLLVM_BUILD_RUNTIME=No",
328 "-DLLVM_PROFDATA_FILE=%s" % profile
,
331 # Using LTO for both profile generation and usage to avoid most
332 # "function control flow change detected (hash mismatch)" error.
333 if profile
and not is_windows(target
):
334 cmake_args
.append("-DLLVM_ENABLE_LTO=Thin")
338 cmake_args
+= cmake_base_args(cc
, cxx
, asm
, ar
, ranlib
, ldflags
, inst_dir
)
339 cmake_args
+= [src_dir
]
340 build_package(build_dir
, cmake_args
)
342 # For some reasons the import library clang.lib of clang.exe is not
343 # installed, so we copy it by ourselves.
344 if is_windows(target
) and is_final_stage
:
345 install_import_library(build_dir
, inst_dir
)
348 # Return the absolute path of a build tool. We first look to see if the
349 # variable is defined in the config file, and if so we make sure it's an
350 # absolute path to an existing tool, otherwise we look for a program in
353 # This expects the name of the key in the config file to match the name of
354 # the tool in the default toolchain on the system (for example, "ld" on Unix
355 # and "link" on Windows).
356 def get_tool(config
, key
):
359 f
= config
[key
].format(**os
.environ
)
361 if not os
.path
.exists(f
):
362 raise ValueError("%s must point to an existing path" % key
)
365 # Assume that we have the name of some program that should be on PATH.
366 tool
= which(f
) if f
else which(key
)
368 raise ValueError("%s not found on PATH" % (f
or key
))
372 # This function is intended to be called on the final build directory when
373 # building clang-tidy. Also clang-format binaries are included that can be used
374 # in conjunction with clang-tidy.
375 # As a separate binary we also ship clangd for the language server protocol that
376 # can be used as a plugin in `vscode`.
377 # Its job is to remove all of the files which won't be used for clang-tidy or
378 # clang-format to reduce the download size. Currently when this function
379 # finishes its job, it will leave final_dir with a layout like this:
383 # clang-apply-replacements
389 # * (nothing will be deleted here)
394 # * (nothing will be deleted here)
397 # clang-format-diff.py
400 def prune_final_dir_for_clang_tidy(final_dir
, target
):
401 # Make sure we only have what we expect.
413 dirs
.append("x86_64-unknown-linux-gnu")
414 for f
in glob
.glob("%s/*" % final_dir
):
415 if os
.path
.basename(f
) not in dirs
:
416 raise Exception("Found unknown file %s in the final directory" % f
)
417 if not os
.path
.isdir(f
):
418 raise Exception("Expected %s to be a directory" % f
)
421 "clang-apply-replacements",
428 re_clang_tidy
= re
.compile(r
"^(" + "|".join(kept_binaries
) + r
")(\.exe)?$", re
.I
)
429 for f
in glob
.glob("%s/bin/*" % final_dir
):
430 if re_clang_tidy
.search(os
.path
.basename(f
)) is None:
433 # Keep include/ intact.
435 # Remove the target-specific files.
437 if os
.path
.exists(os
.path
.join(final_dir
, "x86_64-unknown-linux-gnu")):
438 shutil
.rmtree(os
.path
.join(final_dir
, "x86_64-unknown-linux-gnu"))
440 # In lib/, only keep lib/clang/N.M.O/include and the LLVM shared library.
441 re_ver_num
= re
.compile(r
"^\d+(?:\.\d+\.\d+)?$", re
.I
)
442 for f
in glob
.glob("%s/lib/*" % final_dir
):
443 name
= os
.path
.basename(f
)
446 if is_darwin(target
) and name
in ["libLLVM.dylib", "libclang-cpp.dylib"]:
448 if is_linux(target
) and (
449 fnmatch
.fnmatch(name
, "libLLVM*.so")
450 or fnmatch
.fnmatch(name
, "libclang-cpp.so*")
454 for f
in glob
.glob("%s/lib/clang/*" % final_dir
):
455 if re_ver_num
.search(os
.path
.basename(f
)) is None:
457 for f
in glob
.glob("%s/lib/clang/*/*" % final_dir
):
458 if os
.path
.basename(f
) != "include":
461 # Completely remove libexec/, msbuild-bin and tools, if it exists.
462 shutil
.rmtree(os
.path
.join(final_dir
, "libexec"))
463 for d
in ("msbuild-bin", "tools"):
464 d
= os
.path
.join(final_dir
, d
)
465 if os
.path
.exists(d
):
468 # In share/, only keep share/clang/*tidy*
469 re_clang_tidy
= re
.compile(r
"format|tidy", re
.I
)
470 for f
in glob
.glob("%s/share/*" % final_dir
):
471 if os
.path
.basename(f
) != "clang":
473 for f
in glob
.glob("%s/share/clang/*" % final_dir
):
474 if re_clang_tidy
.search(os
.path
.basename(f
)) is None:
479 parser
= argparse
.ArgumentParser()
485 type=argparse
.FileType("r"),
486 help="Clang configuration file",
489 "--clean", required
=False, action
="store_true", help="Clean the build directory"
495 help="Skip tar packaging stage",
501 help="Do not patch source",
504 args
= parser
.parse_args()
506 if not os
.path
.exists("llvm/README.txt"):
508 "The script must be run from the root directory of the llvm-project tree"
510 source_dir
= os
.getcwd()
511 build_dir
= source_dir
+ "/build"
514 shutil
.rmtree(build_dir
)
517 llvm_source_dir
= source_dir
+ "/llvm"
520 # Merge all the configs we got from the command line.
521 for c
in args
.config
:
522 this_config_dir
= os
.path
.dirname(c
.name
)
523 this_config
= json
.load(c
)
524 patches
= this_config
.get("patches")
526 this_config
["patches"] = [os
.path
.join(this_config_dir
, p
) for p
in patches
]
527 for key
, value
in this_config
.items():
528 old_value
= config
.get(key
)
529 if old_value
is None:
534 elif type(old_value
) != type(value
):
536 "{} is overriding `{}` with a value of the wrong type".format(
540 elif isinstance(old_value
, list):
542 if v
not in old_value
:
544 elif isinstance(old_value
, dict):
545 raise Exception("{} is setting `{}` to a dict?".format(c
.name
, key
))
550 if "stages" in config
:
551 stages
= int(config
["stages"])
552 if stages
not in (1, 2, 3, 4):
553 raise ValueError("We only know how to build 1, 2, 3, or 4 stages.")
555 if "skip_stages" in config
:
556 # The assumption here is that the compiler given in `cc` and other configs
557 # is the result of the last skip stage, built somewhere else.
558 skip_stages
= int(config
["skip_stages"])
559 if skip_stages
>= stages
:
560 raise ValueError("Cannot skip more stages than are built.")
564 if pgo
not in (True, False):
565 raise ValueError("Only boolean values are accepted for pgo.")
566 build_type
= "Release"
567 if "build_type" in config
:
568 build_type
= config
["build_type"]
569 if build_type
not in ("Release", "Debug", "RelWithDebInfo", "MinSizeRel"):
571 "We only know how to do Release, Debug, RelWithDebInfo or "
574 targets
= config
.get("targets")
575 build_clang_tidy
= False
576 if "build_clang_tidy" in config
:
577 build_clang_tidy
= config
["build_clang_tidy"]
578 if build_clang_tidy
not in (True, False):
579 raise ValueError("Only boolean values are accepted for build_clang_tidy.")
580 build_clang_tidy_alpha
= False
581 # check for build_clang_tidy_alpha only if build_clang_tidy is true
582 if build_clang_tidy
and "build_clang_tidy_alpha" in config
:
583 build_clang_tidy_alpha
= config
["build_clang_tidy_alpha"]
584 if build_clang_tidy_alpha
not in (True, False):
586 "Only boolean values are accepted for build_clang_tidy_alpha."
588 build_clang_tidy_external
= False
589 # check for build_clang_tidy_external only if build_clang_tidy is true
590 if build_clang_tidy
and "build_clang_tidy_external" in config
:
591 build_clang_tidy_external
= config
["build_clang_tidy_external"]
592 if build_clang_tidy_external
not in (True, False):
594 "Only boolean values are accepted for build_clang_tidy_external."
597 if "assertions" in config
:
598 assertions
= config
["assertions"]
599 if assertions
not in (True, False):
600 raise ValueError("Only boolean values are accepted for assertions.")
602 for t
in SUPPORTED_TARGETS
:
603 if not is_cross_compile(t
):
608 f
"Cannot use this script on {platform.system()} {platform.machine()}"
611 target
= config
.get("target", host
)
612 if target
not in SUPPORTED_TARGETS
:
613 raise ValueError(f
"{target} is not a supported target.")
615 if is_cross_compile(target
) and not is_linux(host
):
616 raise Exception("Cross-compilation is only supported on Linux")
618 if is_darwin(target
):
619 os
.environ
["MACOSX_DEPLOYMENT_TARGET"] = (
620 "11.0" if target
.startswith("aarch64") else "10.12"
623 if is_windows(target
):
626 cxx_name
= "clang-cl"
632 cc
= get_tool(config
, "cc")
633 cxx
= get_tool(config
, "cxx")
634 asm
= get_tool(config
, "ml" if is_windows(target
) else "as")
635 # Not using lld here as default here because it's not in PATH. But clang
636 # knows how to find it when they are installed alongside each others.
637 ar
= get_tool(config
, "lib" if is_windows(target
) else "ar")
638 ranlib
= None if is_windows(target
) else get_tool(config
, "ranlib")
640 if not os
.path
.exists(source_dir
):
641 os
.makedirs(source_dir
)
643 if not args
.skip_patch
:
644 for p
in config
.get("patches", []):
647 package_name
= "clang"
649 package_name
= "clang-tidy"
650 if not args
.skip_patch
:
652 source_dir
, build_clang_tidy_alpha
, build_clang_tidy_external
655 if not os
.path
.exists(build_dir
):
656 os
.makedirs(build_dir
)
658 stage1_dir
= build_dir
+ "/stage1"
659 stage1_inst_dir
= stage1_dir
+ "/" + package_name
661 final_stage_dir
= stage1_dir
663 if is_darwin(target
):
669 # It's unfortunately required to specify the linker used here because
670 # the linker flags are used in LLVM's configure step before
671 # -DLLVM_ENABLE_LLD is actually processed.
676 elif is_linux(target
):
679 extra_cflags2
= ["-fPIC"]
680 # Silence clang's warnings about arguments not being used in compilation.
683 "-Qunused-arguments",
686 # Avoid libLLVM internal function calls going through the PLT.
687 extra_ldflags
= ["-Wl,-Bsymbolic-functions"]
688 # For whatever reason, LLVM's build system will set things up to turn
689 # on -ffunction-sections and -fdata-sections, but won't turn on the
690 # corresponding option to strip unused sections. We do it explicitly
691 # here. LLVM's build system is also picky about turning on ICF, so
692 # we do that explicitly here, too.
694 # It's unfortunately required to specify the linker used here because
695 # the linker flags are used in LLVM's configure step before
696 # -DLLVM_ENABLE_LLD is actually processed.
697 if is_llvm_toolchain(cc
, cxx
):
698 extra_ldflags
+= ["-fuse-ld=lld", "-Wl,--icf=safe"]
699 extra_ldflags
+= ["-Wl,--gc-sections"]
700 elif is_windows(target
):
703 # clang-cl would like to figure out what it's supposed to be emulating
704 # by looking at an MSVC install, but we don't really have that here.
705 # Force things on based on WinMsvc.cmake.
706 # Ideally, we'd just use WinMsvc.cmake as a toolchain file, but it only
707 # really works for cross-compiles, which this is not.
708 with
open(os
.path
.join(llvm_source_dir
, "cmake/platforms/WinMsvc.cmake")) as f
:
712 for item
in line
.split()
713 if "-fms-compatibility-version=" in item
715 extra_cflags2
= [compat
]
716 extra_cxxflags2
= [compat
]
720 upload_dir
= os
.getenv("UPLOAD_DIR")
721 if assertions
and upload_dir
:
722 extra_cflags2
+= ["-fcrash-diagnostics-dir=%s" % upload_dir
]
723 extra_cxxflags2
+= ["-fcrash-diagnostics-dir=%s" % upload_dir
]
728 [cxx
] + extra_cxxflags
,
729 [asm
] + extra_asmflags
,
740 is_final_stage
=(stages
== 1),
743 if stages
>= 2 and skip_stages
< 2:
744 stage2_dir
= build_dir
+ "/stage2"
745 stage2_inst_dir
= stage2_dir
+ "/" + package_name
746 final_stage_dir
= stage2_dir
748 cc
= stage1_inst_dir
+ "/bin/%s%s" % (cc_name
, exe_ext
)
749 cxx
= stage1_inst_dir
+ "/bin/%s%s" % (cxx_name
, exe_ext
)
750 asm
= stage1_inst_dir
+ "/bin/%s%s" % (cc_name
, exe_ext
)
752 [cc
] + extra_cflags2
,
753 [cxx
] + extra_cxxflags2
,
754 [asm
] + extra_asmflags
,
765 is_final_stage
=(stages
== 2),
766 profile
="gen" if pgo
else None,
769 if stages
>= 3 and skip_stages
< 3:
770 stage3_dir
= build_dir
+ "/stage3"
771 stage3_inst_dir
= stage3_dir
+ "/" + package_name
772 final_stage_dir
= stage3_dir
774 cc
= stage2_inst_dir
+ "/bin/%s%s" % (cc_name
, exe_ext
)
775 cxx
= stage2_inst_dir
+ "/bin/%s%s" % (cxx_name
, exe_ext
)
776 asm
= stage2_inst_dir
+ "/bin/%s%s" % (cc_name
, exe_ext
)
778 [cc
] + extra_cflags2
,
779 [cxx
] + extra_cxxflags2
,
780 [asm
] + extra_asmflags
,
794 llvm_profdata
= stage2_inst_dir
+ "/bin/llvm-profdata%s" % exe_ext
795 merge_cmd
= [llvm_profdata
, "merge", "-o", "merged.profdata"]
796 profraw_files
= glob
.glob(
797 os
.path
.join(stage2_dir
, "build", "profiles", "*.profraw")
799 run_in(stage3_dir
, merge_cmd
+ profraw_files
)
802 shutil
.copy2(os
.path
.join(stage3_dir
, "merged.profdata"), upload_dir
)
805 if stages
>= 4 and skip_stages
< 4:
806 stage4_dir
= build_dir
+ "/stage4"
807 final_stage_dir
= stage4_dir
811 profile_dir
= os
.environ
.get("MOZ_FETCHES_DIR", "")
813 profile_dir
= stage3_dir
814 profile
= os
.path
.join(profile_dir
, "merged.profdata")
816 cc
= stage3_inst_dir
+ "/bin/%s%s" % (cc_name
, exe_ext
)
817 cxx
= stage3_inst_dir
+ "/bin/%s%s" % (cxx_name
, exe_ext
)
818 asm
= stage3_inst_dir
+ "/bin/%s%s" % (cc_name
, exe_ext
)
820 [cc
] + extra_cflags2
,
821 [cxx
] + extra_cxxflags2
,
822 [asm
] + extra_asmflags
,
838 prune_final_dir_for_clang_tidy(
839 os
.path
.join(final_stage_dir
, package_name
), target
842 if not args
.skip_tar
:
843 build_tar_package("%s.tar.zst" % package_name
, final_stage_dir
, package_name
)
846 if __name__
== "__main__":