From 9c8fbc72acf2d542d43dea29b4324d6d8cce07a1 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Thu, 5 Feb 2026 09:54:46 +0000 Subject: [PATCH] meta: add build system --- CMakeLists.txt | 30 +++++++ arch/x86_64/Arch.cmake | 1 + arch/x86_64/Platform/Rosetta.cmake | 14 ++++ arch/x86_64/QEMU.cmake | 5 ++ cmake/BSP.cmake | 95 ++++++++++++++++++++++ cmake/Meta.cmake | 34 ++++++++ cmake/Sysroot.cmake | 115 ++++++++++++++++++++++++++ cmake/Templates.cmake | 80 ++++++++++++++++++ configure-build | 47 +++++++++++ programs/CMakeLists.txt | 9 +++ programs/test/CMakeLists.txt | 9 +++ programs/test/test.c | 6 ++ sys/CMakeLists.txt | 0 util/bsp-tool.py | 124 ++++++++++++++++++++++++++++ util/sysroot-tool.py | 125 +++++++++++++++++++++++++++++ 15 files changed, 694 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 arch/x86_64/Arch.cmake create mode 100644 arch/x86_64/Platform/Rosetta.cmake create mode 100644 arch/x86_64/QEMU.cmake create mode 100644 cmake/BSP.cmake create mode 100644 cmake/Meta.cmake create mode 100644 cmake/Sysroot.cmake create mode 100644 cmake/Templates.cmake create mode 100755 configure-build create mode 100644 programs/CMakeLists.txt create mode 100644 programs/test/CMakeLists.txt create mode 100644 programs/test/test.c create mode 100644 sys/CMakeLists.txt create mode 100755 util/bsp-tool.py create mode 100644 util/sysroot-tool.py diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..7917b2a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,30 @@ +cmake_minimum_required(VERSION 3.14) +project(Rosetta C CXX ASM) + +set(kernel_name mango_kernel) +set(bsp_name rosetta-system.bsp) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake) +include(Meta) +include(Sysroot) +include(BSP) +include(Arch) +include(Templates) + +bsp_reset() +sysroot_reset() + +add_subdirectory(kernel) +add_subdirectory(lib) +add_subdirectory(programs) +add_subdirectory(sys) + +sysroot_add_program(NAME ${kernel_name} BIN_DIR /boot) + +bsp_finalise(BSP_NAME ${bsp_name}) +sysroot_add_file( + ID bsp + SRC_PATH ${CMAKE_BINARY_DIR}/${bsp_name} + DEST_DIR /boot + DEPENDS ${CMAKE_BINARY_DIR}/${bsp_name}) +sysroot_finalise() diff --git a/arch/x86_64/Arch.cmake b/arch/x86_64/Arch.cmake new file mode 100644 index 0000000..56e9491 --- /dev/null +++ b/arch/x86_64/Arch.cmake @@ -0,0 +1 @@ +include(QEMU) diff --git a/arch/x86_64/Platform/Rosetta.cmake b/arch/x86_64/Platform/Rosetta.cmake new file mode 100644 index 0000000..d026c1e --- /dev/null +++ b/arch/x86_64/Platform/Rosetta.cmake @@ -0,0 +1,14 @@ +set(CMAKE_SYSTEM_NAME Rosetta) +set(CMAKE_SYSTEM_PROCESSOR x86_64) + +set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") + +find_program(C_COMPILER x86_64-elf-gcc REQUIRED) +find_program(CXX_COMPILER x86_64-elf-g++ REQUIRED) +find_program(ASM_COMPILER x86_64-elf-as REQUIRED) + +set(CMAKE_C_COMPILER ${C_COMPILER}) +set(CMAKE_CXX_COMPILER ${CXX_COMPILER}) +set(CMAKE_ASM_COMPILER ${ASM_COMPILER}) + +SET(CMAKE_C_FLAGS "-ffreestanding -nostdlib" CACHE STRING "" FORCE) diff --git a/arch/x86_64/QEMU.cmake b/arch/x86_64/QEMU.cmake new file mode 100644 index 0000000..978ecf9 --- /dev/null +++ b/arch/x86_64/QEMU.cmake @@ -0,0 +1,5 @@ +find_program(QEMU qemu-system-${TARGET_ARCH} REQUIRED) + +add_custom_target(run-kernel + COMMAND ${QEMU} -kernel $ + DEPENDS ${kernel_name} ${bsp_name}) diff --git a/cmake/BSP.cmake b/cmake/BSP.cmake new file mode 100644 index 0000000..7917fb8 --- /dev/null +++ b/cmake/BSP.cmake @@ -0,0 +1,95 @@ +find_package(Python COMPONENTS Interpreter) + +set(bsp_manifest ${CMAKE_CURRENT_BINARY_DIR}/bsp-manifest.json) +set(bsp_tool ${CMAKE_SOURCE_DIR}/util/bsp-tool.py) + +function(bsp_reset) + execute_process( + COMMAND ${Python_EXECUTABLE} ${bsp_tool} reset ${bsp_manifest} + COMMAND_ERROR_IS_FATAL ANY) +endfunction(bsp_reset) + +function(bsp_add_library) + set(options) + set(one_value_args NAME HEADER_DIR LIB_DIR) + set(multi_value_args) + + cmake_parse_arguments(PARSE_ARGV 0 arg + "${options}" + "${one_value_args}" + "${multi_value_args}") + + set(target_name ${arg_NAME}) + set(bsp_target_name _bsp-${target_name}) + meta_target_get_header_directories(TARGET ${target_name} OUT header_dirs) + + get_property(bsp_targets GLOBAL PROPERTY bsp_target_list) + list(LENGTH bsp_targets nr_bsp_targets) + if (${nr_bsp_targets} GREATER 0) + math(EXPR serialiser_index "${nr_bsp_targets}-1") + list(GET bsp_targets ${serialiser_index} serialiser) + endif () + + add_custom_target(${bsp_target_name} + COMMAND ${Python_EXECUTABLE} ${bsp_tool} + add-binary ${bsp_manifest} ${target_name} + ${arg_LIB_DIR} $ + COMMAND ${Python_EXECUTABLE} ${bsp_tool} + add-headers ${bsp_manifest} ${target_name} + ${arg_HEADER_DIR} ${header_dirs} + COMMENT "Preparing bsp component: ${target_name}" + DEPENDS ${target_name} ${serialiser}) + + set_property(GLOBAL PROPERTY bsp_target_list ${bsp_targets} ${bsp_target_name}) +endfunction(bsp_add_library) + +function(bsp_add_program) + set(options) + set(one_value_args NAME BIN_DIR) + set(multi_value_args) + + cmake_parse_arguments(PARSE_ARGV 0 arg + "${options}" + "${one_value_args}" + "${multi_value_args}") + + set(target_name ${arg_NAME}) + set(bsp_target_name _bsp-${target_name}) + + get_property(bsp_targets GLOBAL PROPERTY bsp_target_list) + list(LENGTH bsp_targets nr_bsp_targets) + if (${nr_bsp_targets} GREATER 0) + math(EXPR serialiser_index "${nr_bsp_targets}-1") + list(GET bsp_targets ${serialiser_index} serialiser) + endif () + + add_custom_target(${bsp_target_name} + COMMAND ${Python_EXECUTABLE} ${bsp_tool} + add-binary ${bsp_manifest} ${target_name} + ${arg_BIN_DIR} $ + COMMENT "Preparing bsp component: ${target_name}" + DEPENDS ${target_name} ${serialiser}) + + set_property(GLOBAL PROPERTY bsp_target_list ${bsp_targets} ${bsp_target_name}) +endfunction(bsp_add_program) + +function(bsp_finalise) + set(options) + set(one_value_args BSP_NAME) + set(multi_value_args) + + cmake_parse_arguments(PARSE_ARGV 0 arg + "${options}" + "${one_value_args}" + "${multi_value_args}") + + set(bsp_output_path ${CMAKE_CURRENT_BINARY_DIR}/${arg_BSP_NAME}) + get_property(bsp_targets GLOBAL PROPERTY bsp_target_list) + add_custom_command(OUTPUT ${bsp_output_path} + COMMAND ${Python_EXECUTABLE} ${bsp_tool} + build-bsp ${bsp_manifest} ${bsp_output_path} + DEPENDS ${bsp_targets} + COMMENT "Building bsp: ${arg_BSP_NAME}") + add_custom_target(bsp + DEPENDS ${bsp_output_path}) +endfunction(bsp_finalise) diff --git a/cmake/Meta.cmake b/cmake/Meta.cmake new file mode 100644 index 0000000..76fe96e --- /dev/null +++ b/cmake/Meta.cmake @@ -0,0 +1,34 @@ +function(meta_target_add_header_directory) + set(options) + set(one_value_args TARGET PATH) + set(multi_value_args) + + cmake_parse_arguments(PARSE_ARGV 0 arg + "${options}" + "${one_value_args}" + "${multi_value_args}") + + get_property(header_dir_list + TARGET ${arg_TARGET} + PROPERTY meta_header_directories) + set_property( + TARGET ${arg_TARGET} + PROPERTY meta_header_directories + ${header_dir_list} ${arg_PATH}) +endfunction(meta_target_add_header_directory) + +function(meta_target_get_header_directories) + set(options) + set(one_value_args TARGET OUT) + set(multi_value_args) + + cmake_parse_arguments(PARSE_ARGV 0 arg + "${options}" + "${one_value_args}" + "${multi_value_args}") + + get_property(header_dir_list + TARGET ${arg_TARGET} + PROPERTY meta_header_directories) + set(${arg_OUT} ${header_dir_list} PARENT_SCOPE) +endfunction(meta_target_get_header_directories) diff --git a/cmake/Sysroot.cmake b/cmake/Sysroot.cmake new file mode 100644 index 0000000..9cb2d52 --- /dev/null +++ b/cmake/Sysroot.cmake @@ -0,0 +1,115 @@ +find_package(Python COMPONENTS Interpreter) + +set(sysroot_manifest ${CMAKE_CURRENT_BINARY_DIR}/sysroot-manifest.json) +set(sysroot_tool ${CMAKE_SOURCE_DIR}/util/sysroot-tool.py) + +function(sysroot_reset) + execute_process( + COMMAND ${Python_EXECUTABLE} ${sysroot_tool} reset ${sysroot_manifest} + COMMAND_ERROR_IS_FATAL ANY) +endfunction(sysroot_reset) + +function(sysroot_add_library) + set(options) + set(one_value_args NAME HEADER_DIR LIB_DIR) + set(multi_value_args) + + cmake_parse_arguments(PARSE_ARGV 0 arg + "${options}" + "${one_value_args}" + "${multi_value_args}") + + set(target_name ${arg_NAME}) + set(sysroot_target_name _sysroot-${target_name}) + meta_target_get_header_directories(TARGET ${target_name} OUT header_dirs) + + get_property(sysroot_targets GLOBAL PROPERTY sysroot_target_list) + list(LENGTH sysroot_targets nr_sysroot_targets) + if (${nr_sysroot_targets} GREATER 0) + math(EXPR serialiser_index "${nr_sysroot_targets}-1") + list(GET sysroot_targets ${serialiser_index} serialiser) + endif () + + add_custom_target(${sysroot_target_name} + COMMAND ${Python_EXECUTABLE} ${sysroot_tool} + add-binary ${sysroot_manifest} ${target_name} + ${arg_LIB_DIR} $ + COMMAND ${Python_EXECUTABLE} ${sysroot_tool} + add-headers ${sysroot_manifest} ${target_name} + ${arg_HEADER_DIR} ${header_dirs} + COMMENT "Preparing sysroot component: ${target_name}" + DEPENDS ${target_name} ${serialiser}) + + set_property(GLOBAL PROPERTY sysroot_target_list ${sysroot_targets} ${sysroot_target_name}) +endfunction(sysroot_add_library) + +function(sysroot_add_program) + set(options) + set(one_value_args NAME BIN_DIR) + set(multi_value_args) + + cmake_parse_arguments(PARSE_ARGV 0 arg + "${options}" + "${one_value_args}" + "${multi_value_args}") + + set(target_name ${arg_NAME}) + set(sysroot_target_name _sysroot-${target_name}) + + get_property(sysroot_targets GLOBAL PROPERTY sysroot_target_list) + list(LENGTH sysroot_targets nr_sysroot_targets) + if (${nr_sysroot_targets} GREATER 0) + math(EXPR serialiser_index "${nr_sysroot_targets}-1") + list(GET sysroot_targets ${serialiser_index} serialiser) + endif () + + add_custom_target(${sysroot_target_name} + COMMAND ${Python_EXECUTABLE} ${sysroot_tool} + add-binary ${sysroot_manifest} ${target_name} + ${arg_BIN_DIR} $ + COMMENT "Preparing sysroot component: ${target_name}" + DEPENDS ${target_name} ${serialiser}) + + set_property(GLOBAL PROPERTY sysroot_target_list ${sysroot_targets} ${sysroot_target_name}) +endfunction(sysroot_add_program) + +function(sysroot_add_file) + set(options) + set(one_value_args ID SRC_PATH DEST_DIR) + set(multi_value_args DEPENDS) + + cmake_parse_arguments(PARSE_ARGV 0 arg + "${options}" + "${one_value_args}" + "${multi_value_args}") + + set(src_path ${arg_SRC_PATH}) + set(dest_dir ${arg_DEST_DIR}) + set(sysroot_target_name _sysroot-${arg_ID}) + + get_property(sysroot_targets GLOBAL PROPERTY sysroot_target_list) + list(LENGTH sysroot_targets nr_sysroot_targets) + if (${nr_sysroot_targets} GREATER 0) + math(EXPR serialiser_index "${nr_sysroot_targets}-1") + list(GET sysroot_targets ${serialiser_index} serialiser) + endif () + + add_custom_target(${sysroot_target_name} + COMMAND ${Python_EXECUTABLE} ${sysroot_tool} + add-binary ${sysroot_manifest} ${arg_ID} + ${dest_dir} ${src_path} + COMMENT "Preparing sysroot component: ${arg_ID}" + DEPENDS ${target_name} ${serialiser} ${arg_DEPENDS}) + + set_property(GLOBAL PROPERTY sysroot_target_list ${sysroot_targets} ${sysroot_target_name}) +endfunction(sysroot_add_file) + + +function(sysroot_finalise) + get_property(sysroot_targets GLOBAL PROPERTY sysroot_target_list) + add_custom_target(sysroot + COMMAND ${Python_EXECUTABLE} ${sysroot_tool} + build-sysroot ${sysroot_manifest} ${CMAKE_BINARY_DIR}/sysroot + DEPENDS ${sysroot_targets} + COMMENT "Building sysroot...") +endfunction(sysroot_finalise) diff --git a/cmake/Templates.cmake b/cmake/Templates.cmake new file mode 100644 index 0000000..5fa534a --- /dev/null +++ b/cmake/Templates.cmake @@ -0,0 +1,80 @@ +function(rosetta_add_executable) + set(options) + set(one_value_args NAME SYSROOT_PATH) + set(multi_value_args + SUBDIRS + EXTRA_SOURCES) + cmake_parse_arguments(PARSE_ARGV 0 arg + "${options}" + "${one_value_args}" + "${multi_value_args}") + + set(exec_name ${arg_NAME}) + get_property(programs GLOBAL PROPERTY rosetta_program_list) + set_property(GLOBAL PROPERTY rosetta_program_list ${programs} ${exec_name}) + + file(GLOB sources *.c *.h) + + foreach (dir ${arg_SUBDIRS}) + file(GLOB dir_sources ${dir}/*.c ${dir}/*.h) + set(sources ${sources} ${dir_sources}) + endforeach (dir) + + message(STATUS "Building program ${exec_name}") + add_executable(${exec_name} + ${sources} + ${arg_EXTRA_SOURCES}) + + set_target_properties(${exec_name} PROPERTIES + POSITION_INDEPENDENT_CODE ON + sys_bin_dir ${arg_SYSROOT_PATH}) + install(TARGETS ${exec_name} + DESTINATION ${arg_SYSROOT_PATH}) +endfunction(rosetta_add_executable) + +function(rosetta_add_library) + set(options SHARED) + set(one_value_args NAME SYSROOT_PATH) + set(multi_value_args + SOURCE_DIRS + EXTRA_SOURCES) + cmake_parse_arguments(PARSE_ARGV 0 arg + "${options}" + "${one_value_args}" + "${multi_value_args}") + + set(lib_name ${arg_NAME}) + + get_property(libs GLOBAL PROPERTY rosetta_library_list) + set_property(GLOBAL PROPERTY rosetta_library_list ${libs} ${lib_name}) + + file(GLOB sources *.c *.h) + file(GLOB_RECURSE headers include/*.h) + + foreach (dir ${arg_SOURCE_DIRS}) + file(GLOB dir_sources ${dir}/*.c ${dir}/*.h) + set(sources ${sources} ${dir_sources}) + endforeach (dir) + + message(STATUS "Building library ${lib_name}") + if (arg_SHARED) + add_library(${lib_name} SHARED + ${sources} + ${headers} + ${arg_EXTRA_SOURCES}) + else () + add_library(${lib_name} STATIC + ${sources} + ${headers} + ${arg_EXTRA_SOURCES}) + endif () + + target_include_directories(${lib_name} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/include) + set_target_properties(${lib_name} PROPERTIES + POSITION_INDEPENDENT_CODE ON + src_header_dir ${CMAKE_CURRENT_SOURCE_DIR}/include + sys_header_dir ${arg_SYSROOT_PATH}/include + sys_bin_dir ${arg_SYSROOT_PATH}/lib + PREFIX "") +endfunction(rosetta_add_library) diff --git a/configure-build b/configure-build new file mode 100755 index 0000000..ad8fbf1 --- /dev/null +++ b/configure-build @@ -0,0 +1,47 @@ +#!/bin/bash +# vim: ft=bash + +target_arch=$1 + +if [ ! -n "$target_arch" ]; then + echo "Usage: $0 " + exit -1 +fi + +source_dir=$(realpath $(dirname "$0")) +native_build_dir=$source_dir/build-native +target_build_dir=$source_dir/build +sysroot_dir=$target_build_dir/sysroot + +if [ ! -d "$source_dir/arch/$target_arch" ]; then + echo "FATAL: Specified target architecture $target_arch is not supported. See arch/ directory for a list of supported architectures." + exit -1 +fi + +rm -rf $native_build_dir $target_build_dir +mkdir -p $native_build_dir $target_build_dir + +pushd $native_build_dir > /dev/null + +cmake \ + -DCMAKE_RUNTIME_OUTPUT_DIRECTORY="$native_build_dir/bin" \ + -DCMAKE_LIBRARY_OUTPUT_DIRECTORY="$native_build_dir/lib" \ + -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="$native_build_dir/lib" \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + $source_dir/kernel/tools + +popd + +pushd $target_build_dir > /dev/null + +cmake \ + -DBUILD_TOOLS_DIR=$native_build_dir/bin \ + -DCMAKE_INSTALL_PREFIX=$sysroot_dir \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -DTARGET_ARCH=$target_arch \ + $source_dir \ + -DCMAKE_MODULE_PATH=$source_dir/arch/$target_arch \ + -DCMAKE_SYSTEM_NAME=Rosetta \ + -DCMAKE_TOOLCHAIN_FILE=$source_dir/arch/$target_arch/Platform/Rosetta.cmake + +popd > /dev/null diff --git a/programs/CMakeLists.txt b/programs/CMakeLists.txt new file mode 100644 index 0000000..80642bf --- /dev/null +++ b/programs/CMakeLists.txt @@ -0,0 +1,9 @@ +file(GLOB items *) + +foreach(item ${items}) + if (NOT IS_DIRECTORY ${item}) + continue() + endif () + + add_subdirectory(${item}) +endforeach (item) diff --git a/programs/test/CMakeLists.txt b/programs/test/CMakeLists.txt new file mode 100644 index 0000000..caa2ed6 --- /dev/null +++ b/programs/test/CMakeLists.txt @@ -0,0 +1,9 @@ +add_executable(test test.c) +target_link_libraries(test c) + +sysroot_add_program( + NAME test + BIN_DIR /usr/bin) +bsp_add_program( + NAME test + BIN_DIR /usr/bin) diff --git a/programs/test/test.c b/programs/test/test.c new file mode 100644 index 0000000..a35725a --- /dev/null +++ b/programs/test/test.c @@ -0,0 +1,6 @@ +#include + +int _start(void) +{ + return function(); +} diff --git a/sys/CMakeLists.txt b/sys/CMakeLists.txt new file mode 100644 index 0000000..e69de29 diff --git a/util/bsp-tool.py b/util/bsp-tool.py new file mode 100755 index 0000000..0a2e51e --- /dev/null +++ b/util/bsp-tool.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 +import sys +import os +import shutil +import tarfile +from lib.manifest import Manifest, Component + + +def reset(): + if len(sys.argv) < 3: + print("USAGE: {} reset ".format(sys.argv[0])) + + manifest_path = sys.argv[2] + manifest = Manifest(manifest_path) + manifest.reset() + manifest.save() + return 0 + + +def add_headers(): + if len(sys.argv) < 3: + print("USAGE: {} add-headers ".format(sys.argv[0])) + return -1 + + manifest_path = sys.argv[2] + component_name = sys.argv[3] + dest_path = sys.argv[4] + src_path = sys.argv[5] + + manifest = Manifest(manifest_path) + manifest.load() + + component = manifest.get_component(component_name) + component.add_headers(src_path, dest_path) + + manifest.save() + + return 0 + + +def add_binary(): + if len(sys.argv) < 3: + print("USAGE: {} add-binary ".format(sys.argv[0])) + return -1 + + manifest_path = sys.argv[2] + component_name = sys.argv[3] + dest_path = sys.argv[4] + src_path = sys.argv[5] + + manifest = Manifest(manifest_path) + manifest.load() + + component = manifest.get_component(component_name) + component.add_binary(src_path, dest_path) + + manifest.save() + return 0 + + +def build_bsp(): + if len(sys.argv) < 3: + print("USAGE: {} build-bsp ".format(sys.argv[0])) + return -1 + + manifest_path = sys.argv[2] + bsp_path = sys.argv[3] + + if os.path.exists(bsp_path): + os.remove(bsp_path) + + bsp_file = tarfile.open(name=bsp_path, mode='x') + + manifest = Manifest(manifest_path) + manifest.load() + + for n, c in manifest.get_all_components().items(): + for h in c.get_headers(): + header_src = h['src'] + header_dest = h['dest'] + while header_dest.startswith('/'): + header_dest = header_dest[1:] + + for f in os.listdir(header_src): + print('ADD {} -> {}'.format( + os.path.join(header_src, f), + os.path.join(header_dest, f))) + bsp_file.add( + os.path.join(header_src, f), + arcname=os.path.join(header_dest, f)) + + for b in c.get_binaries(): + binary_src = b['src'] + binary_dest = b['dest'] + while binary_dest.startswith('/'): + binary_dest = binary_dest[1:] + + bsp_file.add(binary_src, arcname=binary_dest) + + bsp_file.close() + return 0 + + +if len(sys.argv) < 2: + print("USAGE: {} [args...]".format(sys.argv[0])) + exit(-1) + +commands = { + 'reset': reset, + 'add-headers': add_headers, + 'add-binary': add_binary, + 'build-bsp': build_bsp, +} + +cmd_name = sys.argv[1] +if cmd_name not in commands: + print("FATAL: unrecognised command '{}'".format(cmd_name)) + exit(-1) + +try: + exit(commands[cmd_name]()) +except RuntimeError as e: + print('FATAL: {}'.format(e)) + exit(-1) diff --git a/util/sysroot-tool.py b/util/sysroot-tool.py new file mode 100644 index 0000000..7113409 --- /dev/null +++ b/util/sysroot-tool.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python3 +import sys +import os +import shutil +from lib.manifest import Manifest, Component + + +def reset(): + if len(sys.argv) < 3: + print("USAGE: {} reset ".format(sys.argv[0])) + + manifest_path = sys.argv[2] + manifest = Manifest(manifest_path) + manifest.reset() + manifest.save() + return 0 + + +def add_headers(): + if len(sys.argv) < 3: + print("USAGE: {} add-headers ".format(sys.argv[0])) + return -1 + + manifest_path = sys.argv[2] + component_name = sys.argv[3] + dest_path = sys.argv[4] + src_path = sys.argv[5] + + manifest = Manifest(manifest_path) + manifest.load() + + component = manifest.get_component(component_name) + component.add_headers(src_path, dest_path) + + manifest.save() + + return 0 + + +def add_binary(): + if len(sys.argv) < 3: + print("USAGE: {} add-binary ".format(sys.argv[0])) + return -1 + + manifest_path = sys.argv[2] + component_name = sys.argv[3] + dest_path = sys.argv[4] + src_path = sys.argv[5] + + manifest = Manifest(manifest_path) + manifest.load() + + component = manifest.get_component(component_name) + component.add_binary(src_path, dest_path) + + manifest.save() + return 0 + + +def build_sysroot(): + if len(sys.argv) < 3: + print("USAGE: {} build-sysroot ".format(sys.argv[0])) + return -1 + + manifest_path = sys.argv[2] + sysroot_path = sys.argv[3] + + if os.path.isdir(sysroot_path): + shutil.rmtree(sysroot_path) + + manifest = Manifest(manifest_path) + manifest.load() + + for n, c in manifest.get_all_components().items(): + for h in c.get_headers(): + header_src = h['src'] + header_dest = h['dest'] + while header_dest.startswith('/'): + header_dest = header_dest[1:] + + header_dest = os.path.join(sysroot_path, header_dest) + if not os.path.isdir(header_dest): + os.makedirs(header_dest) + + for f in os.listdir(header_src): + shutil.copy( + os.path.join(header_src, f), + os.path.join(header_dest, f)) + + for b in c.get_binaries(): + binary_src = b['src'] + binary_dest = b['dest'] + while binary_dest.startswith('/'): + binary_dest = binary_dest[1:] + + binary_dest = os.path.join(sysroot_path, binary_dest) + if not os.path.isdir(binary_dest): + os.makedirs(binary_dest) + + shutil.copy(binary_src, binary_dest) + + return 0 + + +if len(sys.argv) < 2: + print("USAGE: {} [args...]".format(sys.argv[0])) + exit(-1) + +commands = { + 'reset': reset, + 'add-headers': add_headers, + 'add-binary': add_binary, + 'build-sysroot': build_sysroot, +} + +cmd_name = sys.argv[1] +if cmd_name not in commands: + print("FATAL: unrecognised command '{}'".format(cmd_name)) + exit(-1) + +try: + exit(commands[cmd_name]()) +except RuntimeError as e: + print('FATAL: {}'.format(e)) + exit(-1)