summaryrefslogtreecommitdiff
path: root/Meta/CMake
diff options
context:
space:
mode:
authorAndrew Kaster <akaster@serenityos.org>2021-08-08 01:31:23 -0600
committerLinus Groh <mail@linusgroh.de>2021-08-28 08:44:17 +0100
commit63956b36d06866b1d4660c2768a9c7eab0e182fb (patch)
treec5bd525d54d4b7e5476cbd4e194e2e130ecd7b69 /Meta/CMake
parentfb15cdcc107adb13cb3c1cea831d36075d6b427b (diff)
downloadserenity-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.txt6
-rw-r--r--Meta/CMake/ConfigureComponents/main.cpp374
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;
-}