mirror of
https://github.com/Leonmmcoset/cleonos.git
synced 2026-04-24 11:14:01 +00:00
235 lines
8.2 KiB
CMake
235 lines
8.2 KiB
CMake
cmake_minimum_required(VERSION 3.20)
|
|
project(CLeonOSKit NONE)
|
|
|
|
set(CLEONOS_KIT_APPS_DIR "${CMAKE_SOURCE_DIR}/apps" CACHE PATH "Directory containing app subdirectories")
|
|
set(CLEONOS_KIT_RUNTIME_DIR "${CMAKE_SOURCE_DIR}/runtime" CACHE PATH "Directory containing user runtime sources")
|
|
set(CLEONOS_KIT_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include" CACHE PATH "Directory containing user runtime headers")
|
|
set(CLEONOS_KIT_LINKER_SCRIPT "${CMAKE_SOURCE_DIR}/linker/user.ld" CACHE FILEPATH "Linker script for user ELF")
|
|
set(CLEONOS_KIT_OUTPUT_DIR "${CMAKE_SOURCE_DIR}/build/apps" CACHE PATH "Output directory for generated ELF files")
|
|
set(CLEONOS_KIT_OBJ_DIR "${CMAKE_SOURCE_DIR}/build/obj" CACHE PATH "Output directory for object files")
|
|
set(CLEONOS_KIT_APP_NAMES "" CACHE STRING "Optional app list, separated by comma/semicolon (empty means all apps)")
|
|
set(CLEONOS_KIT_USE_MAIN_ADAPTER ON CACHE BOOL "When ON, apps can provide plain main(int,char**)")
|
|
set(CLEONOS_KIT_ENABLE_WERROR ON CACHE BOOL "Treat warnings as errors")
|
|
|
|
set(CLEONOS_KIT_CC "x86_64-elf-gcc" CACHE STRING "C compiler for user ELF objects")
|
|
set(CLEONOS_KIT_LD "x86_64-elf-ld" CACHE STRING "Linker for user ELF")
|
|
|
|
function(resolve_tool_with_fallback VAR_NAME)
|
|
set(_fallbacks ${ARGN})
|
|
set(_requested "${${VAR_NAME}}")
|
|
|
|
if("${_requested}" STREQUAL "")
|
|
message(FATAL_ERROR "empty tool variable: ${VAR_NAME}")
|
|
endif()
|
|
|
|
if(IS_ABSOLUTE "${_requested}")
|
|
if(NOT EXISTS "${_requested}")
|
|
message(FATAL_ERROR "${VAR_NAME} not found: ${_requested}")
|
|
endif()
|
|
set(_resolved "${_requested}")
|
|
else()
|
|
unset(_requested_path CACHE)
|
|
unset(_requested_path)
|
|
find_program(_requested_path NAMES "${_requested}")
|
|
if(_requested_path)
|
|
set(_resolved "${_requested_path}")
|
|
else()
|
|
set(_resolved "")
|
|
foreach(_cand IN LISTS _fallbacks)
|
|
unset(_cand_path CACHE)
|
|
unset(_cand_path)
|
|
find_program(_cand_path NAMES "${_cand}")
|
|
if(_cand_path)
|
|
message(STATUS "${VAR_NAME} '${_requested}' not found; fallback to '${_cand}'")
|
|
set(_resolved "${_cand_path}")
|
|
break()
|
|
endif()
|
|
endforeach()
|
|
if("${_resolved}" STREQUAL "")
|
|
message(FATAL_ERROR "${VAR_NAME} tool not found: '${_requested}', fallbacks='${_fallbacks}'")
|
|
endif()
|
|
endif()
|
|
endif()
|
|
|
|
set(${VAR_NAME} "${_resolved}" CACHE STRING "resolved tool path" FORCE)
|
|
set(${VAR_NAME} "${_resolved}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
resolve_tool_with_fallback(CLEONOS_KIT_CC gcc clang cc)
|
|
resolve_tool_with_fallback(CLEONOS_KIT_LD ld ld.lld)
|
|
|
|
execute_process(
|
|
COMMAND ${CLEONOS_KIT_LD} -V
|
|
RESULT_VARIABLE _ld_probe_rc
|
|
OUTPUT_VARIABLE _ld_probe_out
|
|
ERROR_VARIABLE _ld_probe_err
|
|
)
|
|
|
|
execute_process(
|
|
COMMAND ${CLEONOS_KIT_LD} --help
|
|
RESULT_VARIABLE _ld_help_rc
|
|
OUTPUT_VARIABLE _ld_help_out
|
|
ERROR_VARIABLE _ld_help_err
|
|
)
|
|
|
|
set(_ld_probe_text "${_ld_probe_out}\n${_ld_probe_err}\n${_ld_help_out}\n${_ld_help_err}")
|
|
string(TOLOWER "${_ld_probe_text}" _ld_probe_lower)
|
|
|
|
if(_ld_probe_lower MATCHES "i386pep"
|
|
OR _ld_probe_lower MATCHES "pei-"
|
|
OR _ld_probe_lower MATCHES "pe-coff"
|
|
OR _ld_probe_lower MATCHES "appcontainer"
|
|
OR _ld_probe_lower MATCHES "auto-import")
|
|
message(FATAL_ERROR
|
|
"selected linker appears to target PE/COFF, not ELF. "
|
|
"Use an ELF toolchain, for example: "
|
|
"-DCLEONOS_KIT_CC=x86_64-elf-gcc -DCLEONOS_KIT_LD=x86_64-elf-ld")
|
|
endif()
|
|
|
|
if(NOT EXISTS "${CLEONOS_KIT_LINKER_SCRIPT}")
|
|
message(FATAL_ERROR "missing linker script: ${CLEONOS_KIT_LINKER_SCRIPT}")
|
|
endif()
|
|
|
|
if(NOT IS_DIRECTORY "${CLEONOS_KIT_APPS_DIR}")
|
|
message(FATAL_ERROR "missing apps directory: ${CLEONOS_KIT_APPS_DIR}")
|
|
endif()
|
|
|
|
if(NOT IS_DIRECTORY "${CLEONOS_KIT_RUNTIME_DIR}")
|
|
message(FATAL_ERROR "missing runtime directory: ${CLEONOS_KIT_RUNTIME_DIR}")
|
|
endif()
|
|
|
|
if(NOT IS_DIRECTORY "${CLEONOS_KIT_INCLUDE_DIR}")
|
|
message(FATAL_ERROR "missing include directory: ${CLEONOS_KIT_INCLUDE_DIR}")
|
|
endif()
|
|
|
|
file(MAKE_DIRECTORY "${CLEONOS_KIT_OUTPUT_DIR}")
|
|
file(MAKE_DIRECTORY "${CLEONOS_KIT_OBJ_DIR}")
|
|
|
|
set(_runtime_sources
|
|
"${CLEONOS_KIT_RUNTIME_DIR}/runtime.c"
|
|
"${CLEONOS_KIT_RUNTIME_DIR}/syscall.c"
|
|
"${CLEONOS_KIT_RUNTIME_DIR}/stdio.c"
|
|
"${CLEONOS_KIT_RUNTIME_DIR}/libc_string.c"
|
|
"${CLEONOS_KIT_RUNTIME_DIR}/libc_stdlib.c"
|
|
"${CLEONOS_KIT_RUNTIME_DIR}/libc_ctype.c"
|
|
"${CLEONOS_KIT_RUNTIME_DIR}/dlfcn.c"
|
|
)
|
|
|
|
if(CLEONOS_KIT_USE_MAIN_ADAPTER)
|
|
list(APPEND _runtime_sources "${CLEONOS_KIT_RUNTIME_DIR}/main_adapter.c")
|
|
endif()
|
|
|
|
foreach(_src IN LISTS _runtime_sources)
|
|
if(NOT EXISTS "${_src}")
|
|
message(FATAL_ERROR "missing runtime source: ${_src}")
|
|
endif()
|
|
endforeach()
|
|
|
|
set(CLEONOS_KIT_CFLAGS
|
|
-std=c11
|
|
-ffreestanding
|
|
-fno-stack-protector
|
|
-fno-builtin
|
|
-Wall
|
|
-Wextra
|
|
-m64
|
|
-mno-red-zone
|
|
-fno-pic
|
|
-fno-pie
|
|
"-I${CLEONOS_KIT_INCLUDE_DIR}"
|
|
)
|
|
|
|
if(CLEONOS_KIT_ENABLE_WERROR)
|
|
list(APPEND CLEONOS_KIT_CFLAGS -Werror)
|
|
endif()
|
|
|
|
set(CLEONOS_KIT_LDFLAGS "" CACHE STRING "Extra linker flags (semicolon separated)")
|
|
|
|
function(cleonos_compile_object SRC_PATH OUT_VAR)
|
|
file(RELATIVE_PATH _rel "${CMAKE_SOURCE_DIR}" "${SRC_PATH}")
|
|
string(REGEX REPLACE "\\.c$" ".o" _obj_rel "${_rel}")
|
|
set(_obj_path "${CLEONOS_KIT_OBJ_DIR}/${_obj_rel}")
|
|
get_filename_component(_obj_dir "${_obj_path}" DIRECTORY)
|
|
|
|
add_custom_command(
|
|
OUTPUT "${_obj_path}"
|
|
COMMAND ${CMAKE_COMMAND} -E make_directory "${_obj_dir}"
|
|
COMMAND ${CLEONOS_KIT_CC} ${CLEONOS_KIT_CFLAGS} -c "${SRC_PATH}" -o "${_obj_path}"
|
|
DEPENDS "${SRC_PATH}"
|
|
VERBATIM
|
|
)
|
|
|
|
set(${OUT_VAR} "${_obj_path}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
function(cleonos_kit_add_app APP_NAME)
|
|
set(_app_sources ${ARGN})
|
|
|
|
if(NOT _app_sources)
|
|
message(FATAL_ERROR "cleonos_kit_add_app(${APP_NAME}) requires at least one source")
|
|
endif()
|
|
|
|
set(_obj_list)
|
|
foreach(_src IN LISTS _runtime_sources _app_sources)
|
|
cleonos_compile_object("${_src}" _obj)
|
|
list(APPEND _obj_list "${_obj}")
|
|
endforeach()
|
|
|
|
set(_out_path "${CLEONOS_KIT_OUTPUT_DIR}/${APP_NAME}.elf")
|
|
add_custom_command(
|
|
OUTPUT "${_out_path}"
|
|
COMMAND ${CMAKE_COMMAND} -E make_directory "${CLEONOS_KIT_OUTPUT_DIR}"
|
|
COMMAND ${CLEONOS_KIT_LD} ${CLEONOS_KIT_LDFLAGS} -T "${CLEONOS_KIT_LINKER_SCRIPT}" -o "${_out_path}" ${_obj_list}
|
|
DEPENDS ${_obj_list} "${CLEONOS_KIT_LINKER_SCRIPT}"
|
|
VERBATIM
|
|
)
|
|
|
|
add_custom_target("app-${APP_NAME}" DEPENDS "${_out_path}")
|
|
set_property(GLOBAL APPEND PROPERTY CLEONOS_KIT_APP_TARGETS "app-${APP_NAME}")
|
|
set_property(GLOBAL APPEND PROPERTY CLEONOS_KIT_APP_OUTPUTS "${_out_path}")
|
|
endfunction()
|
|
|
|
set(_app_names)
|
|
if("${CLEONOS_KIT_APP_NAMES}" STREQUAL "")
|
|
file(GLOB _app_entries RELATIVE "${CLEONOS_KIT_APPS_DIR}" "${CLEONOS_KIT_APPS_DIR}/*")
|
|
foreach(_entry IN LISTS _app_entries)
|
|
if(IS_DIRECTORY "${CLEONOS_KIT_APPS_DIR}/${_entry}")
|
|
list(APPEND _app_names "${_entry}")
|
|
endif()
|
|
endforeach()
|
|
else()
|
|
string(REPLACE "," ";" _app_names "${CLEONOS_KIT_APP_NAMES}")
|
|
endif()
|
|
|
|
list(REMOVE_DUPLICATES _app_names)
|
|
list(SORT _app_names)
|
|
|
|
if(NOT _app_names)
|
|
message(FATAL_ERROR "no apps selected/found under ${CLEONOS_KIT_APPS_DIR}")
|
|
endif()
|
|
|
|
foreach(_app IN LISTS _app_names)
|
|
if(NOT IS_DIRECTORY "${CLEONOS_KIT_APPS_DIR}/${_app}")
|
|
message(FATAL_ERROR "app directory not found: ${CLEONOS_KIT_APPS_DIR}/${_app}")
|
|
endif()
|
|
|
|
file(GLOB_RECURSE _app_sources CONFIGURE_DEPENDS "${CLEONOS_KIT_APPS_DIR}/${_app}/*.c")
|
|
if(NOT _app_sources)
|
|
message(FATAL_ERROR "no C sources found for app '${_app}' in ${CLEONOS_KIT_APPS_DIR}/${_app}")
|
|
endif()
|
|
|
|
cleonos_kit_add_app("${_app}" ${_app_sources})
|
|
endforeach()
|
|
|
|
get_property(_kit_targets GLOBAL PROPERTY CLEONOS_KIT_APP_TARGETS)
|
|
get_property(_kit_outputs GLOBAL PROPERTY CLEONOS_KIT_APP_OUTPUTS)
|
|
|
|
if(NOT _kit_targets)
|
|
message(FATAL_ERROR "no app targets were generated")
|
|
endif()
|
|
|
|
add_custom_target(apps ALL DEPENDS ${_kit_targets})
|
|
|
|
message(STATUS "CLeonOS kit apps: ${_app_names}")
|
|
message(STATUS "CLeonOS kit output: ${CLEONOS_KIT_OUTPUT_DIR}")
|