# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/.
import argparse import logging import os import subprocess import sys
import mozpack.path as mozpath from mach.decorators import Command, CommandArgument from mozfile import which
from mozbuild import build_commands from mozbuild.util import cpu_count
@Command( "ide",
category="devenv",
description="Generate a project and launch an IDE.",
virtualenv_name="build",
)
@CommandArgument("ide", choices=["eclipse", "visualstudio", "vscode"])
@CommandArgument( "--no-interactive",
default=False,
action="store_true",
help="Just generate the configuration",
)
@CommandArgument("args", nargs=argparse.REMAINDER) def run(command_context, ide, no_interactive, args):
interactive = not no_interactive
backend = None if ide == "eclipse":
backend = "CppEclipse" elif ide == "visualstudio":
backend = "VisualStudio" elif ide == "vscode": ifnot command_context.config_environment.is_artifact_build:
backend = "Clangd"
if ide == "eclipse"andnot which("eclipse"):
command_context.log(
logging.ERROR, "ide",
{}, "Eclipse CDT 8.4 or later must be installed in your PATH.",
)
command_context.log(
logging.ERROR, "ide",
{}, "Download: http://www.eclipse.org/cdt/downloads.php",
) return 1
if ide == "vscode":
rc = build_commands.configure(command_context)
if rc != 0: return rc
# First install what we can through install manifests.
rc = command_context._run_make(
directory=command_context.topobjdir,
target="pre-export",
line_handler=None,
) if rc != 0: return rc
# Then build the rest of the build dependencies by running the full # export target, because we can't do anything better. for target in ("export", "pre-compile"):
rc = command_context._run_make(
directory=command_context.topobjdir,
target=target,
line_handler=None,
) if rc != 0: return rc else: # Here we refresh the whole build. 'build export' is sufficient here and is # probably more correct but it's also nice having a single target to get a fully # built and indexed project (gives a easy target to use before go out to lunch).
res = command_context._mach_context.commands.dispatch( "build", command_context._mach_context
) if res != 0: return 1
if backend: # Generate or refresh the IDE backend.
python = command_context.virtualenv_manager.python_path
config_status = os.path.join(command_context.topobjdir, "config.status")
args = [python, config_status, "--backend=%s" % backend]
res = command_context._run_command_in_objdir(
args=args, pass_thru=True, ensure_exit_code=False
) if res != 0: return 1
if ide == "eclipse":
eclipse_workspace_dir = get_eclipse_workspace_path(command_context)
subprocess.check_call(["eclipse", "-data", eclipse_workspace_dir]) elif ide == "visualstudio":
visual_studio_workspace_dir = get_visualstudio_workspace_path(command_context)
subprocess.call(["explorer.exe", visual_studio_workspace_dir]) elif ide == "vscode": return setup_vscode(command_context, interactive)
def get_eclipse_workspace_path(command_context): from mozbuild.backend.cpp_eclipse import CppEclipseBackend
def setup_vscode(command_context, interactive): from mozbuild.backend.clangd import find_vscode_cmd
# Check if platform has VSCode installed if interactive:
vscode_cmd = find_vscode_cmd() if vscode_cmd isNone:
choice = prompt_bool( "VSCode cannot be found, and may not be installed. Proceed?"
) ifnot choice: return 1
new_settings = {}
artifact_prefix = "" if command_context.config_environment.is_artifact_build:
artifact_prefix = ( "\nArtifact build configured: Skipping clang and rust setup. " "If you later switch to a full build, please re-run this command."
) else:
new_settings = setup_clangd_rust_in_vscode(command_context)
# Add file associations.
new_settings = {
**new_settings, "files.associations": { "*.jsm": "javascript", "*.sjs": "javascript",
}, # Note, the top-level editor settings are left as default to allow the # user's defaults (if any) to take effect. "[javascript][javascriptreact][typescript][typescriptreact][json][jsonc][html]": { "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": True,
}, "files.exclude": {"obj-*": True, relobjdir: True}, "files.watcherExclude": {"obj-*": True, relobjdir: True},
}
import difflib import json
# Load the existing .vscode/settings.json file, to check if if needs to # be created or updated. try: with open(vscode_settings) as fh:
old_settings_str = fh.read() except FileNotFoundError:
print( "Configuration for {} will be created.{}".format(
vscode_settings, artifact_prefix
)
)
old_settings_str = None
if old_settings_str isNone: # No old settings exist with open(vscode_settings, "w") as fh:
json.dump(new_settings, fh, indent=4) else: # Merge our new settings with the existing settings, and check if we # need to make changes. Only prompt & write out the updated config # file if settings actually changed. try:
old_settings = json.loads(old_settings_str)
prompt_prefix = "" except ValueError:
old_settings = {}
prompt_prefix = ( "\n**WARNING**: Parsing of existing settings file failed. " "Existing settings will be lost!"
)
# If we've got an old section with the formatting configuration, remove it # so that we effectively "upgrade" the user to include json from the new # settings. The user is presented with the diffs so should spot any issues.
deprecated = [ "[javascript][javascriptreact][typescript][typescriptreact]", "[javascript][javascriptreact][typescript][typescriptreact][json]", "[javascript][javascriptreact][typescript][typescriptreact][json][html]",
] for entry in deprecated: if entry in old_settings:
old_settings.pop(entry)
settings = {**old_settings, **new_settings}
if old_settings != settings: # Prompt the user with a diff of the changes we're going to make
new_settings_str = json.dumps(settings, indent=4) if interactive:
print( "\nThe following modifications to {settings} will occur:\n{diff}".format(
settings=vscode_settings,
diff="".join(
difflib.unified_diff(
old_settings_str.splitlines(keepends=True),
new_settings_str.splitlines(keepends=True), "a/.vscode/settings.json", "b/.vscode/settings.json",
n=30,
)
),
)
)
choice = prompt_bool( "{}{}\nProceed with modifications to {}?".format(
artifact_prefix, prompt_prefix, vscode_settings
)
) ifnot choice: return 1
with open(vscode_settings, "w") as fh:
fh.write(new_settings_str)
ifnot interactive: return 0
# Open vscode with new configuration, or ask the user to do so if the # binary was not found. if vscode_cmd isNone:
print( "Please open VS Code manually and load directory: {}".format(
command_context.topsrcdir
)
) return 0
if rc != 0:
command_context.log(
logging.ERROR, "ide",
{}, "Unable to open VS Code. Please open VS Code manually and load " "directory: {}".format(command_context.topsrcdir),
) return rc
# The location of the comm/ directory if we're building Thunderbird. `None` # if we're building Firefox.
commtopsrcdir = command_context.substs.get("commtopsrcdir")
if commtopsrcdir: # Thunderbird uses its own Rust workspace, located in comm/rust/ - we # set it as the main workspace to build a little further below. The # working directory for cargo check commands is the workspace's root. if sys.platform == "win32":
cargo_check_command = [sys.executable, "../../mach"] else:
cargo_check_command = ["../../mach"] else: if sys.platform == "win32":
cargo_check_command = [sys.executable, "mach"] else:
cargo_check_command = ["./mach"]
if windows_rs_dir := command_context.config_environment.substs.get( "MOZ_WINDOWS_RS_DIR"
):
rust_analyzer_extra_includes.append(windows_rs_dir)
config = { "clangd.path": clangd_path, "clangd.arguments": [ "-j",
str(cpu_count() // 2), "--limit-results", "0", "--completion-style", "detailed", "--background-index", "--all-scopes-completion", "--log", "info", "--pch-storage", "disk", "--clang-tidy", "--header-insertion=never",
], "rust-analyzer.server.extraEnv": { # Point rust-analyzer at the real target directory used by our # build, so it can discover the files created when we run `./mach # cargo check`. "CARGO_TARGET_DIR": command_context.topobjdir,
}, "rust-analyzer.vfs.extraIncludes": rust_analyzer_extra_includes, "rust-analyzer.cargo.buildScripts.overrideCommand": cargo_check_command, "rust-analyzer.check.overrideCommand": cargo_check_command,
}
# If we're building Thunderbird, configure rust-analyzer to use its Cargo # workspace rather than Firefox's. `linkedProjects` disables rust-analyzer's # project auto-discovery, therefore setting it ensures we use the correct # workspace. if commtopsrcdir:
config["rust-analyzer.linkedProjects"] = [
os.path.join(commtopsrcdir, "rust", "Cargo.toml")
]
if os.path.isdir(clang_tools_path):
shutil.rmtree(clang_tools_path)
# Create base directory where we store clang binary
os.mkdir(clang_tools_path)
from mozbuild.artifact_commands import artifact_toolchain
job, _ = command_context.platform
if job isNone:
command_context.log(
logging.ERROR, "ide",
{}, "The current platform isn't supported. " "Currently only the following platforms are " "supported: win32/win64, linux64 and macosx64.",
) return 1
job += "-clang-tidy"
# We want to unpack data in the clang-tidy mozbuild folder
currentWorkingDir = os.getcwd()
os.chdir(clang_tools_path)
rc = artifact_toolchain(
command_context, verbose=False, from_build=[job], no_unpack=False, retry=0
) # Change back the cwd
os.chdir(currentWorkingDir)
return rc
def prompt_bool(prompt, limit=5): """Prompts the user with prompt and requires a boolean value.""" from mach.util import strtobool
for _ in range(limit): try: return strtobool(input(prompt + " [Y/N]\n")) except ValueError:
print( "ERROR! Please enter a valid option! Please use any of the following:" " Y, N, True, False, 1, 0"
) returnFalse
Messung V0.5
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.