Skip to main content
Glama
gen_sln.bxl8.45 kB
# Copyright (c) Meta Platforms, Inc. and affiliates. # # This source code is licensed under both the MIT license found in the # LICENSE-MIT file in the root directory of this source tree and the Apache # License, Version 2.0 found in the LICENSE-APACHE file in the root directory # of this source tree. load("get_vs_settings.bxl", "get_basic_vs_settings") load("utils.bxl", "basename", "gen_guid", "get_project_file_path", "log_debug", "sanitize") def _gen_entry(project_type_guid, project_name, project_filepath, project_guid): return """Project("{project_type_guid}") = "{project_name}", "{project_filepath}", "{project_guid}" EndProject""".format( project_type_guid = project_type_guid, project_name = project_name, project_filepath = project_filepath, project_guid = project_guid, ) def _gen_folder(folder_path, guid, project_names): project_name = basename(folder_path) if project_name in project_names: # "()" quote folder name to avoid prompt: The solution already contains an item named 'xxx'. project_name = "(" + project_name + ")" # List of project type GUIDs https://github.com/JamesW75/visual-studio-project-type-guid project_type_guid_folder = "{2150E333-8FDC-42A3-9474-1A3956D46DE8}" return _gen_entry( project_type_guid_folder, project_name, project_name, guid, ) def _gen_project(target, vs_settings, project_names): project_name = target.label.name if project_names[project_name] > 1: # Unique name to avoid prompt: The solution already contains an item named 'xxx'. project_name = sanitize(target.label.package + "_" + target.label.name) # List of project type GUIDs https://github.com/JamesW75/visual-studio-project-type-guid project_type_guid_cpp = "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}" return _gen_entry( project_type_guid_cpp, project_name, get_project_file_path(target.label, ".vcxproj"), vs_settings["Globals"]["ProjectGuid"], ) # For each target/project, generate intermediate folder entries if they haven't and the target/project itself, # as well as mappings of item => folder for solution nested projects structure. def _gen_target(target, vs_settings, existing_folders, nested_projects, project_names): entries = [] if target.label.package: folders = target.label.package.split("/") folder_prev = None for i in range(len(folders)): folder = "/".join(folders[0:i + 1]) folder_guid = gen_guid(folder) if folder_prev: nested_projects[folder_guid] = existing_folders[folder_prev] if folder not in existing_folders: entries.append(_gen_folder(folder, folder_guid, project_names)) existing_folders[folder] = folder_guid folder_prev = folder nested_projects[vs_settings["Globals"]["ProjectGuid"]] = existing_folders[folder_prev] entries.append(_gen_project(target, vs_settings, project_names)) return "\n".join(entries) def _gen_nested_projects(nested_projects): return "\n".join([ "\t\t{} = {}".format(child, parent) for (child, parent) in nested_projects.items() ]) def _gen_solution_configuration_platform(project_configuration): return "\t\t{configuration}|{platform} = {configuration}|{platform}".format( configuration = project_configuration["Configuration"], platform = project_configuration["Platform"], ) def _gen_project_configuration_platforms(target_node, vs_settings, explicit_targets): configs = [] guid = vs_settings["Globals"]["ProjectGuid"] for config in vs_settings["ProjectConfigurations"]: config_name = config["Configuration"] + "|" + config["Platform"] configs.append("\t\t{guid}.{config_name}.ActiveCfg = {config_name}".format( guid = guid, config_name = config_name, )) if target_node.label.raw_target() in explicit_targets: configs.append("\t\t{guid}.{config_name}.Build.0 = {config_name}".format( guid = guid, config_name = config_name, )) return "\n".join(configs) def _set_startup_target(targets, vs_settings_list, startup_target_label): targets_labels = [target.label.raw_target() for target in targets] if startup_target_label in targets_labels: startup_target_index = targets_labels.index(startup_target_label) targets[0], targets[startup_target_index] = targets[startup_target_index], targets[0] vs_settings_list[0], vs_settings_list[startup_target_index] = vs_settings_list[startup_target_index], vs_settings_list[0] else: warning("Startup target couldn't be located: {}. Please check passed in targets list, `--recursive_target_types`, `--target_exclude_pattern` and `--target_exclude_pattern`.".format(startup_target_label)) # In buck dependency tree, duplicate targets can exist with exact same label but different # configurations. While VS doesn't like duplicate project names (prompting with message: The # solution already contains an item named 'xxx'). Besides, there is not much value in showing # multiple projects for the same target but with slightly different configuration. Ideally, this # could be more efficient trimming those duplicates while building dependency trees, but it's more # risky of getting missing target nodes while traversaling the dependency tree after trimming. def _dedup_targets(targets, vs_settings_list): deduped_targets = [] deduped_vs_settings_list = [] seen_raw_targets = set() for i in range(len(targets)): raw_target = targets[i].label.raw_target() if raw_target not in seen_raw_targets: seen_raw_targets.add(raw_target) deduped_targets.append(targets[i]) deduped_vs_settings_list.append(vs_settings_list[i]) return deduped_targets, deduped_vs_settings_list def gen_sln(targets, vs_settings_list, explicit_targets, startup_target_label, bxl_ctx): log_debug("# Generating sln for {}", startup_target_label, bxl_ctx = bxl_ctx) if len(targets) != len(vs_settings_list): fail("targets and vs_settings_list are expected to be length.") _set_startup_target(targets, vs_settings_list, startup_target_label) targets, vs_settings_list = _dedup_targets(targets, vs_settings_list) existing_folders = {} # folder path => folder guid nested_projects = {} # project guid => parent guid project_names = {} # project name => count for target in targets: project_names[target.label.name] = project_names.get(target.label.name, 0) + 1 sln_content = """Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 {projects} Global \tGlobalSection(SolutionConfigurationPlatforms) = preSolution {solution_configuration_platforms} \tEndGlobalSection \tGlobalSection(ProjectConfigurationPlatforms) = preSolution {project_configuration_platforms} \tEndGlobalSection \tGlobalSection(NestedProjects) = preSolution {nested_projects} \tEndGlobalSection EndGlobal""".format( projects = "\n".join([ _gen_target(t, s, existing_folders, nested_projects, project_names) for (t, s) in zip(targets, vs_settings_list) ]), solution_configuration_platforms = "\n".join([ _gen_solution_configuration_platform(config) for config in vs_settings_list[-1]["ProjectConfigurations"] ]), project_configuration_platforms = "\n".join([ _gen_project_configuration_platforms(t, s, explicit_targets) for (t, s) in zip(targets, vs_settings_list) ]), nested_projects = _gen_nested_projects(nested_projects), ) return sln_content def _main(bxl_ctx): target_label = bxl_ctx.cli_args.target target_node = bxl_ctx.configured_targets(target_label) basic_vs_settings = get_basic_vs_settings(target_node, bxl_ctx.cli_args) sln_content = gen_sln([target_node], [basic_vs_settings], [target_label], target_node.label, bxl_ctx) bxl_ctx.output.print(sln_content) main = bxl_main( impl = _main, cli_args = { "log_level": cli_args.int(default = 30), "mode_files": cli_args.list(cli_args.string(), default = ["fbsource//arvr/mode/win/dev"]), "target": cli_args.target_label(), }, )

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server