diff options
author | Andrew Kaster <akaster@serenityos.org> | 2021-08-08 01:31:23 -0600 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2021-08-28 08:44:17 +0100 |
commit | 63956b36d06866b1d4660c2768a9c7eab0e182fb (patch) | |
tree | c5bd525d54d4b7e5476cbd4e194e2e130ecd7b69 /Meta/CMake | |
parent | fb15cdcc107adb13cb3c1cea831d36075d6b427b (diff) | |
download | serenity-63956b36d06866b1d4660c2768a9c7eab0e182fb.zip |
Everywhere: Move all host tools into the Lagom/Tools subdirectory
This allows us to remove all the add_subdirectory calls from the top
level CMakeLists.txt that referred to targets linking LagomCore.
Segregating the host tools and Serenity targets helps us get to a place
where the main Serenity build can simply use a CMake toolchain file
rather than swapping all the compiler/sysroot variables after building
host libraries and tools.
Diffstat (limited to 'Meta/CMake')
-rw-r--r-- | Meta/CMake/ConfigureComponents/CMakeLists.txt | 6 | ||||
-rw-r--r-- | Meta/CMake/ConfigureComponents/main.cpp | 374 |
2 files changed, 0 insertions, 380 deletions
diff --git a/Meta/CMake/ConfigureComponents/CMakeLists.txt b/Meta/CMake/ConfigureComponents/CMakeLists.txt deleted file mode 100644 index acc15f9dde..0000000000 --- a/Meta/CMake/ConfigureComponents/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -set(SOURCES - main.cpp -) - -add_executable(ConfigureComponents ${SOURCES}) -target_link_libraries(ConfigureComponents LagomCore) diff --git a/Meta/CMake/ConfigureComponents/main.cpp b/Meta/CMake/ConfigureComponents/main.cpp deleted file mode 100644 index 7f6949416d..0000000000 --- a/Meta/CMake/ConfigureComponents/main.cpp +++ /dev/null @@ -1,374 +0,0 @@ -/* - * Copyright (c) 2021, Max Wipfli <mail@maxwipfli.ch> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include <AK/Format.h> -#include <AK/LexicalPath.h> -#include <AK/QuickSort.h> -#include <AK/Result.h> -#include <AK/String.h> -#include <AK/StringView.h> -#include <AK/Vector.h> -#include <LibCore/ConfigFile.h> -#include <LibCore/File.h> -#include <spawn.h> -#include <sys/ioctl.h> -#include <sys/wait.h> -#include <unistd.h> - -enum class ComponentCategory { - Optional, - Recommended, - Required -}; - -struct ComponentData { - String name; - String description; - ComponentCategory category { ComponentCategory::Optional }; - bool was_selected { false }; - Vector<String> dependencies; - bool is_selected { false }; -}; - -struct WhiptailOption { - String tag; - String name; - String description; - bool checked { false }; -}; - -enum class WhiptailMode { - Menu, - Checklist -}; - -static Optional<String> get_current_working_directory() -{ - char* cwd = getcwd(nullptr, 0); - if (!cwd) { - perror("getcwd"); - return {}; - } - String data { cwd }; - free(cwd); - return data; -} - -static Vector<ComponentData> read_component_data(Core::ConfigFile const& config_file) -{ - VERIFY(!config_file.read_entry("Global", "build_everything", {}).is_empty()); - Vector<ComponentData> components; - - auto groups = config_file.groups(); - quick_sort(groups, [](auto& a, auto& b) { - return a.to_lowercase() < b.to_lowercase(); - }); - - for (auto& component_name : groups) { - if (component_name == "Global") - continue; - auto description = config_file.read_entry(component_name, "description", ""); - auto recommended = config_file.read_bool_entry(component_name, "recommended", false); - auto required = config_file.read_bool_entry(component_name, "required", false); - auto user_selected = config_file.read_bool_entry(component_name, "user_selected", false); - auto depends = config_file.read_entry(component_name, "depends", "").split(';'); - // NOTE: Recommended and required shouldn't be set at the same time. - VERIFY(!recommended || !required); - ComponentCategory category { ComponentCategory::Optional }; - if (recommended) - category = ComponentCategory::Recommended; - else if (required) - category = ComponentCategory ::Required; - - components.append(ComponentData { component_name, move(description), category, user_selected, move(depends), false }); - } - - return components; -} - -static Result<Vector<String>, int> run_whiptail(WhiptailMode mode, Vector<WhiptailOption> const& options, StringView const& title, StringView const& description) -{ - struct winsize w; - if (ioctl(0, TIOCGWINSZ, &w) < 0) { - perror("ioctl"); - return -errno; - } - - auto height = w.ws_row - 6; - auto width = min(w.ws_col - 6, 80); - - int pipefd[2]; - if (pipe(pipefd) < 0) { - perror("pipefd"); - return -errno; - } - - int read_fd = pipefd[0]; - int write_fd = pipefd[1]; - - Vector<String> arguments = { "whiptail", "--notags", "--separate-output", "--output-fd", String::number(write_fd) }; - - if (!title.is_empty()) { - arguments.append("--title"); - arguments.append(title); - } - - switch (mode) { - case WhiptailMode::Menu: - arguments.append("--menu"); - break; - case WhiptailMode::Checklist: - arguments.append("--checklist"); - break; - default: - VERIFY_NOT_REACHED(); - } - - if (description.is_empty()) - arguments.append(String::empty()); - else - arguments.append(String::formatted("\n {}", description)); - - arguments.append(String::number(height)); - arguments.append(String::number(width)); - arguments.append(String::number(height - 9)); - - // Check how wide the name field needs to be. - size_t max_name_width = 0; - for (auto& option : options) { - if (option.name.length() > max_name_width) - max_name_width = option.name.length(); - } - - for (auto& option : options) { - arguments.append(option.tag); - arguments.append(String::formatted("{:{2}} {}", option.name, option.description, max_name_width)); - if (mode == WhiptailMode::Checklist) - arguments.append(option.checked ? "1" : "0"); - } - - char* argv[arguments.size() + 1]; - for (size_t i = 0; i < arguments.size(); ++i) - argv[i] = const_cast<char*>(arguments[i].characters()); - argv[arguments.size()] = nullptr; - - auto* term_variable = getenv("TERM"); - if (!term_variable) { - warnln("getenv: TERM variable not set."); - close(write_fd); - close(read_fd); - return -1; - } - - auto full_term_variable = String::formatted("TERM={}", term_variable); - auto colors = "NEWT_COLORS=root=,black\ncheckbox=black,lightgray"; - - char* env[3]; - env[0] = const_cast<char*>(full_term_variable.characters()); - env[1] = const_cast<char*>(colors); - env[2] = nullptr; - - pid_t pid; - if (posix_spawnp(&pid, arguments[0].characters(), nullptr, nullptr, argv, env)) { - perror("posix_spawnp"); - warnln("\e[31mError:\e[0m Could not execute 'whiptail', maybe it isn't installed."); - close(write_fd); - close(read_fd); - return -errno; - } - - int status = -1; - if (waitpid(pid, &status, 0) < 0) { - perror("waitpid"); - close(write_fd); - close(read_fd); - return -errno; - } - - close(write_fd); - - if (!WIFEXITED(status)) { - close(read_fd); - return -1; - } - - int return_code = WEXITSTATUS(status); - if (return_code > 0) { - close(read_fd); - // posix_spawn returns 127 if it cannot exec the child, so maybe 'whiptail' is missing. - if (return_code == 127) - warnln("\e[31mError:\e[0m Could not execute 'whiptail', maybe it isn't installed."); - return return_code; - } - - auto file = Core::File::construct(); - file->open(read_fd, Core::OpenMode::ReadOnly, Core::File::ShouldCloseFileDescriptor::Yes); - auto data = String::copy(file->read_all()); - return data.split('\n', false); -} - -static bool run_system_command(String const& command, StringView const& command_name) -{ - if (command.starts_with("cmake")) - warnln("\e[34mRunning CMake...\e[0m"); - else - warnln("\e[34mRunning '{}'...\e[0m", command); - auto rc = system(command.characters()); - if (rc < 0) { - perror("system"); - warnln("\e[31mError:\e[0m Could not run {}.", command_name); - return false; - } else if (rc > 0) { - warnln("\e[31mError:\e[0m {} returned status code {}.", command_name, rc); - return false; - } - return true; -} - -int main() -{ - // Step 1: Check if everything is in order. - if (!isatty(STDIN_FILENO)) { - warnln("Not a terminal!"); - return 1; - } - - auto current_working_directory = get_current_working_directory(); - if (!current_working_directory.has_value()) - return 1; - auto lexical_cwd = LexicalPath(*current_working_directory); - auto& parts = lexical_cwd.parts_view(); - if (parts.size() < 2 || parts[parts.size() - 2] != "Build") { - warnln("\e[31mError:\e[0m This program needs to be executed from inside 'Build/*'."); - return 1; - } - - if (!Core::File::exists("components.ini")) { - warnln("\e[31mError:\e[0m There is no 'components.ini' in the current working directory."); - warnln(" It can be generated by running CMake with 'cmake ../.. -G Ninja'"); - return 1; - } - - // Step 2: Open and parse the 'components.ini' file. - auto components_file = Core::ConfigFile::open("components.ini"); - if (components_file->groups().is_empty()) { - warnln("\e[31mError:\e[0m The 'components.ini' file is either not a valid ini file or contains no entries."); - return 1; - } - - bool build_everything = components_file->read_bool_entry("Global", "build_everything", false); - auto components = read_component_data(components_file); - warnln("{} components were read from 'components.ini'.", components.size()); - - // Step 3: Ask the user which starting configuration to use. - Vector<WhiptailOption> configs; - configs.append({ "REQUIRED", "Required", "Only the essentials.", false }); - configs.append({ "RECOMMENDED", "Recommended", "A sensible collection of programs.", false }); - configs.append({ "FULL", "Full", "All available programs.", false }); - configs.append({ "CUSTOM_REQUIRED", "Required", "Customizable.", false }); - configs.append({ "CUSTOM_RECOMMENDED", "Recommended", "Customizable.", false }); - configs.append({ "CUSTOM_FULL", "Full", "Customizable.", false }); - configs.append({ "CUSTOM_CURRENT", "Current", "Customize current configuration.", false }); - - auto configs_result = run_whiptail(WhiptailMode::Menu, configs, "SerenityOS - System Configurations", "Which system configuration do you want to use or customize?"); - if (configs_result.is_error()) { - warnln("ConfigureComponents cancelled."); - return 0; - } - - VERIFY(configs_result.value().size() == 1); - auto type = configs_result.value().first(); - - bool customize = type.starts_with("CUSTOM_"); - StringView build_type = customize ? type.substring_view(7) : type.view(); - - // Step 4: Customize the configuration if the user requested to. In any case, set the components component.is_selected value correctly. - Vector<String> activated_components; - - if (customize) { - Vector<WhiptailOption> options; - for (auto& component : components) { - auto is_required = component.category == ComponentCategory::Required; - - StringBuilder description_builder; - description_builder.append(component.description); - if (is_required) { - if (!description_builder.is_empty()) - description_builder.append(' '); - description_builder.append("[required]"); - } - - // NOTE: Required components will always be preselected. - WhiptailOption option { component.name, component.name, description_builder.to_string(), is_required }; - if (build_type == "REQUIRED") { - // noop - } else if (build_type == "RECOMMENDED") { - if (component.category == ComponentCategory::Recommended) - option.checked = true; - } else if (build_type == "FULL") { - option.checked = true; - } else if (build_type == "CURRENT") { - if (build_everything || component.was_selected) - option.checked = true; - } else { - VERIFY_NOT_REACHED(); - } - options.append(move(option)); - } - - auto result = run_whiptail(WhiptailMode::Checklist, options, "SerenityOS - System Components", "Which optional system components do you want to include?"); - if (result.is_error()) { - warnln("ConfigureComponents cancelled."); - return 0; - } - - auto selected_components = result.value(); - for (auto& component : components) { - if (selected_components.contains_slow(component.name)) { - component.is_selected = true; - } else if (component.category == ComponentCategory::Required) { - warnln("\e[33mWarning:\e[0m {} was not selected even though it is required. It will be enabled anyway.", component.name); - component.is_selected = true; - } - } - } else { - for (auto& component : components) { - if (build_type == "REQUIRED") - component.is_selected = component.category == ComponentCategory::Required; - else if (build_type == "RECOMMENDED") - component.is_selected = component.category == ComponentCategory::Required || component.category == ComponentCategory::Recommended; - else if (build_type == "FULL") - component.is_selected = true; - else - VERIFY_NOT_REACHED(); - } - } - - // Step 5: Generate the cmake command. - Vector<String> cmake_arguments = { "cmake", "../..", "-G", "Ninja", "-DBUILD_EVERYTHING=OFF" }; - for (auto& component : components) - cmake_arguments.append(String::formatted("-DBUILD_{}={}", component.name.to_uppercase(), component.is_selected ? "ON" : "OFF")); - - warnln("\e[34mThe following command will be run:\e[0m"); - outln("{} \\", String::join(' ', cmake_arguments)); - outln(" && ninja clean\n && rm -rf Root"); - warn("\e[34mDo you want to run the command?\e[0m [Y/n] "); - auto character = getchar(); - if (character == 'n' || character == 'N') { - warnln("ConfigureComponents cancelled."); - return 0; - } - - // Step 6: Run CMake, 'ninja clean' and 'rm -rf Root' - auto command = String::join(' ', cmake_arguments); - if (!run_system_command(command, "CMake")) - return 1; - if (!run_system_command("ninja clean", "Ninja")) - return 1; - if (!run_system_command("rm -rf Root", "rm")) - return 1; - return 0; -} |