CMake: generate linker script fragments for segments

* Animations
* Levels
* Dynamic models
* Strings

Started to hook this up to the linker. There are still some errors to fix.
This commit is contained in:
Matt Penny 2024-11-05 02:07:16 -05:00
parent 1df470e87b
commit 13db5ddc5e
13 changed files with 208 additions and 26 deletions

View File

@ -33,14 +33,17 @@ add_library(platform INTERFACE)
find_package(Libultra REQUIRED)
target_link_libraries(platform INTERFACE libultra::libultra)
target_compile_definitions(platform INTERFACE F3DEX_GBI_2)
target_include_directories(platform INTERFACE
"${PROJECT_SOURCE_DIR}/src"
)
add_subdirectory(${ASM_DIR})
add_subdirectory(${ASSETS_DIR})
add_subdirectory(${SRC_DIR})
add_subdirectory(${VPK_DIR})
add_library(code_segment OBJECT)
target_link_libraries(code_segment
add_library(code_segment STATIC)
target_link_libraries(code_segment PRIVATE
platform
engine
@ -51,3 +54,46 @@ target_link_libraries(code_segment
sound_lookup_tables
string_lookup_tables
)
add_executable(portal)
target_link_libraries(portal PRIVATE
asm_sources
code_segment
levels
models_dynamic
string_data_tables
)
if (N64)
# Generate linker script
set(INPUT_LINKER_SCRIPT "${PROJECT_SOURCE_DIR}/portal.ld")
set(OUTPUT_LINKER_SCRIPT "${LINKER_SCRIPT_DIR}/portal.ld")
add_custom_command(
DEPENDS
${INPUT_LINKER_SCRIPT}
anims_linker_script
level_linker_script
models_dynamic_linker_script
string_linker_script
OUTPUT
${OUTPUT_LINKER_SCRIPT}
COMMAND
${CMAKE_CPP} -P -Wall -Werror
-I${LINKER_SCRIPT_DIR}
-o ${OUTPUT_LINKER_SCRIPT} ${INPUT_LINKER_SCRIPT}
COMMENT
"Generating $<PATH:RELATIVE_PATH,${OUTPUT_LINKER_SCRIPT},${PROJECT_SOURCE_DIR}>"
VERBATIM
)
add_custom_target(linker_script
DEPENDS ${OUTPUT_LINKER_SCRIPT}
)
add_dependencies(portal linker_script)
# Link
set(LINKER_MAP_FILE "${LINKER_SCRIPT_DIR}/portal.map")
target_link_options(portal PRIVATE
-T ${OUTPUT_LINKER_SCRIPT}
-Map ${LINKER_MAP_FILE}
)
endif()

View File

@ -3,15 +3,20 @@
####################
set(ASM_FILES
boot.s
entry.s
rom_header.s
sound_data.s
)
add_library(asm_sources INTERFACE)
add_library(asm_sources OBJECT)
add_dependencies(asm_sources
sound_data_tables
)
target_sources(asm_sources INTERFACE
target_sources(asm_sources PRIVATE
${ASM_FILES}
)
target_compile_definitions(asm_sources PRIVATE
# TODO
#BOOT_CODE=...
)

View File

@ -1,6 +1,6 @@
set(VALVE_INTRO_VIDEO "${VPK_DIR}/Portal/hl2/media/valve.bik")
if(NOT EXISTS ${VALVE_INTRO_VIDEO})
if (NOT EXISTS ${VALVE_INTRO_VIDEO})
# The Mac release of Portal uses a .mov instead of a .bik
string(REPLACE ".mov" ".bik" VALVE_INTRO_VIDEO_MAC "${VALVE_INTRO_VIDEO}")
@ -26,6 +26,7 @@ set(SCENE_SCALE 128)
# Tools for asset conversion
set(CONVERT_ASSET "${PROJECT_SOURCE_DIR}/tools/convert_asset.py")
set(GEN_SEGMENT_LD "${PROJECT_SOURCE_DIR}/tools/generate_segment_ld.js")
set(EXPORT_FBX "${PROJECT_SOURCE_DIR}/tools/models/export_fbx.py")
set(MODEL_LIST_UTILS "${PROJECT_SOURCE_DIR}/tools/models/model_list_utils.js")
@ -34,3 +35,27 @@ add_subdirectory(models)
add_subdirectory(sound)
add_subdirectory(test_chambers)
add_subdirectory(translations)
# For linking model and level animations
set(ANIMS_LINKER_SCRIPT "${LINKER_SCRIPT_DIR}/anims.ld")
add_custom_command(
DEPENDS
${GEN_SEGMENT_LD}
OUTPUT
${ANIMS_LINKER_SCRIPT}
COMMAND
${NodeJs_EXECUTABLE} ${GEN_SEGMENT_LD}
--single-segment-name animation_segment
${ANIMS_LINKER_SCRIPT}
0x0D000000
"$<LIST:FILTER,$<TARGET_OBJECTS:models_dynamic>,INCLUDE,_anim\..+$>"
"$<LIST:FILTER,$<TARGET_OBJECTS:levels>,INCLUDE,_anim\..+$>"
COMMENT
"Generating $<PATH:RELATIVE_PATH,${ANIMS_LINKER_SCRIPT},${PROJECT_SOURCE_DIR}>"
COMMAND_EXPAND_LISTS
VERBATIM
)
add_custom_target(anims_linker_script
DEPENDS ${ANIMS_LINKER_SCRIPT}
)

View File

@ -98,7 +98,7 @@ function(_add_texture_convert_command INPUT_FILE OUTPUT_FILE)
set(OUTPUT_FILE "${PAK_MATERIALS_DIR}/${OUTPUT_FILE}.png")
set(ARGS "${ARGN}")
if(NOT ARGS)
if (NOT ARGS)
get_source_file_property(FILE_ARGS ${INPUT_FILE} ARGS)
if (FILE_ARGS)
set(ARGS "${FILE_ARGS}")

View File

@ -222,7 +222,7 @@ foreach(MODEL ${MODELS})
_add_model_export_command(${MODEL} MODEL_FBX)
_add_model_generate_command(${MODEL} ${MODEL_FBX} GENERATED_FILES)
if(MODEL IN_LIST DYNAMIC_MODELS)
if (MODEL IN_LIST DYNAMIC_MODELS)
list(APPEND DYNAMIC_MODEL_GENERATED_FILES ${GENERATED_FILES})
else()
list(APPEND STATIC_MODEL_GENERATED_FILES ${GENERATED_FILES})
@ -235,6 +235,30 @@ add_custom_target(models
DEPENDS ${MODEL_GENERATED_FILES}
)
add_library(models_static OBJECT)
add_dependencies(models_static
materials
models
)
target_sources(models_static PRIVATE
${STATIC_MODEL_GENERATED_FILES}
)
target_link_libraries(models_static PRIVATE
platform
)
add_library(models_dynamic OBJECT)
add_dependencies(models_dynamic
materials
models
)
target_sources(models_dynamic PRIVATE
${DYNAMIC_MODEL_GENERATED_FILES}
)
target_link_libraries(models_dynamic PRIVATE
platform
)
# Add commands for generating dynamic model lists
set(MODEL_GENERATED_HEADERS ${MODEL_GENERATED_FILES})
@ -254,8 +278,8 @@ foreach(GENERATED_HEADER ${MODEL_GENERATED_HEADERS})
OUTPUT_VARIABLE MODEL_NAME
)
if(MODEL_NAME IN_LIST DYNAMIC_MODELS)
if(MODEL_NAME IN_LIST ANIMATED_MODELS)
if (MODEL_NAME IN_LIST DYNAMIC_MODELS)
if (MODEL_NAME IN_LIST ANIMATED_MODELS)
list(APPEND DYNAMIC_ANIMATED_MODEL_HEADERS ${GENERATED_HEADER})
else()
list(APPEND DYNAMIC_MODEL_HEADERS ${GENERATED_HEADER})
@ -316,8 +340,25 @@ target_sources(model_lists INTERFACE
${MODEL_LIST_FILES}
)
add_library(models_static INTERFACE)
add_dependencies(models_static models)
target_sources(models_static INTERFACE
${STATIC_MODEL_GENERATED_FILES}
# Add command for generating dynamic model linker script fragment
set(DYNAMIC_MODELS_LINKER_SCRIPT "${LINKER_SCRIPT_DIR}/dynamic_models.ld")
add_custom_command(
DEPENDS
${GEN_SEGMENT_LD}
OUTPUT
${DYNAMIC_MODELS_LINKER_SCRIPT}
COMMAND
${NodeJs_EXECUTABLE} ${GEN_SEGMENT_LD}
${DYNAMIC_MODELS_LINKER_SCRIPT}
0x03000000
"$<LIST:FILTER,$<TARGET_OBJECTS:models_dynamic>,INCLUDE,_geo\..+$>"
COMMENT
"Generating $<PATH:RELATIVE_PATH,${DYNAMIC_MODELS_LINKER_SCRIPT},${PROJECT_SOURCE_DIR}>"
COMMAND_EXPAND_LISTS
VERBATIM
)
add_custom_target(models_dynamic_linker_script
DEPENDS ${DYNAMIC_MODELS_LINKER_SCRIPT}
)

View File

@ -272,7 +272,7 @@ function(_add_sound_transform_command SOUND_SCRIPT OUTPUT_LIST)
set(INPUT_FILE "${PAK_SOUND_DIR}/${SOUND_NAME}.wav")
set(OUTPUT_FILE "${PROJECT_BINARY_DIR}/${RELATIVE_CURRENT_DIR}/${SOUND_NAME}.wav")
if(SOUND_SCRIPT MATCHES ".*\.jsox")
if (SOUND_SCRIPT MATCHES ".*\.jsox")
_add_sound_transform_command_jsox(${SOUND_SCRIPT} ${INPUT_FILE} ${OUTPUT_FILE})
else()
_add_sound_transform_command_sox(${SOUND_SCRIPT} ${INPUT_FILE} ${OUTPUT_FILE})
@ -411,7 +411,7 @@ foreach(CONVERTED_SOUND ${SOUNDS_CONVERTED})
)
# Only include the sound if an instrument bank doesn't already do so
if(NOT INS_BANK IN_LIST INSTRUMENT_BANKS)
if (NOT INS_BANK IN_LIST INSTRUMENT_BANKS)
list(APPEND SOUND_TABLE_INPUTS ${CONVERTED_SOUND})
endif()
endforeach()

View File

@ -154,6 +154,18 @@ add_custom_target(generated_levels
DEPENDS ${LEVEL_GENERATED_FILES}
)
add_library(levels OBJECT)
add_dependencies(levels
materials
generated_levels
)
target_sources(levels PRIVATE
${LEVEL_GENERATED_FILES}
)
target_link_libraries(levels PRIVATE
platform
)
# Add command for generating level list header
set(LEVEL_GENERATED_HEADERS ${LEVEL_GENERATED_FILES})
@ -187,3 +199,26 @@ add_dependencies(level_list generated_level_list)
target_sources(level_list INTERFACE
${LEVEL_LIST}
)
# Add command for generating level linker script fragment
set(LEVEL_LINKER_SCRIPT "${LINKER_SCRIPT_DIR}/levels.ld")
add_custom_command(
DEPENDS
${GEN_SEGMENT_LD}
OUTPUT
${LEVEL_LINKER_SCRIPT}
COMMAND
${NodeJs_EXECUTABLE} ${GEN_SEGMENT_LD}
${LEVEL_LINKER_SCRIPT}
0x02000000
"$<LIST:FILTER,$<TARGET_OBJECTS:levels>,INCLUDE,_geo\..+$>"
COMMENT
"Generating $<PATH:RELATIVE_PATH,${LEVEL_LINKER_SCRIPT},${PROJECT_SOURCE_DIR}>"
COMMAND_EXPAND_LISTS
VERBATIM
)
add_custom_target(level_linker_script
DEPENDS ${LEVEL_LINKER_SCRIPT}
)

View File

@ -75,9 +75,9 @@ add_custom_target(strings
${STRING_DATA_TABLE_FILES}
)
add_library(string_data_tables INTERFACE)
add_library(string_data_tables OBJECT)
add_dependencies(string_data_tables strings)
target_sources(string_data_tables INTERFACE
target_sources(string_data_tables PRIVATE
${STRING_DATA_TABLE_FILES}
)
@ -86,3 +86,27 @@ add_dependencies(string_lookup_tables strings)
target_sources(string_lookup_tables INTERFACE
${STRING_LOOKUP_TABLE_FILES}
)
# Add command for generating strings linker script fragment
set(STRING_LINKER_SCRIPT "${LINKER_SCRIPT_DIR}/subtitles.ld")
add_custom_command(
DEPENDS
${GEN_SEGMENT_LD}
OUTPUT
${STRING_LINKER_SCRIPT}
COMMAND
${NodeJs_EXECUTABLE} ${GEN_SEGMENT_LD}
--alignment 16
${STRING_LINKER_SCRIPT}
0x04000000
"$<TARGET_OBJECTS:string_data_tables>"
COMMENT
"Generating $<PATH:RELATIVE_PATH,${STRING_LINKER_SCRIPT},${PROJECT_SOURCE_DIR}>"
COMMAND_EXPAND_LISTS
VERBATIM
)
add_custom_target(string_linker_script
DEPENDS ${STRING_LINKER_SCRIPT}
)

View File

@ -24,6 +24,7 @@ set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
find_program(CMAKE_ASM_COMPILER ${N64_TOOLCHAIN_PREFIX}gcc REQUIRED)
find_program(CMAKE_C_COMPILER ${N64_TOOLCHAIN_PREFIX}gcc REQUIRED)
find_program(CMAKE_CPP ${N64_TOOLCHAIN_PREFIX}cpp REQUIRED)
find_program(CMAKE_CXX_COMPILER ${N64_TOOLCHAIN_PREFIX}g++ REQUIRED)
find_program(CMAKE_LINKER ${N64_TOOLCHAIN_PREFIX}ld REQUIRED)

View File

@ -1,5 +1,5 @@
OUTPUT_FORMAT("elf32-bigmips", "elf32-bigmips", "elf32-littlemips")
OUTPUT_ARCH(mips)
OUTPUT_ARCH("mips")
#define BEGIN_SEG(name, addr) \
_##name##SegmentStart = ADDR(.name); \
@ -26,15 +26,15 @@ SECTIONS
BEGIN_SEG(boot, 0x04000000)
{
*asm/rom_header.*(.text);
*asm/boot.*(.text);
*/rom_header.*(.text);
*/boot.*(.text);
}
END_SEG(boot)
BEGIN_SEG(code, 0x80000400) SUBALIGN(16)
{
/* code */
*asm/entry.*(.text);
*/entry.*(.text);
CODE_SEGMENT(.text);
RSP_OBJ(.text);
GSP_OBJ(.text);
@ -68,8 +68,8 @@ SECTIONS
BEGIN_SEG(sound_data, __romPos)
{
*asm/sound_data.*(.data);
*asm/sound_data.*(.bss);
*/sound_data.*(.data);
*/sound_data.*(.bss);
}
END_SEG(sound_data)

View File

@ -73,7 +73,7 @@ target_include_directories(skeletool64 PRIVATE
${LUA_INCLUDE_DIR}
)
target_link_libraries(skeletool64
target_link_libraries(skeletool64 PRIVATE
assimp::assimp
cimg::cimg
PNG::PNG

View File

@ -1,7 +1,7 @@
#include "string.h"
size_t strLength(char* s) {
int size = 0;
size_t size = 0;
while (*s++ != '\0') {
++size;

View File

@ -10,7 +10,7 @@ function sanitize(s) {
function generateSegmentNameFromObject(objectPath) {
const { name } = path.parse(objectPath);
return sanitize(name);
return sanitize(name.split('.')[0]);
}
function generateSegmentContent(objectPath) {
@ -58,6 +58,11 @@ const [outputLinkerScript, loadAddress, ...objectPaths] = positionals;
const singleSegmentName = values['single-segment-name'];
const alignment = values['alignment'];
const outputParentDir = path.dirname(outputLinkerScript);
if (!fs.existsSync(outputParentDir)) {
fs.mkdirSync(outputParentDir, { recursive: true });
}
const output = singleSegmentName ?
generateSegment(singleSegmentName, loadAddress, alignment, objectPaths) :
generateMultiSegments(loadAddress, alignment, objectPaths);