gigatron/rom/Compilers/glcc/CMakeLists.txt
2025-01-28 19:17:01 +03:00

341 lines
12 KiB
CMake

cmake_minimum_required(VERSION 3.16)
project(glcc)
enable_language(C)
# --- Default to RelWithDebInfo
if (NOT "${CMAKE_BUILD_TYPE}")
SET(CMAKE_BUILD_TYPE "RelWithDebInfo")
endif()
# --- Only support out-of-directory builds
if (${PROJECT_SOURCE_DIR} STREQUAL ${PROJECT_BINARY_DIR})
message(FATAL_ERROR "\
Compilation in the source directory is not supported.\
Please create a 'build' directory and run 'cmake SRCDIR' from there.")
endif()
# --- Compute relative path from bindir to srcdir
file(RELATIVE_PATH srcrel "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/foo")
string(REGEX REPLACE "/*foo$" "" srcrel "${srcrel}")
# --- Find Python
find_package(Python3 3.8 REQUIRED QUIET COMPONENTS Interpreter)
set(PYTHON3 "${Python3_EXECUTABLE}" CACHE STRING "Python 3 executable path")
message(STATUS "Using python executable: ${PYTHON3}")
# --- Compile lburg
add_executable(lburg lburg/lburg.c lburg/gram.c)
target_include_directories(lburg PUBLIC lburg)
# --- Run lburg
file(GLOB srcs_md CONFIGURE_DEPENDS
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/src"
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.md" )
foreach(md ${srcs_md})
get_filename_component(mdn "${md}" NAME_WLE)
set(output "${mdn}.c")
list(APPEND srcs_lburg "${output}")
add_custom_command(OUTPUT "${output}"
COMMAND lburg "${srcrel}/src/${md}" "${output}"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/src/${md}"
DEPENDS lburg VERBATIM)
endforeach()
# --- Compile cpp
add_executable(cpp
cpp/cpp.c cpp/lex.c cpp/nlist.c cpp/tokens.c cpp/macro.c cpp/eval.c
cpp/include.c cpp/hideset.c cpp/getopt.c cpp/unix.c )
target_include_directories(cpp PUBLIC cpp)
# --- Compile rcc
add_executable(rcc
src/alloc.c src/bind.c src/dag.c src/decl.c src/enode.c src/error.c
src/expr.c src/event.c src/init.c src/inits.c src/input.c src/lex.c
src/list.c src/main.c src/output.c src/prof.c src/profio.c
src/simp.c src/stmt.c src/string.c src/sym.c src/trace.c src/tree.c
src/types.c src/null.c src/symbolic.c src/stab.c src/gen.c src/bytecode.c
${srcs_lburg} )
target_include_directories(rcc PUBLIC src)
if ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU")
target_compile_options(rcc PRIVATE "-Wno-psabi")
endif()
# --- Compile lcc
add_executable(lcc
etc/lcc.c etc/gigatron-lcc.c )
target_compile_definitions(lcc PUBLIC
"-DTARGET=gigatron")
# --- Compile gtsim
add_executable(gtsim
gigatron/mapsim/gtsim.c )
# --- Stage binary directory to make glcc usable
set(gigatron_targets
glcc glink glink.py gtprof
interface.json interface-dev.json roms.json)
foreach(fn ${gigatron_targets})
set(output "${CMAKE_CURRENT_BINARY_DIR}/${fn}")
if ("${fn}" STREQUAL gtprof)
set(fn "mapsim/${fn}")
endif()
add_custom_command(OUTPUT "${output}"
COMMAND "${CMAKE_COMMAND}" "-E" "copy" "${srcrel}/gigatron/${fn}" "${output}"
MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/gigatron/${fn}"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
VERBATIM)
endforeach()
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/gigatron/glccver.py")
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/gigatron/glccver.py" ver)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/glccver.py" "${ver}")
else()
set(ver "GLCC-unknown-version")
execute_process(COMMAND "git" "describe" "--tags"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/glccver.py"
RESULT_VARIABLE status)
if ("${status}" STREQUAL "0")
file(READ "${CMAKE_CURRENT_BINARY_DIR}/glccver.py" ver)
string(STRIP "${ver}" ver)
endif()
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/glccver.py" "ver=\"${ver}\"\n")
endif()
if (WIN32)
foreach(fn glcc.cmd glink.cmd)
list(APPEND gigatron_targets "${fn}")
add_custom_command(OUTPUT "${fn}"
COMMAND "${CMAKE_COMMAND}" "-E" "echo" "@\"${PYTHON3}\" \"%~dp0\\%~n0\" %*" ">" "${fn}"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
VERBATIM)
endforeach()
endif()
add_custom_target(glcc-ready ALL
COMMAND "${CMAKE_COMMAND}" "-E" "copy_directory" "${srcrel}/include/gigatron/" "include"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
DEPENDS "cpp" "rcc" "lcc" ${gigatron_targets}
VERBATIM)
function(copy_target_to_bindir target)
add_custom_command(TARGET ${target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE:${target}>" "$<TARGET_FILE_NAME:${target}>"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
VERBATIM)
endfunction()
copy_target_to_bindir(cpp)
copy_target_to_bindir(rcc)
copy_target_to_bindir(lcc)
copy_target_to_bindir(gtsim)
# --- Stage map directories
function(add_glcc_map mapname)
set(map_targets "")
file(GLOB mapfiles CONFIGURE_DEPENDS
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/gigatron/"
"${CMAKE_CURRENT_SOURCE_DIR}/gigatron/${mapname}/*.py")
foreach(fn ${mapfiles})
list(APPEND map_targets "${fn}")
add_custom_command(OUTPUT ${fn}
COMMAND "${CMAKE_COMMAND}" "-E" "copy" "${srcrel}/gigatron/${fn}" "${fn}"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/gigatron/${fn}"
VERBATIM )
endforeach()
add_custom_target("${mapname}" ALL
DEPENDS ${map_targets} VERBATIM)
endfunction()
file(GLOB gigatron_maps CONFIGURE_DEPENDS
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/gigatron/"
"${CMAKE_CURRENT_SOURCE_DIR}/gigatron/map*" )
foreach(map ${gigatron_maps})
add_glcc_map("${map}")
endforeach()
# ---- Compile gigatron libraries
# The previous version of add_glcc_library used to rely on
# add_custom_{command/target} to cross-compile the libraries. This
# works very well with the Makefile generators, but fails with the
# Visual Studio generator because only one of the command is
# executed. Whether this is a cmake bug or a msbuild bug is unclear.
#
# The following version takes a completely different approach.
# It builds a cmake script to cross-compile the library.
# This is less efficient but maybe more reliable.
function(add_glcc_library libname libfile)
# Parse the CPU x optional argument
set(cpulist 4 5 6 7)
list(GET ARGN 0 car)
if ("${car}" STREQUAL "CPU")
list(POP_FRONT ARGN car cpulist)
endif()
# Prepare the script
set(srclist "")
set(objlist "")
set(objdir "CMakeFiles/${libname}.glccdir")
set(script "${objdir}/${libname}.cmake")
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${objdir}")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${script}" "
file(REMOVE \"${libfile}\")
set(glcccmd \".\\\\glcc.cmd\")
if (NOT EXISTS \"\${glcccmd}\")
set(glcccmd \"./glcc\")
endif()" )
if ("${CMAKE_GENERATOR}" MATCHES "Makefile")
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/${script}" "
string(ASCII 27 esc)
set(COLORcyan \"\${esc}[36m\")
set(COLORreset \"\${esc}[m\")")
endif()
# Iterate over sources
foreach(fnp ${ARGN})
file(GLOB fn_list CONFIGURE_DEPENDS
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/${fnp}")
foreach(fn ${fn_list})
get_filename_component(fname "${fn}" NAME_WLE)
get_filename_component(fnext "${fn}" LAST_EXT)
list(APPEND srclist "${fn}")
if ("${fnext}" STREQUAL ".c")
foreach(cpu ${cpulist})
set(obj "${objdir}/${fname}_${cpu}.o")
list(APPEND objlist "${obj}")
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/${script}" "
if (\"${srcrel}/${fn}\" IS_NEWER_THAN \"${obj}\")
message(\"\${COLORcyan}Cross-compiling ${obj}\${COLORreset}\")
execute_process(COMMAND \"\${glcccmd}\" \"-c\" \"-cpu=${cpu}\" \"-o\" \"${obj}\" \"${srcrel}/${fn}\"
WORKING_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}\"
RESULT_VARIABLE status)
if (NOT \"\${status}\" EQUAL 0)
message(FATAL_ERROR \"Cross-compilation failed: \${status}\")
endif()
endif()
file(READ \"${obj}\" contents)
file(APPEND \"${libfile}\" \"\${contents}\")" )
endforeach()
elseif ("${fnext}" STREQUAL ".s")
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/${script}" "
file(READ \"${srcrel}/${fn}\" contents)
file(APPEND \"${libfile}\" \"\${contents}\")" )
else()
message(FATAL_ERROR "Library file ${fname}${fext} has an unrecognized suffix")
endif()
endforeach()
endforeach()
# Create target
add_custom_target(${libname} ALL
COMMAND "${CMAKE_COMMAND}" } "-P" "${script}"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
BYPRODUCTS ${objlist}
SOURCES ${srclist}
DEPENDS glcc-ready
VERBATIM)
endfunction()
add_glcc_library("libconx" "mapconx/libconx.a" "gigatron/mapconx/libconx/*.c")
add_glcc_library("libcon_b" "map512k/libcon_b.a" "gigatron/map512k/libcon_b/*.c" "gigatron/map512k/libcon_b/*.s")
add_glcc_library("libcon_n" "map512k/libcon_n.a" "gigatron/map512k/libcon_n/*.c" "gigatron/map512k/libcon_n/*.s")
add_glcc_library("libcon_h" "map512k/libcon_h.a" "gigatron/map512k/libcon_h/*.c" "gigatron/map512k/libcon_h/*.s")
add_glcc_library("libcon1" "map128k/libcon1.a" "gigatron/map128k/libcon1/*.c" "gigatron/map128k/libcon1/*.s")
add_glcc_library("libsim" "mapsim/libsim.a" "gigatron/mapsim/libsim/*.c" "gigatron/mapsim/libsim/*.s")
add_glcc_library("libc-cpu4" "cpu4/libc.a" CPU 4 "gigatron/libc/*.c" "gigatron/libc/*.s" "gigatron/runtime/*.s")
add_glcc_library("libc-cpu5" "cpu5/libc.a" CPU 5 "gigatron/libc/*.c" "gigatron/libc/*.s" "gigatron/runtime/*.s")
add_glcc_library("libc-cpu6" "cpu6/libc.a" CPU 6 "gigatron/libc/*.c" "gigatron/libc/*.s" "gigatron/runtime/*.s")
add_glcc_library("libc-cpu7" "cpu7/libc.a" CPU 7 "gigatron/libc/*.c" "gigatron/libc/*.s" "gigatron/runtime/*.s")
# ---- Installation
set(glcc_install_libdir "lib/gigatron-lcc")
set(glcc_install_bindir "bin")
install(TARGETS cpp rcc lcc gtsim
RUNTIME DESTINATION "${glcc_install_libdir}")
foreach(fn ${gigatron_targets})
get_filename_component(ext "${fn}" EXT)
if ("${ext}" STREQUAL ".json")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${fn}"
DESTINATION "${glcc_install_libdir}")
else()
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${fn}"
DESTINATION "${glcc_install_libdir}")
endif()
endforeach()
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/glccver.py"
DESTINATION "${glcc_install_libdir}")
foreach(dn include cpu4 cpu5 cpu6 ${gigatron_maps})
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${dn}"
DESTINATION "${glcc_install_libdir}")
endforeach()
if (WIN32)
file(RELATIVE_PATH bin_to_lib "/${glcc_install_bindir}" "/${glcc_install_libdir}")
string(REPLACE "/" "\\\\" cmd_to_lib "${bin_to_lib}")
install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory
\"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${glcc_install_bindir}\")")
foreach(pgm glcc glink gtsim gtprof)
set(pycmd "")
if (NOT "${pgm}" STREQUAL gtsim)
set(pycmd "\\\"${PYTHON3}\\\" ")
endif()
set(output "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${glcc_install_bindir}/${pgm}.cmd")
install(CODE "message(STATUS \"Installing: ${output}\")
execute_process(COMMAND ${CMAKE_COMMAND} -E echo
\"@${pycmd}\\\"%~dp0\\\\${cmd_to_lib}\\\\%~n0\\\" %*\"
OUTPUT_FILE \"${output}\") ")
endforeach()
else()
file(RELATIVE_PATH bin_to_lib "/${glcc_install_bindir}" "/${glcc_install_libdir}")
install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory
\"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${glcc_install_bindir}\")")
foreach(pgm glcc glink gtsim gtprof)
set(output "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${glcc_install_bindir}/${pgm}")
install(CODE "message(STATUS \"Creating symlink: ${output}\")
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink
\"${bin_to_lib}/${pgm}\" \"${output}\" )")
endforeach()
endif()