#include "pch.h" #include #include "strings.h" #include "settings.h" #include "type_writers.h" #include "helpers.h" #include "code_writers.h" #include "component_writers.h" #include "file_writers.h" #include "type_writers.h" namespace cppwinrt { settings_type settings; struct usage_exception {}; static constexpr option options[] { { "input", 0, option::no_max, "", "Windows metadata to include in projection" }, { "reference", 0, option::no_max, "", "Windows metadata to reference from projection" }, { "output", 0, 1, "", "Location of generated projection and component templates" }, { "component", 0, 1, "[]", "Generate component templates, and optional implementation" }, { "name", 0, 1, "", "Specify explicit name for component files" }, { "verbose", 0, 0, {}, "Show detailed progress information" }, { "overwrite", 0, 0, {}, "Overwrite generated component files" }, { "prefix", 0, 0, {}, "Use dotted namespace convention for component files (defaults to folders)" }, { "pch", 0, 1, "", "Specify name of precompiled header file (defaults to pch.h; use '.' to disable)" }, { "include", 0, option::no_max, "", "One or more prefixes to include in input" }, { "exclude", 0, option::no_max, "", "One or more prefixes to exclude from input" }, { "base", 0, 0, {}, "Generate base.h unconditionally" }, { "optimize", 0, 0, {}, "Generate component projection with unified construction support" }, { "help", 0, option::no_max, {}, "Show detailed help with examples" }, { "?", 0, option::no_max, {}, {} }, { "library", 0, 1, "", "Specify library prefix (defaults to winrt)" }, { "filter" }, // One or more prefixes to include in input (same as -include) { "license", 0, 1, "[]", "Generate license comment from template file" }, { "brackets", 0, 0 }, // Use angle brackets for #includes (defaults to quotes) { "fastabi", 0, 0 }, // Enable support for the Fast ABI { "ignore_velocity", 0, 0 }, // Ignore feature staging metadata and always include implementations { "synchronous", 0, 0 }, // Instructs cppwinrt to run on a single thread to avoid file system issues in batch builds }; static void print_usage(writer& w) { static auto printColumns = [](writer& w, std::string_view const& col1, std::string_view const& col2) { w.write_printf(" %-20s%s\n", col1.data(), col2.data()); }; static auto printOption = [](writer& w, option const& opt) { if(opt.desc.empty()) { return; } printColumns(w, w.write_temp("-% %", opt.name, opt.arg), opt.desc); }; auto format = R"( C++/WinRT v% Copyright (c) Microsoft Corporation. All rights reserved. cppwinrt.exe [options...] Options: % ^@ Response file containing command line options Where is one or more of: path Path to winmd file or recursively scanned folder )" #if defined(_WIN32) || defined(_WIN64) R"( local Local ^%WinDir^%\System32\WinMetadata folder sdk[+] Current version of Windows SDK [with extensions] 10.0.12345.0[+] Specific version of Windows SDK [with extensions] )" #endif ; w.write(format, CPPWINRT_VERSION_STRING, bind_each(printOption, options)); } static void process_args(reader const& args) { settings.verbose = args.exists("verbose"); settings.fastabi = args.exists("fastabi"); settings.input = args.files("input", database::is_database); settings.reference = args.files("reference", database::is_database); settings.component = args.exists("component"); settings.base = args.exists("base"); settings.license = args.exists("license"); settings.brackets = args.exists("brackets"); path output_folder = args.value("output", "."); create_directories(output_folder / "winrt/impl"); settings.output_folder = canonical(output_folder).string(); settings.output_folder += std::filesystem::path::preferred_separator; for (auto && include : args.values("include")) { settings.include.insert(include); } for (auto && include : args.values("filter")) { settings.include.insert(include); } for (auto && exclude : args.values("exclude")) { settings.exclude.insert(exclude); } if (settings.license) { std::string license_arg = args.value("license"); if (license_arg.empty()) { settings.license_template = R"(// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. )"; } else { std::filesystem::path template_path{ license_arg }; std::ifstream template_file(absolute(template_path)); if (template_file.fail()) { throw_invalid("Cannot read license template file '", absolute(template_path).string() + "'"); } std::string line_buf; while (getline(template_file, line_buf)) { if (line_buf.empty()) { settings.license_template += "//\n"; } else { settings.license_template += "// "; settings.license_template += line_buf; settings.license_template += "\n"; } } } } if (settings.component) { settings.component_overwrite = args.exists("overwrite"); settings.component_name = args.value("name"); if (settings.component_name.empty()) { // For compatibility with C++/WinRT 1.0, the component_name defaults to the *first* // input, hence the use of values() here that will return the args in input order. auto& values = args.values("input"); if (!values.empty()) { settings.component_name = path(values[0]).filename().replace_extension().string(); } } settings.component_pch = args.value("pch", "pch.h"); settings.component_prefix = args.exists("prefix"); settings.component_lib = args.value("library", "winrt"); settings.component_opt = args.exists("optimize"); settings.component_ignore_velocity = args.exists("ignore_velocity"); if (settings.component_pch == ".") { settings.component_pch.clear(); } auto component = args.value("component"); if (!component.empty()) { create_directories(component); settings.component_folder = canonical(component).string(); settings.component_folder += std::filesystem::path::preferred_separator; } } } static auto get_files_to_cache() { std::vector files; files.insert(files.end(), settings.input.begin(), settings.input.end()); files.insert(files.end(), settings.reference.begin(), settings.reference.end()); return files; } static void build_filters(cache const& c) { if (settings.reference.empty()) { return; } std::set include; for (auto file : settings.input) { auto db = std::find_if(c.databases().begin(), c.databases().end(), [&](auto&& db) { return db.path() == file; }); for (auto&& type : db->TypeDef) { if (!type.Flags().WindowsRuntime()) { continue; } std::string full_name{ type.TypeNamespace() }; full_name += '.'; full_name += type.TypeName(); include.insert(full_name); } } settings.projection_filter = { include, {} }; settings.component_filter = { settings.include.empty() ? include : settings.include, settings.exclude }; } static void build_fastabi_cache(cache const& c) { if (!settings.fastabi) { return; } for (auto&& [ns, members] : c.namespaces()) { for (auto&& type : members.classes) { if (!has_fastabi(type)) { continue; } auto default_interface = get_default_interface(type); if (default_interface.type() == TypeDefOrRef::TypeDef) { settings.fastabi_cache.try_emplace(default_interface.TypeDef(), type); } else { settings.fastabi_cache.try_emplace(find_required(default_interface.TypeRef()), type); } } } } static void remove_foundation_types(cache& c) { c.remove_type("Windows.Foundation", "DateTime"); c.remove_type("Windows.Foundation", "EventRegistrationToken"); c.remove_type("Windows.Foundation", "HResult"); c.remove_type("Windows.Foundation", "Point"); c.remove_type("Windows.Foundation", "Rect"); c.remove_type("Windows.Foundation", "Size"); c.remove_type("Windows.Foundation", "TimeSpan"); c.remove_type("Windows.Foundation.Numerics", "Matrix3x2"); c.remove_type("Windows.Foundation.Numerics", "Matrix4x4"); c.remove_type("Windows.Foundation.Numerics", "Plane"); c.remove_type("Windows.Foundation.Numerics", "Quaternion"); c.remove_type("Windows.Foundation.Numerics", "Vector2"); c.remove_type("Windows.Foundation.Numerics", "Vector3"); c.remove_type("Windows.Foundation.Numerics", "Vector4"); } static int run(int const argc, char** argv) { int result{}; writer w; try { auto start = get_start_time(); reader args{ argc, argv, options }; if (!args || args.exists("help") || args.exists("?")) { throw usage_exception{}; } process_args(args); cache c{ get_files_to_cache(), [](TypeDef const& type) { return type.Flags().WindowsRuntime(); } }; remove_foundation_types(c); build_filters(c); settings.base = settings.base || (!settings.component && settings.projection_filter.empty()); build_fastabi_cache(c); if (settings.verbose) { { char* path = argv[0]; #if defined(_WIN32) || defined(_WIN64) char path_buf[32768]; DWORD path_size = GetModuleFileNameA(nullptr, path_buf, sizeof(path_buf)); if (path_size) { path_buf[sizeof(path_buf) - 1] = 0; path = path_buf; } #endif w.write(" tool: %\n", path); } w.write(" ver: %\n", CPPWINRT_VERSION_STRING); for (auto&& file : settings.input) { w.write(" in: %\n", file); } for (auto&& file : settings.reference) { w.write(" ref: %\n", file); } w.write(" out: %\n", settings.output_folder); if (!settings.component_folder.empty()) { w.write(" cout: %\n", settings.component_folder); } } w.flush_to_console(); task_group group; group.synchronous(args.exists("synchronous")); writer ixx; write_preamble(ixx); ixx.write("module;\n"); ixx.write(strings::base_includes); ixx.write("\nexport module winrt;\n#define WINRT_EXPORT export\n\n"); for (auto&&[ns, members] : c.namespaces()) { if (!has_projected_types(members) || !settings.projection_filter.includes(members)) { continue; } ixx.write("#include \"winrt/%.h\"\n", ns); group.add([&, &ns = ns, &members = members] { write_namespace_0_h(ns, members); write_namespace_1_h(ns, members); write_namespace_2_h(ns, members); write_namespace_h(c, ns, members); }); } if (settings.base) { write_base_h(); ixx.flush_to_file(settings.output_folder + "winrt/winrt.ixx"); } if (settings.component) { std::vector classes; for (auto&&[ns, members] : c.namespaces()) { for (auto&& type : members.classes) { if (settings.component_filter.includes(type)) { classes.push_back(type); } } } if (!classes.empty()) { write_fast_forward_h(classes); write_module_g_cpp(classes); for (auto&& type : classes) { write_component_g_h(type); write_component_g_cpp(type); write_component_h(type); write_component_cpp(type); } } } group.get(); if (settings.verbose) { w.write(" time: %ms\n", get_elapsed_time(start)); } } catch (usage_exception const&) { print_usage(w); } catch (std::exception const& e) { w.write("cppwinrt : error %\n", e.what()); result = 1; } w.flush_to_console(result == 0); return result; } } int main(int const argc, char** argv) { return cppwinrt::run(argc, argv); }