diff --git a/.gitattributes b/.gitattributes index e69de29..a9c5470 100644 --- a/.gitattributes +++ b/.gitattributes @@ -0,0 +1,17 @@ +*.c linguist-language=C +*.cmake linguist-vendored +*.cmd linguist-detectable=false +*.cpp linguist-language=C++ +*.cxx linguist-language=C++ +*.dsp linguist-detectable=false +*.dsw linguist-detectable=false +*.h linguist-language=C +*.hpp linguist-language=C++ +*.html linguist-detectable=false +*.hxx linguist-language=C++ +*.sh linguist-detectable=false +*.sln linguist-detectable=false +*.vcxproj linguist-detectable=false +*.vimrc linguist-detectable=false +CMakeLists.txt linguist-vendored +makefile linguist-detectable=false diff --git a/.github/workflows/ci-cell.yml b/.github/workflows/ci-cell.yml new file mode 100644 index 0000000..c17166d --- /dev/null +++ b/.github/workflows/ci-cell.yml @@ -0,0 +1,268 @@ +name: CI cell + +on: + workflow_call: + inputs: + cell-id: + required: true + type: string + os: + required: true + type: string + c-compiler: + required: true + type: string + cpp-compiler: + required: true + type: string + build-type: + required: false + type: string + default: Release + with-clasp: + required: false + type: boolean + default: true + with-cstring: + required: false + type: boolean + default: false + with-test-deps: + required: false + type: boolean + default: true + run-tests: + required: false + type: boolean + default: true + +jobs: + cell: + name: ${{ inputs.cell-id }} + runs-on: ${{ inputs.os }} + + steps: + - uses: actions/checkout@v4 + + - name: Install Clang (Ubuntu) + if: runner.os == 'Linux' && inputs.c-compiler == 'clang' + run: sudo apt-get update && sudo apt-get install -y clang + + - name: Setup MSYS2 MinGW + if: runner.os == 'Windows' && inputs.c-compiler == 'mingw' + uses: msys2/setup-msys2@v2 + with: + msystem: MINGW64 + update: true + install: >- + mingw-w64-x86_64-toolchain + mingw-w64-x86_64-cmake + mingw-w64-x86_64-make + + - name: Install dependencies + shell: bash + run: | + set -euxo pipefail + + DEPS="${RUNNER_TEMP}/sis-deps" + mkdir -p "$DEPS" + echo "SIS_DEPS=$DEPS" >> "$GITHUB_ENV" + + if [ "${{ inputs.c-compiler }}" = "mingw" ]; then + export PATH="/mingw64/bin:$PATH" + fi + + cmake_configure() { + local src="$1" bld="$2" + shift 2 + if [ "${{ inputs.c-compiler }}" = "cl" ]; then + cmake -S "$src" -B "$bld" \ + -DCMAKE_DISABLE_FIND_PACKAGE_MFC=TRUE \ + -DCMAKE_INSTALL_PREFIX="$DEPS" \ + -DCMAKE_PREFIX_PATH="$DEPS" \ + -DBUILD_EXAMPLES=OFF \ + -DBUILD_TESTING=OFF \ + "$@" + elif [ "${{ inputs.c-compiler }}" = "mingw" ]; then + cmake -S "$src" -B "$bld" -G "MinGW Makefiles" \ + -DCMAKE_BUILD_TYPE="${{ inputs.build-type }}" \ + -DCMAKE_INSTALL_PREFIX="$DEPS" \ + -DCMAKE_PREFIX_PATH="$DEPS" \ + -DBUILD_EXAMPLES=OFF \ + -DBUILD_TESTING=OFF \ + "$@" + else + cmake -S "$src" -B "$bld" \ + -DCMAKE_BUILD_TYPE="${{ inputs.build-type }}" \ + -DCMAKE_C_COMPILER="${{ inputs.c-compiler }}" \ + -DCMAKE_CXX_COMPILER="${{ inputs.cpp-compiler }}" \ + -DCMAKE_INSTALL_PREFIX="$DEPS" \ + -DCMAKE_PREFIX_PATH="$DEPS" \ + -DBUILD_EXAMPLES=OFF \ + -DBUILD_TESTING=OFF \ + "$@" + fi + } + + cmake_build_install() { + local bld="$1" + if [ "${{ inputs.c-compiler }}" = "cl" ]; then + cmake --build "$bld" --config "${{ inputs.build-type }}" --parallel + cmake --install "$bld" --config "${{ inputs.build-type }}" + elif [ "${{ inputs.c-compiler }}" = "mingw" ]; then + cmake --build "$bld" --parallel 2 + cmake --install "$bld" + else + cmake --build "$bld" --parallel + cmake --install "$bld" + fi + } + + # STLSoft (required) + STLSRC="${RUNNER_TEMP}/stlsoft-src" + STLBUILD="${RUNNER_TEMP}/stlsoft-build" + git clone --depth 1 https://github.com/synesissoftware/STLSoft "$STLSRC" + cmake_configure "$STLSRC" "$STLBUILD" + cmake_build_install "$STLBUILD" + + # Catch2 v2 + xTests (test-only) + if [ "${{ inputs.with-test-deps }}" = "true" ]; then + CATCHSRC="${RUNNER_TEMP}/catch2-src" + CATCHBUILD="${RUNNER_TEMP}/catch2-build" + git clone --depth 1 --branch v2.x https://github.com/catchorg/Catch2 "$CATCHSRC" + cmake_configure "$CATCHSRC" "$CATCHBUILD" \ + -DCATCH_BUILD_TESTING=OFF \ + -DCATCH_ENABLE_WERROR=OFF \ + -DCATCH_INSTALL_DOCS=OFF + cmake_build_install "$CATCHBUILD" + + XTSRC="${RUNNER_TEMP}/xtests-src" + XTBUILD="${RUNNER_TEMP}/xtests-build" + git clone --depth 1 https://github.com/synesissoftware/xTests "$XTSRC" + cmake_configure "$XTSRC" "$XTBUILD" -DNO_SHWILD=TRUE + cmake_build_install "$XTBUILD" + fi + + # CLASP + if [ "${{ inputs.with-clasp }}" = "true" ]; then + CLASPSRC="${RUNNER_TEMP}/clasp-src" + CLASPBUILD="${RUNNER_TEMP}/clasp-build" + git clone --depth 1 https://github.com/synesissoftware/CLASP "$CLASPSRC" + cmake_configure "$CLASPSRC" "$CLASPBUILD" + cmake_build_install "$CLASPBUILD" + fi + + # cstring + if [ "${{ inputs.with-cstring }}" = "true" ]; then + CSTRSRC="${RUNNER_TEMP}/cstring-src" + CSTRBUILD="${RUNNER_TEMP}/cstring-build" + git clone --depth 1 https://github.com/synesissoftware/cstring "$CSTRSRC" + cmake_configure "$CSTRSRC" "$CSTRBUILD" + cmake_build_install "$CSTRBUILD" + fi + + - name: Configure + shell: bash + run: | + set -euo pipefail + DEPS="${{ env.SIS_DEPS }}" + + if [ "${{ inputs.c-compiler }}" = "mingw" ]; then + export PATH="/mingw64/bin:$PATH" + fi + + # Bare `cstring` link (rstrip) needs include/lib search paths beyond + # find_package(CLASP)-style imported targets. + if [ "${{ inputs.with-cstring }}" = "true" ]; then + if [ "${{ inputs.c-compiler }}" = "cl" ]; then + export INCLUDE="$(cygpath -w "$DEPS/include");${INCLUDE:-}" + export LIB="$(cygpath -w "$DEPS/lib");${LIB:-}" + else + export CPATH="$DEPS/include${CPATH:+:$CPATH}" + export LIBRARY_PATH="$DEPS/lib${LIBRARY_PATH:+:$LIBRARY_PATH}" + fi + fi + + if [ "${{ inputs.c-compiler }}" = "cl" ]; then + cmake -B build -S . \ + -DCMAKE_DISABLE_FIND_PACKAGE_MFC=TRUE \ + -DCMAKE_PREFIX_PATH="$DEPS" \ + -DBUILD_EXAMPLES=OFF \ + -DBUILD_TESTING=ON + elif [ "${{ inputs.c-compiler }}" = "mingw" ]; then + cmake -B build -G "MinGW Makefiles" \ + -DCMAKE_BUILD_TYPE="${{ inputs.build-type }}" \ + -DCMAKE_C_COMPILER=gcc \ + -DCMAKE_CXX_COMPILER=g++ \ + -DCMAKE_PREFIX_PATH="$DEPS" \ + -DBUILD_EXAMPLES=OFF \ + -DBUILD_TESTING=ON + else + cmake -B build -S . \ + -DCMAKE_BUILD_TYPE="${{ inputs.build-type }}" \ + -DCMAKE_C_COMPILER="${{ inputs.c-compiler }}" \ + -DCMAKE_CXX_COMPILER="${{ inputs.cpp-compiler }}" \ + -DCMAKE_PREFIX_PATH="$DEPS" \ + -DBUILD_EXAMPLES=OFF \ + -DBUILD_TESTING=ON + fi + + - name: Build + shell: bash + run: | + set -euo pipefail + if [ "${{ inputs.c-compiler }}" = "mingw" ]; then + export PATH="/mingw64/bin:$PATH" + fi + if [ "${{ inputs.with-cstring }}" = "true" ]; then + DEPS="${{ env.SIS_DEPS }}" + if [ "${{ inputs.c-compiler }}" = "cl" ]; then + export INCLUDE="$(cygpath -w "$DEPS/include");${INCLUDE:-}" + export LIB="$(cygpath -w "$DEPS/lib");${LIB:-}" + else + export CPATH="$DEPS/include${CPATH:+:$CPATH}" + export LIBRARY_PATH="$DEPS/lib${LIBRARY_PATH:+:$LIBRARY_PATH}" + fi + fi + if [ "${{ inputs.c-compiler }}" = "cl" ]; then + cmake --build build --config "${{ inputs.build-type }}" --parallel + elif [ "${{ inputs.c-compiler }}" = "mingw" ]; then + cmake --build build --parallel 2 + else + cmake --build build --parallel + fi + + - name: Run tests + if: inputs.run-tests + shell: bash + run: | + set -euo pipefail + if [ "${{ inputs.c-compiler }}" = "mingw" ]; then + export PATH="/mingw64/bin:$PATH" + fi + export SIS_CMAKE_BUILD_DIR="${{ github.workspace }}/build" + if [ "${{ runner.os }}" = "Windows" ]; then + cmd.exe //c "run_all_unit_tests.cmd -M -v" + else + ./run_all_unit_tests.sh -M -v + fi + + - name: Install and verify + shell: bash + run: | + set -euo pipefail + PREFIX="${RUNNER_TEMP}/install-prefix" + PROJECT="$(tr -d '[:space:]' < .sis/project_name.txt)" + if [ "${{ inputs.c-compiler }}" = "mingw" ]; then + export PATH="/mingw64/bin:$PATH" + fi + if [ "${{ inputs.c-compiler }}" = "cl" ]; then + cmake --install build --config "${{ inputs.build-type }}" --prefix "$PREFIX" + else + cmake --install build --prefix "$PREFIX" + fi + if [ "${{ inputs.c-compiler }}" = "cl" ] || [ "${{ inputs.c-compiler }}" = "mingw" ]; then + test -f "$PREFIX/bin/${PROJECT}.exe" + else + test -x "$PREFIX/bin/${PROJECT}" + fi diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..05d1e48 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,39 @@ +name: CI + +on: + push: + branches: + - master + - boilerplate + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + cell: + name: CI (${{ matrix.id }}) + strategy: + fail-fast: false + matrix: + include: + - id: windows-cl + os: windows-latest + c_compiler: cl + cpp_compiler: cl + - id: windows-mingw + os: windows-latest + c_compiler: mingw + cpp_compiler: g++ + uses: ./.github/workflows/ci-cell.yml + with: + cell-id: ${{ matrix.id }} + os: ${{ matrix.os }} + c-compiler: ${{ matrix.c_compiler }} + cpp-compiler: ${{ matrix.cpp_compiler }} + build-type: Release + with-clasp: false + with-cstring: false + with-test-deps: false + run-tests: true diff --git a/.gitignore b/.gitignore index bc5e712..191488c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,152 @@ +# directories (by name) + +/.svn/ +/.vs/ + +/_build/ +/_internal/ + +/bin/ +/doc/ +/include/ +/lib/ +/node_modules/ + +/include/b64/ +/include/shwild/ +/include/xcontract/ +/include/xcover/ +/include/xtests/ + +/src/b64/ +/src/shwild/ +/src/xcontract/ +/src/xcover/ +/src/xtests/ + +Debug Multithreaded DLL/ +Debug Multithreaded Dll/ +Debug Multithreaded pseudoUNIX/ +Debug Multithreaded pseudoUnix/ +Debug Multithreaded/ +Debug/ +DebugDLLUNIX/ +DebugDll/ +DebugMTDLL/ +DebugMt/ +DebugNox/ +DebugUNIX/ +DebugUnix/ +Release Multithreaded DLL/ +Release Multithreaded Dll/ +Release Multithreaded pseudoUNIX/ +Release Multithreaded pseudoUnix/ +Release Multithreaded/ +Release/ +ReleaseDLLUNIX/ +ReleaseDll/ +ReleaseMTDLL/ +ReleaseMt/ +ReleaseNox/ +ReleaseUnix/ +UDebug/ +UDebugMt/ +URelease/ +UReleaseMt/ +Unicode Debug Multithreaded DLL/ +Unicode Debug Multithreaded Dll/ +Unicode Debug Multithreaded/ +Unicode Debug/ +Unicode Release Multithreaded DLL/ +Unicode Release Multithreaded Dll/ +Unicode Release Multithreaded/ +Unicode Release/ + +Win32/ +ipch/ +x64/ + + +# directories (by pattern) + + +# files (by name) + +.DS_Store +.ruby-version +.svnignore +.svnignore-at-root +.update_deps + +list_changes.cmd +logging-bailout.txt +prepare.cmd +sh.exe.stackdump +update_deps.cmd + +build/makefile.tmpl +build/makefile.tools.xml + +WriteDebugString +WriteDebugString_test + + +# files (by pattern) + +RCa0* +RCb0* + *~ -*.*~ +*.???_obj +*.a +*.app +*.aps +*.b64 +*.bak +*.chm +*.class +*.csproj*user +*.d +*.dll +*.dylib *.exe +*.gch +*.gem +*.idb *.ilk +*.iobj +*.ipch +*.ipdb +*.la +*.lai +*.lib +*.lo +*.log +*.ncb +*.o *.obj -*.map +*.opensdf +*.opt +*.org +*.out +*.pch *.pdb +*.pyc +*.rar +*.res +*.sbr +*.scc +*.sdf +*.slo +*.so +*.suo *.swp +*.tlog *.tmp +*.unsuccessfulbuild +*.vcproj*user +*.vcxproj*user +*.xcuserstate *.zip diff --git a/.sis/project_name.txt b/.sis/project_name.txt new file mode 100644 index 0000000..917da25 --- /dev/null +++ b/.sis/project_name.txt @@ -0,0 +1 @@ +WriteDebugString diff --git a/.sis/script_info_lines.txt b/.sis/script_info_lines.txt new file mode 100644 index 0000000..a387ee3 --- /dev/null +++ b/.sis/script_info_lines.txt @@ -0,0 +1,2 @@ +WriteDebugString is a Windows CLI that writes messages to the debugger via OutputDebugString +Copyright (c) 2025-2026, Matthew Wilson and Synesis Information Systems diff --git a/.vimrc b/.vimrc new file mode 100644 index 0000000..1bf33a0 --- /dev/null +++ b/.vimrc @@ -0,0 +1,70 @@ +" Synesis C/C++ project .vimrc — aligned with .sis/.vscode/c_cxx/settings.json + +set nocompatible +filetype indent plugin on +syntax enable +set autoindent +set backspace=indent,eol,start +set hlsearch +set incsearch +set number + +" files.insertFinalNewline +set eol +set fixeol + +" editor.renderWhitespace: all +set list +set listchars=tab:->,trail:-,extends:>,precedes:<,nbsp:+ + +" editor.detectIndentation: false — global defaults (editor.tabSize: 4, insertSpaces: true) +set colorcolumn=76 +set expandtab +set shiftwidth=4 +set softtabstop=4 +set tabstop=4 + +" colorcolumn draws a full-column tint in Vim (not a VS Code-style 1px line). +" Keep it subtle via the ColorColumn highlight group; reapply after colorscheme changes. +if has('termguicolors') + " set termguicolors +endif + +function! s:ConfigureColorColumn() abort + highlight ColorColumn ctermbg=236 guibg=#2a2a2a cterm=NONE gui=NONE +endfunction + +call s:ConfigureColorColumn() +autocmd ColorScheme * call s:ConfigureColorColumn() + +" files.trimTrailingWhitespace +autocmd BufWritePre * %s/\s\+$//e + +augroup sis_c_cxx + autocmd! + + " [c] / [cpp] + autocmd FileType c,cpp setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=60,64,68,72,76 + + " [rust] + autocmd FileType rs setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=76 + + " [cmake] + autocmd FileType cmake setlocal noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 + + " [shellscript] + autocmd FileType sh,bash,zsh setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2 colorcolumn=60,76 + + " [bat] + autocmd FileType bat,dosbatch setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=60,76 + + " [json] / [markdown] / [yaml] / [ruby] + autocmd FileType json,markdown,yaml,ruby setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2 + + " [python] + autocmd FileType python setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=60,76 + + " [toml] + autocmd FileType toml setlocal noexpandtab tabstop=2 shiftwidth=2 softtabstop=2 +augroup END + diff --git a/.vscode/settings.json b/.vscode/settings.json index 2c808f7..4044afc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,18 +1,183 @@ { - "editor.detectIndentation": false, - "editor.insertSpaces": true, - "editor.tabSize": 4, - "files.associations": { - "format": "cpp", - "istream": "cpp", - "memory": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "utility": "cpp", - "xlocmes": "cpp", - "xlocmon": "cpp", - "xlocnum": "cpp", - "xloctime": "cpp", - "xutility": "cpp", - }, + "[bat]": { + "editor.insertSpaces": true, + "editor.rulers": [ 60, 76 ], + "editor.tabSize": 4, + }, + "[c]": { + "editor.insertSpaces": true, + "editor.rulers": [ 60, 64, 68, 72, 76 ], + "editor.tabSize": 4, + }, + "[cmake]": { + "editor.insertSpaces": false, + "editor.tabSize": 4, + }, + "[cpp]": { + "editor.insertSpaces": true, + "editor.rulers": [ 60, 64, 68, 72, 76 ], + "editor.tabSize": 4, + }, + "[json]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + }, + "[markdown]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + }, + "[python]": { + "diffEditor.ignoreTrimWhitespace": false, + "editor.insertSpaces": true, + "editor.rulers": [ 51, 60, 61, 76 ], + "editor.tabSize": 4, + }, + "[ruby]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + }, + "[shellscript]": { + "editor.insertSpaces": true, + "editor.rulers": [ 60, 76 ], + "editor.tabSize": 2, + }, + "[toml]": { + "editor.insertSpaces": false, + "editor.tabSize": 2, + }, + "[yaml]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + }, + "cmake.configureOnOpen": false, + "editor.detectIndentation": false, + "editor.insertSpaces": false, + "editor.renderWhitespace": "all", + "editor.rulers": [ 76 ], + "editor.tabSize": 2, + "files.associations": { + "__bit_reference": "cpp", + "__bits": "cpp", + "__config": "cpp", + "__debug": "cpp", + "__errc": "cpp", + "__functional_03": "cpp", + "__functional_base": "cpp", + "__hash_table": "cpp", + "__locale": "cpp", + "__memory": "cpp", + "__mutex_base": "cpp", + "__node_handle": "cpp", + "__nullptr": "cpp", + "__split_buffer": "cpp", + "__string": "cpp", + "__threading_support": "cpp", + "__tree": "cpp", + "__tuple": "cpp", + "__verbose_abort": "cpp", + "algorithm": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "bitset": "cpp", + "cctype": "cpp", + "charconv": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "complex": "cpp", + "concepts": "cpp", + "console_functions.h": "c", + "corecrt.h": "c", + "crtdefs.h": "c", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "exception": "cpp", + "execution": "cpp", + "fcntl.h": "c", + "format": "cpp", + "forward_list": "cpp", + "functional": "cpp", + "implicit_link.h": "c", + "initializer_list": "cpp", + "io.h": "c", + "iomanip": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "iterator": "cpp", + "limits": "cpp", + "list": "cpp", + "locale": "cpp", + "map": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "mutex": "cpp", + "new": "cpp", + "numbers": "cpp", + "numeric": "cpp", + "optional": "cpp", + "ostream": "cpp", + "queue": "cpp", + "random": "cpp", + "ranges": "cpp", + "ratio": "cpp", + "semaphore": "cpp", + "set": "cpp", + "setenv.h": "c", + "shwild.h": "c", + "span": "cpp", + "sstream": "cpp", + "stack": "cpp", + "stdexcept": "cpp", + "stdio.h": "c", + "stop_token": "cpp", + "streambuf": "cpp", + "string": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "terse-api.h": "c", + "text_encoding": "cpp", + "thread": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "typeinfo": "cpp", + "uio.h": "c", + "unixem.h": "c", + "unordered_map": "cpp", + "util.h": "c", + "utility": "cpp", + "variant": "cpp", + "vector": "cpp", + "xfacet": "cpp", + "xhash": "cpp", + "xiosbase": "cpp", + "xlocale": "cpp", + "xlocbuf": "cpp", + "xlocinfo": "cpp", + "xlocmes": "cpp", + "xlocmon": "cpp", + "xlocnum": "cpp", + "xloctime": "cpp", + "xmemory": "cpp", + "xstring": "cpp", + "xtests.internal.string.c": "cpp", + "xtr1common": "cpp", + "xtree": "cpp", + "xutility": "cpp", + }, + "files.insertFinalNewline": true, + "files.trimTrailingWhitespace": true, + "git.mergeEditor": false, } + diff --git a/AUTHORS.md b/AUTHORS.md new file mode 100644 index 0000000..d9b948a --- /dev/null +++ b/AUTHORS.md @@ -0,0 +1,17 @@ +# WriteDebugString - Authors + + +## Major Contributors: + +* Matt Wilson ([mwsis](https://github.com/mwsis)) + + +## Defect reports, fixes and suggestions (for which we are very grateful): + +* \ (yet) + + +Contributions are welcomed. + + + diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..eb8efd3 --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,16 @@ +# **WriteDebugString** Changes + + +## 0.0.1 - 3rd August 2026 + +* Initial CMake-based release (**CMakeLists.txt**, helper scripts, and project documentation); +* Added modular GitHub Actions CI (**ci.yml** / **ci-cell.yml**) for Windows (Windows-only tool); +* Added **cmake/BuildType.cmake**; +* Added CMake helper scripts (**prepare_cmake.sh**, **build_cmake.sh**, **clean_cmake.sh**, **remove_cmake_artefacts.sh**) and **run_all_unit_tests.cmd**; +* Added **.sis/script_info_lines.txt** and **.sis/project_name.txt**; +* Project boilerplate bootstrap (**.gitattributes**, **.gitignore**, **.vimrc**, **.vscode/settings.json**, **AUTHORS.md**, **LICENSE**, **README.md**, **INSTALL.md**, **REQUISITES.md**, **TODO.md**, **NEWS.md**); +* Added version macros, **--version**, and explicit **windows.h** include; +* Retired the broken nmake **Makefile**; + + + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..f05142a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,233 @@ +# ######################################################################## # +# File: /CMakeLists.txt +# +# Purpose: Top-level CMake lists file for WriteDebugString +# +# Created: 3rd August 2026 +# Updated: 3rd August 2026 +# +# ######################################################################## # + + +# ########################################################## +# CMake + +cmake_minimum_required(VERSION 3.20 FATAL_ERROR) + +# require out-of-source builds +file(TO_CMAKE_PATH "${CMAKE_CURRENT_BINARY_DIR}/CMakeLists.txt" LOC_PATH) +if(EXISTS "${LOC_PATH}") + + message(FATAL_ERROR "You cannot build in a source directory (or any directory with a CMakeLists.txt file). Please make a build subdirectory. Feel free to remove CMakeCache.txt and CMakeFiles.") +endif() + +# directory for CMake specific extensions and source files. +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) + + +# ########################################################## +# project + +project(WriteDebugString + DESCRIPTION "WriteDebugString is a Windows CLI that writes messages to the debugger via OutputDebugString." + HOMEPAGE_URL "https://github.com/sistools/WriteDebugString" + LANGUAGES C CXX +) + +string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWER) +string(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPER) + +# handle version number +set(RX_PROJ_TAG "${PROJECT_NAME_UPPER}") +set(RX_WS "[ \t]") +file(READ "${CMAKE_SOURCE_DIR}/main.c" _impl_file) +string(REGEX MATCH "#${RX_WS}*define${RX_WS}+_?${RX_PROJ_TAG}_VER_MAJOR${RX_WS}+([0-9]+)" MAJOR_DUMMY ${_impl_file}) +set(_VERSION_MAJOR ${CMAKE_MATCH_1}) +string(REGEX MATCH "#${RX_WS}*define${RX_WS}+_?${RX_PROJ_TAG}_VER_MINOR${RX_WS}+([0-9]+)" MINOR_DUMMY ${_impl_file}) +set(_VERSION_MINOR ${CMAKE_MATCH_1}) +string(REGEX MATCH "#${RX_WS}*define${RX_WS}+_?${RX_PROJ_TAG}_VER_PATCH${RX_WS}+([0-9]+)" PATCH_DUMMY ${_impl_file}) +set(_VERSION_PATCH ${CMAKE_MATCH_1}) + +# set project version number here +set(PROJECT_VERSION_MAJOR ${_VERSION_MAJOR}) +set(PROJECT_VERSION_MINOR ${_VERSION_MINOR}) +set(PROJECT_VERSION_PATCH ${_VERSION_PATCH}) +set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") + +# adhere strictly to C and C++ standards plus extensions. These are actually +# useless since we do not compile anything; they merely state our intention. +set(CMAKE_C_STANDARD 17) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_EXTENSIONS ON) # GNU extensions and POSIX standard +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS ON) + +if(MSVC) + + if(MSVC_VERSION GREATER_EQUAL 1914) + + add_compile_options("/Zc:__cplusplus") + + add_definitions(-D_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING) + endif() + + if(MSVC_VERSION LESS 1930) + + set(CMAKE_C_STANDARD 90) + set(CMAKE_CXX_STANDARD 98) + endif() + + if(MSVC_USE_MT) + + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + endif(MSVC_USE_MT) +else(MSVC) + + if(MSVC_USE_MT) + + # this here just to absorb warning about not using `MSVC_USE_MT` (to + # enable **prepare_cmake.sh** to be simple) + endif(MSVC_USE_MT) +endif(MSVC) + + +# ########################################################## +# dependencies, includes, options + +# ################################################ +# includes - 1 + +include(BuildType) +#[====[ +include(LanguageFullVersion) +include(TargetMacros) +#]====] + + +# ################################################ +# dependencies, features, and options + + +# ###################################### +# options + +option(BUILD_EXAMPLES "Build examples" ON) + +option(BUILD_TESTING "Build tests" ON) + + +# ###################################### +# features + +# This tool targets Windows only (WinSTL). +if(NOT WIN32) + + message(FATAL_ERROR "${PROJECT_NAME} targets Windows only") +endif() + + +# ###################################### +# dependencies +# +# required: +# - STLSoft; +# +# required if testing enabled: +# - (none); +# +# optional: + + +# ############################ +# STLSoft + +if(DEFINED STLSOFT) + + message("-- STLSOFT provided as CMake variable with value '${STLSOFT}'") + + set(STLSOFT_INCLUDE_DIR ${STLSOFT}/include) +elseif(DEFINED ENV{STLSOFT}) + + message("-- STLSOFT provided as environment variable with value '$ENV{STLSOFT}'") + + set(STLSOFT_INCLUDE_DIR $ENV{STLSOFT}/include) +else() + + set(STLSoft_REQUIRED_VERSION_ 1.11.1) + + find_package(STLSoft ${STLSoft_REQUIRED_VERSION_} REQUIRED) + + message("-- CMake package STLSoft found (version ${STLSoft_VERSION}; ${STLSoft_REQUIRED_VERSION_} requested)") +endif() + +if(DEFINED STLSOFT_INCLUDE_DIR) + + include_directories(${STLSOFT_INCLUDE_DIR}) +endif() + + +# ################################################ +# includes - 2 + +include(CMakePackageConfigHelpers) +if(BUILD_TESTING) + + include(CTest) +endif(BUILD_TESTING) +include(GNUInstallDirs) + + +# ########################################################## +# tool + +add_executable(${PROJECT_NAME} + main.c +) + +target_compile_options(${PROJECT_NAME} + PRIVATE + $<$,$,$>: + -Werror -Wall -Wextra -pedantic + + -Wno-ignored-qualifiers + -Wno-incompatible-pointer-types-discards-qualifiers + -Wno-unused-parameter + > + $<$: + /WX /W4 + > +) + +target_link_libraries(${PROJECT_NAME} + $<$:STLSoft::STLSoft> +) + +install(TARGETS ${PROJECT_NAME} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) + + +# ################################################ +# examples + + +# ################################################ +# tests + +if(BUILD_TESTING) + + message("-- enabled building of tests ...") +else(BUILD_TESTING) + + message("-- disabled building of tests - define BUILD_TESTING to enable") +endif(BUILD_TESTING) + + +# ########################################################## +# completion + +message(NOTICE "Generating CMake build scripts for ${PROJECT_NAME} ${PROJECT_VERSION}, for C${CMAKE_C_STANDARD} C++${CMAKE_CXX_STANDARD}") + + +# ############################## end of file ############################# # diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000..b40e426 --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,84 @@ +# WriteDebugString - Installation and Use + + +- [Requisites](#requisites) +- [Building](#building) + - [via CMake](#via-cmake) + + +## Requisites + +The **WriteDebugString** program (implemented in [**main.c**](./main.c)) is implemented in terms of: + +* [**STLSoft**](https://github.com/synesissoftware/STLSoft) - for WinSTL diagnostics helpers and platform utilities; + +Detailed instructions are provided in the [**REQUISITES.md**](./REQUISITES.md) document for how to obtain and install **STLSoft**. + +> **NOTE**: **WriteDebugString** targets Windows only. + + +## Building + + +### via CMake + +The primary choice for installation is by use of **CMake**. + +1. Obtain the latest distribution of **WriteDebugString**, from + https://github.com/sistools/WriteDebugString/, e.g. + + ```bash + $ mkdir -p ~/open-source + $ cd ~/open-source + $ git clone https://github.com/sistools/WriteDebugString/ + ``` + +2. Prepare the CMake configuration, via the **prepare_cmake.sh** script, as + in: + + ```bash + $ cd ~/open-source/WriteDebugString + $ ./prepare_cmake.sh + ``` + + **NOTE**: if you do not have **STLSoft** installed via **CMake** package + config, point at a local tree with `-s` / `--stlsoft-root-dir`, or set the + **STLSOFT** environment variable. + + Tests are currently a no-op for this project; you may disable the testing + option with `-T` if desired: + + ```bash + $ cd ~/open-source/WriteDebugString + $ ./prepare_cmake.sh -T + ``` + +3. Run a build of the generated **CMake**-derived build files via the + **build_cmake.sh** script, as in: + + ```bash + $ cd ~/open-source/WriteDebugString + $ ./build_cmake.sh + ``` + + (**NOTE**: if you provide the flag `--run-make` (=== `-m`) in step 2 then you do + not need this step.) + +4. As a check, execute the built program, as in: + + ```bash + $ cd ~/open-source/WriteDebugString + $ ./_build/WriteDebugString.exe --help + ``` + + You should see usage output naming **WriteDebugString**. + +5. Install (optional), as in: + + ```bash + $ cd ~/open-source/WriteDebugString + $ cmake --install ./_build --config Release + ``` + + + diff --git a/LICENSE b/LICENSE index a753d5b..e9f5dfb 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ WriteDebugString - BSD 3-Clause License -Copyright (c) 2025, sistools +Copyright (c) 2025-2026, Synesis Information Systems All rights reserved. Redistribution and use in source and binary forms, with or without @@ -28,4 +28,3 @@ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/NEWS.md b/NEWS.md new file mode 100644 index 0000000..db8f646 --- /dev/null +++ b/NEWS.md @@ -0,0 +1,9 @@ +# WriteDebugString - News + + +| Date | News Item | +| -------------------- | -------------------------------------------------- | +| 3rd August 2026 | 0.0.1 released | + + + diff --git a/README.md b/README.md index 43ae8ed..ef5ffb6 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,89 @@ # WriteDebugString -[![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg) +Windows CLI that writes messages to the debugger via **OutputDebugString** -Simple Windows CLI program that permits writing to the Windows debugger + +![C](https://img.shields.io/badge/C-00599C?style=flat&logo=c&logoColor=white) +[![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) +[![GitHub release](https://img.shields.io/github/v/release/sistools/WriteDebugString.svg)](https://github.com/sistools/WriteDebugString/releases/latest) +[![Last Commit](https://img.shields.io/github/last-commit/sistools/WriteDebugString)](https://github.com/sistools/WriteDebugString/commits/master) +[![CI](https://github.com/sistools/WriteDebugString/actions/workflows/ci.yml/badge.svg)](https://github.com/sistools/WriteDebugString/actions/workflows/ci.yml) ## Table of Contents +- [Introduction](#introduction) +- [Installation](#installation) +- [Components](#components) +- [Examples](#examples) +- [Project Information](#project-information) + - [Where to get help](#where-to-get-help) + - [Contribution guidelines](#contribution-guidelines) + - [Dependencies](#dependencies) + - [Related projects](#related-projects) + - [License](#license) + ## Introduction +**WriteDebugString** is a small Windows-only utility that writes one or more +messages to the Windows debug output stream (as consumed by debuggers and +tools such as DebugView), using **STLSoft**/**WinSTL** helpers. - +## Installation + +Detailed instructions - via **CMake** - are provided in the accompanying +[INSTALL.md](./INSTALL.md) file. + + +## Components + +The project creates a single executable program, **WriteDebugString**. + + +## Examples + +```plaintext +> WriteDebugString.exe hello world +wrote 2 message(s) to debug stream + +> WriteDebugString.exe --sleep-after-writes "hold for listener" +wrote 1 message(s) to debug stream +``` + + +## Project Information + + +### Where to get help + +[GitHub Page](https://github.com/sistools/WriteDebugString "GitHub Page") + + +### Contribution guidelines + +Defect reports, feature requests, and pull requests are welcome on [the **WriteDebugString** GitHub page](https://github.com/sistools/WriteDebugString). + + +### Dependencies + +**WriteDebugString** depends on: + +* [**STLSoft**](https://github.com/synesissoftware/STLSoft); + + +### Related projects + +Other (similar) projects include: + +* [**ReadDebugString**](https://github.com/sistools/ReadDebugString) +* [**realpath**](https://github.com/sistools/realpath) + + +### License + +**WriteDebugString** is released under the 3-clause BSD license. See [LICENSE](./LICENSE) for details. + + + diff --git a/REQUISITES.md b/REQUISITES.md new file mode 100644 index 0000000..8dd9a95 --- /dev/null +++ b/REQUISITES.md @@ -0,0 +1,45 @@ +# WriteDebugString - Requisites + + +- [Introduction](#introduction) +- [Installation by CMake](#installation-by-cmake) + - [STLSoft](#stlsoft) +- [Installation by other means](#installation-by-other-means) + + +## Introduction + +The **WriteDebugString** program (implemented in [**main.c**](./main.c)) is implemented in terms of: + +* [**STLSoft**](https://github.com/synesissoftware/STLSoft) - for WinSTL diagnostics helpers and platform utilities; + +> **NOTE**: **WriteDebugString** is a Windows-only tool. + + +## Installation by CMake + + +### STLSoft + +The **STLSoft** libraries provide a wide range of compiler/library discrimination and compatibility facilities, operating system API façades, and a number of extended components over and above what is provided in the standard library. + +**STLSoft** is obtained from **https://github.com/synesissoftware/STLSoft**, and it provides the means to install via **CMake**, as in the following: + +```bash +$ mkdir -p ~/open-source +$ cd ~/open-source +$ git clone https://github.com/synesissoftware/STLSoft +$ cd ~/open-source/STLSoft +$ ./prepare_cmake.sh -m +$ cmake --install ./_build --config Release +``` + +Alternatively, set the **STLSOFT** environment variable (or pass `-DSTLSOFT=...` / `./prepare_cmake.sh -s ...`) to a local checkout that contains an `include/` directory. + + +## Installation by other means + +If you do not use **CMake** to install **STLSoft**, ensure the headers are available via the **STLSOFT** environment variable (pointing at the library root) before configuring this project. + + + diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..db2ba1d --- /dev/null +++ b/TODO.md @@ -0,0 +1,10 @@ +# WriteDebugString - TODO list + + +## WriteDebugString 0.0.x TODOs: + +* Consider promoting from ad-hoc argv parsing toward **CLASP** later (optional; **realpath** stays manual); +* Set GitHub repository topics: `c`, `cli`, `command-line`, `cmake`, `stlsoft`, `windows`, `win32`, `debugging`, `debugger`, `outputdebugstring`, `bsd-3-clause`, `sistools`; + + + diff --git a/build_cmake.sh b/build_cmake.sh new file mode 100755 index 0000000..cca1448 --- /dev/null +++ b/build_cmake.sh @@ -0,0 +1,130 @@ +#! /bin/bash + +ScriptPath=$0 +Dir=$(cd $(dirname "$ScriptPath"); pwd) +Basename=$(basename "$ScriptPath") +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +if [[ -n "$MSYSTEM" ]]; then + + DefaultMakeCmd=mingw32-make.exe + MinGW=1 +else + + DefaultMakeCmd=make +fi +MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} + +IgnoreRemainingFlagsAndOptions=0 +Targets=() + + +# ########################################################## +# functions + +function join_by { local IFS="$1"; shift; echo "$*"; } + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + if [ $IgnoreRemainingFlagsAndOptions -ne 0 ]; then + + Targets+=($1) + + shift + + continue + else + + if [ ! ${1:0:1} = '-' ]; then + + Targets+=($1) + + shift + + continue + fi + fi + + case $1 in + --) + + IgnoreRemainingFlagsAndOptions=1 + ;; + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Executes CMake-generated artefacts to (re)build project + +$ScriptPath [ ... flags/options ... ] + +Flags/options: + + behaviour: + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + + exit 1 + ;; + esac + + shift +done + + +# ########################################################## +# main() + +if [ ! -d "$CMakeDir" ]; then + + >&2 echo "$ScriptPath: CMake build directory '$CMakeDir' not found so nothing to do; use script 'prepare_cmake.sh' if you wish to prepare CMake artefacts" + + exit 1 +else + + cd $CMakeDir + + if [ ! -f "$CMakeDir/Makefile" ]; then + + >&2 echo "$ScriptPath: CMake build directory '$CMakeDir' does not contain expected file 'Makefile', so a clean cannot be performed. It is recommended that you remove all CMake artefacts using script 'remove_cmake_artefacts.sh' followed by regeneration via 'prepare_cmake.sh'" + + cd ->/dev/null + + exit 1 + else + + if [ -z "$Targets" ]; then + + echo "Executing build (via command \`$MakeCmd\`)" + else + + echo "Executing build (via command \`$MakeCmd\`) with specific target(s) $(join_by , "${Targets[@]}")" + fi + + $MakeCmd ${Targets[*]} + status=$? + + cd ->/dev/null + + exit $status + fi +fi + + +# ############################## end of file ############################# # + diff --git a/clean_cmake.sh b/clean_cmake.sh new file mode 100755 index 0000000..886a201 --- /dev/null +++ b/clean_cmake.sh @@ -0,0 +1,92 @@ +#! /bin/bash + +ScriptPath=$0 +Dir=$(cd $(dirname "$ScriptPath"); pwd) +Basename=$(basename "$ScriptPath") +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +if [[ -n "$MSYSTEM" ]]; then + + DefaultMakeCmd=mingw32-make.exe + MinGW=1 +else + + DefaultMakeCmd=make +fi +MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + case $1 in + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Executes CMake-generated artefacts to clean project + +$ScriptPath [ ... flags/options ... ] + +Flags/options: + + behaviour: + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + + exit 1 + ;; + esac + + shift +done + + +# ########################################################## +# main() + +if [ ! -d "$CMakeDir" ]; then + + >&2 echo "$ScriptPath: CMake build directory '$CMakeDir' not found so nothing to do; use script 'prepare_cmake.sh' if you wish to prepare CMake artefacts" + + exit 1 +else + + cd $CMakeDir + + if [ ! -f "$CMakeDir/Makefile" ]; then + + >&2 echo "$ScriptPath: CMake build directory '$CMakeDir' does not contain expected file 'Makefile', so a clean cannot be performed. It is recommended that you remove all CMake artefacts using script 'remove_cmake_artefacts.sh' followed by regeneration via 'prepare_cmake.sh'" + + cd ->/dev/null + + exit 1 + else + + echo "Cleaning build (via command \`$MakeCmd clean\`)" + + $MakeCmd clean + status=$? + + cd ->/dev/null + + exit $status + fi +fi + + +# ############################## end of file ############################# # + diff --git a/cmake/BuildType.cmake b/cmake/BuildType.cmake new file mode 100644 index 0000000..a315b8d --- /dev/null +++ b/cmake/BuildType.cmake @@ -0,0 +1,59 @@ + +# ######################################################################## # +# File: /cmake/BuildType.cmake +# +# Purpose: CMake module file (for BuildType) +# +# Created: 16th October 2019 +# Updated: 25th October 2024 +# +# ######################################################################## # + + +# Including this module sets the `CMAKE_BUILD_TYPE` value as follows: +# +# 1. If user specifies on the command line, then `CMAKE_BUILD_TYPE` already +# has a valid, so this is accepted; +# 2. If the top-level .git directory is specified, then "Debug" is used; +# otherwise +# 3. "Release" is used. +# +# Note: +# - `CMAKE_BUILD_TYPE` is the build (configuration) type; +# - `CMAKE_CONFIGURATION_TYPES` is, if specified, a list of valid +# configurations (see +# https://cmake.org/cmake/help/latest/variable/CMAKE_CONFIGURATION_TYPES.html); +# +# Example usage: +# +#[========[ + +# CMakeLists.txt + +include(BuildType) + +]========] + + +if(EXISTS "${CMAKE_SOURCE_DIR}/.git") + set(DEFAULT_BUILD_TYPE "Debug") +else() + set(DEFAULT_BUILD_TYPE "Release") +endif() + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + + message(STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.") + + set(CACHE CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" + STRING "Choose the type of build." FORCE + ) + + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Release" "MinSizeRel" "RelWithDebInfo" + ) +endif() + +# ############################## end of file ############################# # + diff --git a/main.c b/main.c index e1e8c0d..352921c 100644 --- a/main.c +++ b/main.c @@ -1,11 +1,25 @@ -#include +#include + +#if _STLSOFT_VER < 0x010b0184 +# error requires STLSoft v1.11.1-b4 or later +#endif + #include +#include + +#include #include #include #include + +#define WRITEDEBUGSTRING_VER_MAJOR 0 +#define WRITEDEBUGSTRING_VER_MINOR 0 +#define WRITEDEBUGSTRING_VER_PATCH 1 + + int main(int argc, char* argv[]) { stlsoft_C_string_slice_m_t const program_name = platformstl_C_get_executable_name_from_path(argv[0]); @@ -27,8 +41,22 @@ int main(int argc, char* argv[]) { fprintf( stdout - , "USAGE: %.*s { --help | [ --sleep-after-writes ] [ ... ] }\n" + , "USAGE: %.*s { --help | --version | [ --sleep-after-writes ] [ ... ] }\n" + , (int)program_name.len, program_name.ptr + ); + + return EXIT_SUCCESS; + } + else + if (0 == strcmp("--version", argv[1])) + { + fprintf( + stdout + , "%.*s %d.%d.%d\n" , (int)program_name.len, program_name.ptr + , WRITEDEBUGSTRING_VER_MAJOR + , WRITEDEBUGSTRING_VER_MINOR + , WRITEDEBUGSTRING_VER_PATCH ); return EXIT_SUCCESS; @@ -42,7 +70,7 @@ int main(int argc, char* argv[]) { char const* const arg = argv[i]; - if (0 == strcmp("--sleep-after-writes", argv[i])) + if (0 == strcmp("--sleep-after-writes", arg)) { do_sleep = 1; } @@ -69,4 +97,3 @@ int main(int argc, char* argv[]) return EXIT_SUCCESS; } } - diff --git a/prepare_cmake.sh b/prepare_cmake.sh new file mode 100755 index 0000000..d837045 --- /dev/null +++ b/prepare_cmake.sh @@ -0,0 +1,186 @@ +#! /bin/bash + +ScriptPath=$0 +Dir=$(cd $(dirname "$ScriptPath"); pwd) +Basename=$(basename "$ScriptPath") +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +if [[ -n "$MSYSTEM" ]]; then + + DefaultMakeCmd=mingw32-make.exe + MinGW=1 +else + + DefaultMakeCmd=make +fi +MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} + +Configuration=Release +MSVC_MT=0 +MinGW="${MinGW:=0}" +RunMake=0 +STLSoftDirGiven= +TestingDisabled=0 +VerboseMakefile=0 + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + case $1 in + --cmake-verbose-makefile|-v) + + VerboseMakefile=1 + ;; + --debug-configuration|-d) + + Configuration=Debug + ;; + --disable-testing|-T) + + TestingDisabled=1 + ;; + --mingw) + + MinGW=1 + ;; + --msvc-mt) + + MSVC_MT=1 + ;; + --run-make|-m) + + RunMake=1 + ;; + --stlsoft-root-dir|-s) + + shift + STLSoftDirGiven=$1 + ;; + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Creates/reinitialises the CMake build script(s) + +$ScriptPath [ ... flags/options ... ] + +Flags/options: + + behaviour: + + -v + --cmake-verbose-makefile + configures CMake to run verbosely (by setting CMAKE_VERBOSE_MAKEFILE + to be ON) + + -d + --debug-configuration + use Debug configuration (by setting CMAKE_BUILD_TYPE=Debug). Default + is to use Release + + -T + --disable-testing + disables building of tests (by setting BUILD_TESTING=OFF) + + --mingw + uses explicitly the "MinGW Makefiles" generator, and defaults the + make-command to "mingw32-make.exe" + + --msvc-mt + when using Visual C++ (MSVC), the static runtime library will be + selected; the default is the dynamic runtime library + + -m + --run-make + executes make after a successful running of CMake + + -s + --stlsoft-root-dir + specifies the STLSoft root-directory, which will be passed to CMake + as the variable STLSOFT, and which will override the environment + variable STLSOFT (if present) + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + + exit 1 + ;; + esac + + shift +done + + +# ########################################################## +# main() + +mkdir -p $CMakeDir || exit 1 + +cd $CMakeDir + +echo "Executing CMake (in ${CMakeDir})" + +if [ $MSVC_MT -eq 0 ]; then CMakeMsvcMtFlag="OFF" ; else CMakeMsvcMtFlag="ON" ; fi +if [ -z $STLSoftDirGiven ]; then CMakeSTLSoftVariable="" ; else CMakeSTLSoftVariable="-DSTLSOFT=$STLSoftDirGiven/" ; fi +if [ $TestingDisabled -eq 0 ]; then CMakeBuildTestingFlag="ON" ; else CMakeBuildTestingFlag="OFF" ; fi +if [ $VerboseMakefile -eq 0 ]; then CMakeVerboseMakefileFlag="OFF" ; else CMakeVerboseMakefileFlag="ON" ; fi + +if [ $MinGW -ne 0 ]; then + + cmake \ + $CMakeSTLSoftVariable \ + -DBUILD_TESTING:BOOL=$CMakeBuildTestingFlag \ + -DCMAKE_BUILD_TYPE=$Configuration \ + -G "MinGW Makefiles" \ + -S $Dir \ + -B $CMakeDir \ + || (cd ->/dev/null ; exit 1) +else + + cmake \ + $CMakeSTLSoftVariable \ + -DBUILD_TESTING:BOOL=$CMakeBuildTestingFlag \ + -DCMAKE_BUILD_TYPE=$Configuration \ + -DCMAKE_VERBOSE_MAKEFILE:BOOL=$CMakeVerboseMakefileFlag \ + -DMSVC_USE_MT:BOOL=$CMakeMsvcMtFlag \ + -S $Dir \ + -B $CMakeDir \ + || (cd ->/dev/null ; exit 1) +fi + +status=0 + +if [ $RunMake -ne 0 ]; then + + echo "Executing build (via command \`$MakeCmd\`)" + + $MakeCmd + status=$? +fi + +cd ->/dev/null + +if [ $VerboseMakefile -ne 0 ]; then + + echo -e "contents of $CMakeDir:" + ls -al $CMakeDir +fi + +exit $status + + +# ############################## end of file ############################# # + diff --git a/remove_cmake_artefacts.sh b/remove_cmake_artefacts.sh new file mode 100755 index 0000000..7416db9 --- /dev/null +++ b/remove_cmake_artefacts.sh @@ -0,0 +1,151 @@ +#! /bin/bash + +ScriptPath=$0 +Dir=$(cd $(dirname "$ScriptPath"); pwd) +Basename=$(basename "$ScriptPath") +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} + +Directories=( + CMakeFiles + Testing + cmake + examples + projects + src + test +) +Files=( + CMakeCache.txt + CTestTestfile.cmake + DartConfiguration.tcl + Makefile + cmake_install.cmake + install_manifest.txt +) + + +# ########################################################## +# operating environment detection + +OsName="$(uname -s)" +case "${OsName}" in + CYGWIN*|MINGW*|MSYS_NT*) + + Directories+=( + ARM64 + Win32 + x64 + ) + Files+=( + "*.filters" + "*.sln" + "*.vcxproj" + ) + ;; + *) + + ;; +esac + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + case $1 in + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Removes all known CMake artefacts + +$ScriptPath [ ... flags/options ... ] + +Flags/options: + + behaviour: + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + + exit 1 + ;; + esac + + shift +done + + +# ########################################################## +# main() + +if [ ! -d "$CMakeDir" ]; then + + echo "$ScriptPath: CMake build directory '$CMakeDir' not found so nothing to do; use script 'prepare_cmake.sh' if you wish to prepare CMake artefacts" + + exit 0 +else + + echo "Removing all cmake artefacts in '$CMakeDir'" + + num_dirs_removed=0 + num_files_removed=0 + + for d in ${Directories[@]} + do + + fq_dir_path="$CMakeDir/$d" + + [ -d "$fq_dir_path" ] || continue + + echo "removing directory '$d'" + + rm -dfr "$fq_dir_path" + + num_dirs_removed=$((num_dirs_removed+1)) + done + + cd "$CMakeDir" + + for f in ${Files[@]} + do + + for fq_file_path in $f + do + + [ -f "$fq_file_path" ] || continue + + echo "removing file '$fq_file_path'" + + rm -f "$fq_file_path" + + num_files_removed=$((num_files_removed+1)) + done + done + + cd ->/dev/null + + if [ 0 -eq $num_dirs_removed ] && [ 0 -eq $num_files_removed ]; then + + echo "nothing to do" + else + + echo "removed $num_dirs_removed directories and $num_files_removed files" + fi +fi + + +# ############################## end of file ############################# # + diff --git a/run_all_unit_tests.cmd b/run_all_unit_tests.cmd new file mode 100644 index 0000000..8c88eae --- /dev/null +++ b/run_all_unit_tests.cmd @@ -0,0 +1,141 @@ +@echo off + +SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION + +SET SCRIPT_DIRECTORY=%~dp0 +SET SCRIPT_PATH_DOC=%~n0[%~x0] +IF DEFINED SIS_CMAKE_BUILD_DIR ( + + SET "CMAKE_DIR=%SIS_CMAKE_BUILD_DIR%" +) ELSE ( + + SET "CMAKE_DIR=%SCRIPT_DIRECTORY%_build" +) + +SET ListOnly=0 +SET Verbose=0 +SET status=0 + +FOR %%a IN (%*) DO ( + IF /I {--help}=={%%a} ( + IF EXIST "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" ( + + type "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" + ) + ECHO ^ + +Runs all ^(matching^) component and unit test programs ^ + +^ + +%SCRIPT_PATH_DOC% [ ... flags/options ... ] ^ + +^ + +Flags/options: ^ + + behaviour: ^ + +^ + + -l ^ + + --list-only ^ + + lists the target programs but does not execute them ^ + +^ + + -M ^ + + --no-make ^ + + accepted for parity with the .sh script ^(build is not invoked^) ^ + +^ + + -v ^ + + --verbose ^ + + lists each test program before executing it ^ + +^ + + standard flags: ^ + +^ + + --help ^ + + displays this help and terminates ^ + + + EXIT /B 0 + ) ELSE IF /I {-l}=={%%a} ( + SET ListOnly=1 + ) ELSE IF /I {--list-only}=={%%a} ( + SET ListOnly=1 + ) ELSE IF /I {-M}=={%%a} ( + REM no-op: this .cmd never invokes the build + ) ELSE IF /I {--no-make}=={%%a} ( + REM no-op: this .cmd never invokes the build + ) ELSE IF /I {-v}=={%%a} ( + SET Verbose=1 + ) ELSE IF /I {--verbose}=={%%a} ( + SET Verbose=1 + ) ELSE ( + ECHO %SCRIPT_PATH_DOC%: unrecognised argument '%%a'; use --help for usage 1>&2 + + EXIT /B 1 + ) +) + +IF NOT EXIST "%CMAKE_DIR%" ( + + ECHO %SCRIPT_PATH_DOC%: CMake build directory '%CMAKE_DIR%' does not exist 1>&2 + + EXIT /B 1 +) + +SET "ProjectName=" +FOR /F "usebackq delims=" %%p IN ("%SCRIPT_DIRECTORY%.sis\project_name.txt") DO SET "ProjectName=%%p" + +IF NOT DEFINED ProjectName ( + + ECHO %SCRIPT_PATH_DOC%: could not read project name from .sis\project_name.txt 1>&2 + + EXIT /B 1 +) + +IF !ListOnly! EQU 1 ( + + ECHO Listing all component and unit test programs +) ELSE ( + + ECHO Running all component and unit test programs +) + +FOR /F "usebackq delims=" %%f IN (`DIR /A:-D /B /S "%CMAKE_DIR%\*.exe" 2^>NUL ^| FINDSTR /I /R "!ProjectName!.*test.*\.exe$"`) DO ( + IF !ListOnly! EQU 1 ( + + ECHO would execute %%f: + ) ELSE ( + + IF !Verbose! EQU 1 ( + + ECHO executing %%f: + ) + + "%%f" + IF ERRORLEVEL 1 ( + + SET status=1 + + GOTO :done + ) + ) +) + +:done +EXIT /B !status!