meta: replace cmake mono-build system with a custom build co-ordinator

every system component now has its own self-contained build system, and a
seed file describing the component and its build system and dependencies.

a new tool, meadow, collects and uses these seed files to build the
components into a full system. meadow also manages the target system root
and a host prefix where toolchain tools are installed to.

the build system has also been updated to use a new $ARCH-rosetta-gcc
compiler, and the patches files necessary to build it have been
added to toolchain/cross-compiler.
This commit is contained in:
2026-07-19 13:34:32 +01:00
parent 59034be9e6
commit 1ec33767ab
104 changed files with 7111 additions and 257 deletions
+2 -2
View File
@@ -243,7 +243,6 @@ docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
@@ -341,5 +340,6 @@ pyrightconfig.json
# End of https://www.toptal.com/developers/gitignore/api/c,vim,linux,macos,windows,cmake,python
build*
build
build-native
.cache
+35 -5
View File
@@ -1,10 +1,12 @@
set(CMAKE_SYSTEM_NAME Rosetta)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
#set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
set(CMAKE_C_COMPILER_WORKS TRUE)
set(CMAKE_CXX_COMPILER_WORKS TRUE)
find_program(C_COMPILER x86_64-elf-gcc REQUIRED)
find_program(CXX_COMPILER x86_64-elf-g++ REQUIRED)
find_program(C_COMPILER x86_64-rosetta-gcc REQUIRED)
find_program(CXX_COMPILER x86_64-rosetta-g++ REQUIRED)
#find_program(ASM_COMPILER x86_64-elf-as REQUIRED)
add_compile_definitions(__magenta__=1 __rosetta__=1)
@@ -13,17 +15,45 @@ set(CMAKE_C_COMPILER ${C_COMPILER})
set(CMAKE_CXX_COMPILER ${CXX_COMPILER})
#set(CMAKE_ASM_COMPILER ${ASM_COMPILER})
SET(CMAKE_C_FLAGS "-ffreestanding -nostdlib -z max-page-size=0x1000 -m64 -mcmodel=large -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -D_64BIT -DBYTE_ORDER=1234" CACHE STRING "" FORCE)
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,-shared" CACHE STRING "" FORCE)
SET(CMAKE_C_FLAGS "-z max-page-size=0x1000 -m64 -mcmodel=large -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -D_64BIT -DBYTE_ORDER=1234" CACHE STRING "" FORCE)
set(CMAKE_SHARED_LINKER_FLAGS "-shared" CACHE STRING "" FORCE)
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--unresolved-symbols=report-all,--dynamic-linker=/lib/ld64.so" CACHE STRING "" FORCE)
set(CMAKE_C_LINK_OPTIONS_PIE "-pie")
set(CMAKE_C_LINK_PIE_SUPPORTED TRUE)
set(CMAKE_C_LINK_NO_PIE_SUPPORTED TRUE)
SET(CMAKE_ASM_FLAGS "${CFLAGS} -x assembler-with-cpp")
if ("$ENV{ROSETTA_SYSROOT}" STREQUAL "")
message(FATAL_ERROR "No system root has been specified. Please define the $ROSETTA_SYSROOT environment variable")
endif ()
set(CMAKE_SYSROOT $ENV{ROSETTA_SYSROOT})
set(CMAKE_SYSTEM_LIBRARY_PATH
$ENV{ROSETTA_SYSROOT}/lib
$ENV{ROSETTA_SYSROOT}/usr/lib)
set(CMAKE_C_OUTPUT_EXTENSION .o)
set(CMAKE_CXX_OUTPUT_EXTENSION .o)
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
set(CMAKE_DL_LIBS "dl")
set(CMAKE_INSTALL_RPATH \$ORIGIN/../lib)
set(CMAKE_SKIP_BUILD_RPATH FALSE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
#set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,")
#set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":")
set(CMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN "\$ORIGIN")
set(CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG "-Wl,-rpath-link,")
set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,-soname,")
set(CMAKE_EXE_EXPORTS_C_FLAG "-Wl,--export-dynamic")
set(CMAKE_C_LINK_GROUP_USING_cross_refs_SUPPORTED TRUE)
set(CMAKE_C_LINK_GROUP_USING_cross_refs
"LINKER:--start-group"
"LINKER:--end-group"
)
set(CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME 1)
link_libraries(-lgcc)
+7
View File
@@ -0,0 +1,7 @@
[seed]
name = 'cdrom'
[build]
build_system = 'cmake'
# vim: ft=toml
+5
View File
@@ -0,0 +1,5 @@
[command]
name = 'debug'
description = 'Run the system under a debugger'
# vim: ft=toml
+12
View File
@@ -0,0 +1,12 @@
[command]
name = 'run-kernel'
description = 'Run the kernel image directly under QEMU'
[dependency]
commands = [ 'qemu-system-x86_64' ]
seeds = [ 'magenta', 'bsp' ]
[exec]
args = [ 'src:run-kernel.py']
# vim: ft=toml
+30
View File
@@ -0,0 +1,30 @@
import os
import shutil
import subprocess
sysroot = os.environ['MEADOW_SYSROOT']
native_root = os.environ['MEADOW_NATIVE_ROOT']
tmp = os.environ['MEADOW_TEMP']
bsp = os.path.join(sysroot, 'boot', 'rosetta-system.bsp')
kernel_exe = os.path.join(sysroot, 'boot', 'magenta_kernel')
kernel_exe_elf32 = os.path.join(tmp, 'magenta_kernel.elf32')
e64patch = os.path.join(native_root, 'bin', 'e64patch')
shutil.copyfile(kernel_exe, kernel_exe_elf32)
subprocess.run([ e64patch, kernel_exe_elf32 ])
qemu_args = [
'qemu-system-x86_64',
'-m', '128M',
'-cpu', 'qemu64,+rdrand',
'-kernel', kernel_exe_elf32,
'-initrd', bsp,
'-serial', 'stdio',
'--append', 'kernel.early-console=ttyS0'
]
try:
subprocess.run(qemu_args)
except KeyboardInterrupt:
pass
+19
View File
@@ -0,0 +1,19 @@
[platform]
name = 'x86_64-pc'
arch = 'x86_64'
[cmake]
module_paths = [ '.' ]
system_name = 'Rosetta'
toolchain_file = 'Platform/Rosetta.cmake'
[extension]
commands = [
'command/run-kernel.command',
]
seeds = [
'cdrom.seed'
]
# vim: ft=toml
+15
View File
@@ -0,0 +1,15 @@
[seed]
name = 'base'
[dependency]
no_standard_dependencies = true
[build]
build_system = 'source-only'
build_for = 'target'
watch_files = [ 'src:**' ]
[install]
"/" = [ 'src:boot' ]
# vim: ft=toml
+1
View File
@@ -37,6 +37,7 @@ function(add_interface)
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR})
add_dependencies(iflib-${arg_NAME} ifgen-${arg_NAME})
add_library(interface::${arg_NAME} ALIAS iflib-${arg_NAME})
install(FILES ${header_path} DESTINATION include/${arg_PARENT_DIR})
endfunction(add_interface)
function(iface_get_header_path)
+12
View File
@@ -0,0 +1,12 @@
[seed]
name = 'libmagenta'
[dependency]
no_standard_dependencies = true
[build]
build_system = 'cmake'
source_dir = 'kernel/libmagenta'
watch_files = [ 'src:**/*.c', 'src:**/*.h' ]
# vim: ft=toml
+22
View File
@@ -0,0 +1,22 @@
[seed]
name = 'magenta-headers'
[dependency]
no_standard_dependencies = true
[build]
build_system = 'source-only'
build_for = 'target'
source_dir = 'kernel/libmagenta'
watch_files = [
'src:include/magenta/*.h',
'src:include-user/magenta/*.h',
]
[install]
"/usr/include/magenta" = [
'src:include/magenta/*.h',
'src:include-user/magenta/*.h',
]
# vim: ft=toml
+15
View File
@@ -0,0 +1,15 @@
[seed]
name = 'magenta-tools'
[dependency]
no_standard_dependencies = true
[build]
build_for = 'host'
build_system = 'cmake'
source_dir = 'kernel/tools'
[publish]
path = [ 'install:bin/' ]
# vim: ft=toml
+18
View File
@@ -0,0 +1,18 @@
[seed]
name = 'magenta'
[dependency]
no_standard_dependencies = true
seeds = [
'magenta-tools'
]
[build]
build_system = 'cmake'
source_dir = 'kernel'
watch_files = [ 'src:**/*.c', 'src:**/*.h' ]
[install]
prefix = "/"
# vim: ft=toml
+5 -1
View File
@@ -1,7 +1,11 @@
cmake_minimum_required(VERSION 3.31)
project(rosetta-interface)
include(Msg-Interface)
file(GLOB if_files *.xpc)
foreach (file ${if_files})
get_filename_component(name ${file} NAME_WLE)
add_interface(NAME ${name} PATH ${file} PARENT_DIR rosetta)
sysroot_add_interface(NAME ${name} DEST_DIR /usr/include)
endforeach (file)
+13
View File
@@ -0,0 +1,13 @@
[seed]
name = 'librosetta-interface'
[dependency]
no_standard_dependencies = true
seeds = [ 'xpcg' ]
[build]
build_system = 'cmake'
watch_files = [ 'src:*.xpc' ]
module_paths = [ 'root-src:cmake/' ]
# vim: ft=toml
+1 -1
Submodule kernel updated: bd6872d672...a14d0173c8
+15
View File
@@ -0,0 +1,15 @@
[seed]
name = 'libfx-host'
[dependency]
no_standard_dependencies = true
[build]
build_for = 'host'
build_system = 'cmake'
source_dir = 'lib/libfx'
[publish.cmake]
module_paths = [ 'src:cmake/' ]
# vim: ft=toml
+16
View File
@@ -0,0 +1,16 @@
[seed]
name = 'libfx'
[build]
build_system = 'cmake'
source_dir = 'lib/libfx'
configure_args = [
'-Dfx_assemblies=fx.runtime;fx.collections;fx.serial;fx.io;fx.term;fx.cmdline',
'-Dfx_enable_floating_point=0',
'-Dfx_enable_tests=0',
]
[publish.cmake]
module_paths = [ 'src:cmake/' ]
# vim: ft=toml
+12 -21
View File
@@ -1,10 +1,12 @@
cmake_minimum_required(VERSION 3.31)
project(libc C ASM)
set(source_dirs core malloc io exec)
set(LIBC_STANDALONE FALSE)
set(public_include_dirs
${CMAKE_CURRENT_SOURCE_DIR}/include)
add_subdirectory(runtime)
foreach (dir ${source_dirs})
add_subdirectory(${dir})
set(sources ${sources} ${component_sources})
@@ -12,22 +14,11 @@ foreach (dir ${source_dirs})
set(public_include_dirs ${public_include_dirs} ${component_public_include_dirs})
endforeach (dir)
rosetta_add_library(SHARED
NAME libc
PUBLIC_INCLUDE_DIRS ${public_include_dirs}
SOURCES ${sources}
HEADERS ${headers})
sysroot_add_library(
NAME libc
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
bsp_add_library(
NAME libc
LIB_DIR /usr/lib)
target_link_libraries(libc PRIVATE librosetta libxpc-static liblaunch-static interface::fs)
target_link_libraries(libc PUBLIC libmagenta)
target_compile_definitions(libc PRIVATE ENABLE_GLOBAL_HEAP=1)
add_subdirectory(pthread)
add_library(libc SHARED ${sources} ${headers})
target_include_directories(libc PUBLIC ${public_include_dirs})
target_link_libraries(libc PRIVATE rosetta libxpc.a liblaunch.a libmagenta.a)
target_compile_options(libc PRIVATE -ffreestanding -nostdlib)
target_link_options(libc PRIVATE -ffreestanding -nostdlib)
target_compile_definitions(libc PRIVATE ENABLE_GLOBAL_HEAP=1 BUILD_SHARED=1)
set_target_properties(libc PROPERTIES PREFIX "")
install(TARGETS libc)
+16 -13
View File
@@ -1,3 +1,8 @@
if (LIBC_STANDALONE)
cmake_minimum_required(VERSION 3.31)
project(libc-core C ASM)
endif ()
set(source_dirs assert stdio stdlib string errno ctype wctype unistd)
foreach (dir ${source_dirs})
@@ -12,18 +17,16 @@ file(GLOB sys_sources
${CMAKE_CURRENT_SOURCE_DIR}/sys/${CMAKE_SYSTEM_PROCESSOR}/*.c
${CMAKE_CURRENT_SOURCE_DIR}/sys/${CMAKE_SYSTEM_PROCESSOR}/*.S)
set(component_sources ${sources} ${sys_sources} PARENT_SCOPE)
set(component_headers ${headers} PARENT_SCOPE)
rosetta_add_library(STATIC
NAME libc-core
PUBLIC_INCLUDE_DIRS ${public_include_dirs}
SOURCES ${sources} ${sys_sources}
HEADERS ${headers})
sysroot_add_library(
NAME libc-core
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
if (NOT LIBC_STANDALONE)
set(component_sources ${sources} ${sys_sources} PARENT_SCOPE)
set(component_headers ${headers} PARENT_SCOPE)
return ()
endif ()
add_library(libc-core STATIC ${sources} ${sys_sources} ${headers})
target_include_directories(libc-core PUBLIC ${public_include_dirs})
target_link_libraries(libc-core PRIVATE libmagenta librosetta)
target_compile_definitions(libc-core PRIVATE ENABLE_GLOBAL_HEAP=1 BUILD_STATIC=1)
set_target_properties(libc-core PROPERTIES
PREFIX "")
install(TARGETS libc-core)
+18
View File
@@ -0,0 +1,18 @@
[seed]
name = 'libc-core'
[dependency]
no_standard_dependencies = true
seeds = [
'libc-headers',
'libmagenta',
'librosetta'
]
[build]
build_system = 'cmake'
configure_args = [
'-DLIBC_STANDALONE=TRUE'
]
# vim: ft=toml
+17 -16
View File
@@ -1,5 +1,10 @@
set(source_dirs unistd spawn)
if (LIBC_STANDALONE)
cmake_minimum_required(VERSION 3.31)
project(libc-exec C ASM)
endif ()
file(GLOB sources *.c *.h)
foreach (dir ${source_dirs})
@@ -13,21 +18,17 @@ endforeach (dir)
file(GLOB_RECURSE sub_headers ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h)
set(headers ${headers} ${sub_headers})
set(component_sources ${sources} PARENT_SCOPE)
set(component_headers ${headers} PARENT_SCOPE)
set(component_public_include_dirs ${CMAKE_CURRENT_SOURCE_DIR}/include PARENT_SCOPE)
rosetta_add_library(STATIC
NAME libc-exec
PUBLIC_INCLUDE_DIRS
${public_include_dirs}
${CMAKE_CURRENT_SOURCE_DIR}/include
SOURCES ${sources}
HEADERS ${headers})
sysroot_add_library(
NAME libc-exec
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
if (NOT LIBC_STANDALONE)
set(component_sources ${sources} PARENT_SCOPE)
set(component_headers ${headers} PARENT_SCOPE)
set(component_public_include_dirs ${CMAKE_CURRENT_SOURCE_DIR}/include PARENT_SCOPE)
endif ()
add_library(libc-exec STATIC ${sources} ${headers})
target_include_directories(libc-exec PUBLIC
${public_include_dirs}
${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(libc-exec libc-core libc-io libmagenta liblaunch-static)
target_compile_definitions(libc-exec PRIVATE ENABLE_GLOBAL_HEAP=1 BUILD_STATIC=1)
set_target_properties(libc-exec PROPERTIES PREFIX "")
install(TARGETS libc-exec)
+18
View File
@@ -0,0 +1,18 @@
[seed]
name = 'libc-exec'
[dependency]
seeds = [
'libc-core',
'libc-io',
'libmagenta',
'liblaunch-static',
]
[build]
build_system = 'cmake'
configure_args = [
'-DLIBC_STANDALONE=TRUE'
]
# vim: ft=toml
+8
View File
@@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.31)
project(libc-headers C)
file(GLOB headers *.h)
file(GLOB sys_headers sys/*.h)
install(FILES ${headers} DESTINATION include)
install(FILES ${sys_headers} DESTINATION include/sys)
+16
View File
@@ -0,0 +1,16 @@
[seed]
name = 'libc-headers'
[dependency]
no_standard_dependencies = true
[build]
build_system = 'source-only'
build_for = 'target'
watch_files = [ 'src:**' ]
[install]
"/usr/include" = [ 'src:*.h' ]
"/usr/include/sys" = [ 'src:sys/*.h' ]
# vim: ft=toml
+19 -17
View File
@@ -1,5 +1,10 @@
set(source_dirs unistd stdio)
if (LIBC_STANDALONE)
cmake_minimum_required(VERSION 3.31)
project(libc-io C ASM)
endif ()
file(GLOB sources *.c *.h)
foreach (dir ${source_dirs})
@@ -13,21 +18,18 @@ endforeach (dir)
file(GLOB_RECURSE sub_headers ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h)
set(headers ${headers} ${sub_headers})
set(component_sources ${sources} PARENT_SCOPE)
set(component_headers ${headers} PARENT_SCOPE)
set(component_public_include_dirs ${CMAKE_CURRENT_SOURCE_DIR}/include PARENT_SCOPE)
if (NOT LIBC_STANDALONE)
set(component_sources ${sources} PARENT_SCOPE)
set(component_headers ${headers} PARENT_SCOPE)
set(component_public_include_dirs ${CMAKE_CURRENT_SOURCE_DIR}/include PARENT_SCOPE)
return ()
endif ()
rosetta_add_library(STATIC
NAME libc-io
PUBLIC_INCLUDE_DIRS
${public_include_dirs}
${CMAKE_CURRENT_SOURCE_DIR}/include
SOURCES ${sources}
HEADERS ${headers})
sysroot_add_library(
NAME libc-io
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
target_link_libraries(libc-io libc-core interface::fs libxpc-static libmagenta)
add_library(libc-io STATIC ${sources} ${headers})
target_include_directories(libc-io PUBLIC
${public_include_dirs}
${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(libc-io libc-core libxpc.a libmagenta)
target_compile_definitions(libc-io PRIVATE ENABLE_GLOBAL_HEAP=1 BUILD_STATIC=1)
set_target_properties(libc-io PROPERTIES PREFIX "")
install(TARGETS libc-io)
+19
View File
@@ -0,0 +1,19 @@
[seed]
name = 'libc-io'
[dependency]
no_standard_dependencies = true
seeds = [
'libmagenta',
'libc-core',
'librosetta-interface',
'libxpc-static'
]
[build]
build_system = 'cmake'
configure_args = [
'-DLIBC_STANDALONE=TRUE'
]
# vim: ft=toml
+17
View File
@@ -0,0 +1,17 @@
[seed]
name = 'libc'
[dependency]
seeds = [
'libc-headers',
'libmagenta',
'librosetta',
'libxpc-static',
'liblaunch-static',
'librosetta-interface'
]
[build]
build_system = 'cmake'
# vim: ft=toml
+16 -16
View File
@@ -1,5 +1,10 @@
set(source_dirs stdlib string)
if (LIBC_STANDALONE)
cmake_minimum_required(VERSION 3.31)
project(libc-malloc C ASM)
endif ()
file(GLOB sources *.c *.h)
foreach (dir ${source_dirs})
@@ -13,22 +18,17 @@ endforeach (dir)
file(GLOB_RECURSE sub_headers ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h)
set(headers ${headers} ${sub_headers})
set(component_sources ${sources} PARENT_SCOPE)
set(component_headers ${headers} PARENT_SCOPE)
set(component_public_include_dirs ${CMAKE_CURRENT_SOURCE_DIR}/include PARENT_SCOPE)
rosetta_add_library(STATIC
NAME libc-malloc
PUBLIC_INCLUDE_DIRS
${public_include_dirs}
${CMAKE_CURRENT_SOURCE_DIR}/include
SOURCES ${sources}
HEADERS ${headers})
sysroot_add_library(
NAME libc-malloc
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
if (NOT LIBC_STANDALONE)
set(component_sources ${sources} PARENT_SCOPE)
set(component_headers ${headers} PARENT_SCOPE)
set(component_public_include_dirs ${CMAKE_CURRENT_SOURCE_DIR}/include PARENT_SCOPE)
endif ()
add_library(libc-malloc STATIC ${sources} ${headers})
target_compile_definitions(libc-malloc PRIVATE LIBC_STATIC=1 ENABLE_GLOBAL_HEAP=1)
target_include_directories(libc-malloc PUBLIC ${public_include_dirs} include)
target_compile_definitions(libc-malloc PRIVATE ENABLE_GLOBAL_HEAP=1 BUILD_STATIC=1)
target_link_libraries(libc-malloc libc-core libmagenta)
set_target_properties(libc-malloc PROPERTIES PREFIX "")
install(TARGETS libc-malloc)
install(FILES ${sub_headers} DESTINATION include/heap)
+17
View File
@@ -0,0 +1,17 @@
[seed]
name = 'libc-malloc'
[dependency]
no_standard_dependencies = true
seeds = [
'libmagenta',
'libc-core'
]
[build]
build_system = 'cmake'
configure_args = [
'-DLIBC_STANDALONE=TRUE'
]
# vim: ft=toml
+27 -27
View File
@@ -1,4 +1,7 @@
set(pthread_source_dirs thread)
cmake_minimum_required(VERSION 3.31)
project(libc-pthread C ASM)
set(pthread_source_dirs thread mutex)
foreach (dir ${pthread_source_dirs})
file(GLOB dir_sources ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.c)
@@ -17,30 +20,27 @@ set(pthread_sources ${pthread_sources} ${pthread_sys_sources})
set(pthread_headers ${pthread_headers} ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread.h)
set(pthread_public_include_dir ${CMAKE_CURRENT_SOURCE_DIR}/include)
rosetta_add_library(STATIC
NAME libc-pthread
PUBLIC_INCLUDE_DIRS ${pthread_public_include_dir}
SOURCES ${pthread_sources}
HEADERS ${pthread_headers})
rosetta_add_library(SHARED
NAME libpthread
PUBLIC_INCLUDE_DIRS ${pthread_public_include_dir}
SOURCES ${pthread_sources}
HEADERS ${pthread_headers})
if (PTHREAD_STATIC)
add_library(libc-pthread STATIC ${pthread_sources} ${pthread_headers})
target_link_libraries(libc-pthread PRIVATE libc-io libmagenta)
target_include_directories(libc-pthread PUBLIC
${public_include_dirs}
${CMAKE_CURRENT_SOURCE_DIR}/include)
set_target_properties(libc-pthread PROPERTIES PREFIX "")
target_compile_definitions(libc-pthread PRIVATE ENABLE_GLOBAL_HEAP=1 BUILD_STATIC=1)
install(TARGETS libc-pthread)
else ()
add_library(libpthread SHARED ${pthread_sources} ${pthread_headers})
target_link_libraries(libpthread PRIVATE magenta)
target_link_libraries(libpthread PUBLIC c)
target_include_directories(libpthread PUBLIC
${public_include_dirs}
${CMAKE_CURRENT_SOURCE_DIR}/include)
set_target_properties(libpthread PROPERTIES PREFIX "")
target_compile_options(libpthread PRIVATE -ffreestanding -nostdlib)
target_link_options(libpthread PRIVATE -ffreestanding -nostdlib)
target_compile_definitions(libpthread PRIVATE ENABLE_GLOBAL_HEAP=1 BUILD_SHARED=1)
install(TARGETS libpthread)
endif ()
sysroot_add_library(
NAME libc-pthread
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
sysroot_add_library(
NAME libpthread
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
bsp_add_library(
NAME libpthread
LIB_DIR /usr/lib)
target_link_libraries(libc-pthread PRIVATE libc-io libmagenta)
target_link_libraries(libpthread PRIVATE libmagenta)
target_link_libraries(libpthread PUBLIC libc)
install(FILES include/pthread.h DESTINATION include)
+17
View File
@@ -0,0 +1,17 @@
[seed]
name = 'libc-pthread'
[dependency]
no_standard_dependencies = true
seeds = [
'libmagenta',
'libc-io'
]
[build]
build_system = 'cmake'
configure_args = [
'-DPTHREAD_STATIC=TRUE'
]
# vim: ft=toml
+7
View File
@@ -0,0 +1,7 @@
[seed]
name = 'libpthread'
[build]
build_system = 'cmake'
# vim: ft=toml
+12 -6
View File
@@ -1,10 +1,16 @@
cmake_minimum_required(VERSION 3.31)
project(libc-runtime C ASM)
file(GLOB runtime_sources
${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_SYSTEM_PROCESSOR}/*.s)
rosetta_add_object_library(
NAME libc-runtime STATIC
SOURCES ${runtime_sources})
foreach (s ${runtime_sources})
get_filename_component(object_name ${s} NAME)
get_filename_component(object_basename ${s} NAME_WE)
# TODO find a better way of finding the compiled object files
set(object_path
${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/libc-runtime.dir/${CMAKE_SYSTEM_PROCESSOR}/${object_name}.obj)
install(FILES ${object_path} DESTINATION lib RENAME "${object_basename}.o")
endforeach (s)
sysroot_add_object_library(
NAME libc-runtime
LIB_DIR /usr/lib)
add_library(libc-runtime OBJECT ${runtime_sources})
+13
View File
@@ -0,0 +1,13 @@
[seed]
name = 'libc-runtime'
[dependency]
no_standard_dependencies = true
[build]
build_system = 'cmake'
configure_args = [
'-DLIBC_STANDALONE=TRUE'
]
# vim: ft=toml
+16 -22
View File
@@ -1,33 +1,27 @@
cmake_minimum_required(VERSION 3.31)
project(fs C ASM)
file(GLOB sources
${CMAKE_CURRENT_SOURCE_DIR}/*.c
${CMAKE_CURRENT_SOURCE_DIR}/interface/*.c)
file(GLOB headers
${CMAKE_CURRENT_SOURCE_DIR}/*.h
${CMAKE_CURRENT_SOURCE_DIR}/include/fs/*.h)
file(GLOB public_headers
${CMAKE_CURRENT_SOURCE_DIR}/include/fs/*.h)
set(public_include_dirs
${CMAKE_CURRENT_SOURCE_DIR}/include)
rosetta_add_library(
NAME libfs SHARED STATIC
PUBLIC_INCLUDE_DIRS ${public_include_dirs}
SOURCES ${sources}
HEADERS ${headers})
if (FS_STATIC)
add_library(fs STATIC ${sources} ${headers})
target_link_libraries(fs magenta libc-core libxpc.a)
set_target_properties(fs PROPERTIES POSITION_INDEPENDENT_CODE FALSE)
else ()
add_library(fs SHARED ${sources} ${headers})
target_link_libraries(fs magenta c xpc)
endif ()
sysroot_add_library(
NAME libfs
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
sysroot_add_library(
NAME libfs-static
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
bsp_add_library(
NAME libfs
LIB_DIR /usr/lib)
target_link_libraries(libfs libmagenta interface::fs libc libxpc)
target_link_libraries(libfs-static libmagenta interface::fs libc-core libxpc-static)
set_target_properties(libfs-static PROPERTIES POSITION_INDEPENDENT_CODE FALSE)
target_include_directories(fs PUBLIC include)
install(TARGETS fs)
install(FILES ${public_headers} DESTINATION include/fs)
+16
View File
@@ -0,0 +1,16 @@
[seed]
name = 'libfs-static'
[dependency]
no_standard_dependencies = true
seeds = [
'libxpc-static',
'liblaunch-static',
'librosetta-interface'
]
[build]
build_system = 'cmake'
configure_args = [ '-DFS_STATIC=TRUE' ]
# vim: ft=toml
+13
View File
@@ -0,0 +1,13 @@
[seed]
name = 'libfs'
[dependency]
seeds = [
'libxpc',
'librosetta-interface'
]
[build]
build_system = 'cmake'
# vim: ft=toml
+15 -15
View File
@@ -1,25 +1,25 @@
cmake_minimum_required(VERSION 3.31)
project(launch C ASM)
file(GLOB sources
${CMAKE_CURRENT_SOURCE_DIR}/*.c)
file(GLOB headers
${CMAKE_CURRENT_SOURCE_DIR}/include/launch.h
${CMAKE_CURRENT_SOURCE_DIR}/*.h)
file(GLOB public_headers
${CMAKE_CURRENT_SOURCE_DIR}/include/launch.h)
set(public_include_dirs
${CMAKE_CURRENT_SOURCE_DIR}/include)
rosetta_add_library(
NAME liblaunch SHARED STATIC
PUBLIC_INCLUDE_DIRS ${public_include_dirs}
SOURCES ${sources}
HEADERS ${headers})
if (LAUNCH_STATIC)
add_library(launch STATIC ${sources} ${headers})
target_link_libraries(launch PRIVATE librosetta libmagenta libc-core)
else ()
add_library(launch SHARED ${sources} ${headers})
target_link_libraries(launch PRIVATE rosetta magenta c)
endif ()
sysroot_add_library(
NAME liblaunch
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
bsp_add_library(
NAME liblaunch
LIB_DIR /usr/lib)
target_link_libraries(liblaunch-static PRIVATE librosetta libmagenta libc-core)
target_link_libraries(liblaunch PRIVATE librosetta libmagenta libc)
target_include_directories(launch PUBLIC include)
install(TARGETS launch)
install(FILES ${public_headers} DESTINATION include)
+16
View File
@@ -0,0 +1,16 @@
[seed]
name = 'liblaunch-static'
[dependency]
no_standard_dependencies = true
seeds = [
'librosetta',
'libmagenta',
'libc-core'
]
[build]
build_system = 'cmake'
configure_args = [ '-DLAUNCH_STATIC=TRUE' ]
# vim: ft=toml
+7
View File
@@ -0,0 +1,7 @@
[seed]
name = 'liblaunch'
[build]
build_system = 'cmake'
# vim: ft=toml
+8 -10
View File
@@ -1,15 +1,13 @@
cmake_minimum_required(VERSION 3.31)
project(librosetta C ASM)
file(GLOB sources *.c)
file(GLOB headers include/rosetta/*.h)
rosetta_add_library(
NAME librosetta STATIC
PUBLIC_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include
SOURCES ${sources}
HEADERS ${headers})
add_library(rosetta STATIC ${sources} ${headers})
target_include_directories(rosetta PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
sysroot_add_library(
NAME librosetta
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
target_link_libraries(rosetta PRIVATE libmagenta)
target_link_libraries(librosetta PRIVATE libmagenta)
install(TARGETS rosetta)
install(FILES ${headers} DESTINATION include/rosetta)
+13
View File
@@ -0,0 +1,13 @@
[seed]
name = 'librosetta'
[dependency]
no_standard_dependencies = true
seeds = [
'libmagenta',
]
[build]
build_system = 'cmake'
# vim: ft=toml
+16 -16
View File
@@ -1,28 +1,28 @@
cmake_minimum_required(VERSION 3.31)
project(xpc C ASM)
file(GLOB sources
${CMAKE_CURRENT_SOURCE_DIR}/*.c)
file(GLOB headers
${CMAKE_CURRENT_SOURCE_DIR}/*.h
${CMAKE_CURRENT_SOURCE_DIR}/include/xpc/*.h)
file(GLOB public_headers
${CMAKE_CURRENT_SOURCE_DIR}/include/xpc/*.h)
set(public_include_dirs
${CMAKE_CURRENT_SOURCE_DIR}/include)
rosetta_add_library(
NAME libxpc SHARED STATIC
PUBLIC_INCLUDE_DIRS ${public_include_dirs}
SOURCES ${sources}
HEADERS ${headers})
if (XPC_STATIC)
add_library(xpc STATIC ${sources} ${headesr})
target_link_libraries(xpc magenta libc-core)
else ()
add_library(xpc SHARED ${sources} ${headesr})
target_link_libraries(xpc magenta c)
endif ()
sysroot_add_library(
NAME libxpc
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
sysroot_add_library(
NAME libxpc-static
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
target_link_libraries(libxpc libmagenta libc)
target_link_libraries(libxpc-static libmagenta libc-core)
target_include_directories(xpc PUBLIC ${public_include_dirs})
install(TARGETS xpc)
install(FILES ${public_headers} DESTINATION include/xpc)
#set_target_properties(libxpc-static PROPERTIES POSITION_INDEPENDENT_CODE FALSE)
+15
View File
@@ -0,0 +1,15 @@
[seed]
name = 'libxpc-static'
[dependency]
no_standard_dependencies = true
seeds = [
'libmagenta',
'libc-core'
]
[build]
build_system = 'cmake'
configure_args = [ '-DXPC_STATIC=TRUE' ]
# vim: ft=toml
+7
View File
@@ -0,0 +1,7 @@
[seed]
name = 'libxpc'
[build]
build_system = 'cmake'
# vim: ft=toml
Executable
+18
View File
@@ -0,0 +1,18 @@
#!/bin/bash
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
if [ ! -d "$SCRIPT_DIR/build" ]; then
mkdir build
fi
if [ ! -d "$SCRIPT_DIR/build/meadow_venv" ]; then
echo 'Initialising meadow...'
python3 -m venv $SCRIPT_DIR/build/meadow_venv
source $SCRIPT_DIR/build/meadow_venv/bin/activate
pip install -r $SCRIPT_DIR/toolchain/meadow/requirements.txt
else
source $SCRIPT_DIR/build/meadow_venv/bin/activate
fi
python3 $SCRIPT_DIR/toolchain/meadow/main.py "$@"
+1
View File
@@ -3,6 +3,7 @@ file(GLOB items *)
set(bshell_interactive 0)
set(bshell_verbose 0)
set(bshell_enable_floating_point 0)
set(bshell_enable_native_commands 0)
foreach(item ${items})
if (NOT IS_DIRECTORY ${item})
+18
View File
@@ -0,0 +1,18 @@
[seed]
name = 'bshell'
[dependency]
seeds = [
'libfx',
]
[build]
build_system = 'cmake'
source_dir = 'programs/bshell'
configure_args = [
'-Dbshell_interactive=FALSE',
'-Dbshell_enable_native_commands=FALSE',
'-Dbshell_enable_floating_point=FALSE',
]
# vim: ft=toml
+8 -16
View File
@@ -1,17 +1,9 @@
rosetta_add_misc_service(
NAME bshell-test
CFG_FILE ${CMAKE_CURRENT_SOURCE_DIR}/bshell-test.service)
cmake_minimum_required(VERSION 3.31)
project(bshell-test)
rosetta_service_add_file(
NAME bshell-test
SRC_FILE ${CMAKE_CURRENT_SOURCE_DIR}/test.bshell
DEST_DIR /sbin)
sysroot_add_service(
NAME bshell-test
BIN_DIR /usr/bin
SVC_DIR /etc/herdd/services)
bsp_add_service(
NAME bshell-test
BIN_DIR /usr/bin
SVC_DIR /etc/herdd/services)
install(
FILES ${CMAKE_CURRENT_SOURCE_DIR}/bshell-test.service
DESTINATION etc/herdd/services)
install(
FILES ${CMAKE_CURRENT_SOURCE_DIR}/test.bshell
DESTINATION sbin)
+12
View File
@@ -0,0 +1,12 @@
[seed]
name = 'bshell-test'
[build]
build_system = 'cmake'
[install]
prefix = "/"
'/etc/herdd/services' = [ 'bshell-test.service' ]
'/sbin' = [ 'test.bshell' ]
# vim: ft=toml
+6 -14
View File
@@ -1,15 +1,7 @@
file(GLOB sources *.c)
rosetta_add_service(
NAME devmd
SOURCES ${sources}
CFG_FILE ${CMAKE_CURRENT_SOURCE_DIR}/devmd.service)
target_link_libraries(devmd libc libc-runtime)
cmake_minimum_required(VERSION 3.31)
project(devmd C)
sysroot_add_service(
NAME devmd
BIN_DIR /usr/bin
SVC_DIR /etc/herdd/services)
bsp_add_service(
NAME devmd
BIN_DIR /usr/bin
SVC_DIR /etc/herdd/services)
file(GLOB sources *.c)
add_executable(devmd ${sources})
target_link_libraries(devmd c -l:crt0.o)
install(TARGETS devmd)
+10
View File
@@ -0,0 +1,10 @@
[seed]
name = 'devmd'
[build]
build_system = 'cmake'
[install]
"/etc/herdd/services" = [ 'src:devmd.service' ]
# vim: ft=toml
+6 -8
View File
@@ -1,13 +1,11 @@
cmake_minimum_required(VERSION 3.31)
project(herdd C)
file(GLOB sources *.c)
add_executable(herdd ${sources})
target_link_libraries(herdd
libc libc-runtime
libmagenta libpthread liblaunch librosetta
c -l:crt0.o
magenta pthread launch rosetta
fx.runtime fx.collections fx.serial)
sysroot_add_program(
NAME herdd
BIN_DIR /usr/bin)
bsp_add_program(
NAME herdd
BIN_DIR /usr/bin)
install(TARGETS herdd)
+15
View File
@@ -0,0 +1,15 @@
[seed]
name = 'herdd'
[dependency]
seeds = [
'liblaunch',
'librosetta',
'libfx'
]
[build]
build_system = 'cmake'
watch_files = [ 'src:*.c', 'src:*.h' ]
# vim: ft=toml
+6 -14
View File
@@ -1,15 +1,7 @@
file(GLOB sources *.c)
rosetta_add_service(
NAME nsd
SOURCES ${sources}
CFG_FILE ${CMAKE_CURRENT_SOURCE_DIR}/nsd.service)
target_link_libraries(nsd libc libc-runtime)
cmake_minimum_required(VERSION 3.31)
project(nsd C)
sysroot_add_service(
NAME nsd
BIN_DIR /usr/bin
SVC_DIR /etc/herdd/services)
bsp_add_service(
NAME nsd
BIN_DIR /usr/bin
SVC_DIR /etc/herdd/services)
file(GLOB sources *.c)
add_executable(nsd ${sources})
target_link_libraries(nsd c -l:crt0.o)
install(TARGETS nsd)
+10
View File
@@ -0,0 +1,10 @@
[seed]
name = 'nsd'
[build]
build_system = 'cmake'
[install]
"/etc/herdd/services" = [ 'src:nsd.service' ]
# vim: ft=toml
+15
View File
@@ -0,0 +1,15 @@
[seed]
name = 'herdd-targets'
[dependency]
no_standard_dependencies = true
[build]
build_system = 'source-only'
build_for = 'target'
watch_files = [ 'src:*.target' ]
[install]
"/etc/herdd/targets" = [ 'src:*.target' ]
# vim: ft=toml
+11 -6
View File
@@ -1,15 +1,19 @@
cmake_minimum_required(VERSION 3.31)
project(bootstrap C ASM)
file(GLOB c_sources *.c *.h)
file(GLOB arch_sources arch/${CMAKE_SYSTEM_PROCESSOR}/*.S)
add_executable(bootstrap ${c_sources} ${arch_sources})
set(static_deps
magenta rosetta
libc-core.a libc-malloc.a libc-io.a
libfs.a
liblaunch.a
libxpc.a)
target_link_libraries(bootstrap
libmagenta librosetta
libc-core libc-malloc libc-pthread
libfs-static
liblaunch-static
libxpc-static
interface::fs)
"$<LINK_GROUP:cross_refs,${static_deps}>")
target_compile_options(bootstrap PRIVATE
-fno-stack-protector -nostdlib -ffreestanding -fno-PIC)
@@ -17,3 +21,4 @@ target_link_options(bootstrap PRIVATE
-static -nostdlib -ffreestanding)
set_target_properties(bootstrap PROPERTIES POSITIION_INDEPENDENT_CODE FALSE)
install(TARGETS bootstrap DESTINATION boot)
+24
View File
@@ -0,0 +1,24 @@
[seed]
name = 'bootstrap'
[dependency]
no_standard_dependencies = true
seeds = [
'libmagenta',
'librosetta',
'libc-core',
'libc-malloc',
'libc-pthread',
'libfs-static',
'liblaunch-static',
'libxpc-static',
'librosetta-interface',
]
[build]
build_system = 'cmake'
[install]
prefix = "/"
# vim: ft=toml
+38
View File
@@ -0,0 +1,38 @@
[seed]
name = 'bsp'
[build]
build_system = 'generic'
build_command = {
args = [
'root-src:toolchain/mkbsp/mkbsp',
'--preset',
'src:rosetta.preset',
'--sysroot',
'install:.',
'--out',
'bin:rosetta-system.bsp',
],
}
watch_files = [ 'install:**' ]
[dependency]
seeds = [
'ld',
'bshell',
'libc',
'libpthread',
'libfx',
'liblaunch',
'libfs',
'libxpc',
'herdd',
'herdd-targets',
'nsd',
'devmd',
]
[install]
"/boot" = [ 'bin:rosetta-system.bsp' ]
# vim: ft=toml
+8
View File
@@ -0,0 +1,8 @@
[bootstrap]
bootstrap_exec = '/boot/bootstrap'
[contents]
"/lib" = [ '/lib/ld64.so' ]
"/usr/bin" = [ '/usr/bin/herdd' ]
# vim: ft=toml
+16
View File
@@ -0,0 +1,16 @@
[contents]
"/usr/lib" = [
'/usr/lib/libc.so',
'/usr/lib/libpthread.so',
'/usr/lib/libfs.so',
'/usr/lib/libfx.runtime.so',
'/usr/lib/libfx.collections.so',
'/usr/lib/libfx.io.so',
'/usr/lib/libfx.serial.so',
'/usr/lib/libfx.term.so',
'/usr/lib/libfx.cmdline.so',
'/usr/lib/liblaunch.so',
'/usr/lib/libxpc.so',
]
# vim: ft=toml
+12
View File
@@ -0,0 +1,12 @@
[contents]
"/usr/bin" = [
'/usr/bin/devmd',
'/usr/bin/nsd',
]
"/etc/herdd/services" = [
'/etc/herdd/services/devmd.service',
'/etc/herdd/services/nsd.service',
]
# vim: ft=toml
+7
View File
@@ -0,0 +1,7 @@
[contents]
"/etc/herdd/targets" = [
'/etc/herdd/targets/minimal.target',
'/etc/herdd/targets/single-user.target',
]
# vim: ft=toml
+8
View File
@@ -0,0 +1,8 @@
[contents]
"/usr/bin" = [ '/usr/bin/bshell' ]
"/usr/lib" = [
'/usr/lib/libbshell.runtime.so',
'/usr/lib/libbshell.core.so',
]
# vim: ft=toml
+8 -9
View File
@@ -1,3 +1,6 @@
cmake_minimum_required(VERSION 3.31)
project(ld C ASM)
file(GLOB c_sources *.c *.h)
file(GLOB arch_sources arch/${CMAKE_SYSTEM_PROCESSOR}/*.S)
@@ -7,9 +10,11 @@ set_target_properties(ld PROPERTIES
OUTPUT_NAME "ld64"
SUFFIX ".so")
set(libc_deps
libc-core.a libc-malloc.a libc-io.a)
target_link_libraries(ld
libc-core libc-malloc libc-io libmagenta librosetta libxpc-static
interface::fs)
"$<LINK_GROUP:cross_refs,${libc_deps}>"
libmagenta.a librosetta.a -l:libxpc.a)
target_compile_options(ld PRIVATE
-fvisibility=hidden
@@ -19,10 +24,4 @@ target_link_options(ld PRIVATE
# -Wl,--entry="_ld_start"
-T ${CMAKE_CURRENT_SOURCE_DIR}/arch/${CMAKE_SYSTEM_PROCESSOR}/layout.ld
-fPIC -nostdlib -ffreestanding -Wl,-shared)
sysroot_add_program(
NAME ld
BIN_DIR /lib)
bsp_add_program(
NAME ld
BIN_DIR /lib)
install(TARGETS ld DESTINATION lib)
+23
View File
@@ -0,0 +1,23 @@
[seed]
name = 'ld'
[dependency]
no_standard_dependencies = true
seeds = [
'libc-core',
'libc-malloc',
'libc-io',
'libc-headers',
'libxpc-static',
'libmagenta',
'librosetta',
'librosetta-interface',
]
[build]
build_system = 'cmake'
[install]
prefix = "/"
# vim: ft=toml
+42
View File
@@ -0,0 +1,42 @@
[target]
name = 'rosetta'
base_components = [
'libmagenta',
'libc',
'libpthread',
'libc-headers',
]
default_prefix = '/usr'
[dependency]
seeds = [
'libfx-host',
'xpcg',
'magenta',
'libmagenta',
'librosetta',
'libc',
'libpthread',
'libc-core',
'libc-io',
'libc-runtime',
'libc-pthread',
'libc-exec',
'libc-malloc',
'librosetta-interface',
'ld',
'bootstrap',
'bshell',
'libfs',
'libxpc',
'libfx',
'base',
'herdd',
'herdd-targets',
'nsd',
'devmd',
'bsp'
]
# vim: ft=toml
@@ -0,0 +1,139 @@
diff --git a/bfd/config.bfd b/bfd/config.bfd
index 4dde5321f23..94c1a871ec2 100644
--- a/bfd/config.bfd
+++ b/bfd/config.bfd
@@ -242,7 +242,17 @@ esac
case "${targ}" in
# START OF targmatch.h
+ i[3-7]86-*-rosetta*)
+ targ_defvec=i386_elf32_vec
+ targ_selvecs=
+ targ64_selvecs=x86_64_elf64_vec
+ ;;
#ifdef BFD64
+ x86_64-*-rosetta*)
+ targ_defvec=x86_64_elf64_vec
+ targ_selvecs=i386_elf32_vec
+ want64=true
+ ;;
aarch64-*-darwin*)
targ_defvec=aarch64_mach_o_vec
targ_selvecs="arm_mach_o_vec mach_o_le_vec mach_o_be_vec mach_o_fat_vec"
diff --git a/config.sub b/config.sub
index 3d35cde174d..19cd8f07cd7 100755
--- a/config.sub
+++ b/config.sub
@@ -2102,6 +2102,7 @@ case $os in
| rhapsody* \
| riscix* \
| riscos* \
+ | rosetta* \
| rtems* \
| rtmk* \
| rtu* \
diff --git a/gas/configure.tgt b/gas/configure.tgt
index f0ea55d9def..4f194e70501 100644
--- a/gas/configure.tgt
+++ b/gas/configure.tgt
@@ -126,6 +126,7 @@ esac
generic_target=${cpu_type}-$vendor-$os
# Note: This table is alpha-sorted, please try to keep it that way.
case ${generic_target} in
+ i386-*-rosetta*) fmt=elf em=gnu;;
aarch64*-*-elf*) fmt=elf;;
aarch64*-*-fuchsia*) fmt=elf;;
aarch64*-*-haiku*) fmt=elf em=haiku ;;
diff --git a/ld/Makefile.am b/ld/Makefile.am
index c219662d2e3..8d17fed7581 100644
--- a/ld/Makefile.am
+++ b/ld/Makefile.am
@@ -153,6 +153,7 @@ endif
# These all start with e so 'make clean' can find them.
ALL_EMULATION_SOURCES = \
+ eelf_i386_rosetta.c \
eaix5ppc.c \
eaix5rs6.c \
eaixppc.c \
@@ -373,6 +374,7 @@ ALL_EMULATION_SOURCES = \
ALL_EMULATIONS = $(ALL_EMULATION_SOURCES:.c=.@OBJEXT@)
ALL_64_EMULATION_SOURCES = \
+ eelf_x86_64_rosetta.c \
eaarch64elf.c \
eaarch64elf32.c \
eaarch64elf32b.c \
diff --git a/ld/Makefile.in b/ld/Makefile.in
index f1ba6af5269..a4d76c4cc0b 100644
--- a/ld/Makefile.in
+++ b/ld/Makefile.in
@@ -668,6 +668,7 @@ LIBIBERTY = ../libiberty/libiberty.a
# These all start with e so 'make clean' can find them.
ALL_EMULATION_SOURCES = \
+ eelf_i386_rosetta.c \
eaix5ppc.c \
eaix5rs6.c \
eaixppc.c \
@@ -887,6 +888,7 @@ ALL_EMULATION_SOURCES = \
ALL_EMULATIONS = $(ALL_EMULATION_SOURCES:.c=.@OBJEXT@)
ALL_64_EMULATION_SOURCES = \
+ eelf_x86_64_rosetta.c \
eaarch64elf.c \
eaarch64elf32.c \
eaarch64elf32b.c \
@@ -1474,6 +1476,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_i386_be.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_i386_fbsd.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_i386_haiku.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_i386_rosetta.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_i386_sol2.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_i386_vxworks.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_iamcu.Po@am__quote@
@@ -1482,6 +1485,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_x86_64.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_x86_64_fbsd.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_x86_64_haiku.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_x86_64_rosetta.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_x86_64_sol2.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eh8300elf.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eh8300elf_linux.Po@am__quote@
diff --git a/ld/configure.tgt b/ld/configure.tgt
index 3e158913b89..53c091fb78f 100644
--- a/ld/configure.tgt
+++ b/ld/configure.tgt
@@ -82,6 +82,13 @@ fi
# Please try to keep this table more or less in alphabetic order - it
# makes it much easier to lookup a specific archictecture.
case "${targ}" in
+i[3-7]86-*-rosetta*) targ_emul=elf_i386_rosetta
+ targ_extra_emuls=elf_i386
+ targ64_extra_emuls="elf_x86_64_rosetta elf_x86_64"
+ ;;
+x86_64-*-rosetta*) targ_emul=elf_x86_64_rosetta
+ targ_extra_emuls="elf_i386_rosetta elf_x86_64 elf_i386"
+ ;;
aarch64_be-*-elf) targ_emul=aarch64elfb
targ_extra_emuls="aarch64elf aarch64elf32 aarch64elf32b armelfb armelf"
;;
diff --git a/ld/emulparams/elf_i386_rosetta.sh b/ld/emulparams/elf_i386_rosetta.sh
new file mode 100644
index 00000000000..002e918bc53
--- /dev/null
+++ b/ld/emulparams/elf_i386_rosetta.sh
@@ -0,0 +1,4 @@
+source_sh ${srcdir}/emulparams/elf_i386.sh
+TEXT_START_ADDR=0x08000000
+GENERATE_SHLIB_SCRIPT=yes
+GENERATE_PIE_SCRIPT=yes
diff --git a/ld/emulparams/elf_x86_64_rosetta.sh b/ld/emulparams/elf_x86_64_rosetta.sh
new file mode 100644
index 00000000000..4ddde5ab2a5
--- /dev/null
+++ b/ld/emulparams/elf_x86_64_rosetta.sh
@@ -0,0 +1,3 @@
+source_sh ${srcdir}/emulparams/elf_x86_64.sh
+GENERATE_SHLIB_SCRIPT=yes
+GENERATE_PIE_SCRIPT=yes
@@ -0,0 +1,14 @@
[command]
name = 'build-compiler'
description = 'Build a GCC cross-compiler that targets the Rosetta operating system'
[dependency]
seeds = [
'libc-headers',
'magenta-headers',
]
[exec]
args = [ 'src:build.py']
# vim: ft=toml
+31
View File
@@ -0,0 +1,31 @@
import os
class Builder:
def get_prefix(self):
return os.environ.get('MEADOW_NATIVE_ROOT', None)
def get_target(self):
env = os.environ
target = os.environ.get('MEADOW_TARGET_PLATFORM', None)
parts = target.split('-')
return f'{parts[0]}-rosetta'
def download(self):
pass
def configure(self):
pass
def build(self):
pass
def install(self):
pass
print(f'building cross compiler for {get_gcc_target()}, installed to {get_prefix()}')
@@ -0,0 +1 @@
../binutils-gdb/configure --target=x86_64-rosetta --prefix=/opt/cross-rosetta --with-sysroot=/opt/cross-rosetta --disable-nls --disable-werror --enable-default-execstack=no --with-gmp=/opt/homebrew --enable-shared
@@ -0,0 +1 @@
../gcc/configure --target=x86_64-rosetta --prefix=/opt/cross-rosetta --with-sysroot=/Users/wash/projects/rosetta/build/target-root --disable-nls --enable-languages=c,c++ --enable-shared --enable-initfini-array --with-gmp=/opt/homebrew
File diff suppressed because it is too large Load Diff
+42
View File
@@ -0,0 +1,42 @@
class Args:
def __init__(self, argv):
self.__argv = argv
def get_positional(self, index):
if len(self.__argv) > index:
return self.__argv[index]
return None
def get_named(self, name, index, nr_args):
found_name = False
values = []
for s in self.__argv:
if found_name:
if nr_args > 0:
nr_args -= 1
values.append(s)
continue
else:
break
if s == '--{}'.format(name):
if index > 0:
index -= 1
continue
found_name = True
continue
if nr_args == 0:
return found_name
if nr_args > 0 or not found_name:
return None
if len(values) == 1:
return values[0]
return values
+146
View File
@@ -0,0 +1,146 @@
import os
import shutil
from env import Environment
from path import Path
from pathlib import Path as SysPath
class UnknownBuildSystemError(Exception):
pass
class BuildConfigurationError(Exception):
pass
class BuildError(Exception):
pass
class BuildSystem:
def __init__(self, **kwargs):
self.__name = None
self.__source_dir = None
self.__bin_dir = None
self.__parent = None
self.__install = None
if 'name' in kwargs:
self.__name = kwargs['name']
if 'source_dir' in kwargs:
self.__source_dir = kwargs['source_dir']
if 'bin_dir' in kwargs:
self.__bin_dir = kwargs['bin_dir']
if 'parent' in kwargs:
self.__parent = kwargs['parent']
if 'install' in kwargs:
self.__install = kwargs['install']
def name(self):
return self.__name
def source_dir(self):
return self.__source_dir
def binary_dir(self):
return self.__bin_dir
def parent(self):
return self.__parent
def install_manifest(self):
return self.__install
def build_for(self):
return 'target'
def get_path_namespaces(self):
ns = {
'src': os.path.abspath(self.source_dir()),
'root-src': Environment.source_root(),
'bin': os.path.abspath(self.binary_dir()),
}
if self.build_for() == 'host':
ns['install'] = Environment.native_root()
else:
ns['install'] = Environment.system_root()
return ns
def check_out_of_date(self):
self.__config_out_of_date = self._is_configuration_out_of_date()
self.__build_out_of_date = self._is_build_out_of_date()
def is_configuration_out_of_date(self):
return self.__config_out_of_date
def is_build_out_of_date(self):
return self.__build_out_of_date
def configure(self):
return
def build(self):
return
def __copy_dir(self, src, dst):
dst_dir = os.path.dirname(dst)
SysPath(dst_dir).mkdir(parents=True, exist_ok=True)
shutil.copytree(src, dst, dirs_exist_ok=True)
def __copy_file(self, src, dst):
dst_dir = os.path.dirname(dst)
SysPath(dst_dir).mkdir(parents=True, exist_ok=True)
shutil.copyfile(src, dst)
def install_from_seed(self):
manifest = self.install_manifest()
if manifest is None:
return
ns = self.get_path_namespaces()
source_dir = self.source_dir()
dest_dir = Environment.system_root()
if self.build_for() == 'host':
dest_dir = Environment.native_root()
for dest, src in manifest.items():
if dest[0] != '/':
continue
dest = Path(dest).remove_root().get_path()
for p in src:
path = Path(p)
files = path.expand_path(relative_to=ns)
for p2 in files:
file_name = os.path.basename(p2)
rel_path = os.path.relpath(p2, start=source_dir)
src_path = p2
dst_path = os.path.join(dest_dir, dest, file_name)
if os.path.isdir(src_path):
self.__copy_dir(src_path, dst_path)
else:
self.__copy_file(src_path, dst_path)
def install(self):
return
+237
View File
@@ -0,0 +1,237 @@
import os
import shutil
from command import Command
from config import Config
from cache import Cache
from seed import Seed
from target import Target
from env import Environment
from platform import Platform
from colorama import Fore, Style
class SetCommand(Command):
def __init__(self):
super().__init__(
name='set',
description='Set a configuration key value.')
def run(self, args):
key = args.get_positional(0)
value = args.get_positional(1)
if key is None or value is None:
print('usage: meadow set <key> <value>')
return -1
try:
value_i = int(value)
Config.set(key, value_i)
except:
Config.set(key, value)
return 0
class SeedsCommand(Command):
def __init__(self):
super().__init__(
name='seeds',
description='List all available seeds.')
def write_dot(self, path):
f = open(path, mode='w')
f.write('digraph seeds {\n')
f.write(' node [shape=Mrecord];\n')
nodes = {}
seeds = Seed.all_seeds()
targets = Target.all_targets()
for s in seeds.values():
if s.name() in nodes:
continue
sname = s.name().replace('-', '_')
nodes[s.name()] = s
f.write(' {} [label="{}"];\n'.format(sname, s.name()))
for d in s.dependencies().values():
continue
for t in targets.values():
if t.name() in nodes:
continue
t.resolve()
tname = t.name().replace('-', '_')
nodes[t.name()] = t
f.write(' {} [label="{}",shape=hexagon];\n'.format(tname, t.name()))
for s in seeds.values():
for k, d in s.dependencies().items():
if d.name() not in nodes:
nodes[d.name()] = d
dname = d.name().replace('-', '_')
f.write(' {} [label="{}",shape=diamond];\n'.format(dname, d.name()))
sname = s.name().replace('-', '_')
dname = d.name().replace('-', '_')
if d.is_resolved():
f.write(' {} -> {};\n'.format(dname, sname))
else:
f.write(' {} -> {}[style=dotted];\n'.format(dname, sname))
for t in targets.values():
for k, d in t.dependencies().items():
tname = t.name().replace('-', '_')
dname = d.name().replace('-', '_')
if d.is_resolved():
f.write(' {} -> {};\n'.format(dname, tname))
else:
f.write(' {} -> {}[style=dotted];\n'.format(dname, tname))
f.write('}\n')
f.close()
def run(self, args):
seeds = Seed.all_seeds()
dot_path = args.get_named('to-dot-file', 0, 1)
if dot_path is not None:
self.write_dot(dot_path)
return 0
for s in seeds.values():
print('{}'.format(s.name()))
class PlatformsCommand(Command):
def __init__(self):
super().__init__(
name='platforms',
description='List all available platforms')
def run(self, args):
print('Supported platforms:')
platforms = Platform.all_platforms()
current_platform = Platform.current_platform()
for p in platforms.values():
if current_platform is not None and p.name() == current_platform.name():
print(f'* {Fore.GREEN}{p.name()}{Style.RESET_ALL}')
else:
print(f' {p.name()}')
class HelpCommand(Command):
def __init__(self):
super().__init__(
name='help',
description='List all available commands.')
def run(self, args):
print('Available commands:')
commands = Command.all_commands()
max_len = 0
for c in commands.values():
if len(c.name()) > max_len:
max_len = len(c.name())
max_len += 5
for c in commands.values():
print(' ', end='')
print(c.name(), end='')
for i in range(len(c.name()), max_len):
print(' ', end='')
print(c.description())
class BuildCommand(Command):
def __init__(self):
super().__init__(
name='build',
description='Build the currently selected target.')
def run(self, args):
verbose = args.get_named('verbose', 0, 0)
current_target = Target.current_target()
if current_target is None:
print(f'{Fore.RED}Err:{Style.RESET_ALL} no build target has been set. Use `meadow set target.name <...>` to specify which target to build')
return -1
current_platform = Platform.current_platform()
if current_platform is None:
print(f'{Fore.RED}Err:{Style.RESET_ALL} no target platform has been set. Use `meadow set target.platform <...>` to specify which platform to target')
return -1
components = current_target.resolve()
for c in components:
build_system = None
if isinstance(c, Seed):
build_system = c.build_system()
build_system.check_out_of_date()
for c in components:
build_system = None
if isinstance(c, Seed):
build_system = c.build_system()
if build_system is not None:
out_of_date = \
build_system.is_configuration_out_of_date() \
or build_system.is_build_out_of_date()
if out_of_date:
print(f'{Fore.GREEN}>>>{Style.RESET_ALL} Building {c.name()}')
if build_system.is_configuration_out_of_date():
print(f'{Fore.CYAN} >>{Style.RESET_ALL} Configuring build...')
build_system.configure(verbose=verbose)
if out_of_date:
print(f'{Fore.CYAN} >>{Style.RESET_ALL} Building...')
build_system.build(verbose=verbose)
print(f'{Fore.CYAN} >>{Style.RESET_ALL} Installing...')
build_system.install(verbose=verbose)
print(f'{Style.BRIGHT}{Fore.GREEN}>>> Build Complete!{Style.RESET_ALL}')
class CleanCommand(Command):
def __init__(self):
super().__init__(
name='clean',
description='Delete all build-related files.')
def run(self, args):
build_dir = Environment.build_root()
for i in os.listdir(build_dir):
if i.startswith('meadow') and ('cache' not in i):
continue
ipath = os.path.join(build_dir, i)
if os.path.isdir(ipath):
shutil.rmtree(ipath)
else:
os.remove(ipath)
Cache.reset()
return 0
+69
View File
@@ -0,0 +1,69 @@
import json
import os
cache_path = 'build/meadow-cache.json'
cache_data = None
class Cache:
def load():
global cache_data
if not os.path.exists(cache_path):
cache_data = {}
return
with open(cache_path, mode='r') as f:
cache_data = json.load(f)
def reset():
global cache_data
cache_data = {}
def save():
global cache_data
with open(cache_path, mode='w') as f:
json.dump(cache_data, f, indent=4)
def get(path):
parts = path.split('.')
container = cache_data
for p in parts[:-1]:
if p not in container:
return None
if not isinstance(container[p], dict):
print('Err: element "{}" in cache key "{}" is not a dictionary'.format(p, path))
return
container = container[p]
if parts[-1] in container:
return container[parts[-1]]
return None
def set(path, value):
parts = path.split('.')
container = cache_data
for p in parts[:-1]:
if p not in container:
container[p] = {}
if not isinstance(container[p], dict):
print('Err: element "{}" in cache key "{}" is not a dictionary'.format(p, path))
return
container = container[p]
container[parts[-1]] = value
+316
View File
@@ -0,0 +1,316 @@
import os
import json
import subprocess
from build import *
from pathlib import Path as SysPath
from cache import Cache
from env import Environment
from platform import Platform
from target import Target
from path import Path
class CMakeBuildSystem(BuildSystem):
def __init__(self, **kwargs):
name = kwargs.get('name', None)
source_dir = kwargs.get('source_dir', None)
bin_dir = kwargs.get('bin_dir', None)
parent = kwargs.get('parent', None)
self.__data = kwargs.get('data', None)
super().__init__(**kwargs)
def build_for(self):
if self.__data is None or 'build_for' not in self.__data:
return 'target'
return self.__data['build_for']
def __get_watched_files(self):
result = []
ns = self.get_path_namespaces()
if 'watch_files' in self.__data:
watch_list = self.__data['watch_files']
for p in watch_list:
path = Path(p)
real_paths = path.expand_path(relative_to=ns)
for p2 in real_paths:
result.append(p2)
manifest_path = os.path.join(self.binary_dir(), 'compile_commands.json')
manifest_file = None
manifest = None
try:
manifest_file = open(manifest_path, mode='r')
except:
return result
try:
manifest = json.load(manifest_file)
except:
return result
for v in manifest:
if 'file' not in v:
continue
path = v['file']
result.append(path)
return result
def __get_build_mtime(self):
files = self.__get_watched_files()
result = 0
for path in files:
mtime = os.path.getmtime(path)
if mtime > result:
result = mtime
return result
def __get_configure_mtime(self):
source_dir = os.path.abspath(self.source_dir())
result = 0
for root, dirs, files in os.walk(source_dir):
for f in files:
if f != 'CMakeLists.txt' and not f.endswith('.cmake'):
continue
target_path = os.path.join(root, f)
mtime = os.path.getmtime(target_path)
if mtime > result:
result = mtime
return result
def _is_configuration_out_of_date(self):
cache_file = os.path.join(self.binary_dir(), 'CMakeCache.txt')
if not os.path.isfile(cache_file):
return True
current_mtime = self.__get_configure_mtime()
target_mtime = Cache.get(f'component.{self.name()}.configure-mtime')
if target_mtime is None:
target_mtime = 0
if current_mtime > target_mtime:
return True
for d in self.parent().collect_dependencies():
build_system = d.build_system()
if build_system is None:
continue
if build_system.is_build_out_of_date() or build_system.is_configuration_out_of_date():
return True
return False
def _is_build_out_of_date(self):
current_mtime = self.__get_build_mtime()
target_mtime = Cache.get(f'component.{self.name()}.build-mtime')
if target_mtime is None:
target_mtime = 0
if current_mtime > target_mtime:
return True
for d in self.parent().collect_dependencies():
build_system = d.build_system()
if build_system is None:
continue
if build_system.is_build_out_of_date() or build_system.is_configuration_out_of_date():
return True
return False
def __get_published_items(self):
published = {}
for d in self.parent().collect_dependencies():
build_sys = d.build_system()
ns = {}
if build_sys is not None:
ns = build_sys.get_path_namespaces()
p = d.publish()
if p is None:
continue
path = p.path()
if path is not None:
if 'path' not in published:
published['path'] = []
path = Path.expand_all(path, relative_to=ns)
published['path'].extend(path)
cmake = p.cmake()
if cmake is not None:
if 'cmake' not in published:
published['cmake'] = {}
if 'module_paths' in cmake:
if 'module_paths' not in published['cmake']:
published['cmake']['module_paths'] = []
module_paths = cmake['module_paths']
module_paths = Path.expand_all(module_paths, relative_to=ns)
published['cmake']['module_paths'].extend(module_paths)
return published
def configure(self, **kwargs):
verbose = kwargs.get('verbose', False)
ns = self.get_path_namespaces()
stdout = None
if not verbose:
stdout = subprocess.DEVNULL
target = Target.current_target()
platform = Platform.current_platform()
cmake_platform = platform.get_component('cmake')
cmake_args = [
'cmake',
'-DCMAKE_EXPORT_COMPILE_COMMANDS=ON',
'--no-warn-unused-cli'
]
if 'configure_args' in self.__data:
cmake_args.extend(self.__data['configure_args'])
published = self.__get_published_items()
env = os.environ.copy()
if 'path' in published:
path = ''
if 'PATH' in env:
path = env['PATH']
if len(path):
path += ':'
path += ':'.join(published['path'])
env['PATH'] = path
module_paths = []
if 'cmake' in published:
cmake_publish = published['cmake']
for p in cmake_publish.get('module_paths', []):
path = Path(p)
for p2 in path.expand_path(relative_to=ns):
module_paths.append(p2)
install_details = self.parent().install()
install_prefix = ''
if self.build_for() == 'host':
install_prefix = Environment.native_root()
cmake_platform = None
seed_install_prefix = '/'
if install_details is not None:
seed_install_prefix = install_details.get('prefix', seed_install_prefix)
seed_install_prefix = Path(seed_install_prefix).remove_root().get_path()
install_prefix = os.path.join(install_prefix, seed_install_prefix)
else:
install_prefix = Environment.system_root()
env['ROSETTA_SYSROOT'] = Environment.system_root()
seed_install_prefix = target.install_prefix()
if install_details is not None:
seed_install_prefix = install_details.get('prefix', seed_install_prefix)
seed_install_prefix = Path(seed_install_prefix).remove_root().get_path()
install_prefix = os.path.join(install_prefix, seed_install_prefix)
cmake_args.append(f'-DCMAKE_INSTALL_PREFIX={install_prefix}')
if cmake_platform is not None:
if 'module_paths' in cmake_platform:
for p in cmake_platform['module_paths']:
module_paths.append(os.path.join(platform.base_directory(), p))
if 'toolchain_file' in cmake_platform:
toolchain_file = os.path.join(platform.base_directory(), cmake_platform['toolchain_file'])
cmake_args.append(f'-DCMAKE_TOOLCHAIN_FILE={toolchain_file}')
if 'system_name' in cmake_platform:
cmake_args.append(f'-DCMAKE_SYSTEM_NAME={cmake_platform['system_name']}')
if 'module_paths' in self.__data:
for p in self.__data['module_paths']:
path = Path(p)
for p2 in path.expand_path(relative_to=ns):
module_paths.append(p2)
if len(module_paths) > 0:
cmake_args.append(f'-DCMAKE_MODULE_PATH={';'.join(module_paths)}')
source_dir = os.path.abspath(self.source_dir())
bin_dir = os.path.abspath(self.binary_dir())
cmake_args.append(source_dir)
SysPath(bin_dir).mkdir(parents=True, exist_ok=True)
result = subprocess.run(cmake_args, cwd=bin_dir, env=env, stdout=stdout)
if result.returncode == 0:
Cache.set(f'component.{self.name()}.configure-mtime', self.__get_configure_mtime())
else:
raise BuildConfigurationError(f'CMake configuration for {self.name()} failed. See log for details')
def __find_build_command(self):
bin_dir = os.path.abspath(self.binary_dir())
if os.path.isfile(os.path.join(bin_dir, 'build.ninja')):
return 'ninja'
return None
def build(self, **kwargs):
verbose = kwargs.get('verbose', False)
stdout = None
if not verbose:
stdout = subprocess.DEVNULL
bin_dir = os.path.abspath(self.binary_dir())
build_cmd = self.__find_build_command()
if build_cmd is None:
raise BuildError(f'Cannot determine which command to use to build {self.name()}')
env = os.environ.copy()
if self.build_for() != 'host':
env['ROSETTA_SYSROOT'] = Environment.system_root()
args = [ build_cmd ]
result = subprocess.run(args, cwd=bin_dir, stdout=stdout, env=env)
if result.returncode != 0:
raise BuildConfigurationError(f'{build_cmd} build for {self.name()} failed. See log for details')
def install(self, **kwargs):
self.install_from_seed()
verbose = kwargs.get('verbose', False)
stdout = None
if not verbose:
stdout = subprocess.DEVNULL
bin_dir = os.path.abspath(self.binary_dir())
build_cmd = self.__find_build_command()
if build_cmd is None:
raise BuildError(f'Cannot determine which command to use to build {self.name()}')
args = [ build_cmd, 'install' ]
result = subprocess.run(args, cwd=bin_dir, stdout=stdout)
if result.returncode == 0:
Cache.set(f'component.{self.name()}.build-mtime', self.__get_build_mtime())
+205
View File
@@ -0,0 +1,205 @@
import os
import sys
import tomli
import tempfile
import subprocess
from dependency import *
from colorama import Fore, Style
from env import Environment
from path import Path
from config import Config
commands = {}
class CommandConfigurationError(Exception):
pass
class CommandExecutionError(Exception):
pass
class Command(DependencyItem):
def all_commands():
return commands
def __init__(self, **kwargs):
super().__init__()
if 'name' in kwargs:
self.__name = kwargs['name']
if 'description' in kwargs:
self.__description = kwargs['description']
def name(self):
return self.__name
def description(self):
return self.__description
def dependencies(self):
return None
def register(cmd):
commands[cmd.name()] = cmd
def get(name):
if name in commands:
return commands[name]
return None
def run(self, args):
return
class UserCommand(Command):
def load_file(self, path):
with open(path, mode='rb') as f:
self.__data = tomli.load(f)
def __init_dependencies(self):
if 'dependency' not in self.__data:
return
dependency = self.__data['dependency']
self.__dependencies = {}
if 'seeds' in dependency:
seeds = dependency['seeds']
for s in seeds:
self.__dependencies[s] = SeedDependency(parent=self.name(), name=s)
if 'commands' in dependency:
commands = dependency['commands']
for c in commands:
self.__dependencies[c] = ProgramDependency(parent=self.name(), name=c)
def __init__(self, **kwargs):
if 'path' not in kwargs:
return
self.__tmpdir = tempfile.TemporaryDirectory()
self.__path = kwargs['path']
self.load_file(self.__path)
cmd = self.__data['command']
super().__init__(name=cmd['name'], description=cmd['description'])
self.__init_dependencies()
def dependencies(self):
return self.__dependencies
def scan_directory(paths):
for p in paths:
for root, dirs, files in os.walk(p):
for f in files:
if not f.endswith('.command'):
continue
cmd_path = os.path.join(root, f)
cmd = None
try:
cmd = UserCommand(path=cmd_path)
except tomli.TOMLDecodeError as e:
print('Err: Failed to parse command file {}\n {}'.format(seed_path, e))
return -1
Command.register(cmd)
def get_path_namespaces(self):
ns = {
'src': os.path.dirname(self.__path),
'root-src': Environment.source_root(),
'install': Environment.system_root(),
}
return ns
def get_environment(self):
return {
'MEADOW_SYSROOT': Environment.system_root(),
'MEADOW_NATIVE_ROOT': Environment.native_root(),
'MEADOW_SOURCE_ROOT': Environment.source_root(),
'MEADOW_TEMP': self.__tmpdir.name,
'MEADOW_TARGET_PLATFORM': Config.get('target.platform'),
}
def run(self, args):
from seed import Seed
deps = self.resolve()
for c in deps:
build_system = None
if isinstance(c, Seed):
build_system = c.build_system()
build_system.check_out_of_date()
for c in deps:
build_system = None
if isinstance(c, Seed):
build_system = c.build_system()
if build_system is not None:
out_of_date = \
build_system.is_configuration_out_of_date() \
or build_system.is_build_out_of_date()
if out_of_date:
print(f'{Fore.GREEN}>>>{Style.RESET_ALL} Building {c.name()}')
if build_system.is_configuration_out_of_date():
print(f'{Fore.CYAN} >>{Style.RESET_ALL} Configuring build...')
build_system.configure(verbose=False)
if out_of_date:
print(f'{Fore.CYAN} >>{Style.RESET_ALL} Building...')
build_system.build(verbose=False)
print(f'{Fore.CYAN} >>{Style.RESET_ALL} Installing...')
build_system.install(verbose=False)
exec_info = self.__data.get('exec', None)
if exec_info is None:
raise CommandConfigurationError(f'Command {self.name()} has no executable configured')
args = exec_info.get('args', None)
if args is None or len(args) == 0:
raise CommandConfigurationError(f'Command {self.name()} has no executable configured')
ns = self.get_path_namespaces()
expanded_args = []
for p in args:
parts = p.split(':')
if len(parts) < 2 or parts[0] not in ns:
expanded_args.append(p)
continue
paths = Path(p).expand_path(relative_to=ns)
expanded_args.extend(paths)
if expanded_args[0].endswith('.py'):
expanded_args.insert(0, sys.executable)
env = os.environ | self.get_environment()
result = None
try:
result = subprocess.run(expanded_args, env=env)
except KeyboardInterrupt:
pass
if result is not None and result.returncode != 0:
raise CommandExecutionError(f'Execution of {self.name()} failed. See log for details')
+64
View File
@@ -0,0 +1,64 @@
import json
import os
config_path = 'build/meadow-config.json'
config_data = None
class Config:
def load():
global config_data
if not os.path.exists(config_path):
config_data = {}
return
with open(config_path, mode='r') as f:
config_data = json.load(f)
def save():
global config_data
with open(config_path, mode='w') as f:
json.dump(config_data, f, indent=4)
def get(path):
parts = path.split('.')
container = config_data
for p in parts[:-1]:
if p not in container:
return None
if not isinstance(container[p], dict):
print('Err: element "{}" in config key "{}" is not a dictionary'.format(p, path))
return
container = container[p]
if parts[-1] in container:
return container[parts[-1]]
return None
def set(path, value):
parts = path.split('.')
container = config_data
for p in parts[:-1]:
if p not in container:
container[p] = {}
if not isinstance(container[p], dict):
print('Err: element "{}" in config key "{}" is not a dictionary'.format(p, path))
return
container = container[p]
container[parts[-1]] = value
+156
View File
@@ -0,0 +1,156 @@
import os
class DependencyResolutionError(Exception):
pass
class DependencyItem:
def __init__(self):
self.__target = None
self.__dep_list = None
def name(self):
return None
def target(self):
return self.__target
def dependencies(self):
return None
def dependency_list(self):
return self.__dep_list
def publish(self):
return None
def reset_resolution(self):
self.__dep_list = None
def resolve(self, **kwargs):
if self.__dep_list is not None:
return self.__dep_list
ctx = None
dep_list = None
if 'ctx' in kwargs:
ctx = kwargs['ctx']
else:
ctx = {}
if 'dep_list' in kwargs:
dep_list = kwargs['dep_list']
else:
dep_list = []
if self.name() in ctx:
return
ctx[self.name()] = self
deps = self.dependencies()
if deps is None:
return
for d in deps.values():
d_value = d.resolve_self()
if d_value is not None:
d_value.resolve(ctx=ctx, dep_list=dep_list)
dep_list.append(self)
return dep_list
class Dependency:
def __init__(self, parent):
self.__parent = parent
def name(self, parent):
return None
def parent_name(self):
return self.__parent
def resolve_self(self):
return None
def is_resolved(self):
return False
class SeedDependency(Dependency):
def __init__(self, **kwargs):
self.__target_seed = None
if 'name' in kwargs:
self.__name = kwargs['name']
if 'parent' in kwargs:
super().__init__(kwargs['parent'])
def name(self):
return self.__name
def target(self):
return self.__target_seed
def resolve_self(self):
from seed import Seed
if self.__target_seed is not None:
return self.__target_seed
target = Seed.get(self.__name)
if target is None:
raise DependencyResolutionError(
'{} depends on seed "{}", but the required seed cannot be found'.format(self.parent_name(), self.__name))
self.__target_seed = target
return self.__target_seed
def is_resolved(self):
return self.__target_seed is not None
class ProgramDependency(Dependency):
def __init__(self, **kwargs):
if 'name' in kwargs:
self.__name = kwargs['name']
if 'parent' in kwargs:
super().__init__(kwargs['parent'])
def __is_exe(self, fpath):
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
def name(self):
return self.__name
def resolve_self(self):
if self.__is_exe(self.__name):
return None
path_string = os.environ['PATH']
path_list = path_string.split(':')
for d in path_list:
exe_path = os.path.join(d, self.__name)
if self.__is_exe(exe_path):
return None
raise DependencyResolutionError(f'{self.parent_name()} depends on command `{self.__name}`, but the command cannot be found. Make sure that the named command exists, the containing directory is in $PATH if necessary, and the executable file has the correct permissions.')
+28
View File
@@ -0,0 +1,28 @@
import os
source_root = None
class Environment:
def set_source_root(path):
global source_root
source_root = path
def source_root():
global source_root
return source_root
def build_root():
global source_root
return os.path.join(source_root, 'build')
def system_root():
return os.path.join(Environment.build_root(), 'target-root')
def native_root():
return os.path.join(Environment.build_root(), 'host-root')
+140
View File
@@ -0,0 +1,140 @@
import os
import json
import shutil
import subprocess
from build import *
from pathlib import Path as SysPath
from cache import Cache
from env import Environment
from platform import Platform
from target import Target
from path import Path
class GenericBuildSystem(BuildSystem):
def __init__(self, **kwargs):
self.__data = kwargs.get('data', None)
super().__init__(**kwargs)
def __get_watched_files(self):
result = []
ns = self.get_path_namespaces()
if 'watch_files' in self.__data:
watch_list = self.__data['watch_files']
for p in watch_list:
path = Path(p)
real_paths = path.expand_path(relative_to=ns)
for p2 in real_paths:
result.append(p2)
manifest_path = os.path.join(self.binary_dir(), 'compile_commands.json')
manifest_file = None
manifest = None
try:
manifest_file = open(manifest_path, mode='r')
except:
return result
try:
manifest = json.load(manifest_file)
except:
return result
for v in manifest:
if 'file' not in v:
continue
path = v['file']
result.append(path)
return result
def __get_mtime(self):
files = self.__get_watched_files()
result = 0
for path in files:
mtime = os.path.getmtime(path)
if mtime > result:
result = mtime
return result
def _is_configuration_out_of_date(self):
return False
def _is_build_out_of_date(self):
current_mtime = self.__get_mtime()
target_mtime = Cache.get(f'component.{self.name()}.build-mtime')
if target_mtime is None:
return True
if current_mtime > target_mtime:
return True
for d in self.parent().collect_dependencies():
build_system = d.build_system()
if build_system is None:
continue
if build_system.is_build_out_of_date() or build_system.is_configuration_out_of_date():
return True
return False
def __run_command(self, name, **kwargs):
verbose = kwargs.get('verbose', False)
ns = self.get_path_namespaces()
stdout = None
if not verbose:
stdout = subprocess.DEVNULL
cmd = self.__data.get(name, None)
if cmd is None:
return
args = cmd.get('args', None)
if args is None:
raise BuildConfigurationError(f'{self.name()} is incorrectly configured. build_command has no args defined')
expanded_args = []
for p in args:
parts = p.split(':')
if len(parts) < 2 or parts[0] not in ns:
expanded_args.append(p)
continue
paths = Path(p).expand_path(relative_to=ns)
expanded_args.extend(paths)
result = subprocess.run(expanded_args, stdout=stdout)
if result.returncode != 0:
raise BuildConfigurationError(f'Execution of {name} for {self.name()} failed. See log for details')
def configure(self, **kwargs):
self.__run_command('configure_command', **kwargs)
def build(self, **kwargs):
self.__run_command('build_command', **kwargs)
def install(self, **kwargs):
self.install_from_seed()
previous_mtime = Cache.get(f'component.{self.name()}.build-mtime')
if previous_mtime is None:
previous_mtime = 0
new_mtime = self.__get_mtime()
if new_mtime > previous_mtime:
Cache.set(f'component.{self.name()}.build-mtime', new_mtime)
+95
View File
@@ -0,0 +1,95 @@
import sys
import os
import tomli
from seed import Seed
from target import Target
from platform import Platform
from config import Config
from cache import Cache
from command import Command, UserCommand
from args import Args
from env import Environment
from dependency import SeedDependency, DependencyResolutionError
from builtin import *
from colorama import init as colorama_init
from colorama import Fore, Style
def main():
colorama_init()
Command.register(SetCommand())
Command.register(SeedsCommand())
Command.register(PlatformsCommand())
Command.register(HelpCommand())
Command.register(BuildCommand())
Command.register(CleanCommand())
Config.load()
Cache.load()
Environment.set_source_root(os.getcwd())
Seed.scan_directory([
'base',
'external',
'interface',
'toolchain',
'lib',
'programs',
'services',
'sys'
])
UserCommand.scan_directory([
'toolchain'
])
Target.scan_directory('./target')
platforms = Platform.scan_directory('./arch')
current_platform = Platform.current_platform()
if current_platform:
current_platform.load_extensions()
if len(sys.argv) < 2:
print(f'{Fore.CYAN}Usage:{Style.RESET_ALL} {sys.argv[0]} <command> [args...]')
return -1
command_name = sys.argv[1]
command = Command.get(command_name)
if command is None:
print(f'{Fore.RED}Err:{Style.RESET_ALL} unknown command "{command_name}"')
return -1
current_target = Target.current_target()
seeds = Seed.all_seeds()
if current_target is not None:
system_dep_names = current_target.base_components()
for s in seeds.values():
if s.name() in system_dep_names or not s.should_include_standard_dependencies():
continue
for n in system_dep_names:
s.add_dependency(n, SeedDependency(parent=s.name(), name=n))
try:
current_target.resolve()
except DependencyResolutionError as e:
print(f'{Fore.RED}Err:{Style.RESET_ALL} {e}')
return -1
args = Args(sys.argv[2:])
result = None
try:
result = command.run(args)
except Exception as e:
print(f'{Fore.RED}Err:{Style.RESET_ALL} {e}')
finally:
Cache.save()
Config.save()
return result
if __name__ == '__main__':
exit(main())
+88
View File
@@ -0,0 +1,88 @@
import glob
import os
class Path:
def __init__(self, value):
self.__path = value
self.__namespace = None
parts = value.split(':')
if len(parts) != 2:
return
if len(parts[0]) < 3:
return
self.__namespace = parts[0]
self.__path = parts[1]
def get_path(self):
return self.__path
def remove_root(self):
while len(self.__path) > 0 and self.__path[0] == '/':
self.__path = self.__path [1:]
if len(self.__path) == 0:
self.__path= '.'
return self
def expand_path(self, **kwargs):
relative_to = None
if 'relative_to' in kwargs:
relative_to = kwargs['relative_to']
if isinstance(relative_to, dict):
if self.__namespace is not None:
relative_to = relative_to[self.__namespace]
else:
relative_to = None
paths = glob.glob(self.__path, root_dir=relative_to, recursive=True)
if len(paths) == 0 and '*' not in self.__path:
if relative_to is not None:
return [os.path.join(relative_to, self.__path)]
return [self.__path]
if relative_to is not None:
abs_paths = []
for p in paths:
abs_paths.append(os.path.join(relative_to, p))
return abs_paths
return paths
def expand_all(paths, **kwargs):
relative_to = None
if 'relative_to' in kwargs:
relative_to = kwargs['relative_to']
result = []
for p in paths:
if not isinstance(p, Path):
p = Path(p)
r = p.expand_path(relative_to=relative_to)
result.extend(r)
return result
def get_namespace(self, **kwargs):
if self.__namespace is not None:
return self.__namespace
if 'default' in kwargs:
return kwargs['default']
return None
+119
View File
@@ -0,0 +1,119 @@
import os
import sys
import tomli
from config import Config
from command import Command, UserCommand
all_platforms = {}
class Platform:
def all_platforms():
return all_platforms
def current_platform():
name = Config.get('target.platform')
if not name or name not in all_platforms:
return None
return all_platforms[name]
def load_file(self, path):
self.__path = path
with open(path, mode='rb') as f:
self.__data = tomli.load(f)
def __init__(self, **kwargs):
if 'path' in kwargs:
self.__platform_file = os.path.abspath(kwargs['path'])
self.load_file(kwargs['path'])
def base_directory(self):
return os.path.dirname(self.__platform_file)
def name(self):
if 'platform' not in self.__data:
return None
platform = self.__data['platform']
if 'name' in platform:
return platform['name']
return None
def arch(self):
if 'platform' not in self.__data:
return None
platform = self.__data['platform']
if 'arch' in platform:
return platform['arch']
return None
def load_extensions(self):
from seed import Seed
if 'extension' not in self.__data:
return
all_seeds = Seed.all_seeds()
extension_dir = os.path.dirname(self.__path)
extension = self.__data['extension']
if 'seeds' in extension:
seeds = extension['seeds']
for seed_filename in seeds:
seed_path = os.path.join(extension_dir, seed_filename)
seed = None
try:
seed = Seed(path=seed_path)
except tomli.TOMLDecodeError as e:
print('Err: Failed to parse seed file {}\n {}'.format(seed_path, e))
return -1
all_seeds[seed.name()] = seed
if 'commands' in extension:
commands = extension['commands']
for cmd_filename in commands:
cmd_path = os.path.join(extension_dir, cmd_filename)
cmd = None
try:
cmd = UserCommand(path=cmd_path)
except tomli.TOMLDecodeError as e:
print('Err: Failed to parse command file {}\n {}'.format(seed_path, e))
return -1
Command.register(cmd)
def get_component(self, name):
if name in self.__data:
return self.__data[name]
return None
def scan_directory(root_path):
for root, dirs, files in os.walk(root_path):
for f in files:
if not f.endswith('.platform'):
continue
platform_path = os.path.join(root, f)
platform = None
try:
platform = Platform(path=platform_path)
except tomli.TOMLDecodeError as e:
print('Err: Failed to parse platform file {}\n {}'.format(platform_path, e))
continue
all_platforms[platform.name()] = platform
+21
View File
@@ -0,0 +1,21 @@
import os
class Publish:
def __init__(self, **kwargs):
self.__data = None
self.__install_root = None
if 'data' in kwargs:
self.__data = kwargs['data']
if 'install_path' in kwargs:
self.__install_root = kwargs['install_path']
def path(self):
return self.__data.get('path', None)
def cmake(self):
return self.__data.get('cmake', None)
+2
View File
@@ -0,0 +1,2 @@
tomli
colorama
+219
View File
@@ -0,0 +1,219 @@
import os
import sys
import tomli
from dependency import *
from cmake import CMakeBuildSystem
from publish import Publish
from build import UnknownBuildSystemError
from env import Environment
from source_only import SourceOnlyBuildSystem
from generic import GenericBuildSystem
all_seeds = {}
class SeedParseError(Exception):
pass
class Seed(DependencyItem):
def all_seeds():
return all_seeds
def get(name):
if name in all_seeds:
return all_seeds[name]
return None
def load_file(self, path):
with open(path, mode='rb') as f:
self.__data = tomli.load(f)
def __init_dependencies(self):
self.__dependencies = {}
if 'dependency' not in self.__data:
return
dependency = self.__data['dependency']
if 'seeds' in dependency:
seeds = dependency['seeds']
self.__dependencies = {}
for s in seeds:
self.__dependencies[s] = SeedDependency(parent=self.name(), name=s)
def __init_build_system(self):
self.__build_system = None
if 'build' not in self.__data:
return
build = self.__data['build']
if 'build_system' not in build:
return
source_dir = os.path.dirname(self.__seed_path)
bin_dir = os.path.join(Environment.build_root(), self.name())
install = self.__data.get('install', None)
if 'source_dir' in build:
source_dir = build['source_dir']
match build['build_system']:
case 'none':
self.__build_system = None
case 'cmake':
self.__build_system = CMakeBuildSystem(
parent=self,
name=self.name(),
source_dir=source_dir,
bin_dir=bin_dir,
install=install,
data=build)
case 'source-only':
self.__build_system = SourceOnlyBuildSystem(
parent=self,
name=self.name(),
source_dir=source_dir,
bin_dir=bin_dir,
install=install,
data=build)
case 'generic':
self.__build_system = GenericBuildSystem(
parent=self,
name=self.name(),
source_dir=source_dir,
bin_dir=bin_dir,
install=install,
data=build)
case _:
raise UnknownBuildSystemError(
'Seed {} has unrecognised build system "{}"'.format(self.name(), build['build_system']))
def __init_publish(self):
install_path = Environment.system_root()
if 'build' in self.__data and 'build_for' in self.__data['build']:
build_for = self.__data['build']['build_for']
if build_for == 'host':
install_path = Environment.native_root()
self.__publish = None
if 'publish' not in self.__data:
return
self.__publish = Publish(install_path=install_path, data=self.__data['publish'])
def add_dependency(self, name, dep):
self.__dependencies[name] = dep
def collect_dependencies(self, **kwargs):
ctx = None
if 'ctx' in kwargs:
ctx = kwargs['ctx']
else:
ctx = {}
for k, d in self.__dependencies.items():
if k in ctx:
continue
ctx[d.name()] = d.target()
if isinstance(d.target(), Seed):
d.target().collect_dependencies(ctx=ctx)
return list(ctx.values())
def __init__(self, **kwargs):
super().__init__()
if not 'path' in kwargs:
return
self.__seed_path = kwargs['path']
self.load_file(kwargs['path'])
self.__init_dependencies()
self.__init_build_system()
self.__init_publish()
def seed_path(self):
return self.__seed_path
def name(self):
if not 'seed' in self.__data:
return None
s = self.__data['seed']
if 'name' in s:
return s['name']
return None
def type(self):
if not 'seed' in self.__data:
return None
s = self.__data['seed']
if 'type' in s:
return s['type']
return 'component'
def dependencies(self):
return self.__dependencies
def publish(self):
return self.__publish
def install(self):
return self.__data.get('install', None)
def should_include_standard_dependencies(self):
if 'dependency' not in self.__data:
return True
s = self.__data['dependency']
if 'no_standard_dependencies' in s:
return not s['no_standard_dependencies']
return True
def build_system(self):
return self.__build_system
def scan_directory(paths):
for p in paths:
for root, dirs, files in os.walk(p):
for f in files:
if not f.endswith('.seed'):
continue
seed_path = os.path.join(root, f)
seed = None
try:
seed = Seed(path=seed_path)
except tomli.TOMLDecodeError as e:
raise SeedParseError('Err: Failed to parse seed file {}: {}'.format(seed_path, e))
all_seeds[seed.name()] = seed
def resolve_all():
for s in all_seeds.values():
deps = s.dependencies()
for k, v in deps.items():
v.resolve()
+119
View File
@@ -0,0 +1,119 @@
import os
import json
import shutil
import subprocess
from build import *
from pathlib import Path as SysPath
from cache import Cache
from env import Environment
from platform import Platform
from target import Target
from path import Path
class SourceOnlyBuildSystem(BuildSystem):
def __init__(self, **kwargs):
self.__data = kwargs.get('data', None)
super().__init__(**kwargs)
def __get_watched_files(self):
result = []
ns = self.get_path_namespaces()
if 'watch_files' in self.__data:
watch_list = self.__data['watch_files']
for p in watch_list:
path = Path(p)
real_paths = path.expand_path(relative_to=ns)
for p2 in real_paths:
result.append(p2)
manifest_path = os.path.join(self.binary_dir(), 'compile_commands.json')
manifest_file = None
manifest = None
try:
manifest_file = open(manifest_path, mode='r')
except:
return result
try:
manifest = json.load(manifest_file)
except:
return result
for v in manifest:
if 'file' not in v:
continue
path = v['file']
result.append(path)
return result
def __get_mtime(self):
files = self.__get_watched_files()
result = 0
for path in files:
mtime = os.path.getmtime(path)
if mtime > result:
result = mtime
return result
def _is_configuration_out_of_date(self):
parent = self.parent()
seed_path = parent.seed_path()
seed_mtime = os.path.getmtime(seed_path)
target_mtime = Cache.get(f'component.{self.name()}.configure-mtime')
if target_mtime is None:
return True
return seed_mtime > target_mtime
def _is_build_out_of_date(self):
current_mtime = self.__get_mtime()
target_mtime = Cache.get(f'component.{self.name()}.build-mtime')
if target_mtime is None:
return True
if current_mtime > target_mtime:
return True
for d in self.parent().collect_dependencies():
build_system = d.build_system()
if build_system is None:
continue
if build_system.is_build_out_of_date() or build_system.is_configuration_out_of_date():
return True
return False
def configure(self, **kwargs):
parent = self.parent()
seed_path = parent.seed_path()
seed_mtime = os.path.getmtime(seed_path)
Cache.set(f'component.{self.name()}.configure-mtime', seed_mtime)
def build(self, **kwargs):
pass
def install(self, **kwargs):
self.install_from_seed()
previous_mtime = Cache.get(f'component.{self.name()}.build-mtime')
if previous_mtime is None:
previous_mtime = 0
new_mtime = self.__get_mtime()
if new_mtime > previous_mtime:
Cache.set(f'component.{self.name()}.build-mtime', new_mtime)
+105
View File
@@ -0,0 +1,105 @@
import os
import sys
import tomli
from dependency import *
from config import Config
from path import Path
all_targets = {}
class Target(DependencyItem):
def all_targets():
global all_targets
return all_targets
def current_target():
name = Config.get('target.name')
if not name or name not in all_targets:
return None
return all_targets[name]
def load_file(self, path):
with open(path, mode='rb') as f:
self.__data = tomli.load(f)
def __init_dependencies(self):
self.__dependencies = {}
if 'dependency' not in self.__data:
return
dependency = self.__data['dependency']
if 'seeds' in dependency:
seeds = dependency['seeds']
self.__dependencies = {}
for s in seeds:
self.__dependencies[s] = SeedDependency(parent=self.name(), name=s)
def __init__(self, **kwargs):
super().__init__()
if 'path' not in kwargs:
return
self.load_file(kwargs['path'])
self.__init_dependencies()
def name(self):
if not 'target' in self.__data:
return None
s = self.__data['target']
if 'name' in s:
return s['name']
return None
def dependencies(self):
return self.__dependencies
def base_components(self):
if not 'target' in self.__data:
return None
s = self.__data['target']
if 'base_components' in s:
return s['base_components']
return []
def install_prefix(self, **kwargs):
make_relative = kwargs.get('make_relative', False)
path = self.__data.get('target', {}).get('default_prefix', '/')
if make_relative:
path = Path(path).remove_root().get_path
return path
def scan_directory(root_path):
global all_targets
for root, dirs, files in os.walk(root_path):
for f in files:
if not f.endswith('.target'):
continue
target_path = os.path.join(root, f)
target = None
try:
target = Target(path=target_path)
except tomli.TOMLDecodeError as e:
print('Err: Failed to parse target file {}\n {}'.format(target_path, e))
continue
all_targets[target.name()] = target
+41
View File
@@ -0,0 +1,41 @@
class Args:
def __init__(self, argv):
self.__argv = argv
def get_positional(self, index):
if len(self.__argv) > index:
return self.__argv[index]
return None
def get_named(self, name, index, nr_args):
found_name = False
values = []
for s in self.__argv:
if found_name:
if len(values) < nr_args:
values.append(s)
continue
else:
break
if s == '--{}'.format(name):
if index > 0:
index -= 1
continue
found_name = True
continue
if nr_args == 0:
return found_name
if len(values) < nr_args or not found_name:
return None
if len(values) == 1:
return values[0]
return values
+98
View File
@@ -0,0 +1,98 @@
import os
import struct
import tarfile
from pathlib import Path
from elf import ELF64Image
class BSPWriteError(Exception):
pass
class BSP:
def __init__(self, out_path, **kwargs):
if os.path.exists(out_path):
os.remove(out_path)
self.__bootstrap_exec_path = None
self.__path = out_path
self.__sysroot = kwargs.get('sysroot', None)
out_dir = os.path.dirname(out_path)
Path(out_dir).mkdir(parents=True, exist_ok=True)
self.__tarfile = tarfile.open(name=out_path, mode='x')
def add_file(self, src, dst):
if self.__sysroot is not None:
while src[0] == '/':
src = src[1:]
src = os.path.join(self.__sysroot, src)
print(f'tarfile.add({src}, arcname={dst})')
self.__tarfile.add(src, arcname=dst)
def set_bootstrap_program(self, path):
if self.__sysroot is not None:
while path[0] == '/':
path = path[1:]
path = os.path.join(self.__sysroot, path)
self.__bootstrap_exec_path = path
def __write_trailer(self):
bootstrap_offset = os.path.getsize(self.__path)
print(f'bootstrap_offset was {bootstrap_offset}')
bsp = open(self.__path, mode='ab')
prog = open(self.__bootstrap_exec_path, mode='rb')
padding = 0x1000 - (bootstrap_offset % 0x1000)
bsp.write(b'\0' * padding)
bootstrap_offset += padding
prog_len = 0
print(f'bootstrap_offset is now {bootstrap_offset}')
while True:
data = prog.read(1024)
bsp.write(data)
prog_len += len(data)
if len(data) < 1024:
break
prog.close()
prog_elf = ELF64Image()
if prog_elf.load(self.__bootstrap_exec_path) != 0:
raise BSPWriteError(f'{self.__bootstrap_exec_path} is not a valid ELF binary')
for ph in prog_elf.ph_list:
print('{}: {}/{} ({}/{} bytes) {}'.format(
ph.type,
ph.offset, ph.vaddr,
ph.filesz, ph.memsz, ph.flags))
trailer = struct.pack('>IQIQIQQQQQQQ',
0xcafebabe,
0, bootstrap_offset,
bootstrap_offset, prog_len,
prog_elf.text.offset, prog_elf.text.vaddr, prog_elf.text.memsz,
prog_elf.data.offset, prog_elf.data.vaddr, prog_elf.data.memsz,
prog_elf.entry)
bsp.write(trailer)
bsp.close()
prog.close()
def __del__(self):
self.close()
def close(self):
self.__tarfile.close()
if self.__bootstrap_exec_path is None:
return
self.__write_trailer()
+102
View File
@@ -0,0 +1,102 @@
from enum import Enum, Flag
import struct
class ELFPType(Enum):
NULL = 0
LOAD = 1
DYNAMIC = 2
INTERP = 3
NOTE = 4
SHLIB = 5
PHDR = 6
TLS = 7
class ELFPFlag(Flag):
NONE = 0
EXEC = 1
WRITE = 2
READ = 4
class ELFEndian(Enum):
LITTLE = 1
BIG = 2
class ELF64Phdr:
def __init__(self):
self.type = ELFPType.NULL
self.flags = 0
self.offset = 0
self.vaddr = 0
self.paddr = 0
self.filesz = 0
self.memsz = 0
self.align = 0
return
def parse(self, buf, endian):
endian_marker = '>' if endian == ELFEndian.BIG else '<'
entry = struct.unpack('{}IIQQQQQQ'.format(endian_marker), buf)
self.type = ELFPType(entry[0])
self.flags = ELFPFlag.NONE
self.offset = entry[2]
self.vaddr = entry[3]
self.paddr = entry[4]
self.filesz = entry[5]
self.memsz = entry[6]
self.align = entry[7]
if entry[1] & ELFPFlag.READ.value: self.flags |= ELFPFlag.READ
if entry[1] & ELFPFlag.WRITE.value: self.flags |= ELFPFlag.WRITE
if entry[1] & ELFPFlag.EXEC.value: self.flags |= ELFPFlag.EXEC
class ELF64Image:
def __init__(self):
self.ph_list = []
self.text = None
self.data = None
self.entry = None
def load(self, path):
f = open(path, mode='rb')
ident_bytes = f.read(16)
ident = struct.unpack('BBBBBBBBBBBBBBBB', ident_bytes)
if ident[0] != 0x7F or ident[1] != ord('E') or ident[2] != ord('L') or ident[3] != ord('F'):
f.close()
return -1
endian = ELFEndian(ident[5])
endian_marker = '>' if endian == ELFEndian.BIG else '<'
hdr_bytes = f.read(48)
hdr = struct.unpack('{}HHIQQQIHHHHHH'.format(endian_marker), hdr_bytes)
self.entry = hdr[3]
phoff = hdr[4]
phnum = hdr[9]
phentsize = hdr[8]
for i in range(0, phnum):
f.seek(phoff + (i * phentsize))
phdr_bytes = f.read(phentsize)
phdr = ELF64Phdr()
phdr.parse(phdr_bytes, endian)
if phdr.flags == ELFPFlag.READ | ELFPFlag.EXEC:
self.text = phdr
if phdr.flags == ELFPFlag.READ | ELFPFlag.WRITE:
self.data = phdr
self.ph_list.append(phdr)
f.close()
return 0
+46
View File
@@ -0,0 +1,46 @@
import sys
import os
import tomli
from colorama import init as colorama_init
from colorama import Fore, Style
from args import Args
from preset import Preset
from bsp import BSP
def main():
colorama_init()
args = Args(sys.argv)
preset_path = args.get_named('preset', 0, 1)
if preset_path is None:
print(f'{Fore.RED}Err:{Style.RESET_ALL} no preset specified')
return -1
out_path = args.get_named('out', 0, 1)
if out_path is None:
print(f'{Fore.RED}Err:{Style.RESET_ALL} no output path specified')
return -1
sysroot_path = args.get_named('sysroot', 0, 1)
if sysroot_path is None:
sysroot_path = '/'
preset = Preset(preset_path)
bsp = BSP(out_path, sysroot=sysroot_path)
for dst, src in preset.contents().items():
for src_filepath in src:
src_filename = os.path.basename(src_filepath)
dst_filepath = os.path.join(dst, src_filename)
bsp.add_file(src_filepath, dst_filepath)
bsp.set_bootstrap_program(preset.bootstrap_program())
bsp.close()
return 0
if __name__ == '__main__':
exit(main())
+18
View File
@@ -0,0 +1,18 @@
#!/bin/bash
SOURCE_ROOT="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )/../.."
if [ ! -d "$SOURCE_ROOT/build" ]; then
mkdir build
fi
if [ ! -d "$SOURCE_ROOT/build/mkbsp_venv" ]; then
echo 'Initialising mkbsp...'
python3 -m venv $SOURCE_ROOT/build/mkbsp_venv
source $SOURCE_ROOT/build/mkbsp_venv/bin/activate
pip install -r $SOURCE_ROOT/toolchain/mkbsp/requirements.txt
else
source $SOURCE_ROOT/build/mkbsp_venv/bin/activate
fi
python3 $SOURCE_ROOT/toolchain/mkbsp/main.py "$@"

Some files were not shown because too many files have changed in this diff Show More