# ════════════════════════════════════════════════════════════════════════════ # GNU-free CMake build for ncurses 6.5 (FenrirOS) # # Self-contained: generates all headers and sources that the GNU Makefile # would normally produce, then compiles and links everything. # # Prerequisite: run ./configure ONCE before cmake to emit ncurses_cfg.h, # curses.head, MKterm.h.awk, ncurses_dll.h, and other configure outputs. # configure is a POSIX-sh script — not GNU make. # # Builds: # libncursesw.a — wide-character curses library (single unified lib) # libpanelw.a — panel library # libformw.a — form library # libmenuw.a — menu library # tic, infocmp, tput, clear, tset/reset, toe, tabs # ════════════════════════════════════════════════════════════════════════════ cmake_minimum_required(VERSION 3.13) project(ncurses C) set(S "${CMAKE_CURRENT_SOURCE_DIR}") set(INC "${S}/include") set(GEN "${S}/ncurses") # generated .c go next to the ncurses sources if(NOT EXISTS "${INC}/ncurses_cfg.h") message(FATAL_ERROR "include/ncurses_cfg.h not found — run ./configure first.") endif() find_program(AWK NAMES gawk awk REQUIRED) find_program(SH NAMES sh REQUIRED) # ── Generate include headers ────────────────────────────────────────────────── # curses.h = curses.head + MKkey_defs.sh(Caps) + curses.wide + curses.tail if(NOT EXISTS "${INC}/curses.h") message(STATUS "Generating curses.h ...") execute_process( COMMAND ${SH} -c "cat '${INC}/curses.head'; AWK='${AWK}' ${SH} '${INC}/MKkey_defs.sh' '${INC}/Caps' '${INC}/Caps-ncurses'; cat '${INC}/curses.wide' '${INC}/curses.tail'" OUTPUT_FILE "${INC}/curses.h" WORKING_DIRECTORY "${INC}" COMMAND_ERROR_IS_FATAL ANY) endif() # term.h = MKterm.h.awk(Caps) + edit_cfg.sh if(NOT EXISTS "${INC}/term.h") message(STATUS "Generating term.h ...") execute_process(COMMAND ${AWK} -f "${INC}/MKterm.h.awk" "${INC}/Caps" "${INC}/Caps-ncurses" OUTPUT_FILE "${INC}/term.h" COMMAND_ERROR_IS_FATAL ANY) execute_process(COMMAND ${SH} "${INC}/edit_cfg.sh" "${INC}/ncurses_cfg.h" "${INC}/term.h" WORKING_DIRECTORY "${INC}" COMMAND_ERROR_IS_FATAL ANY) endif() # ncurses.h = copy of curses.h if(NOT EXISTS "${INC}/ncurses.h") file(COPY_FILE "${INC}/curses.h" "${INC}/ncurses.h") endif() # hashsize.h if(NOT EXISTS "${INC}/hashsize.h") execute_process(COMMAND ${SH} "${INC}/MKhashsize.sh" "${INC}/Caps" OUTPUT_FILE "${INC}/hashsize.h" COMMAND_ERROR_IS_FATAL ANY) endif() # parametrized.h if(NOT EXISTS "${INC}/parametrized.h") execute_process(COMMAND ${SH} -c "AWK='${AWK}' ${SH} '${INC}/MKparametrized.sh' '${INC}/Caps'" OUTPUT_FILE "${INC}/parametrized.h" COMMAND_ERROR_IS_FATAL ANY) endif() # ncurses_def.h if(NOT EXISTS "${INC}/ncurses_def.h") execute_process(COMMAND ${SH} -c "AWK='${AWK}' ${SH} '${INC}/MKncurses_def.sh' '${INC}/ncurses_defs'" OUTPUT_FILE "${INC}/ncurses_def.h" COMMAND_ERROR_IS_FATAL ANY) endif() # ── Generate source files in ncurses/ ───────────────────────────────────────── # names.c if(NOT EXISTS "${GEN}/names.c") execute_process(COMMAND ${AWK} -f "${S}/ncurses/tinfo/MKnames.awk" "${INC}/Caps" bigstrings=1 OUTPUT_FILE "${GEN}/names.c" COMMAND_ERROR_IS_FATAL ANY) endif() # codes.c if(NOT EXISTS "${GEN}/codes.c") execute_process(COMMAND ${AWK} -f "${S}/ncurses/tinfo/MKcodes.awk" bigstrings=1 "${INC}/Caps" OUTPUT_FILE "${GEN}/codes.c" COMMAND_ERROR_IS_FATAL ANY) endif() # comp_captab.c (needs make_hash helper built from the host compiler) if(NOT EXISTS "${GEN}/comp_captab.c" OR NOT EXISTS "${GEN}/comp_userdefs.c") # Build make_hash as a host tool (not cross-compiled). # It needs ncurses headers from include/ and ncurses/. if(NOT EXISTS "${S}/ncurses/tinfo/make_hash") execute_process( COMMAND cc -DHAVE_CONFIG_H -I${INC} -I${S}/ncurses -I${S}/ncurses/tinfo -I${S} -o "${S}/ncurses/tinfo/make_hash" "${S}/ncurses/tinfo/make_hash.c" COMMAND_ERROR_IS_FATAL ANY) endif() endif() if(NOT EXISTS "${GEN}/comp_captab.c") execute_process( COMMAND ${SH} "${S}/ncurses/tinfo/MKcaptab.sh" "${AWK}" 1 "${S}/ncurses/tinfo/MKcaptab.awk" "${INC}/Caps" WORKING_DIRECTORY "${S}/ncurses/tinfo" OUTPUT_FILE "${GEN}/comp_captab.c" COMMAND_ERROR_IS_FATAL ANY) endif() # comp_userdefs.c if(NOT EXISTS "${GEN}/comp_userdefs.c") execute_process( COMMAND ${SH} "${S}/ncurses/tinfo/MKuserdefs.sh" "${AWK}" 1 "${INC}/Caps" "${INC}/Caps-ncurses" WORKING_DIRECTORY "${S}/ncurses/tinfo" OUTPUT_FILE "${GEN}/comp_userdefs.c" COMMAND_ERROR_IS_FATAL ANY) endif() # fallback.c (stub — no pre-compiled terminfo entries; tic populates at install) if(NOT EXISTS "${GEN}/fallback.c") file(WRITE "${GEN}/fallback.c" "#include \n" "NCURSES_EXPORT(const TERMTYPE2 *)\n" "_nc_fallback2(const char *name) { (void)name; return 0; }\n" "#if NCURSES_EXT_NUMBERS\n" "NCURSES_EXPORT(const TERMTYPE *)\n" "_nc_fallback(const char *name) { (void)name; return 0; }\n" "#endif\n") endif() # expanded.c if(NOT EXISTS "${GEN}/expanded.c") execute_process( COMMAND ${SH} "${S}/ncurses/tty/MKexpanded.sh" "musl-clang -E" -DHAVE_CONFIG_H "-I${INC}" "-I${S}/ncurses" OUTPUT_FILE "${GEN}/expanded.c" WORKING_DIRECTORY "${S}" ERROR_QUIET RESULT_VARIABLE _exp_rc) if(NOT _exp_rc EQUAL 0) file(WRITE "${GEN}/expanded.c" "/* expanded.c — generation failed, stub */\n") endif() endif() # lib_gen.c if(NOT EXISTS "${GEN}/lib_gen.c") execute_process( COMMAND ${SH} -c "${SH} '${S}/ncurses/base/MKlib_gen.sh' 'musl-clang -E -DHAVE_CONFIG_H -DNCURSES_WIDECHAR=1 -I${INC} -I${S}/ncurses' '${AWK}' generated < '${INC}/curses.h'" OUTPUT_FILE "${GEN}/lib_gen.c" WORKING_DIRECTORY "${S}" ERROR_QUIET RESULT_VARIABLE _lg_rc) if(NOT _lg_rc EQUAL 0) file(WRITE "${GEN}/lib_gen.c" "/* lib_gen.c — generation failed, stub */\n") endif() endif() # keys.list — extract KEY_ names from Caps (needed by MKkeyname.awk and make_keys) if(NOT EXISTS "${INC}/keys.list") execute_process( COMMAND ${SH} "${S}/ncurses/tinfo/MKkeys_list.sh" "${INC}/Caps" OUTPUT_FILE "${INC}/keys.list" WORKING_DIRECTORY "${S}" COMMAND_ERROR_IS_FATAL ANY) endif() # lib_keyname.c — must use keys.list, NOT Caps if(NOT EXISTS "${GEN}/lib_keyname.c") execute_process(COMMAND ${AWK} -f "${S}/ncurses/base/MKkeyname.awk" bigstrings=1 "${INC}/keys.list" OUTPUT_FILE "${GEN}/lib_keyname.c" COMMAND_ERROR_IS_FATAL ANY) endif() # unctrl.c if(NOT EXISTS "${GEN}/unctrl.c") execute_process( COMMAND ${SH} -c "echo | '${AWK}' -f '${S}/ncurses/base/MKunctrl.awk' bigstrings=1" OUTPUT_FILE "${GEN}/unctrl.c" COMMAND_ERROR_IS_FATAL ANY) endif() # link_test.c (placeholder) if(NOT EXISTS "${GEN}/link_test.c") file(WRITE "${GEN}/link_test.c" "/* link_test.c — placeholder */\n") endif() # make_keys + init_keytry.h — make_keys generates a trie from keys.list if(NOT EXISTS "${S}/ncurses/tinfo/init_keytry.h" OR NOT "${S}/ncurses/tinfo/init_keytry.h" IS_NEWER_THAN "${INC}/keys.list") if(NOT EXISTS "${S}/ncurses/tinfo/make_keys") execute_process( COMMAND cc -DHAVE_CONFIG_H -I${INC} -I${S}/ncurses -I${S}/ncurses/tinfo -I${S} -o "${S}/ncurses/tinfo/make_keys" "${S}/ncurses/tinfo/make_keys.c" COMMAND_ERROR_IS_FATAL ANY) endif() execute_process( COMMAND "${S}/ncurses/tinfo/make_keys" "${INC}/keys.list" OUTPUT_FILE "${S}/ncurses/tinfo/init_keytry.h" COMMAND_ERROR_IS_FATAL ANY) endif() # ── Generated headers for programs ──────────────────────────────────────────── # termsort.h — sort order arrays for infocmp/dump_entry if(NOT EXISTS "${S}/progs/termsort.h") execute_process( COMMAND ${SH} "${S}/progs/MKtermsort.sh" "${AWK}" "${INC}/Caps" OUTPUT_FILE "${S}/progs/termsort.h" COMMAND_ERROR_IS_FATAL ANY) endif() # transform.h — program name mapping for tic/tput/tset if(NOT EXISTS "${S}/progs/transform.h") file(WRITE "${S}/progs/transform.h" "#ifndef __TRANSFORM_H\n\ #define __TRANSFORM_H 1\n\ #include \n\ extern bool same_program(const char *, const char *);\n\ #define PROG_CAPTOINFO \"captoinfo\"\n\ #define PROG_INFOTOCAP \"infotocap\"\n\ #define PROG_CLEAR \"clear\"\n\ #define PROG_RESET \"reset\"\n\ #define PROG_INIT \"init\"\n\ #endif /* __TRANSFORM_H */\n") endif() # ── Compile settings ────────────────────────────────────────────────────────── add_compile_definitions(HAVE_CONFIG_H _GNU_SOURCE NDEBUG NCURSES_WIDECHAR=1) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release") endif() add_compile_options( -O2 -fPIC -Wno-unused-parameter -Wno-sign-compare -Wno-missing-field-initializers -Wno-implicit-fallthrough -Wno-unused-but-set-variable ) include_directories("${INC}" "${S}/ncurses" "${S}/ncurses/tinfo" "${S}" "${S}/progs") # ── Source lists ────────────────────────────────────────────────────────────── set(TTY_SRCS ncurses/tty/hardscroll.c ncurses/tty/hashmap.c ncurses/tty/lib_mvcur.c ncurses/tty/lib_tstp.c ncurses/tty/lib_twait.c ncurses/tty/lib_vidattr.c ncurses/tty/tty_update.c) set(BASE_SRCS ncurses/base/lib_addch.c ncurses/base/lib_addstr.c ncurses/base/lib_beep.c ncurses/base/lib_bkgd.c ncurses/base/lib_box.c ncurses/base/lib_chgat.c ncurses/base/lib_clear.c ncurses/base/lib_clearok.c ncurses/base/lib_clrbot.c ncurses/base/lib_clreol.c ncurses/base/lib_color.c ncurses/base/lib_colorset.c ncurses/base/lib_delch.c ncurses/base/lib_delwin.c ncurses/base/lib_echo.c ncurses/base/lib_endwin.c ncurses/base/lib_erase.c ncurses/base/lib_flash.c ncurses/base/lib_getch.c ncurses/base/lib_getstr.c ncurses/base/lib_hline.c ncurses/base/lib_immedok.c ncurses/base/lib_inchstr.c ncurses/base/lib_initscr.c ncurses/base/lib_insch.c ncurses/base/lib_insdel.c ncurses/base/lib_insnstr.c ncurses/base/lib_instr.c ncurses/base/lib_isendwin.c ncurses/base/lib_leaveok.c ncurses/base/lib_mouse.c ncurses/base/lib_move.c ncurses/base/lib_mvwin.c ncurses/base/lib_newterm.c ncurses/base/lib_newwin.c ncurses/base/lib_nl.c ncurses/base/lib_overlay.c ncurses/base/lib_pad.c ncurses/base/lib_printw.c ncurses/base/lib_redrawln.c ncurses/base/lib_refresh.c ncurses/base/lib_restart.c ncurses/base/lib_scanw.c ncurses/base/lib_screen.c ncurses/base/lib_scroll.c ncurses/base/lib_scrollok.c ncurses/base/lib_scrreg.c ncurses/base/lib_set_term.c ncurses/base/lib_slk.c ncurses/base/lib_slkatr_set.c ncurses/base/lib_slkatrof.c ncurses/base/lib_slkatron.c ncurses/base/lib_slkatrset.c ncurses/base/lib_slkattr.c ncurses/base/lib_slkclear.c ncurses/base/lib_slkcolor.c ncurses/base/lib_slkinit.c ncurses/base/lib_slklab.c ncurses/base/lib_slkrefr.c ncurses/base/lib_slkset.c ncurses/base/lib_slktouch.c ncurses/base/lib_touch.c ncurses/base/lib_ungetch.c ncurses/base/lib_vline.c ncurses/base/lib_wattroff.c ncurses/base/lib_wattron.c ncurses/base/lib_winch.c ncurses/base/lib_window.c ncurses/base/nc_panel.c ncurses/base/safe_sprintf.c ncurses/base/vsscanf.c ncurses/base/lib_freeall.c ncurses/base/version.c ncurses/base/tries.c ncurses/base/use_window.c) set(TRACE_SRCS ncurses/trace/lib_tracedmp.c ncurses/trace/lib_tracemse.c ncurses/trace/varargs.c ncurses/trace/lib_trace.c ncurses/trace/lib_traceatr.c ncurses/trace/lib_tracebits.c ncurses/trace/lib_tracechr.c ncurses/trace/trace_buf.c ncurses/trace/trace_tries.c ncurses/trace/trace_xnames.c ncurses/trace/visbuf.c) set(TINFO_SRCS ncurses/tinfo/access.c ncurses/tinfo/add_tries.c ncurses/tinfo/alloc_ttype.c ncurses/tinfo/comp_error.c ncurses/tinfo/comp_hash.c ncurses/tinfo/db_iterator.c ncurses/tinfo/doalloc.c ncurses/tinfo/entries.c ncurses/tinfo/free_ttype.c ncurses/tinfo/getenv_num.c ncurses/tinfo/hashed_db.c ncurses/tinfo/home_terminfo.c ncurses/tinfo/init_keytry.c ncurses/tinfo/lib_acs.c ncurses/tinfo/lib_baudrate.c ncurses/tinfo/lib_cur_term.c ncurses/tinfo/lib_data.c ncurses/tinfo/lib_has_cap.c ncurses/tinfo/lib_kernel.c ncurses/tinfo/lib_longname.c ncurses/tinfo/lib_napms.c ncurses/tinfo/lib_options.c ncurses/tinfo/lib_print.c ncurses/tinfo/lib_raw.c ncurses/tinfo/lib_setup.c ncurses/tinfo/lib_termcap.c ncurses/tinfo/lib_termname.c ncurses/tinfo/lib_tgoto.c ncurses/tinfo/lib_ti.c ncurses/tinfo/lib_tparm.c ncurses/tinfo/lib_tputs.c ncurses/tinfo/lib_ttyflags.c ncurses/tinfo/name_match.c ncurses/tinfo/obsolete.c ncurses/tinfo/read_entry.c ncurses/tinfo/read_termcap.c ncurses/tinfo/strings.c ncurses/tinfo/trim_sgr0.c ncurses/tinfo/use_screen.c ncurses/tinfo/write_entry.c) set(TICLIB_SRCS ncurses/tinfo/alloc_entry.c ncurses/tinfo/captoinfo.c ncurses/tinfo/comp_expand.c ncurses/tinfo/comp_parse.c ncurses/tinfo/comp_scan.c ncurses/tinfo/parse_entry.c) set(EXT_TINFO_SRCS ncurses/base/define_key.c ncurses/base/key_defined.c ncurses/base/keybound.c ncurses/base/keyok.c) set(EXT_FUNCS_SRCS ncurses/base/legacy_coding.c ncurses/base/lib_dft_fgbg.c ncurses/base/new_pair.c ncurses/base/resizeterm.c ncurses/base/wresize.c) set(WIDE_SRCS ncurses/widechar/charable.c ncurses/widechar/lib_add_wch.c ncurses/widechar/lib_box_set.c ncurses/widechar/lib_cchar.c ncurses/widechar/lib_erasewchar.c ncurses/widechar/lib_get_wch.c ncurses/widechar/lib_get_wstr.c ncurses/widechar/lib_hline_set.c ncurses/widechar/lib_in_wch.c ncurses/widechar/lib_in_wchnstr.c ncurses/widechar/lib_ins_wch.c ncurses/widechar/lib_inwstr.c ncurses/widechar/lib_key_name.c ncurses/widechar/lib_pecho_wchar.c ncurses/widechar/lib_slk_wset.c ncurses/widechar/lib_unget_wch.c ncurses/widechar/lib_vid_attr.c ncurses/widechar/lib_vline_set.c ncurses/widechar/lib_wacs.c ncurses/widechar/lib_wunctrl.c ncurses/widechar/widechars.c) set(GEN_SRCS ncurses/codes.c ncurses/comp_captab.c ncurses/comp_userdefs.c ncurses/expanded.c ncurses/fallback.c ncurses/lib_gen.c ncurses/lib_keyname.c ncurses/names.c ncurses/unctrl.c ncurses/link_test.c) # ── libncursesw ─────────────────────────────────────────────────────────────── add_library(ncursesw STATIC ${TTY_SRCS} ${BASE_SRCS} ${TRACE_SRCS} ${TINFO_SRCS} ${TICLIB_SRCS} ${EXT_TINFO_SRCS} ${EXT_FUNCS_SRCS} ${WIDE_SRCS} ${GEN_SRCS}) target_compile_definitions(ncursesw PRIVATE BUILDING_NCURSES) # ── libpanelw / libformw / libmenuw ─────────────────────────────────────────── file(GLOB PANEL_SRCS "${S}/panel/*.c") add_library(panelw STATIC ${PANEL_SRCS}) target_include_directories(panelw PRIVATE "${S}/panel") file(GLOB FORM_SRCS "${S}/form/*.c") add_library(formw STATIC ${FORM_SRCS}) target_include_directories(formw PRIVATE "${S}/form" "${S}/menu") file(GLOB MENU_SRCS "${S}/menu/*.c") add_library(menuw STATIC ${MENU_SRCS}) target_include_directories(menuw PRIVATE "${S}/menu") # ── Programs ────────────────────────────────────────────────────────────────── add_executable(tic progs/tic.c progs/dump_entry.c progs/tparm_type.c progs/transform.c) add_executable(infocmp progs/infocmp.c progs/dump_entry.c progs/tparm_type.c) add_executable(tput progs/tput.c progs/tparm_type.c progs/transform.c progs/tty_settings.c progs/reset_cmd.c progs/clear_cmd.c) add_executable(tset progs/tset.c progs/tparm_type.c progs/transform.c progs/tty_settings.c progs/reset_cmd.c) add_executable(toe progs/toe.c progs/dump_entry.c progs/tparm_type.c) add_executable(tabs progs/tabs.c progs/tty_settings.c) add_executable(ncurses_clear progs/clear.c progs/clear_cmd.c progs/tty_settings.c) set_target_properties(ncurses_clear PROPERTIES OUTPUT_NAME clear) foreach(prog tic infocmp tput tset toe tabs ncurses_clear) target_link_libraries(${prog} PRIVATE ncursesw) endforeach() # ── Install ─────────────────────────────────────────────────────────────────── install(TARGETS ncursesw panelw formw menuw ARCHIVE DESTINATION lib) install(TARGETS tic infocmp tput ncurses_clear tset toe tabs RUNTIME DESTINATION bin) # reset → tset symlink install(CODE "execute_process(COMMAND \${CMAKE_COMMAND} -E create_symlink tset \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/bin/reset)") # Public headers install(FILES ${INC}/curses.h ${INC}/ncurses.h ${INC}/term.h ${INC}/termcap.h ${INC}/unctrl.h ${INC}/tic.h ${INC}/term_entry.h ${INC}/nc_tparm.h ${INC}/ncurses_dll.h ${INC}/ncurses_cfg.h ${S}/panel/panel.h ${S}/form/form.h ${S}/menu/menu.h ${S}/menu/eti.h DESTINATION include) # ncursesw/ include symlinks (programs expect ) install(CODE " file(MAKE_DIRECTORY \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/include/ncursesw) foreach(h curses.h ncurses.h term.h termcap.h unctrl.h tic.h term_entry.h nc_tparm.h panel.h form.h menu.h eti.h) execute_process(COMMAND \${CMAKE_COMMAND} -E create_symlink ../\${h} \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/include/ncursesw/\${h}) endforeach() ") # Library compatibility symlinks install(CODE " foreach(lib ncurses panel form menu) execute_process(COMMAND \${CMAKE_COMMAND} -E create_symlink lib\${lib}w.a \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/lib/lib\${lib}.a) endforeach() execute_process(COMMAND \${CMAKE_COMMAND} -E create_symlink libncursesw.a \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/lib/libcurses.a) execute_process(COMMAND \${CMAKE_COMMAND} -E create_symlink libncursesw.a \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/lib/libtinfo.a) ") # ── pkg-config ──────────────────────────────────────────────────────────────── foreach(pc ncursesw ncurses tinfo panelw formw menuw) if(pc STREQUAL "ncursesw" OR pc STREQUAL "ncurses" OR pc STREQUAL "tinfo") set(_lib ncursesw) set(_cflags "-I\${includedir} -I\${includedir}/ncursesw") set(_req "") else() string(REPLACE "w" "" _base "${pc}") set(_lib "${pc}") set(_cflags "-I\${includedir}") set(_req "Requires: ncursesw\n") endif() file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${pc}.pc" "prefix=${CMAKE_INSTALL_PREFIX}\nexec_prefix=\${prefix}\nlibdir=\${exec_prefix}/lib\nincludedir=\${prefix}/include\n\nName: ${pc}\nDescription: ncurses 6.5 (FenrirOS GNU-free build)\nVersion: 6.5\n${_req}Libs: -L\${libdir} -l${_lib}\nCflags: ${_cflags}\n") install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${pc}.pc" DESTINATION lib/pkgconfig) endforeach()