diff --git a/.gitignore b/.gitignore index b3e4ded..5b93486 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ build/ sandbox/ +VERSION \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 463cfb4..d5ed929 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -54,5 +54,6 @@ "stdexcept": "cpp", "typeinfo": "cpp", "pointers": "cpp" - } + }, + "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools" } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 10a9960..e44d355 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,50 +1,54 @@ +## # @author Christian Burger cmake_minimum_required(VERSION 3.16.3) + +include("cmake/version.cmake") project(NCursesPtyWindow - VERSION 0.1.0 - HOMEPAGE_URL "https://gitea.xndr.de/christian/shellipt") -### 3.16.3 does not pick up the project's homepage URL by itself + HOMEPAGE_URL "https://gitea.xndr.de/christian/NCursesPtyWindow" + VERSION ${SEMANTIC_VERSION}) set(CMAKE_CXX_STANDARD 17) include(CTest) enable_testing() -include(ExternalProject) -include("cmake/ncurses.cmake") -include("cmake/gsl.cmake") - add_library(NCursesPtyWindow Window.cpp SingleUserInput.cpp Debug.cpp) ### libraries +include("cmake/ncurses.cmake") +target_link_libraries(NCursesPtyWindow ${CURSES_LIBRARIES}) + +include("cmake/gsl.cmake") + include("cmake/libvterm.cmake") if(EXISTS libvtermProject) add_dependencies(NCursesPtyWindow libvtermProject) endif() +target_link_libraries(NCursesPtyWindow ${LIBVTERM_LIBRARY}) find_library(UTIL_LIBRARY util) +target_link_libraries(NCursesPtyWindow ${UTIL_LIBRARY}) -target_link_libraries(NCursesPtyWindow ${CURSES_LIBRARIES} ${LIBVTERM_LIBRARY} ${UTIL_LIBRARY}) - -### threads set(THREADS_PREFER_PTHREAD_FLAG true) find_package(Threads REQUIRED) target_link_libraries(NCursesPtyWindow Threads::Threads) ### demo application add_executable(NCursesPtyApp main.cpp App.cpp) -target_link_libraries(NCursesPtyApp ${CURSES_LIBRARIES} NCursesPtyWindow) +target_link_libraries(NCursesPtyApp NCursesPtyWindow) ### installation and packaging -set_target_properties(NCursesPtyWindow PROPERTIES PUBLIC_HEADER "Window.hpp;SingleUserInput.hpp") +set_target_properties(NCursesPtyWindow PROPERTIES PUBLIC_HEADER "Window.hpp;SingleUserInput.hpp" + VERSION "${CMAKE_PROJECT_VERSION}") install(TARGETS NCursesPtyWindow ARCHIVE PUBLIC_HEADER) set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) set(CPACK_PACKAGE_CONTACT "Christian Burger ") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Library for a pseudo terminal where the host end is a ncurses window") +# 3.16.3 does not pick up the project's homepage URL by itself set(CPACK_DEBIAN_PACKAGE_HOMEPAGE ${CMAKE_PROJECT_HOMEPAGE_URL}) set(CPACK_GENERATOR "DEB" "TGZ") diff --git a/cmake/gsl.cmake b/cmake/gsl.cmake index dd4cd95..bcf5f06 100644 --- a/cmake/gsl.cmake +++ b/cmake/gsl.cmake @@ -1,6 +1,8 @@ +## +# @brief Includes Microsoft's "C++ Guidelines Standard Library" # @author Christian Burger -find_path(GSL_INCLUDE_DIR "gsl") +find_path(GSL_INCLUDE_DIR "gsl/gsl" REQUIRED) if(GSL_INCLUDE_DIR STREQUAL "GSL_INCLUDE_DIR-NOTFOUND") message(SEND_ERROR "Microsoft GSL not found.") else() diff --git a/cmake/libvterm.cmake b/cmake/libvterm.cmake index 636b572..88b250b 100644 --- a/cmake/libvterm.cmake +++ b/cmake/libvterm.cmake @@ -1,15 +1,21 @@ -# @author Christian Burger -# @brief searches for libvterm and builds it if not found +## +# @brief Includes `libvterm` (builds it if not found on the system). # -# provides LIBVTERM_LIBRARY and include path -# dependency must be added like this: -# if(EXISTS libvtermProject) -# add_dependencies( libvtermProject) -# endif() +# Provides ${LIBVTERM_LIBRARY} and implicitly adds path for correct +# `#include<>`. +# +# @warning dependency must be added like this: +# if(TARGET libvtermProject) +# add_dependencies( libvtermProject) +# endif() +# +# @author Christian Burger find_library(LIBVTERM_LIBRARY NAMES libvterm.so.0.0.2 vterm) +include(ExternalProject) + if(LIBVTERM_LIBRARY STREQUAL "LIBVTERM_LIBRARY-NOTFOUND") message(STATUS "libvterm not found — building it") ExternalProject_Add( diff --git a/cmake/ncurses.cmake b/cmake/ncurses.cmake index 2761644..a811778 100644 --- a/cmake/ncurses.cmake +++ b/cmake/ncurses.cmake @@ -1,3 +1,5 @@ +## +# @brief Includes the UTF-8 C++ version of the `ncurses` library. # @author Christian Burger set(CURSES_NEED_NCURSES TRUE) diff --git a/cmake/version.cmake b/cmake/version.cmake new file mode 100644 index 0000000..2f1520b --- /dev/null +++ b/cmake/version.cmake @@ -0,0 +1,77 @@ +## +# @brief a ${SEMANTIC_VERSION} based on Git tags (or a `VERSION` file) à la +# `v..` is provided +# +# Versions have the format "v.." in accordance with +# Semantic Versioning. If a version is provided by a file named `VERSION`, the +# full version must be given. If a version is provided by Git tags, only part of +# the version must be given, the format is then: "v.". The +# version is automatically deduced from the distance in commits to the latest +# Git tag. The version set in the file overrides the tags in the Git repository. +# +# based upon Semantic Versioning: https://semver.org/ +# +# @attention The version-part is a bit flaky; it gives the distance in +# commits to the . version. Due to the non-linear +# nature of the commit history (because of branches), it is ambigous +# (i. e. multiple commits can be found at the same distance). On top +# of that, it is your job to make sure, that patches only fix bugs +# and do not change the API (no new functionalty; or old removed). +# +# One option to address both issues is: Stay in one branch for +# releases — for example named 'release' — and cherry-pick new +# versions into the branch (alphas, betas, candidates and releases). +# Optional: squash cherry-picked commits, so that the part of +# the version is only incremented by one. +# @warning To update the version you have to run CMake again. +# +# @todo escape/quote paths +# @todo test cases for CMake file components? +# @todo make variables local (see: unset()) and put them in a "namespace" +# @author Christian Burger +find_package(Git) + +function(get_semantic_version) + if(EXISTS "${CMAKE_SOURCE_DIR}/VERSION") + message(STATUS "using file `VERSION` to determine version") + file(READ "VERSION" REPOSITORY_VERSION) + elseif(GIT_FOUND) + message(STATUS "using Git to determine project version") + execute_process(COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_SOURCE_DIR} describe --always --match v[0-9]*.[0-9]* + OUTPUT_VARIABLE REPOSITORY_VERSION) + else() + message(WARNING "We need Git or a file \"VERSION\" to determine a version (e. g. \"v1.0\").") + endif() + + # test cases + #set(REPOSITORY_VERSION "v0.1") # = 0.1.0 + #set(REPOSITORY_VERSION "v0.1-1-g12345678") # = 0.1.1 + #set(REPOSITORY_VERSION "v0.1") # = 0.0.0 + #set(REPOSITORY_VERSION "1234abcd") # = 0.0.0 + #set(REPOSITORY_VERSION "") # = 0.1.0 + + string(REGEX MATCH "^v([0-9]+)\.([0-9]+)([-\\.]([0-9]+))?" SEMANTIC_VERSION_PREPROCESSED "${REPOSITORY_VERSION}") + + if("${SEMANTIC_VERSION_PREPROCESSED}" STREQUAL "") + message(STATUS "Found no version tag (e. g. \"v1.0\").") + endif() + + set(SEMANTIC_VERSION_MAJOR ${CMAKE_MATCH_1}) + set(SEMANTIC_VERSION_MINOR ${CMAKE_MATCH_2}) + set(SEMANTIC_VERSION_PATCH ${CMAKE_MATCH_4}) + + if("${SEMANTIC_VERSION_MAJOR}" STREQUAL "") + set(SEMANTIC_VERSION "0.0.0") + else() + if("${SEMANTIC_VERSION_PATCH}" STREQUAL "") + set(SEMANTIC_VERSION_PATCH "0") + endif() + set(SEMANTIC_VERSION "${SEMANTIC_VERSION_MAJOR}.${SEMANTIC_VERSION_MINOR}.${SEMANTIC_VERSION_PATCH}") + endif() + + message(STATUS "Project version is: ${SEMANTIC_VERSION}") + + set(SEMANTIC_VERSION "${SEMANTIC_VERSION}" PARENT_SCOPE) +endfunction() + +get_semantic_version()