From 34126c21a202543f7cc7a335f4a0e338c8b303c7 Mon Sep 17 00:00:00 2001 From: William McVicar <12842622+McMassiveNZ@users.noreply.github.com> Date: Thu, 4 May 2023 22:33:04 +0200 Subject: [PATCH] Initial commit --- .clang-format | 148 ++++++++++++++++++++++++ .github/workflows/auto-clang-format.yml | 23 ++++ .github/workflows/ci.yml | 117 +++++++++++++++++++ .gitignore | 40 +++++++ .gitmodules | 3 + CMakeLists.txt | 28 +++++ LICENSE | 24 ++++ README.md | 4 + external/vcpkg | 1 + scripts/.clang-tidy | 19 +++ scripts/cmake/compilerwarnings.cmake | 106 +++++++++++++++++ scripts/cmake/googletest.cmake | 18 +++ scripts/cmake/precompiled.cmake | 8 ++ scripts/cmake/sanitizers.cmake | 20 ++++ scripts/cmake/staticanalysis.cmake | 16 +++ src/CMakeLists.txt | 47 ++++++++ src/main.cpp | 20 ++++ src/platform/null_window.cpp | 28 +++++ src/platform/win32_window.cpp | 132 +++++++++++++++++++++ src/window.h | 27 +++++ test/CMakeLists.txt | 14 +++ test/test_main.cpp | 6 + 22 files changed, 849 insertions(+) create mode 100644 .clang-format create mode 100644 .github/workflows/auto-clang-format.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 CMakeLists.txt create mode 100644 LICENSE create mode 100644 README.md create mode 160000 external/vcpkg create mode 100644 scripts/.clang-tidy create mode 100644 scripts/cmake/compilerwarnings.cmake create mode 100644 scripts/cmake/googletest.cmake create mode 100644 scripts/cmake/precompiled.cmake create mode 100644 scripts/cmake/sanitizers.cmake create mode 100644 scripts/cmake/staticanalysis.cmake create mode 100644 src/CMakeLists.txt create mode 100644 src/main.cpp create mode 100644 src/platform/null_window.cpp create mode 100644 src/platform/win32_window.cpp create mode 100644 src/window.h create mode 100644 test/CMakeLists.txt create mode 100644 test/test_main.cpp diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..5c8ef4d --- /dev/null +++ b/.clang-format @@ -0,0 +1,148 @@ +--- +Language: Cpp +AccessModifierOffset: -4 +AlignAfterOpenBracket: DontAlign +AlignConsecutiveAssignments: false +AlignConsecutiveBitFields: false +AlignConsecutiveDeclarations: false +AlignConsecutiveMacros: false +AlignEscapedNewlines: DontAlign +AlignOperands: Align +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: Empty +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: Always + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true + BeforeLambdaBody: true + BeforeWhile: true + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakAfterJavaFieldAnnotations: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: false +BreakConstructorInitializers: BeforeComma +BreakInheritanceList: BeforeComma +BreakStringLiterals: false +ColumnLimit: 0 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth : 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: false +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"Precompiled.hpp"' + Priority: 0 + SortPriority: -1 + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + - Regex: '.*' + Priority: 1 + SortPriority: 0 +IncludeIsMainRegex: '(_Test)?$' +IncludeIsMainSourceRegex: '' +IndentCaseBlocks: false +IndentCaseLabels: true +IndentExternBlock: NoIndent +IndentGotoLabels: true +IndentPPDirectives: None +IndentWidth: 4 +IndentWrappedFunctionNames: true +InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 60 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Left +ReflowComments: true +SortIncludes: false +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: c++20 +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 4 +TypenameMacros: [] +UseCRLF: true +UseTab: Always +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE \ No newline at end of file diff --git a/.github/workflows/auto-clang-format.yml b/.github/workflows/auto-clang-format.yml new file mode 100644 index 0000000..fb75b76 --- /dev/null +++ b/.github/workflows/auto-clang-format.yml @@ -0,0 +1,23 @@ +name: auto-clang-format +on: [pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - uses: DoozyX/clang-format-lint-action@v0.13 + with: + source: '.' + exclude: './third_party ./external' + extensions: 'h,cpp,hpp' + clangFormatVersion: 13 + inplace: True + - uses: EndBug/add-and-commit@v4 + with: + author_name: Clang Robot + author_email: robot@example.com + message: ':art: Committing clang-format changes' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..3738a6c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,117 @@ +name: CI + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +env: + CLANG_TIDY_VERSION: "13.0.0" + +jobs: + build: + runs-on: ${{matrix.os}} + strategy: + fail-fast: false + matrix: + os: [windows-latest, ubuntu-latest, macos-latest] + build_configuration: [Debug, Release] + compiler: [llvm, gcc] + vcpkg_bootstrap: [bootstrap-vcpkg.sh] + + exclude: + - os: windows-latest + vcpkg_bootstrap: bootstrap-vcpkg.sh + + include: + - os: 'windows-latest' + triplet: x64-windows + vcpkg_bootstrap: bootstrap-vcpkg.bat + compiler: llvm + build_configuration: Debug + + - os: 'windows-latest' + triplet: x64-windows + vcpkg_bootstrap: bootstrap-vcpkg.bat + compiler: llvm + build_configuration: Release + + - os: 'windows-latest' + triplet: x64-windows + vcpkg_bootstrap: bootstrap-vcpkg.bat + compiler: gcc + build_configuration: Debug + + - os: 'windows-latest' + triplet: x64-windows + vcpkg_bootstrap: bootstrap-vcpkg.bat + compiler: gcc + build_configuration: Release + + - os: 'windows-latest' + triplet: x64-windows + vcpkg_bootstrap: bootstrap-vcpkg.bat + compiler: msvc + build_configuration: Debug + + - os: 'windows-latest' + triplet: x64-windows + vcpkg_bootstrap: bootstrap-vcpkg.bat + compiler: msvc + build_configuration: Release + + - os: 'ubuntu-latest' + triplet: x64-linux + + - os: 'macos-latest' + triplet: x64-osx + + steps: + - name: checkout + uses: actions/checkout@v3 + with: + submodules: true + + - name: cache + uses: actions/cache@v3 + with: + path: | + ~/vcpkg + ./build/vcpkg_installed + ${{ env.HOME }}/.cache/vcpkg/archives + ${{ env.XDG_CACHE_HOME }}/vcpkg/archives + ${{ env.LOCALAPPDATA }}\vcpkg\archives + ${{ env.APPDATA }}\vcpkg\archives + key: ${{ runner.os }}-${{ matrix.compiler }}-${{ matrix.build_configuration }}-${{ hashFiles('**/CMakeLists.txt') }}-${{ hashFiles('./vcpkg.json')}} + restore-keys: | + ${{ runner.os }}-${{ matrix.build_configuration }}- + + - name: setup dependencies + uses: aminya/setup-cpp@v1 + with: + compiler: ${{ matrix.compiler }} + vcvarsall: ${{ contains(matrix.os, 'windows')}} + cmake: true + vcpkg: true + ccache: true + clangtidy: ${{ env.CLANG_TIDY_VERSION }} + cppcheck: true + + - name: Boostrap Vcpkg + run: ${{github.workspace}}/external/vcpkg/${{matrix.vcpkg_bootstrap}} -disableMetrics + + - name: Install packaged dependencies + run: ${{github.workspace}}/external/vcpkg/vcpkg install spdlog --triplet ${{matrix.triplet}} + + - name: Configure CMake + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{matrix.build_configuration}} + -DCMAKE_TOOLCHAIN_FILE=${{github.workspace}}/external/vcpkg/scripts/buildsystems/vcpkg.cmake + + - name: Build + run: cmake --build ${{github.workspace}}/build --config ${{matrix.build_configuration}} + + - name: Test + working-directory: ${{github.workspace}}/build + run: ctest -C ${{matrix.build_configuration}} + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4a7e2fa --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# MSVC Specific +*.pdb +*.exp + +build/ +.vs/ +Testing/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..cda8672 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "external/vcpkg"] + path = external/vcpkg + url = https://github.com/Microsoft/vcpkg.git diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..a5c9ec4 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.23) + +project(starter_window VERSION 1.0.0) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED true) +set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE) + +set_property(GLOBAL PROPERTY USE_FOLDERS ON) +OPTION(ENABLE_TESTS "Enable Unit Tests" OFF) +OPTION(ENABLE_ALL_REASONABLE_WARNINGS "Enable all possible reasonable warnings" ON ) +OPTION(ENABLE_WARNINGS_AS_ERRORS "Warnings are treated as Errors" ON) +OPTION(ENABLE_STATIC_ANALYSIS "Enable Static Analysis Tools" OFF) +OPTION(ENABLE_SANITIZERS "Enable Sanitizer Tools" OFF) + +set(CMAKE_SCRIPTS_DIR ${CMAKE_CURRENT_LIST_DIR}/scripts/cmake) + +include(${CMAKE_SCRIPTS_DIR}/compilerwarnings.cmake) +include(${CMAKE_SCRIPTS_DIR}/sanitizers.cmake) +include(${CMAKE_SCRIPTS_DIR}/staticanalysis.cmake) + +if (ENABLE_TESTS) + message("-- Unit Testing Enabled") + enable_testing() + add_subdirectory(test) +endif() + +add_subdirectory(src) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fdddb29 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/README.md b/README.md new file mode 100644 index 0000000..74eb559 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# window-starter +[![build](https://github.com/McMassiveNZ/window-starter/actions/workflows/ci.yml/badge.svg)](https://github.com/McMassiveNZ/window-starter/actions/workflows/ci.yml) + +A window-starter cpp project which can open a simple window. The project contains boilerplate for CMake, testing and basic CI. Static Analysis, Unit Tests and Sanitizers are off by default diff --git a/external/vcpkg b/external/vcpkg new file mode 160000 index 0000000..af031ae --- /dev/null +++ b/external/vcpkg @@ -0,0 +1 @@ +Subproject commit af031ae388730db1cf6d1d7b3752c74209d7bbe1 diff --git a/scripts/.clang-tidy b/scripts/.clang-tidy new file mode 100644 index 0000000..1aaa846 --- /dev/null +++ b/scripts/.clang-tidy @@ -0,0 +1,19 @@ +--- +Checks: "*, + -abseil-*, + -altera-*, + -android-*, + -fuchsia-*, + -google-*, + -llvm*, + -modernize-use-trailing-return-type, + -zircon-*, + -readability-else-after-return, + -readability-static-accessed-through-instance, + -readability-avoid-const-params-in-decls, + -cppcoreguidelines-non-private-member-variables-in-classes, + -misc-non-private-member-variables-in-classes, +" +WarningsAsErrors: '' +HeaderFilterRegex: '' +FormatStyle: none \ No newline at end of file diff --git a/scripts/cmake/compilerwarnings.cmake b/scripts/cmake/compilerwarnings.cmake new file mode 100644 index 0000000..1c00012 --- /dev/null +++ b/scripts/cmake/compilerwarnings.cmake @@ -0,0 +1,106 @@ +include_guard() + +function( target_enable_warnings _target ) + if(MSVC) + target_compile_options( + ${_target} + PUBLIC + /W4 # Baseline reasonable warnings + /w14242 # 'identifier': conversion from 'type1' to 'type1', possible loss of data + /w14254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data + /w14263 # 'function': member function does not override any base class virtual member function + /w14265 # 'classname': class has virtual functions, but destructor is not virtual instances of this class may not + # be destructed correctly + /w14287 # 'operator': unsigned/negative constant mismatch + /we4289 # nonstandard extension used: 'variable': loop control variable declared in the for-loop is used outside + # the for-loop scope + /w14296 # 'operator': expression is always 'boolean_value' + /w14311 # 'variable': pointer truncation from 'type1' to 'type2' + /w14545 # expression before comma evaluates to a function which is missing an argument list + /w14546 # function call before comma missing argument list + /w14547 # 'operator': operator before comma has no effect; expected operator with side-effect + /w14549 # 'operator': operator before comma has no effect; did you intend 'operator'? + /w14555 # expression has no effect; expected expression with side- effect + /w14619 # pragma warning: there is no warning number 'number' + /w14640 # Enable warning on thread un-safe static member initialization + /w14826 # Conversion from 'type1' to 'type_2' is sign-extended. This may cause unexpected runtime behavior. + /w14905 # wide string literal cast to 'LPSTR' + /w14906 # string literal cast to 'LPWSTR' + /w14928 # illegal copy-initialization; more than one user-defined conversion has been implicitly applied + /permissive- # standards conformance mode for MSVC compiler. + ) + elseif(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") + target_compile_options( + ${_target} + INTERFACE + -Wall + -Wextra # reasonable and standard + -Wextra-semi # Warn about semicolon after in-class function definition. + -Wshadow # warn the user if a variable declaration shadows one from a parent context + -Wnon-virtual-dtor # warn the user if a class with virtual functions has a non-virtual destructor. This helps + + # catch hard to track down memory errors + -Wold-style-cast # warn for c-style casts + -Wcast-align # warn for potential performance problem casts + -Wunused # warn on anything being unused + -Woverloaded-virtual # warn if you overload (not override) a virtual function + -Wpedantic # warn if non-standard C++ is used + -Wconversion # warn on type conversions that may lose data + -Wsign-conversion # warn on sign conversions + -Wnull-dereference # warn if a null dereference is detected + -Wdouble-promotion # warn if float is implicit promoted to double + -Wformat=2 # warn on security issues around functions that format output (ie printf) + -Wimplicit-fallthrough # warn on statements that fallthrough without an explicit annotation + ) + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options( + ${_target} + INTERFACE + -Wall + -Wextra # reasonable and standard + -Wextra-semi # Warn about semicolon after in-class function definition. + -Wshadow # warn the user if a variable declaration shadows one from a parent context + -Wnon-virtual-dtor # warn the user if a class with virtual functions has a non-virtual destructor. This helps + + # catch hard to track down memory errors + -Wold-style-cast # warn for c-style casts + -Wcast-align # warn for potential performance problem casts + -Wunused # warn on anything being unused + -Woverloaded-virtual # warn if you overload (not override) a virtual function + -Wpedantic # warn if non-standard C++ is used + -Wconversion # warn on type conversions that may lose data + -Wsign-conversion # warn on sign conversions + -Wnull-dereference # warn if a null dereference is detected + -Wdouble-promotion # warn if float is implicit promoted to double + -Wformat=2 # warn on security issues around functions that format output (ie printf) + -Wimplicit-fallthrough # warn on statements that fallthrough without an explicit annotation + -Wmisleading-indentation # warn if indentation implies blocks where blocks do not exist + -Wduplicated-cond # warn if if / else chain has duplicated conditions + -Wduplicated-branches # warn if if / else branches have duplicated code + -Wlogical-op # warn about logical operations being used where bitwise were probably wanted + -Wuseless-cast # warn if you perform a cast to the same type + ) + endif() +endfunction() + +function(target_warnings_as_errors _target) + if(MSVC) + target_compile_options( + ${_target} + PUBLIC + /WX + ) + elseif(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") + target_compile_options( + ${_target} + PUBLIC + -Werror + ) + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options( + ${_target} + PUBLIC + -Werror + ) + endif() +endfunction() \ No newline at end of file diff --git a/scripts/cmake/googletest.cmake b/scripts/cmake/googletest.cmake new file mode 100644 index 0000000..29379ff --- /dev/null +++ b/scripts/cmake/googletest.cmake @@ -0,0 +1,18 @@ +include_guard() + +include(FetchContent) +FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG 58d77fa8070e8cec2dc1ed015d66b454c8d78850 # release-1.12.1 +) +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) + +set_property(TARGET + gtest + gtest_main + gmock + gmock_main + PROPERTY FOLDER GoogleTest) diff --git a/scripts/cmake/precompiled.cmake b/scripts/cmake/precompiled.cmake new file mode 100644 index 0000000..aefae37 --- /dev/null +++ b/scripts/cmake/precompiled.cmake @@ -0,0 +1,8 @@ +include_guard() + +function( target_precompiled_header _target _header _source ) + if( MSVC ) + set_target_properties( ${_target} PROPERTIES COMPILE_FLAGS "/Yu${_header}" ) + set_source_files_properties( ${_source} PROPERTIES COMPILE_FLAGS "/Yc${_header}" ) + endif() +endfunction() \ No newline at end of file diff --git a/scripts/cmake/sanitizers.cmake b/scripts/cmake/sanitizers.cmake new file mode 100644 index 0000000..baeb0d6 --- /dev/null +++ b/scripts/cmake/sanitizers.cmake @@ -0,0 +1,20 @@ +include_guard() + +function( target_enable_sanitizers _target ) + if( MSVC ) + string(FIND "$ENV{PATH}" "$ENV{VSINSTALLDIR}" index_of_vs_install_dir) + + if("${index_of_vs_install_dir}" STREQUAL "-1") + message( + SEND_ERROR + "Using MSVC sanitizers requires setting the MSVC environment before building the project. Please manually open the MSVC command prompt and rebuild the project." + ) + endif() + + target_compile_options(${_target} PUBLIC /fsanitize=address /Zi /INCREMENTAL:NO) + target_link_options(${_target} PUBLIC /INCREMENTAL:NO) + else() + target_compile_options(${_target} INTERFACE -fsanitize=address,leak,undefined) + target_link_options(${_target} INTERFACE -fsanitize=address,leak,undefined) + endif() +endfunction() \ No newline at end of file diff --git a/scripts/cmake/staticanalysis.cmake b/scripts/cmake/staticanalysis.cmake new file mode 100644 index 0000000..72736a4 --- /dev/null +++ b/scripts/cmake/staticanalysis.cmake @@ -0,0 +1,16 @@ +include_guard() + +function(target_enable_static_analysis _target) + set(_VS_CLANG_TIDY "false") + find_program(CLANGTIDY clang-tidy) + if(CLANGTIDY) + set(_VS_CLANG_TIDY "true") + endif() + set_target_properties( + ${_target} + PROPERTIES + VS_GLOBAL_EnableMicrosoftCodeAnalysis true + VS_GLOBAL_CodeAnalysisRuleSet "AllRules.ruleset" + VS_GLOBAL_EnableClangTidyCodeAnalysis "${_VS_CLANG_TIDY}" + ) +endfunction() \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..16f66cf --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,47 @@ +set(current_target starter_window) + +set(SOURCE_FILES) +set(STARTER_WINDOW_SRC + main.cpp + window.h +) +source_group("" FILES ${STARTER_WINDOW_SRC}) + +if(MSVC) +set(PLATFORM_SRC + platform/win32_window.cpp +) +else() +set(PLATFORM_SRC + platform/null_window.cpp +) +endif() +source_group(platform FILES ${PLATFORM_SRC}) + +list(APPEND SOURCE_FILES ${PLATFORM_SRC}) +list(APPEND SOURCE_FILES ${STARTER_WINDOW_SRC}) + +add_executable( + ${current_target} + ${SOURCE_FILES} +) + +if( ENABLE_ALL_REASONABLE_WARNINGS ) + MESSAGE("-- Additional Warnings Enabled") + target_enable_warnings(${current_target}) +endif() + +if( ENABLE_WARNINGS_AS_ERRORS ) + MESSAGE("-- Warnings as Errors") + target_warnings_as_errors(${current_target}) +endif() + +if( ENABLE_SANITIZERS ) + MESSAGE("-- Sanitizers Enabled") + target_enable_sanitizers(${current_target}) +endif() + +if( ENABLE_STATIC_ANALYSIS ) + MESSAGE("-- Static Analysis Enabled") + target_enable_static_analysis(${current_target}) +endif() diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..a3961ef --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,20 @@ +#include "window.h" + +constexpr int CW_USEDEFAULT = 0x80000000; + +auto main() -> int +{ + auto window = swCreateWindow({ + .x = CW_USEDEFAULT, + .y = CW_USEDEFAULT, + .width = CW_USEDEFAULT, + .height = CW_USEDEFAULT, + .name = "Starter Window" + }); + + while (!window->ShouldClose()) + { + window->PumpMessages(); + } +} + diff --git a/src/platform/null_window.cpp b/src/platform/null_window.cpp new file mode 100644 index 0000000..9e3d114 --- /dev/null +++ b/src/platform/null_window.cpp @@ -0,0 +1,28 @@ +#include "../window.h" + +namespace starter_window +{ + +class NullWindowImpl final : public Window +{ +public: + NullWindowImpl() = default; + ~NullWindowImpl() override = default; + + NullWindowImpl(NullWindowImpl&&) = delete; + NullWindowImpl& operator=(NullWindowImpl&&) = delete; + NullWindowImpl(const NullWindowImpl&) = delete; + NullWindowImpl& operator=(const NullWindowImpl&) = delete; + + void PumpMessages() override {} + bool ShouldClose() override { return false; } + +}; + +} // namespace starter_window + +std::unique_ptr swCreateWindow(starter_window::WindowCreateParams) +{ + auto result = std::make_unique(); + return result; +} diff --git a/src/platform/win32_window.cpp b/src/platform/win32_window.cpp new file mode 100644 index 0000000..2452567 --- /dev/null +++ b/src/platform/win32_window.cpp @@ -0,0 +1,132 @@ +#include "../window.h" + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#include + +static LRESULT CALLBACK WindowProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_DESTROY: + { + PostQuitMessage(0); + return 0; + } + + case WM_PAINT: + { + PAINTSTRUCT ps = {}; + HDC hdc = BeginPaint(window, &ps); + FillRect(hdc, &ps.rcPaint, reinterpret_cast(COLOR_WINDOW + 1)); + EndPaint(window, &ps); + return 0; + } + } + return DefWindowProc(window, message, wParam, lParam); +} + +namespace starter_window +{ + +class Win32WindowImpl final : public Window +{ +public: + Win32WindowImpl(); + ~Win32WindowImpl() override = default; + + Win32WindowImpl(const Win32WindowImpl&) = delete; + Win32WindowImpl& operator=(const Win32WindowImpl&) = delete; + + bool init(WindowCreateParams params); + void PumpMessages() override; + bool ShouldClose() override; + + HINSTANCE hInstance; + HWND hWnd; + bool m_close; +}; + +Win32WindowImpl::Win32WindowImpl() + : hInstance(GetModuleHandle(NULL)) + , hWnd(nullptr) + , m_close(false) +{ +} + +bool Win32WindowImpl::init(WindowCreateParams params) +{ + const char className[] = "Win32WindowImpl"; + + WNDCLASSEX wc = {}; + + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + wc.lpfnWndProc = WindowProc; + wc.hInstance = hInstance; + wc.lpszClassName = className; + + if (RegisterClassEx(&wc) == NULL) + { + MessageBox(nullptr, "Call to RegisterClass failed", NULL, MB_OK); + return false; + } + + HWND window = CreateWindowEx( + 0, + className, + params.name, + WS_OVERLAPPEDWINDOW, + params.x, params.y, params.width, params.height, + NULL, + NULL, + hInstance, + NULL); + + if (window == NULL) + { + MessageBox(nullptr, "Call to CreateWindow failed", NULL, MB_OK); + return false; + } + + ShowWindow(window, SW_SHOW); + return true; +} + +void Win32WindowImpl::PumpMessages() +{ + MSG message = {}; + if (GetMessage(&message, NULL, 0, 0) != 0) + { + TranslateMessage(&message); + DispatchMessage(&message); + } + else + { + // GetMessage returned WM_QUIT + m_close = true; + } +} + +bool Win32WindowImpl::ShouldClose() +{ + return m_close; +} +} // namespace starter_window + +std::unique_ptr swCreateWindow(starter_window::WindowCreateParams params) +{ + auto result = std::make_unique(); + if (result->init(params) == false) + { + result = nullptr; + } + + return result; +} \ No newline at end of file diff --git a/src/window.h b/src/window.h new file mode 100644 index 0000000..91fbc43 --- /dev/null +++ b/src/window.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +namespace starter_window +{ + +struct WindowCreateParams +{ + int x; + int y; + int width; + int height; + const char* name; +}; + +class Window +{ +public: + virtual ~Window() = default; + virtual void PumpMessages() = 0; + virtual bool ShouldClose() = 0; +}; + +} + +std::unique_ptr swCreateWindow(starter_window::WindowCreateParams params); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..921320b --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,14 @@ +include(${CMAKE_SCRIPTS_DIR}/googletest.cmake) + +add_executable( + window-starter-test + test_main.cpp +) + +target_link_libraries( + window-starter-test + gtest_main +) + +include(GoogleTest) +gtest_discover_tests(window-starter-test) diff --git a/test/test_main.cpp b/test/test_main.cpp new file mode 100644 index 0000000..d46382c --- /dev/null +++ b/test/test_main.cpp @@ -0,0 +1,6 @@ +#include + +TEST(testmain, example) +{ + EXPECT_EQ(42, 7*6); +} \ No newline at end of file