simh-testsetgenerator/cmake/add_simulator.cmake
B. Scott Michel 191b2131e9 CMake: Make generate.py reusable
Make generate.py resuable outside of open-simh, as suggested and
motivated by Richard Cornwell's simulator repository.

- Make the "experimental" rule optional. Do not generate a Python
  "KeyError" if the rule is missing.

- Add documentation on how to use the CMake infrastructure outside
  of open-simh: Customize the packaging.py script, season to taste.

- Update the KA10 simulator customization, moving it to its own
  Python script, simgen/pdp10_simulator.py. Preparatory move that
  anticipates additional frontpanel and display options.

- generate.py option "--skip-orphans": Skip the orphaned simulator
  check (i.e., don't cross-reference the simulators in packaging.py
  with what was scraped from the makefile.)

- Add "TEST_ARGS" argument to CMake's add_simulator function so that the
  IBM 1130 simulator can pass to "-g" on the command line to disable the
  GUI when running RegisterSanityCheck, i.e.:

    ibm1130 RegisterSanityCheck -g

  This fixes an edge case Heisenbug encountered during Github CI/CD
  tests where ibm1130 appears to hang indefinitely on the Windows
  runners.

  The cause is the GUI's Pump() thread function being prematurely
  terminated before all GUI resources are acquired. The net result is an
  infinite loop in the MS C runtime trying to exit the process with
  unstable internal state. (Separate patch: synchronization across main
  and Pump() threads to ensure resource acquisition completes.)

  This issue never shows up on non-Windows platforms or the SIMH makefile.

- cmake/generator.py, cmake/simgen: Add a "test_args" keyword argument
  to the BasicSimulator constructor that holds the tests argument
  parameter emitted as the "TEST_ARGS" argument to a simulator's
  add_simulator(). Ensure that the IBM 1130 emits 'TEST_ARG "-g"' in its
  add_simulator().

- scp.c: reset_all_p() adds 'P' to the existing switches, versus saving
  sim_switches and ONLY setting the 'P' power-up reset switch. Net effect
  is that the IBM 1130 simulator actually sees the 'G' flag that inhibits
  the GUI during the console device reset.
2024-05-21 15:57:21 -04:00

455 lines
17 KiB
CMake

