diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml deleted file mode 100644 index bd8ca207..00000000 --- a/.github/workflows/builds.yml +++ /dev/null @@ -1,106 +0,0 @@ -name: Builds - -#on: [pull_request] - -concurrency: - group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-macos - cancel-in-progress: true - -jobs: - build: - runs-on: ${{matrix.os}} - name: ${{matrix.name}} - strategy: - fail-fast: false - matrix: - include: - - identifier: windows-debug - os: windows-2019 - name: 🏁 Windows Debug - target: template_debug - platform: windows - arch: x86_64 - - identifier: windows-release - os: windows-2019 - name: 🏁 Windows Release - target: template_release - platform: windows - arch: x86_64 - - identifier: macos-debug - os: macos-latest - name: 🍎 macOS (universal) Debug - target: template_debug - platform: macos - arch: universal - - identifier: macos-release - os: macos-latest - name: 🍎 macOS (universal) Release - target: template_release - platform: macos - arch: universal - - identifier: linux-debug - os: ubuntu-18.04 - name: 🐧 Linux Debug - runner: ubuntu-20.04 - target: template_debug - platform: linux - arch: x86_64 - - identifier: linux-release - os: ubuntu-18.04 - name: 🐧 Linux Release - runner: ubuntu-20.04 - target: template_release - platform: linux - arch: x86_64 - - steps: - - - name: Checkout project - uses: actions/checkout@v3 - with: - submodules: recursive - - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: '3.x' - - - name: Set up SCons - shell: bash - run: | - python -c "import sys; print(sys.version)" - python -m pip install scons - scons --version - - - name: Linux dependencies - if: ${{ matrix.platform == 'linux' }} - run: | - sudo apt-get update -qq - sudo apt-get install -qqq build-essential pkg-config - - - name: Setup MinGW for Windows/MinGW build - if: ${{ matrix.platform == 'windows' }} - uses: egor-tensin/setup-mingw@v2 - - - name: Compile godot-cpp - shell: sh - run: | - scons target='${{ matrix.target }}' platform='${{ matrix.platform }}' arch='${{ matrix.arch }}' - working-directory: godot-cpp - - - name: Compile Extension - shell: sh - run: | - scons target='${{ matrix.target }}' platform='${{ matrix.platform }}' arch='${{ matrix.arch }}' - - - name: Delete compilation files - if: ${{ matrix.platform == 'windows' }} - run: | - Remove-Item game/bin/openvic2/* -Include *.exp,*.lib,*.pdb -Force - - - name: Upload artifact - uses: actions/upload-artifact@v3 - with: - name: ${{ github.event.repository.name }} - path: | - ${{ github.workspace }}/game/bin/openvic2/* diff --git a/.gitignore b/.gitignore index 3b0260e7..d475c436 100644 --- a/.gitignore +++ b/.gitignore @@ -64,4 +64,23 @@ bin/* *.exp # Build configuarion. -/custom.py \ No newline at end of file +/custom.py +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps +*.sln +*.vcxproj +*.vcxproj.filters +gen/ +x64/ +openvic2.dir/ +Debug/ +.vs/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..67b633aa --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,112 @@ +cmake_minimum_required( VERSION 3.22 ) + +message( STATUS "Using CMake ${CMAKE_VERSION}" ) + +# Add paths to modules +list( APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) + +# Turn on link time optimization for everything +set( CMAKE_INTERPROCEDURAL_OPTIMIZATION ON ) + +# Output compile commands to compile_commands.json (for debugging CMake issues) +set( CMAKE_EXPORT_COMPILE_COMMANDS ON ) + +# Build universal lib on macOS +# Note that CMAKE_OSX_ARCHITECTURES must be set before project(). +if ( APPLE ) + set( CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "" ) +endif() + +# Main project information +project( openvic2 + LANGUAGES + CXX + C + VERSION + 0.1.0 +) + +# Create our library +add_library( ${PROJECT_NAME} SHARED ) + +target_compile_features( ${PROJECT_NAME} + PRIVATE + cxx_std_17 +) + +# LIB_ARCH is the architecture being built. It is set to the build system's architecture. +# For macOS, we build a universal library (both arm64 and x86_64). +set( LIB_ARCH ${CMAKE_SYSTEM_PROCESSOR} ) +if ( APPLE ) + set( LIB_ARCH "universal" ) +endif() + +# LIB_DIR is where the actual library ends up. This is used in both the build directory and the +# install directory and needs to be consistent with the paths in the gdextension file. +# e.g. linux.release.x86_64 = "lib/Linux-x86_64/libopenvic2.so" +set( LIB_DIR "lib/${CMAKE_SYSTEM_NAME}-${LIB_ARCH}" ) + +message( STATUS "Building ${PROJECT_NAME} for ${LIB_ARCH} on ${CMAKE_SYSTEM_NAME}") + +# BUILD_OUTPUT_DIR is where we put the resulting library (in the build directory) +set( BUILD_OUTPUT_DIR "${PROJECT_BINARY_DIR}/${PROJECT_NAME}/" ) + +set_target_properties( ${PROJECT_NAME} + PROPERTIES + CXX_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN true + DEBUG_POSTFIX "-d" + RUNTIME_OUTPUT_DIRECTORY "${BUILD_OUTPUT_DIR}/${LIB_DIR}" + LIBRARY_OUTPUT_DIRECTORY "${BUILD_OUTPUT_DIR}/${LIB_DIR}" +) + +# Warnings +if( MSVC ) + target_compile_options( ${PROJECT_NAME} PRIVATE /W4 ) +else() + target_compile_options( ${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic ) +endif() + +add_subdirectory( extension/src ) + +# Install library and extension file in ${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME} +set( INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/" ) + +install( TARGETS ${PROJECT_NAME} + LIBRARY + DESTINATION ${INSTALL_DIR}/${LIB_DIR} + RUNTIME + DESTINATION ${INSTALL_DIR}/${LIB_DIR} +) + +add_subdirectory( game/bin ) + +# ccache +find_program( CCACHE_FOUND ccache ) +if( CCACHE_FOUND ) + set_property( GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache ) + set_property( GLOBAL PROPERTY RULE_LAUNCH_LINK ccache ) +endif( CCACHE_FOUND ) + +# godot-cpp +# From here: https://github.com/godotengine/godot-cpp +if ( NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/godot-cpp/Makefile" ) + message( + FATAL_ERROR + "[${PROJECT_NAME}] The godot-cpp submodule was not downloaded. Please update submodules: git submodule update --init --recursive." + ) +endif() + +set( GODOT_CPP_SYSTEM_HEADERS ON CACHE BOOL "" FORCE ) + +add_subdirectory( godot-cpp ) + +set_target_properties( godot-cpp + PROPERTIES + CXX_VISIBILITY_PRESET hidden # visibility needs to be the same as the main library +) + +target_link_libraries( ${PROJECT_NAME} + PRIVATE + godot-cpp +) diff --git a/README.md b/README.md index 409c75dd..c6ee0a00 100644 --- a/README.md +++ b/README.md @@ -3,18 +3,19 @@ Main Repo for the OpenVic2 Project ## Required * [Godot 4 Beta 16](https://downloads.tuxfamily.org/godotengine/4.0/beta16/) -* [scons](https://scons.org/) +* [cmake](https://www.cmake.org/) ## Build/Run Instructions -1. Install [Godot 4 Beta 16](https://downloads.tuxfamily.org/godotengine/4.0/beta16/) and [scons](https://scons.org/) for your system. -2. Run the command `git submodule update --init --recursive` to retrieve all related submodules. -3. Run `scons` in the project root, you should see a libopenvic2 file in `game/bin/openvic2`. -4. Open with Godot 4 Beta 16, click import and navigate to the `game` directory. -5. Import and edit. -6. Once loaded, click the play button at the top right, if you see `Hello GDExtension Singleton!` in the output at the bottom then it is working. +1. Install [Godot 4 Beta 16](https://downloads.tuxfamily.org/godotengine/4.0/beta16/) and [cmake](https://www.cmake.org/) for your system. +3. Create a build folder inside the project folder and CD to it. +4. Run "cmake .." from the build folder, specify cmake options if you need to, and specify the CMAKE_BUILD_TYPE to either Release or Debug (-DCMAKE_BUILD_TYPE=Release) etc +5. Run the build script based on your platform (Makefile, Ninja, Xcode, Visual Studio etc) to build the project +6. Open with Godot 4 Beta 16, click import and navigate to the `game` directory. +7. Import and edit. +8. Once loaded, click the play button at the top right, if you see `Hello GDExtension Singleton!` in the output at the bottom then it is working. ## Project Export -1. Build the extension with `scons` or `scons target=template_debug`. (or `scons target=template_release` for release) +1. Build the extension (^^^) 2. Open `game/project.godot` with Godot 4 Beta 16. 3. Click `Project` at the top left, click `Export`. 4. If you do not have the templates, you must download the templates, there is highlighted white text at the bottom of the Export subwindow that opens up the template manager for you to download. @@ -26,7 +27,6 @@ Main Repo for the OpenVic2 Project * On Linux x86_64 run `game/export/Linux-x86_64/OpenVic2.sh`. ## Extension Debugging -1. If in a clean build, build the extension with `scons`. -2. Build with `scons dev_build=yes`. +1. If in a clean build, build the extension. 3. [Setup your IDE](https://godotengine.org/qa/108346/how-can-i-debug-runtime-errors-of-native-library-in-godot) so your Command/Host/Launching App is your Godot 4 binary and the Working Directory is the `game` directory. 4. Start the debugger. diff --git a/SConstruct b/SConstruct deleted file mode 100644 index 4e6fe709..00000000 --- a/SConstruct +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env python -import os -import sys -from glob import glob -from pathlib import Path - -# Neccessary to have our own build options without errors -SAVED_ARGUMENTS = ARGUMENTS.copy() -ARGUMENTS.pop('intermediate_delete', True) - -env = SConscript("godot-cpp/SConstruct") - -ARGUMENTS = SAVED_ARGUMENTS - -# Custom options and profile flags. -customs = ["custom.py"] -profile = ARGUMENTS.get("profile", "") -if profile: - if os.path.isfile(profile): - customs.append(profile) - elif os.path.isfile(profile + ".py"): - customs.append(profile + ".py") -opts = Variables(customs, ARGUMENTS) - -opts.Add( - BoolVariable("intermediate_delete", "Enables automatically deleting unassociated intermediate binary files.", True) -) - -opts.Update(env) -Help(opts.GenerateHelpText(env)) - -def GlobRecursive(pattern, node='.'): - import SCons - results = [] - for f in Glob(str(node) + '/*', source=True): - if type(f) is SCons.Node.FS.Dir: - results += GlobRecursive(pattern, f) - results += Glob(str(node) + '/' + pattern, source=True) - return results - -# For the reference: -# - CCFLAGS are compilation flags shared between C and C++ -# - CFLAGS are for C-specific compilation flags -# - CXXFLAGS are for C++-specific compilation flags -# - CPPFLAGS are for pre-processor flags -# - CPPDEFINES are for pre-processor defines -# - LINKFLAGS are for linking flags - -# tweak this if you want to use different folders, or more folders, to store your source code in. -env.Append(CPPPATH=["extension/src/"]) -sources = GlobRecursive("*.cpp", "extension/src") - -# Remove unassociated intermediate binary files if allowed, usually the result of a renamed or deleted source file -if env["intermediate_delete"]: - def remove_extension(file : str): - if file.find(".") == -1: return file - return file[:file.rindex(".")] - - found_one = False - for obj_file in [file[:-len(".os")] for file in glob("extension/src/*.os", recursive=True)]: - found = False - for source_file in sources: - if remove_extension(str(source_file)) == obj_file: - found = True - break - if not found: - if not found_one: - found_one = True - print("Unassociated intermediate files found...") - print("Removing "+obj_file+".os") - os.remove(obj_file+".os") - -if env["platform"] == "macos": - library = env.SharedLibrary( - "game/bin/openvic2/libopenvic2.{}.{}.framework/libopenvic2.{}.{}".format( - env["platform"], env["target"], env["platform"], env["target"] - ), - source=sources, - ) -else: - suffix = ".{}.{}.{}".format(env["platform"], env["target"], env["arch"]) - library = env.SharedLibrary( - "game/bin/openvic2/libopenvic2{}{}".format(suffix, env["SHLIBSUFFIX"]), - source=sources, - ) - -Default(library) diff --git a/cmake/ClangFormat.cmake b/cmake/ClangFormat.cmake new file mode 100644 index 00000000..2b9338fd --- /dev/null +++ b/cmake/ClangFormat.cmake @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: Unlicense + +find_program( CLANG_FORMAT_PROGRAM NAMES clang-format ) + +if ( CLANG_FORMAT_PROGRAM ) + # get version information + execute_process( + COMMAND "${CLANG_FORMAT_PROGRAM}" --version + OUTPUT_VARIABLE CLANG_FORMAT_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + message( STATUS "Using clang-format: ${CLANG_FORMAT_PROGRAM} (${CLANG_FORMAT_VERSION})" ) + + get_target_property( CLANG_FORMAT_SOURCES ${PROJECT_NAME} SOURCES ) + + # Remove some files from the list + list( FILTER CLANG_FORMAT_SOURCES EXCLUDE REGEX ".*/extern/.*" ) + list( FILTER CLANG_FORMAT_SOURCES EXCLUDE REGEX ".*/gen/.*" ) + list( FILTER CLANG_FORMAT_SOURCES EXCLUDE REGEX ".*/*.gdextension.in" ) + list( FILTER CLANG_FORMAT_SOURCES EXCLUDE REGEX ".*/Version.h.in" ) + + add_custom_target( clang-format + COMMAND "${CLANG_FORMAT_PROGRAM}" --style=file -i ${CLANG_FORMAT_SOURCES} + COMMENT "Running clang-format..." + COMMAND_EXPAND_LISTS + VERBATIM + ) + + unset( CLANG_FORMAT_VERSION ) + unset( CLANG_FORMAT_SOURCES ) +endif() \ No newline at end of file diff --git a/cmake/CompilerWarnings.cmake b/cmake/CompilerWarnings.cmake new file mode 100644 index 00000000..4d496c9b --- /dev/null +++ b/cmake/CompilerWarnings.cmake @@ -0,0 +1,115 @@ +# SPDX-License-Identifier: Unlicense +# by Andy Maloney + +string( TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPERCASE ) + +if ( NOT MSVC ) + option( ${PROJECT_NAME_UPPERCASE}_WARN_EVERYTHING "Turn on all warnings (not recommended - used for lib development)" OFF ) +endif() + +option( ${PROJECT_NAME_UPPERCASE}_WARNING_AS_ERROR "Treat warnings as errors" ON ) + +# Add warnings based on compiler +# Set some helper variables for readability +set( compiler_is_clang "$,$>" ) +set( compiler_is_gnu "$" ) +set( compiler_is_msvc "$" ) + +target_compile_options( ${PROJECT_NAME} + PRIVATE + # MSVC only + $<${compiler_is_msvc}: + /W4 + + /w14263 # 'function': member function does not override any base class virtual member function + /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'? + /w14619 # pragma warning: there is no warning number 'number' + /w14640 # thread un-safe static member initialization + /w14905 # wide string literal cast to 'LPSTR' + /w14906 # string literal cast to 'LPWSTR' + + # Disable warnings which bleed through from godot-cpp's macros. + /wd4100 # unreferenced formal parameter + > + + # Clang and GNU + $<$: + -Wall + -Wcast-align + -Wctor-dtor-privacy + -Wextra + -Wformat=2 + -Wnon-virtual-dtor + -Wnull-dereference + -Woverloaded-virtual + -Wpedantic + -Wshadow + -Wunused + -Wwrite-strings + + # Disable warnings which bleed through from godot-cpp's macros. + -Wno-unused-parameter + > + + # Clang only + $<${compiler_is_clang}: + -Wdocumentation + -Wimplicit-fallthrough + > + + # GNU only + $<${compiler_is_gnu}: + -Walloc-zero + -Wduplicated-branches + -Wduplicated-cond + -Wlogical-op + > +) + +# Turn on (almost) all warnings on Clang, Apple Clang, and GNU. +# Useful for internal development, but too noisy for general development. +function( set_warn_everything ) + message( STATUS "[${PROJECT_NAME}] Turning on (almost) all warnings") + + target_compile_options( ${PROJECT_NAME} + PRIVATE + # Clang and GNU + $<$: + -Weverything + -Wno-c++98-compat + -Wno-c++98-compat-pedantic + -Wno-padded + > + ) +endfunction() + +if ( NOT MSVC AND ${PROJECT_NAME_UPPERCASE}_WARN_EVERYTHING ) + set_warn_everything() +endif() + +# Treat warnings as errors +function( set_warning_as_error ) + message( STATUS "[${PROJECT_NAME}] Treating warnings as errors") + + if ( CMAKE_VERSION VERSION_GREATER_EQUAL "3.24" ) + set_target_properties( ${PROJECT_NAME} + PROPERTIES + COMPILE_WARNING_AS_ERROR ON + ) + else() + target_compile_options( ${PROJECT_NAME} + PRIVATE + $<${compiler_is_msvc}:/WX> + $<$:-Werror> + ) + endif() +endfunction() + +if ( ${PROJECT_NAME_UPPERCASE}_WARNING_AS_ERROR ) + set_warning_as_error() +endif() \ No newline at end of file diff --git a/cmake/GetGitRevisionDescription.cmake b/cmake/GetGitRevisionDescription.cmake new file mode 100644 index 00000000..2055ce29 --- /dev/null +++ b/cmake/GetGitRevisionDescription.cmake @@ -0,0 +1,284 @@ +# - Returns a version string from Git +# +# These functions force a re-configure on each git commit so that you can +# trust the values of the variables in your build system. +# +# get_git_head_revision( [ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR]) +# +# Returns the refspec and sha hash of the current head revision +# +# git_describe( [ ...]) +# +# Returns the results of git describe on the source tree, and adjusting +# the output so that it tests false if an error occurs. +# +# git_describe_working_tree( [ ...]) +# +# Returns the results of git describe on the working tree (--dirty option), +# and adjusting the output so that it tests false if an error occurs. +# +# git_get_exact_tag( [ ...]) +# +# Returns the results of git describe --exact-match on the source tree, +# and adjusting the output so that it tests false if there was no exact +# matching tag. +# +# git_local_changes() +# +# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes. +# Uses the return code of "git diff-index --quiet HEAD --". +# Does not regard untracked files. +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2020 Ryan Pavlik +# http://academic.cleardefinition.com +# +# Copyright 2009-2013, Iowa State University. +# Copyright 2013-2020, Ryan Pavlik +# Copyright 2013-2020, Contributors +# SPDX-License-Identifier: BSL-1.0 +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +if(__get_git_revision_description) + return() +endif() +set(__get_git_revision_description YES) + +# We must run the following at "include" time, not at function call time, +# to find the path to this module rather than the path to a calling list file +get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) + +# Function _git_find_closest_git_dir finds the next closest .git directory +# that is part of any directory in the path defined by _start_dir. +# The result is returned in the parent scope variable whose name is passed +# as variable _git_dir_var. If no .git directory can be found, the +# function returns an empty string via _git_dir_var. +# +# Example: Given a path C:/bla/foo/bar and assuming C:/bla/.git exists and +# neither foo nor bar contain a file/directory .git. This wil return +# C:/bla/.git +# +function(_git_find_closest_git_dir _start_dir _git_dir_var) + set(cur_dir "${_start_dir}") + set(git_dir "${_start_dir}/.git") + while(NOT EXISTS "${git_dir}") + # .git dir not found, search parent directories + set(git_previous_parent "${cur_dir}") + get_filename_component(cur_dir "${cur_dir}" DIRECTORY) + if(cur_dir STREQUAL git_previous_parent) + # We have reached the root directory, we are not in git + set(${_git_dir_var} + "" + PARENT_SCOPE) + return() + endif() + set(git_dir "${cur_dir}/.git") + endwhile() + set(${_git_dir_var} + "${git_dir}" + PARENT_SCOPE) +endfunction() + +function(get_git_head_revision _refspecvar _hashvar) + _git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR) + + if("${ARGN}" STREQUAL "ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR") + set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR TRUE) + else() + set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR FALSE) + endif() + if(NOT "${GIT_DIR}" STREQUAL "") + file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_SOURCE_DIR}" + "${GIT_DIR}") + if("${_relative_to_source_dir}" MATCHES "[.][.]" AND NOT ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR) + # We've gone above the CMake root dir. + set(GIT_DIR "") + endif() + endif() + if("${GIT_DIR}" STREQUAL "") + set(${_refspecvar} + "GITDIR-NOTFOUND" + PARENT_SCOPE) + set(${_hashvar} + "GITDIR-NOTFOUND" + PARENT_SCOPE) + return() + endif() + + # Check if the current source dir is a git submodule or a worktree. + # In both cases .git is a file instead of a directory. + # + if(NOT IS_DIRECTORY ${GIT_DIR}) + # The following git command will return a non empty string that + # points to the super project working tree if the current + # source dir is inside a git submodule. + # Otherwise the command will return an empty string. + # + execute_process( + COMMAND "${GIT_EXECUTABLE}" rev-parse + --show-superproject-working-tree + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + OUTPUT_VARIABLE out + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT "${out}" STREQUAL "") + # If out is empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule + file(READ ${GIT_DIR} submodule) + string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE + ${submodule}) + string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE) + get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH) + get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} + ABSOLUTE) + set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD") + else() + # GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree + file(READ ${GIT_DIR} worktree_ref) + # The .git directory contains a path to the worktree information directory + # inside the parent git repo of the worktree. + # + string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir + ${worktree_ref}) + string(STRIP ${git_worktree_dir} git_worktree_dir) + _git_find_closest_git_dir("${git_worktree_dir}" GIT_DIR) + set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD") + endif() + else() + set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD") + endif() + set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") + if(NOT EXISTS "${GIT_DATA}") + file(MAKE_DIRECTORY "${GIT_DATA}") + endif() + + if(NOT EXISTS "${HEAD_SOURCE_FILE}") + return() + endif() + set(HEAD_FILE "${GIT_DATA}/HEAD") + configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY) + + configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" + "${GIT_DATA}/grabRef.cmake" @ONLY) + include("${GIT_DATA}/grabRef.cmake") + + set(${_refspecvar} + "${HEAD_REF}" + PARENT_SCOPE) + set(${_hashvar} + "${HEAD_HASH}" + PARENT_SCOPE) +endfunction() + +function(git_describe _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + get_git_head_revision(refspec hash) + if(NOT GIT_FOUND) + set(${_var} + "GIT-NOTFOUND" + PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_var} + "HEAD-HASH-NOTFOUND" + PARENT_SCOPE) + return() + endif() + + # TODO sanitize + #if((${ARGN}" MATCHES "&&") OR + # (ARGN MATCHES "||") OR + # (ARGN MATCHES "\\;")) + # message("Please report the following error to the project!") + # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") + #endif() + + #message(STATUS "Arguments to execute_process: ${ARGN}") + + execute_process( + COMMAND "${GIT_EXECUTABLE}" describe --tags --always ${hash} ${ARGN} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE res + OUTPUT_VARIABLE out + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT res EQUAL 0) + set(out "${out}-${res}-NOTFOUND") + endif() + + set(${_var} + "${out}" + PARENT_SCOPE) +endfunction() + +function(git_describe_working_tree _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + if(NOT GIT_FOUND) + set(${_var} + "GIT-NOTFOUND" + PARENT_SCOPE) + return() + endif() + + execute_process( + COMMAND "${GIT_EXECUTABLE}" describe --dirty ${ARGN} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE res + OUTPUT_VARIABLE out + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT res EQUAL 0) + set(out "${out}-${res}-NOTFOUND") + endif() + + set(${_var} + "${out}" + PARENT_SCOPE) +endfunction() + +function(git_get_exact_tag _var) + git_describe(out --exact-match ${ARGN}) + set(${_var} + "${out}" + PARENT_SCOPE) +endfunction() + +function(git_local_changes _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + get_git_head_revision(refspec hash) + if(NOT GIT_FOUND) + set(${_var} + "GIT-NOTFOUND" + PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_var} + "HEAD-HASH-NOTFOUND" + PARENT_SCOPE) + return() + endif() + + execute_process( + COMMAND "${GIT_EXECUTABLE}" diff-index --quiet HEAD -- + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE res + OUTPUT_VARIABLE out + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + if(res EQUAL 0) + set(${_var} + "CLEAN" + PARENT_SCOPE) + else() + set(${_var} + "DIRTY" + PARENT_SCOPE) + endif() +endfunction() \ No newline at end of file diff --git a/cmake/GetGitRevisionDescription.cmake.in b/cmake/GetGitRevisionDescription.cmake.in new file mode 100644 index 00000000..e35156f2 --- /dev/null +++ b/cmake/GetGitRevisionDescription.cmake.in @@ -0,0 +1,43 @@ +# +# Internal file for GetGitRevisionDescription.cmake +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright 2009-2012, Iowa State University +# Copyright 2011-2015, Contributors +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +# SPDX-License-Identifier: BSL-1.0 + +set(HEAD_HASH) + +file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) + +string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) +if(HEAD_CONTENTS MATCHES "ref") + # named branch + string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") + if(EXISTS "@GIT_DIR@/${HEAD_REF}") + configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) + else() + configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY) + file(READ "@GIT_DATA@/packed-refs" PACKED_REFS) + if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}") + set(HEAD_HASH "${CMAKE_MATCH_1}") + endif() + endif() +else() + # detached HEAD + configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) +endif() + +if(NOT HEAD_HASH) + file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) + string(STRIP "${HEAD_HASH}" HEAD_HASH) +endif() \ No newline at end of file diff --git a/cmake/GitVersionInfo.cmake b/cmake/GitVersionInfo.cmake new file mode 100644 index 00000000..3bc6cf97 --- /dev/null +++ b/cmake/GitVersionInfo.cmake @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: Unlicense + +find_program( GIT_PROGRAM git ) + +if ( GIT_PROGRAM ) + # get version information + execute_process( + COMMAND "${GIT_PROGRAM}" --version + OUTPUT_VARIABLE GIT_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + message( STATUS "Using git: ${GIT_PROGRAM} (${GIT_VERSION})" ) + + include( GetGitRevisionDescription ) + + get_git_head_revision( GIT_REFSPEC GIT_SHA1 ) + git_describe( GIT_SHORT ) + + string( TOUPPER ${PROJECT_NAME} UPPER_PROJECT_NAME ) + + set( VERSION_INPUT_FILE "extension/src/Version.h.in" ) + set( VERSION_OUTPUT_FILE "${CMAKE_BINARY_DIR}/gen/Version.h" ) + + configure_file( "${VERSION_INPUT_FILE}" "${VERSION_OUTPUT_FILE}" ) + + target_sources( ${PROJECT_NAME} + PRIVATE + "${VERSION_INPUT_FILE}" + "${VERSION_OUTPUT_FILE}" + ) + + get_filename_component( VERSION_OUTPUT_FILE_DIR ${VERSION_OUTPUT_FILE} DIRECTORY ) + + target_include_directories( ${PROJECT_NAME} + PRIVATE + ${VERSION_OUTPUT_FILE_DIR} + ) + + message( STATUS "${PROJECT_NAME} version: ${GIT_SHORT}" ) + + unset( VERSION_INPUT_FILE ) + unset( VERSION_OUTPUT_FILE ) + unset( VERSION_OUTPUT_FILE_DIR ) + unset( GIT_VERSION ) +endif() \ No newline at end of file diff --git a/cmake/ccache.cmake b/cmake/ccache.cmake new file mode 100644 index 00000000..483f1399 --- /dev/null +++ b/cmake/ccache.cmake @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: Unlicense + +# See: https://crascit.com/2016/04/09/using-ccache-with-cmake/ +find_program( CCACHE_PROGRAM ccache ) + +if ( CCACHE_PROGRAM ) + # get version information + execute_process( + COMMAND "${CCACHE_PROGRAM}" --version + OUTPUT_VARIABLE CCACHE_VERSION + ) + + string( REGEX MATCH "[^\r\n]*" CCACHE_VERSION ${CCACHE_VERSION} ) + + message( STATUS "Using ccache: ${CCACHE_PROGRAM} (${CCACHE_VERSION})" ) + + # Turn on ccache for all targets + set( CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}" ) + set( CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}" ) + + unset( CCACHE_VERSION ) +endif() \ No newline at end of file diff --git a/extension/src/CMakeLists.txt b/extension/src/CMakeLists.txt new file mode 100644 index 00000000..2b3eaecd --- /dev/null +++ b/extension/src/CMakeLists.txt @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: Unlicense + +# Get Sources +file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS *.c**) +file(GLOB_RECURSE HEADERS CONFIGURE_DEPENDS *.h**) + +target_sources( ${PROJECT_NAME} + PRIVATE + ${SOURCES} + ${HEADERS} +) + +target_include_directories( ${PROJECT_NAME} + PRIVATE + "src" +) \ No newline at end of file diff --git a/extension/src/TestSingleton.hpp b/extension/src/TestSingleton.hpp index 0a591ac2..de27589a 100644 --- a/extension/src/TestSingleton.hpp +++ b/extension/src/TestSingleton.hpp @@ -6,7 +6,7 @@ namespace OpenVic2 { class TestSingleton : public godot::Object { - GDCLASS(TestSingleton, godot::Object); + GDCLASS(TestSingleton, godot::Object) static TestSingleton *singleton; diff --git a/extension/src/Version.h.in b/extension/src/Version.h.in new file mode 100644 index 00000000..ef5a99ba --- /dev/null +++ b/extension/src/Version.h.in @@ -0,0 +1,45 @@ +#pragma once +// This file is generated by cmake. Changes will be overwritten. +// clang-format off + +#include + +// The version number of this extension. Used for #if comparisons. +// This is generated using the version set in the CMake project macro. +#define ${UPPER_PROJECT_NAME}_VERSION ${UPPER_PROJECT_NAME}_VERSION_CHECK( ${PROJECT_VERSION_MAJOR}, ${PROJECT_VERSION_MINOR}, ${PROJECT_VERSION_PATCH} ) + +// Creates a version number for use in macro comparisons. +// +// Example: +// +// // Check if the version is less than 2.1.0 +// #if ${UPPER_PROJECT_NAME}_VERSION < ${UPPER_PROJECT_NAME}_VERSION_CHECK(2, 1, 0) +// // do stuff +// #endif +// +// Returns an integer which may be used in comparisons +#define ${UPPER_PROJECT_NAME}_VERSION_CHECK( major, minor, patch ) ( ((major)<<16) | ((minor)<<8) | (patch) ) + +#define ${UPPER_PROJECT_NAME}_VERSION_MAJOR ${PROJECT_VERSION_MAJOR} +#define ${UPPER_PROJECT_NAME}_VERSION_MINOR ${PROJECT_VERSION_MINOR} +#define ${UPPER_PROJECT_NAME}_VERSION_PATCH ${PROJECT_VERSION_PATCH} + +namespace VersionInfo { + // Project name and version as a string. + // This is generated using the project name from the cmake project macro and the current git commit information. + // + // It uses the form " -<# commits since last tag>-". + // If there are no commits since the last tag, only the tag is shown. + constexpr std::string_view VERSION_STR = "${PROJECT_NAME} ${GIT_SHORT}"; + + // The version information as a string. + // This is generated using the current git commit information. + // + // It uses the form "-<# commits since last tag>-". + // If there are no commits since the last tag, only the tag is shown. + constexpr std::string_view VERSION_SHORT_STR = "${GIT_SHORT}"; + + // The full git SHA1 hash as a string. + // This is generated using the current git commit information. + constexpr std::string_view GIT_SHA1_STR = "${GIT_SHA1}"; +} diff --git a/game/bin/CMakeLists.txt b/game/bin/CMakeLists.txt new file mode 100644 index 00000000..e9341454 --- /dev/null +++ b/game/bin/CMakeLists.txt @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: Unlicense + +add_custom_target( templates + SOURCES + openvic2.gdextension +) + +add_dependencies( ${PROJECT_NAME} templates ) + +# We shouldn't be relying on CMAKE_BUILD_TYPE (see https://github.com/asmaloney/GDExtensionTemplate/issues/25) +# But until we fix it here and in godot-cpp, ensure it's one we expect. +set ( ALLOWED_BUILDS "Debug;Release" ) +if ( NOT "${CMAKE_BUILD_TYPE}" IN_LIST ALLOWED_BUILDS ) + set( CMAKE_BUILD_TYPE "Debug" ) +endif() + +# Get our gdextension input file name based on build type +string( TOLOWER ${CMAKE_BUILD_TYPE} BUILD_TYPE ) +set( GD_EXTENSION_FILE_INPUT openvic2.gdextension ) + +# Workaround to add the "lib" prefix to the library in our template file if using MSYS2. +if ( MINGW ) + set( LIB_PREFIX "lib") +endif() + +# Generate our project's .gdextension file from the template +set( GD_EXTENSION_FILE ${PROJECT_NAME}.gdextension ) +configure_file( ${GD_EXTENSION_FILE_INPUT} ${PROJECT_BINARY_DIR}/${PROJECT_NAME}/${GD_EXTENSION_FILE} ) + +# Install the gdextension file from the build directory +install( + FILES ${BUILD_OUTPUT_DIR}/${GD_EXTENSION_FILE} + DESTINATION ${INSTALL_DIR} +) + +unset( ALLOWED_BUILDS ) +unset( BUILD_TYPE ) +unset( GD_EXTENSION_FILE ) +unset( GD_EXTENSION_FILE_INPUT ) +unset( LIB_PREFIX ) \ No newline at end of file