meta: add build system

This commit is contained in:
2026-02-05 09:54:46 +00:00
parent 62c5653d5b
commit 9c8fbc72ac
15 changed files with 694 additions and 0 deletions

30
CMakeLists.txt Normal file
View File

@@ -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()

1
arch/x86_64/Arch.cmake Normal file
View File

@@ -0,0 +1 @@
include(QEMU)

View File

@@ -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)

5
arch/x86_64/QEMU.cmake Normal file
View File

@@ -0,0 +1,5 @@
find_program(QEMU qemu-system-${TARGET_ARCH} REQUIRED)
add_custom_target(run-kernel
COMMAND ${QEMU} -kernel $<TARGET_FILE:${kernel_name}>
DEPENDS ${kernel_name} ${bsp_name})

95
cmake/BSP.cmake Normal file
View File

@@ -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} $<TARGET_FILE:${target_name}>
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} $<TARGET_FILE:${target_name}>
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)

34
cmake/Meta.cmake Normal file
View File

@@ -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)

115
cmake/Sysroot.cmake Normal file
View File

@@ -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} $<TARGET_FILE:${target_name}>
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} $<TARGET_FILE:${target_name}>
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)

80
cmake/Templates.cmake Normal file
View File

@@ -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)

47
configure-build Executable file
View File

@@ -0,0 +1,47 @@
#!/bin/bash
# vim: ft=bash
target_arch=$1
if [ ! -n "$target_arch" ]; then
echo "Usage: $0 <target arch>"
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

9
programs/CMakeLists.txt Normal file
View File

@@ -0,0 +1,9 @@
file(GLOB items *)
foreach(item ${items})
if (NOT IS_DIRECTORY ${item})
continue()
endif ()
add_subdirectory(${item})
endforeach (item)

View File

@@ -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)

6
programs/test/test.c Normal file
View File

@@ -0,0 +1,6 @@
#include <function.h>
int _start(void)
{
return function();
}

0
sys/CMakeLists.txt Normal file
View File

124
util/bsp-tool.py Executable file
View File

@@ -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 <manifest-path>".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 <manifest-path> <component-name> <source-directory> <dest-directory>".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 <manifest-path> <component-name> <source-file> <dest-directory>".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 <manifest-path> <dest-path>".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: {} <command> [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)

125
util/sysroot-tool.py Normal file
View File

@@ -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 <manifest-path>".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 <manifest-path> <component-name> <source-directory> <dest-directory>".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 <manifest-path> <component-name> <source-file> <dest-directory>".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 <manifest-path> <dest-directory>".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: {} <command> [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)