## Put everything together into one nice function.
include (CTest)
## Regenerate the git commit ID if git exists.
find_program(GIT_COMMAND git)
if (GIT_COMMAND)
message(STATUS "Git command is ${GIT_COMMAND}")
else ()
message(STATUS "Git not found -- will not update or include .git-commit-id.h")
endif ()
add_custom_target(update_sim_commit ALL
COMMAND ${CMAKE_COMMAND}
-D GIT_COMMIT_DEST=${CMAKE_SOURCE_DIR}
-P ${CMAKE_SOURCE_DIR}/cmake/git-commit-id.cmake
BYPRODUCTS
${CMAKE_SOURCE_DIR}/.git-commit-id
${CMAKE_SOURCE_DIR}/.git-commit-id.h
WORKING_DIRECTORY
${CMAKE_SOURCE_DIR}
)
## Simulator sources and library:
set(SIM_SOURCES
${CMAKE_SOURCE_DIR}/scp.c
${CMAKE_SOURCE_DIR}/sim_card.c
${CMAKE_SOURCE_DIR}/sim_console.c
${CMAKE_SOURCE_DIR}/sim_disk.c
${CMAKE_SOURCE_DIR}/sim_ether.c
${CMAKE_SOURCE_DIR}/sim_fio.c
${CMAKE_SOURCE_DIR}/sim_imd.c
${CMAKE_SOURCE_DIR}/sim_scsi.c
${CMAKE_SOURCE_DIR}/sim_serial.c
${CMAKE_SOURCE_DIR}/sim_sock.c
${CMAKE_SOURCE_DIR}/sim_tape.c
${CMAKE_SOURCE_DIR}/sim_timer.c
${CMAKE_SOURCE_DIR}/sim_tmxr.c
${CMAKE_SOURCE_DIR}/sim_video.c)
set(SIM_VIDEO_SOURCES
${CMAKE_SOURCE_DIR}/display/display.c
${CMAKE_SOURCE_DIR}/display/sim_ws.c)
## Build a simulator core library, with and without AIO support. The AIO variant
## has "_aio" appended to its name, e.g., "simhz64_aio" or "simhz64_video_aio".
function(build_simcore _targ)
cmake_parse_arguments(SIMH "VIDEO;INT64;ADDR64;BESM6_SDL_HACK" "" "" ${ARGN})
# Additional library targets that depend on simulator I/O:
add_library(${_targ} STATIC ${SIM_SOURCES})
set(sim_aio_lib "${_targ}_aio")
add_library(${sim_aio_lib} STATIC ${SIM_SOURCES})
# Components that need to be turned on while building the library, but
# don't export out to the dependencies (hence PRIVATE.)
foreach (lib IN ITEMS "${_targ}" "${sim_aio_lib}")
set_target_properties(${lib} PROPERTIES
C_STANDARD 99
EXCLUDE_FROM_ALL True
)
target_compile_definitions(${lib} PRIVATE USE_SIM_CARD USE_SIM_IMD)
target_compile_options(${lib} PRIVATE ${EXTRA_TARGET_CFLAGS})
target_link_options(${lib} PRIVATE ${EXTRA_TARGET_LFLAGS})
# Make sure that the top-level directory is part of the libary's include path:
target_include_directories("${lib}" PUBLIC "${CMAKE_SOURCE_DIR}")
if (SIMH_INT64)
target_compile_definitions(${lib} PUBLIC USE_INT64)
endif (SIMH_INT64)
if (SIMH_ADDR64)
target_compile_definitions(${lib} PUBLIC USE_ADDR64)
endif (SIMH_ADDR64)
if (SIMH_VIDEO)
if (WITH_VIDEO)
# It's the video library
target_sources(${lib} PRIVATE ${SIM_VIDEO_SOURCES})
target_link_libraries(${lib} PUBLIC simh_video)
endif ()
if (CMAKE_HOST_APPLE AND NOT SIMH_BESM6_SDL_HACK)
## (a) The BESM6 SDL hack is temporary. If SDL_MAIN_AVAILABLE needs
## to be defined, it belongs in the simh_video interface library.
## (b) BESM6 doesn't use SIMH's video capabilities correctly and
## the makefile filters out SDL_MAIN_AVAILABLE on macOS.
## (c) This shouldn't be just an Apple platform quirk; SDL_main should
## be used by all platforms. <sigh!>
target_compile_definitions("${lib}" PUBLIC SDL_MAIN_AVAILABLE)
endif ()
endif ()
# Define SIM_BUILD_TOOL for the simulator'
target_compile_definitions("${lib}" PRIVATE
"SIM_BUILD_TOOL=CMake (${CMAKE_GENERATOR})"
)
target_link_libraries(${lib} PUBLIC
simh_network
simh_regexp
os_features
thread_lib
)
# Ensure that sim_rev.h picks up .git-commit-id.h if the git command is
# available.
if (GIT_COMMAND)
target_compile_definitions("${lib}" PRIVATE SIM_NEED_GIT_COMMIT_ID)
endif ()
add_dependencies(${lib} update_sim_commit)
endforeach ()
target_compile_definitions(${sim_aio_lib} PUBLIC ${AIO_FLAGS})
# Create target cppcheck rule, if detected.
if (ENABLE_CPPCHECK AND cppcheck_cmd)
get_property(cppcheck_includes TARGET ${_targ} PROPERTY INCLUDE_DIRECTORIES)
get_property(cppcheck_defines TARGET ${_targ} PROPERTY COMPILE_DEFINITIONS)
list(TRANSFORM cppcheck_includes PREPEND "-I")
list(TRANSFORM cppcheck_defines PREPEND "-D")
add_custom_target("${_targ}_cppcheck"
COMMAND ${cppcheck_cmd} ${cppcheck_defines} ${cppcheck_includes} ${SIM_SOURCES}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
VERBATIM
)
add_dependencies(cppcheck "${_targ}_cppcheck")
endif (ENABLE_CPPCHECK AND cppcheck_cmd)
endfunction(build_simcore _targ)
##+
## Basic template for simh executables and unit tests.
##-
## FEATURE_INT64: Use the simhi64 library (defines USE_INT64)
## FEATURE_FULL64: Use the simhz64 library (defines USE_INT64, USE_ADDR64)
## BUILDROMS: Build the hardcoded boot rooms
## FEATURE_VIDEO: Add video support
## FEATURE_DISPLAY: Add display support
##
## BESM6_SDL_HACK: A TEMPORARY feature to work around issues with BESM6 and
## SDL and SIMH video. Because it's a day ending in "y", there's going to
## be another makefile quirk.
list(APPEND ADD_SIMULATOR_OPTIONS
"FEATURE_INT64"
"FEATURE_FULL64"
"BUILDROMS"
"FEATURE_VIDEO"
"FEATURE_DISPLAY"
"NO_INSTALL"
"BESM6_SDL_HACK"
"USES_AIO"
)
## TEST: The test script name that will be executed by the simulator within CTest.
## LABEL: The test name label, used to group tests, e.g., "VAX" for all of the
## VAX simulator tests. If you want to run a subset of tests, add the "-L <regexp>"
## argument to the ctest command line.
## PKG_FAMILY: The simulator family to which a simulator belongs. If not specificed,
## defaults to "default_family".
list(APPEND ADD_SIMULATOR_1ARG
"TEST"
"LABEL"
"PKG_FAMILY"
)
## DEFINES: List of extra command line manifest constants ("-D" items)
## INCLUDES: List of extra include directories
## SOURCES: List of source files
## TEST_ARGS: Additional arguments to append to the command line after
## "RegisterSanityCheck"
list(APPEND ADD_SIMULATOR_NARG
"DEFINES"
"INCLUDES"
"SOURCES"
"TEST_ARGS"
)
function (simh_executable_template _targ)
cmake_parse_arguments(SIMH "${ADD_SIMULATOR_OPTIONS}" "${ADD_SIMULATOR_1ARG}" "${ADD_SIMULATOR_NARG}" ${ARGN})
if (NOT DEFINED SIMH_SOURCES)
message(FATAL_ERROR "${_targ}: No source files?")
endif (NOT DEFINED SIMH_SOURCES)
if (SIMH_USES_AIO AND NOT WITH_ASYNC)
message(WARNING
"!!! ${_targ}: Asynchronous I/O not enabled, but this simulator specifies USES_AIO\n"
"!!! Some features will be crippled, notably networking.")
endif ()
add_executable("${_targ}" "${SIMH_SOURCES}")
set_target_properties(${_targ} PROPERTIES
C_STANDARD 99
RUNTIME_OUTPUT_DIRECTORY ${SIMH_LEGACY_INSTALL}
)
target_compile_options(${_targ} PRIVATE ${EXTRA_TARGET_CFLAGS})
target_link_options(${_targ} PRIVATE ${EXTRA_TARGET_LFLAGS})
if (MINGW)
## target_compile_options(${_targ} PUBLIC "-fms-extensions")
target_link_options(${_targ} PUBLIC "-mconsole")
elseif (MSVC)
target_link_options(${_targ} PUBLIC "/SUBSYSTEM:CONSOLE")
endif ()
if (DEFINED SIMH_DEFINES)
target_compile_definitions("${_targ}" PUBLIC "${SIMH_DEFINES}")
endif (DEFINED SIMH_DEFINES)
# This is a quick cheat to make sure that all of the include paths are
# absolute paths.
if (DEFINED SIMH_INCLUDES)
set(_normalized_includes)
foreach (inc IN LISTS SIMH_INCLUDES)
if (NOT IS_ABSOLUTE "${inc}")
message(">> Fixing include for ${_targ}: ${inc} -> ${CMAKE_SOURCE_DIR}/${inc}")
get_filename_component(inc "${CMAKE_SOURCE_DIR}/${inc}" ABSOLUTE)
endif ()
list(APPEND _normalized_includes "${inc}")
endforeach ()
target_include_directories("${_targ}" PUBLIC "${_normalized_includes}")
endif ()
if (WITH_VIDEO)
if (SIMH_FEATURE_DISPLAY)
target_compile_definitions(${_targ} PUBLIC USE_DISPLAY)
endif ()
endif ()
set(SIMH_SIMLIB simhcore)
if (SIMH_FEATURE_INT64)
set(SIMH_SIMLIB simhi64)
elseif (SIMH_FEATURE_FULL64)
set(SIMH_SIMLIB simhz64)
endif ()
if (SIMH_FEATURE_VIDEO OR SIMH_FEATURE_DISPLAY)
if (NOT SIMH_BESM6_SDL_HACK)
string(APPEND SIMH_SIMLIB "_video")
else ()
string(APPEND SIMH_SIMLIB "_besm6")
endif ()
endif ()
# Uses AIO...
if (SIMH_USES_AIO)
set(SIMH_SIMLIB "${SIMH_SIMLIB}_aio")
endif()
target_link_libraries("${_targ}" PUBLIC "${SIMH_SIMLIB}")
endfunction ()
function (add_simulator _targ)
simh_executable_template(${_targ} "${ARGN}")
cmake_parse_arguments(SIMH "${ADD_SIMULATOR_OPTIONS}" "${ADD_SIMULATOR_1ARG}" "${ADD_SIMULATOR_NARG}" ${ARGN})
set(pkg_family "default_family")
if (SIMH_PKG_FAMILY)
set(pkg_family ${SIMH_PKG_FAMILY})
endif ()
set(_install_opts)
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.21")
list(APPEND _install_opts RUNTIME_DEPENDENCY_SET simhRuntime)
endif ()
install(TARGETS ${_targ}
${_install_opts}
RUNTIME
COMPONENT ${pkg_family}
)
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.21")
## Collect runtime dependencies. The simhRuntime install() is invoked by cpack-setup.cmake
install(IMPORTED_RUNTIME_ARTIFACTS ${_targ} COMPONENT ${pkg_family} BUNDLE COMPONENT ${pkg_family})
endif()
## Simulator-specific tests:
list(APPEND test_cmd "${_targ}" "RegisterSanityCheck")
if (SIMH_TEST_ARGS)
list(APPEND test_cmd ${SIMH_TEST_ARGS})
endif ()
if (DEFINED SIMH_TEST)
string(APPEND test_fname ${CMAKE_CURRENT_SOURCE_DIR} "/tests/${SIMH_TEST}_test.ini")
IF (EXISTS "${test_fname}")
list(APPEND test_cmd "${test_fname}" "-v")
ENDIF ()
endif ()
add_test(NAME "simh-${_targ}" COMMAND ${test_cmd})
if (SIMH_LABEL)
set_tests_properties("simh-${_targ}" PROPERTIES LABELS "simh-${SIMH_LABEL}")
endif ()
if (BUILD_SHARED_DEPS)
## Make sure that the tests can find the DLLs/shared objects:
file(TO_NATIVE_PATH "${SIMH_DEP_TOPDIR}/bin" native_dep_bindir)
file(TO_NATIVE_PATH "${CMAKE_BINARY_DIR}" native_binary_dir)
endif ()
## Build up test environment:
## - Simulators that link SDL2 need to use the dummy (null) drivers on tests within
## the CI/CD environment. While not STRICTLY necessary, it's a good idea.
list(APPEND test_add_env "SDL_VIDEODRIVER=dummy")
list(APPEND test_add_env "SDL_AUDIODRIVER=dummy")
if (WIN32)
if (BUILD_SHARED_DEPS)
set(test_path "PATH=${native_dep_bindir}\\\$<SEMICOLON>${native_binary_dir}\\$<SEMICOLON>")
string(REPLACE ";" "\\\$<SEMICOLON>" escaped_path "$ENV{PATH}")
string(APPEND test_path "${escaped_path}")
list(APPEND test_add_env "${test_path}")
endif ()
else ()
if (BUILD_SHARED_DEPS)
list(APPEND test_add_env "LD_LIBRARY_PATH=${native_dep_bindir}:${native_binary_dir}:\$LD_LIBRARY_PATH")
endif ()
endif ()
set_property(TEST "simh-${_targ}" PROPERTY ENVIRONMENT "${test_add_env}")
if (DONT_USE_ROMS)
target_compile_definitions(DONT_USE_INTERNAL_ROM)
elseif (SIMH_BUILDROMS)
add_dependencies(${_targ} BuildROMs)
endif ()
# Create target 'cppcheck' rule, if cppcheck detected:
if (ENABLE_CPPCHECK AND cppcheck_cmd)
get_property(cppcheck_includes TARGET ${_targ} PROPERTY INCLUDE_DIRECTORIES)
get_property(cppcheck_defines TARGET ${_targ} PROPERTY COMPILE_DEFINITIONS)
list(TRANSFORM cppcheck_includes PREPEND "-I")
list(TRANSFORM cppcheck_defines PREPEND "-D")
add_custom_target("${_targ}_cppcheck"
COMMAND ${cppcheck_cmd} ${cppcheck_defines} ${cppcheck_includes} ${SIMH_SOURCES}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_dependencies(cppcheck "${_targ}_cppcheck")
endif (ENABLE_CPPCHECK AND cppcheck_cmd)
endfunction ()
function(add_unit_test _targ)
set(UNIT_TARGET "simbase-${_targ}")
set(UNIT_TEST "simbase-${_targ}")
simh_executable_template(${UNIT_TARGET} "${ARGN}")
cmake_parse_arguments(SIMH "FEATURE_INT64;FEATURE_FULL64;BUILDROMS;FEATURE_VIDEO,FEATURE_DISPLAY"
"SOURCE_DIR;LABEL"
"DEFINES;INCLUDES;SOURCES"
${ARGN})
target_link_libraries(${UNIT_TARGET} PUBLIC unittest)
add_test(NAME ${UNIT_TEST} COMMAND ${UNIT_TARGET})
set(TEST_LABEL "simbase;unit")
if (SIMH_LABEL)
list(APPEND TEST_LABEL "simbase-${SIMH_LABEL}")
endif ()
set_tests_properties(${UNIT_TEST} PROPERTIES LABELS "${TEST_LABEL}")
endfunction ()
##~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=
## Now build things!
##~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=
if (ENABLE_CPPCHECK AND cppcheck_cmd)
add_custom_target(cppcheck)
endif ()
build_simcore(simhcore)
build_simcore(simhi64 INT64)
build_simcore(simhz64 INT64 ADDR64)
build_simcore(simhcore_video VIDEO)
build_simcore(simhi64_video VIDEO INT64)
build_simcore(simhz64_video VIDEO INT64 ADDR64)
## Temporary hack for BESM6's breakage.
build_simcore(simhi64_besm6 VIDEO INT64 BESM6_SDL_HACK)
if (NOT DONT_USE_ROMS)
add_executable(BuildROMs sim_BuildROMs.c)
target_include_directories(BuildROMs PUBLIC "${CMAKE_SOURCE_DIR}")
target_link_libraries(BuildROMs os_features)
add_custom_command(
OUTPUT
${CMAKE_SOURCE_DIR}/VAX/vax_ka655x_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka620_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka630_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka610_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka410_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka411_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka412_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka41a_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka41d_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka42a_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka42b_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka43a_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka46a_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka47a_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka48a_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_is1000_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka410_xs_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka420_rdrz_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka420_rzrz_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka4xx_4pln_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka4xx_8pln_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka4xx_dz_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka4xx_spx_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka750_bin_new.h
${CMAKE_SOURCE_DIR}/VAX/vax_ka750_bin_old.h
${CMAKE_SOURCE_DIR}/VAX/vax_vcb02_bin.h
${CMAKE_SOURCE_DIR}/VAX/vax_vmb_exe.h
${CMAKE_SOURCE_DIR}/PDP11/pdp11_vt_lunar_rom.h
${CMAKE_SOURCE_DIR}/PDP11/pdp11_dazzle_dart_rom.h
${CMAKE_SOURCE_DIR}/PDP11/pdp11_11logo_rom.h
${CMAKE_SOURCE_DIR}/swtp6800/swtp6800/swtp_swtbugv10_bin.h
MAIN_DEPENDENCY BuildROMs
COMMAND BuildROMS
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
endif ()
## Front panel test.
##
## From all evidence in makefile, sim_frontpanel isn't used yet by any targets.
##
## Needs curses...
add_executable(frontpaneltest
${CMAKE_SOURCE_DIR}/frontpanel/FrontPanelTest.c
${CMAKE_SOURCE_DIR}/sim_sock.c
${CMAKE_SOURCE_DIR}/sim_frontpanel.c)
target_include_directories(frontpaneltest PUBLIC "${CMAKE_SOURCE_DIR}")
target_link_libraries(frontpaneltest PUBLIC os_features thread_lib)
if (WIN32)
target_link_libraries(frontpaneltest PUBLIC simh_network)
if (MSVC)
target_link_options(frontpaneltest PUBLIC "/SUBSYSTEM:CONSOLE")
elseif (MINGW)
target_link_options(frontpaneltest PUBLIC "-mconsole")
endif ()
endif (WIN32)