From dd8a9c3cd197ef6d6594d887892c6d9894dcf599 Mon Sep 17 00:00:00 2001 From: "Maarten L. Hekkelman" Date: Tue, 15 Aug 2023 10:30:15 +0200 Subject: [PATCH] refactored into a lib and an executable --- .gitignore | 1 + CMakeLists.txt | 97 +---- cmake/GetGitRevisionDescription.cmake | 284 -------------- cmake/GetGitRevisionDescription.cmake.in | 43 --- cmake/VersionString.cmake | 361 ++++++++++++++++-- libdssp/CMakeLists.txt | 194 ++++++++++ {cmake => libdssp/cmake}/dsspConfig.cmake.in | 0 {cmake => libdssp/cmake}/libdssp.pc.in | 0 {include => libdssp/include}/dssp.hpp | 0 .../mmcif_pdbx}/dssp-extension.dic | 0 {src => libdssp/src}/dssp-io.cpp | 13 +- {src => libdssp/src}/dssp-io.hpp | 0 {src => libdssp/src}/dssp.cpp | 0 test/unit-test-dssp.cpp | 2 +- 14 files changed, 537 insertions(+), 458 deletions(-) delete mode 100644 cmake/GetGitRevisionDescription.cmake delete mode 100644 cmake/GetGitRevisionDescription.cmake.in create mode 100644 libdssp/CMakeLists.txt rename {cmake => libdssp/cmake}/dsspConfig.cmake.in (100%) rename {cmake => libdssp/cmake}/libdssp.pc.in (100%) rename {include => libdssp/include}/dssp.hpp (100%) rename {mmcif_pdbx => libdssp/mmcif_pdbx}/dssp-extension.dic (100%) rename {src => libdssp/src}/dssp-io.cpp (99%) rename {src => libdssp/src}/dssp-io.hpp (100%) rename {src => libdssp/src}/dssp.cpp (100%) diff --git a/.gitignore b/.gitignore index 9813670..f8a913d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ build/ .gdb_history **/*.dssp src/revision.hpp +libdssp/src/revision.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 820c340..4ef6bed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,23 +108,7 @@ if(NOT PDB_REDO_META) find_package(cifpp 5.1.0 REQUIRED) endif() -# The DSSP code is in a separate library, optionally to be used by others -add_library(dssp - ${PROJECT_SOURCE_DIR}/src/dssp.cpp - ${PROJECT_SOURCE_DIR}/include/dssp.hpp - ${PROJECT_SOURCE_DIR}/src/dssp-io.cpp - ${PROJECT_SOURCE_DIR}/src/dssp-io.hpp -) - -add_library(dssp::dssp ALIAS dssp) - -target_link_libraries(dssp PUBLIC cifpp::cifpp) - -target_include_directories(dssp - PUBLIC - "$" - "$" -) +add_subdirectory(libdssp) add_executable(mkdssp ${PROJECT_SOURCE_DIR}/src/mkdssp.cpp) @@ -134,87 +118,14 @@ if(USE_RSRC) mrc_target_resources(mkdssp ${CIFPP_SHARE_DIR}/mmcif_pdbx.dic ${CIFPP_SHARE_DIR}/mmcif_ddl.dic - ${PROJECT_SOURCE_DIR}/mmcif_pdbx/dssp-extension.dic) + ${PROJECT_SOURCE_DIR}/libdssp/mmcif_pdbx/dssp-extension.dic) endif() # Install rules -install(TARGETS dssp - EXPORT dsspTargets - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) - -if(MSVC AND BUILD_SHARED_LIBS) - install( - FILES $ - DESTINATION ${CMAKE_INSTALL_LIBDIR} - OPTIONAL) -endif() - -install(EXPORT dsspTargets - FILE "dsspTargets.cmake" - NAMESPACE dssp:: - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/dssp -) - -install( - FILES include/dssp.hpp - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - COMPONENT Devel -) - -set(CONFIG_TEMPLATE_FILE ${PROJECT_SOURCE_DIR}/cmake/dsspConfig.cmake.in) - -configure_package_config_file( - ${CONFIG_TEMPLATE_FILE} - ${CMAKE_CURRENT_BINARY_DIR}/dssp/dsspConfig.cmake - INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/dssp -) - -install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/dssp/dsspConfig.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/dssp/dsspConfigVersion.cmake" - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/dssp - COMPONENT Devel -) - -set(dssp_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}) -set_target_properties(dssp PROPERTIES - VERSION ${PROJECT_VERSION} - SOVERSION ${dssp_MAJOR_VERSION} - INTERFACE_dssp_MAJOR_VERSION ${dssp_MAJOR_VERSION}) - -set_property(TARGET dssp APPEND PROPERTY - COMPATIBLE_INTERFACE_STRING dssp_MAJOR_VERSION -) - -write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/dssp/dsspConfigVersion.cmake" - VERSION ${PROJECT_VERSION} - COMPATIBILITY AnyNewerVersion -) - -# pkgconfig support -set(prefix ${CMAKE_INSTALL_PREFIX}) -set(exec_prefix ${CMAKE_INSTALL_PREFIX}) -set(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) -set(includedir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}) - -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/libdssp.pc.in - ${CMAKE_CURRENT_BINARY_DIR}/libdssp.pc.in @ONLY) -file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/libdssp.pc - INPUT ${CMAKE_CURRENT_BINARY_DIR}/libdssp.pc.in) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libdssp.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) - install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${BIN_INSTALL_DIR} ) -set(CIFPP_DATA_DIR "${CMAKE_INSTALL_FULL_DATADIR}/libcifpp") -install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/mmcif_pdbx/dssp-extension.dic" - DESTINATION ${CIFPP_DATA_DIR}) - if(GENERATE_DOCUMENTATION) # manual find_program(PANDOC pandoc) @@ -268,12 +179,12 @@ if(ENABLE_TESTING) # We still depend on boost for the testing headers-only library find_package(Boost REQUIRED) - add_executable(unit-test-dssp ${PROJECT_SOURCE_DIR}/test/unit-test-dssp.cpp ${PROJECT_SOURCE_DIR}/src/dssp-io.cpp) + add_executable(unit-test-dssp ${PROJECT_SOURCE_DIR}/test/unit-test-dssp.cpp ${PROJECT_SOURCE_DIR}/libdssp/src/dssp-io.cpp) if(USE_RSRC) mrc_target_resources(unit-test-dssp ${CIFPP_SHARE_DIR}/mmcif_pdbx.dic ${CIFPP_SHARE_DIR}/mmcif_ddl.dic - ${CMAKE_CURRENT_SOURCE_DIR}/mmcif_pdbx/dssp-extension.dic) + ${CMAKE_CURRENT_SOURCE_DIR}/libdssp/mmcif_pdbx/dssp-extension.dic) endif() target_include_directories(unit-test-dssp PRIVATE diff --git a/cmake/GetGitRevisionDescription.cmake b/cmake/GetGitRevisionDescription.cmake deleted file mode 100644 index 4fbd90d..0000000 --- a/cmake/GetGitRevisionDescription.cmake +++ /dev/null @@ -1,284 +0,0 @@ -# - 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() diff --git a/cmake/GetGitRevisionDescription.cmake.in b/cmake/GetGitRevisionDescription.cmake.in deleted file mode 100644 index 116efc4..0000000 --- a/cmake/GetGitRevisionDescription.cmake.in +++ /dev/null @@ -1,43 +0,0 @@ -# -# 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() diff --git a/cmake/VersionString.cmake b/cmake/VersionString.cmake index a54638a..05c80c6 100644 --- a/cmake/VersionString.cmake +++ b/cmake/VersionString.cmake @@ -1,6 +1,6 @@ # SPDX-License-Identifier: BSD-2-Clause -# Copyright (c) 2021 NKI/AVL, Netherlands Cancer Institute +# Copyright (c) 2021-2023 NKI/AVL, Netherlands Cancer Institute # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: @@ -22,60 +22,359 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# This cmake extension writes out a revision.hpp file in a specified directory. +# The file will contain a C++ inline function that can be used to write out +# version information. + cmake_minimum_required(VERSION 3.15) +# We want the revision.hpp file to be updated whenever the status of the +# git repository changes. Use the same technique as in GetGitRevisionDescription.cmake + + +#[=======================================================================[.rst: +.. command:: write_version_header + + Write a file named revision.hpp containing version info:: + + write_version_header( + [FILE_NAME ] + [LIB_NAME ] + ) + + This command will generate the code to write a file name + revision.hpp in the directory ````. + + ``FILE_NAME`` + Specify the name of the file to create, default is ``revision.hpp``. + + ``LIB_NAME`` + Specify the library name which will be used as a prefix part for the + variables contained in the revision file. +#]=======================================================================] + +# First locate a .git file or directory. +function(_get_git_dir _start_dir _variable) + + set(cur_dir "${_start_dir}") + set(git_dir "${_start_dir}/.git") + + while(NOT EXISTS "${git_dir}") + # .git dir not found, search parent directories + set(prev_dir "${cur_dir}") + get_filename_component(cur_dir "${cur_dir}" DIRECTORY) + if(cur_dir STREQUAL prev_dir OR cur_dir STREQUAL ${_start_dir}) + # we are not in git since we either hit root or + # the CMAKE_SOURCE_DIR which should be the top + set(${_variable} + "" + PARENT_SCOPE) + return() + endif() + set(git_dir "${cur_dir}/.git") + endwhile() + + set(${_variable} "${git_dir}" PARENT_SCOPE) +endfunction() + +# Locate the git refspec hash and load the hash +# This code locates the file containing the git refspec/hash +# and loads it. Doing it this way assures that each time the git +# repository changes the revision.hpp file gets out of date. +function(_get_git_hash _data_dir _variable) + + # Be pessimistic + set(_variable "" PARENT_SCOPE) + + # Load git package if needed + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + + # And fail if not found + if(NOT GIT_FOUND) + return() + endif() + + # Locate the nearest .git file or directory + _get_git_dir(${CMAKE_CURRENT_SOURCE_DIR} GIT_DIR) + + # And fail if not found + if("${GIT_DIR}" STREQUAL "") + 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(IS_DIRECTORY ${GIT_DIR}) + set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD") + else() + # 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 not 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) + _get_git_dir("${git_worktree_dir}" GIT_DIR) + set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD") + endif() + endif() + + # Fail if the 'head' file was not found + if(NOT EXISTS "${HEAD_SOURCE_FILE}") + return() + endif() + + # Make a copy of the head file + set(HEAD_FILE "${_data_dir}/HEAD") + configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY) + + # Now we create a cmake file that will read the contents of this + # head file in the appropriate way + file(WRITE "${_data_dir}/grab-ref.cmake.in" [[ +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}" "@VERSION_STRING_DATA@/head-ref" COPYONLY) + else() + configure_file("@GIT_DIR@/packed-refs" "@VERSION_STRING_DATA@/packed-refs" COPYONLY) + file(READ "@VERSION_STRING_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" "@VERSION_STRING_DATA@/head-ref" COPYONLY) +endif() + +if(NOT HEAD_HASH) + file(READ "@VERSION_STRING_DATA@/head-ref" HEAD_HASH LIMIT 1024) + string(STRIP "${HEAD_HASH}" HEAD_HASH) +endif() +]]) + + configure_file("${VERSION_STRING_DATA}/grab-ref.cmake.in" + "${VERSION_STRING_DATA}/grab-ref.cmake" @ONLY) + + # Include the aforementioned file, this will define + # the HEAD_HASH variable we're looking for + include("${VERSION_STRING_DATA}/grab-ref.cmake") + + set(${_variable} "${HEAD_HASH}" PARENT_SCOPE) +endfunction() + # Create a revision file, containing the current git version info, if any function(write_version_header dir) + + set(flags ) + set(options LIB_NAME FILE_NAME) + set(sources ) + cmake_parse_arguments(VERSION_STRING_OPTION "${flags}" "${options}" "${sources}" ${ARGN}) + # parameter check if(NOT IS_DIRECTORY ${dir}) message(FATAL_ERROR "First parameter to write_version_header should be a directory where the final revision.hpp file will be placed") endif() - include(GetGitRevisionDescription) - if(NOT(GIT-NOTFOUND OR HEAD-HASH-NOTFOUND)) - git_describe_working_tree(BUILD_VERSION_STRING --match=build --dirty) - - if(BUILD_VERSION_STRING MATCHES "build-([0-9]+)-g([0-9a-f]+)(-dirty)?") - set(BUILD_GIT_TAGREF "${CMAKE_MATCH_2}") - if(CMAKE_MATCH_3) - set(BUILD_VERSION_STRING "${CMAKE_MATCH_1}*") - else() - set(BUILD_VERSION_STRING "${CMAKE_MATCH_1}") - endif() - endif() + if(VERSION_STRING_OPTION_FILE_NAME) + set(file_name "${VERSION_STRING_OPTION_FILE_NAME}") else() - message(WARNING "no git info available, cannot update version string") + set(file_name "revision.hpp") endif() - string(TIMESTAMP BUILD_DATE_TIME "%Y-%m-%dT%H:%M:%SZ" UTC) + # Where to store intermediate files + set(VERSION_STRING_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/VersionString") + if(NOT EXISTS "${VERSION_STRING_DATA}") + file(MAKE_DIRECTORY "${VERSION_STRING_DATA}") + endif() - if(ARGC GREATER 1) - set(VAR_PREFIX "${ARGV1}") + # Load the git hash using the wizzard-like code above. + _get_git_hash("${VERSION_STRING_DATA}" GIT_HASH) + + # If git was found, fetch the git description string + if(GIT_HASH) + execute_process( + COMMAND "${GIT_EXECUTABLE}" describe --dirty --match=build + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE res + OUTPUT_VARIABLE out + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(res EQUAL 0) + set(REVISION_STRING "${out}") + endif() endif() - file(WRITE "${PROJECT_BINARY_DIR}/revision.hpp.in" [[// Generated revision file + # Check the revision string, if it matches we fill in the required info + if(REVISION_STRING MATCHES "build-([0-9]+)-g([0-9a-f]+)(-dirty)?") + set(BUILD_NUMBER ${CMAKE_MATCH_1}) + if(CMAKE_MATCH_3) + set(REVISION_GIT_TAGREF "${CMAKE_MATCH_2}*") + else() + set(REVISION_GIT_TAGREF "${CMAKE_MATCH_2}") + endif() + + string(TIMESTAMP REVISION_DATE_TIME "%Y-%m-%dT%H:%M:%SZ" UTC) + else() + message(STATUS "no git info available, cannot update version string") + + set(REVISION_GIT_TAGREF "") + set(BUILD_NUMBER 0) + set(REVISION_DATE_TIME "") + endif() + + if(VERSION_STRING_OPTION_LIB_NAME) + set(VAR_PREFIX "${VERSION_STRING_OPTION_LIB_NAME}") + set(IDENT_PREFIX "${VERSION_STRING_OPTION_LIB_NAME}_") + else() + set(VAR_PREFIX "") + set(IDENT_PREFIX "") + endif() + + file(WRITE "${VERSION_STRING_DATA}/${file_name}.in" [[// This file was generated by VersionString.cmake #pragma once #include -const char k@VAR_PREFIX@ProjectName[] = "@PROJECT_NAME@"; -const char k@VAR_PREFIX@VersionNumber[] = "@PROJECT_VERSION@"; -const char k@VAR_PREFIX@VersionGitTag[] = "@BUILD_GIT_TAGREF@"; -const char k@VAR_PREFIX@BuildInfo[] = "@BUILD_VERSION_STRING@"; -const char k@VAR_PREFIX@BuildDate[] = "@BUILD_DATE_TIME@"; +constexpr const char k@VAR_PREFIX@ProjectName[] = "@PROJECT_NAME@"; +constexpr const char k@VAR_PREFIX@VersionNumber[] = "@PROJECT_VERSION@"; +constexpr int k@VAR_PREFIX@BuildNumber = @BUILD_NUMBER@; +constexpr const char k@VAR_PREFIX@RevisionGitTag[] = "@REVISION_GIT_TAGREF@"; +constexpr const char k@VAR_PREFIX@RevisionDate[] = "@REVISION_DATE_TIME@"; + +#ifndef VERSION_INFO_DEFINED +#define VERSION_INFO_DEFINED 1 + +class version_info_base +{ + public: + virtual ~version_info_base() = default; + + static void write(std::ostream &os, bool verbose) + { + auto s_head = head(); + if (s_head != nullptr) + write(s_head, os, verbose); + } + + protected: + + struct instance + { + const char *m_name; + const char *m_version; + int m_build; + const char *m_git_tag; + const char *m_revision_date; + + instance *m_next = nullptr; + }; + + static void write(const instance *inst, std::ostream &os, bool verbose) + { + if (inst->m_next != nullptr) + { + write(inst->m_next, os, verbose); + if (not verbose) + return; + os << '-' << std::endl; + } + + os << inst->m_name << " version " << inst->m_version << std::endl; + + if (verbose) + { + if (inst->m_build != 0) + { + os << "build: " << inst->m_build << ' ' << inst->m_revision_date << std::endl; + if (inst->m_git_tag[0] != 0) + os << "git tag: " << inst->m_git_tag << std::endl; + } + else + os << "No revision information available" << std::endl; + } + } + + using instance_ptr = instance *; + + static instance_ptr &head() + { + static instance_ptr s_head = nullptr; + return s_head; + } +}; + +template +class version_info : public version_info_base +{ + public: + using implementation_type = T; + + protected: + version_info() + { + auto &s_head = head(); + static instance s_next{ + implementation_type::name(), + implementation_type::version(), + implementation_type::build_number(), + implementation_type::git_tag(), + implementation_type::revision_date(), + s_head }; + s_head = &s_next; + } +}; inline void write_version_string(std::ostream &os, bool verbose) { - os << k@VAR_PREFIX@ProjectName << " version " << k@VAR_PREFIX@VersionNumber << std::endl; - if (verbose) - { - os << "build: " << k@VAR_PREFIX@BuildInfo << ' ' << k@VAR_PREFIX@BuildDate << std::endl; - if (k@VAR_PREFIX@VersionGitTag[0] != 0) - os << "git tag: " << k@VAR_PREFIX@VersionGitTag << std::endl; - } + version_info_base::write(os, verbose); } + +#endif + +class version_info_@IDENT_PREFIX@impl : public version_info +{ + public: + static constexpr const char *name() { return k@VAR_PREFIX@ProjectName; } + static constexpr const char *version() { return k@VAR_PREFIX@VersionNumber; } + static constexpr int build_number() { return k@VAR_PREFIX@BuildNumber; } + static constexpr const char *git_tag() { return k@VAR_PREFIX@RevisionGitTag; } + static constexpr const char *revision_date() { return k@VAR_PREFIX@RevisionDate; } +} s_@IDENT_PREFIX@instance; ]]) - configure_file("${PROJECT_BINARY_DIR}/revision.hpp.in" "${dir}/revision.hpp" @ONLY) + configure_file("${VERSION_STRING_DATA}/${file_name}.in" "${dir}/${file_name}" @ONLY) endfunction() diff --git a/libdssp/CMakeLists.txt b/libdssp/CMakeLists.txt new file mode 100644 index 0000000..40006b0 --- /dev/null +++ b/libdssp/CMakeLists.txt @@ -0,0 +1,194 @@ +# SPDX-License-Identifier: BSD-2-Clause + +# Copyright (c) 2021 NKI/AVL, Netherlands Cancer Institute + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 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. + +cmake_minimum_required(VERSION 3.15) + +# set the project name +project(libdssp VERSION 4.4.2 LANGUAGES CXX) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +include(GNUInstallDirs) +include(CheckFunctionExists) +include(CheckIncludeFiles) +include(CheckLibraryExists) +include(CMakePackageConfigHelpers) +include(Dart) +include(FindFilesystem) +include(GenerateExportHeader) + +set(CXX_EXTENSIONS OFF) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Filesystem REQUIRED) + +if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers") +elseif(MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") +endif() + +# Optionally build a version to be installed inside CCP4 +option(BUILD_FOR_CCP4 "Build a version to be installed in CCP4" OFF) +option(GENERATE_DOCUMENTATION "Generate the documentation files using pandoc" OFF) + +if(BUILD_FOR_CCP4) + if("$ENV{CCP4}" STREQUAL "" OR NOT EXISTS $ENV{CCP4}) + message(FATAL_ERROR "A CCP4 built was requested but CCP4 was not sourced") + else() + list(APPEND CMAKE_MODULE_PATH "$ENV{CCP4}") + list(APPEND CMAKE_PREFIX_PATH "$ENV{CCP4}") + set(CMAKE_INSTALL_PREFIX "$ENV{CCP4}") + + if(WIN32) + set(BUILD_SHARED_LIBS ON) + endif() + endif() +endif() + +if(MSVC) + # make msvc standards compliant... + add_compile_options(/permissive-) + + macro(get_WIN32_WINNT version) + if(WIN32 AND CMAKE_SYSTEM_VERSION) + set(ver ${CMAKE_SYSTEM_VERSION}) + string(REPLACE "." "" ver ${ver}) + string(REGEX REPLACE "([0-9])" "0\\1" ver ${ver}) + + set(${version} "0x${ver}") + endif() + endmacro() + + get_WIN32_WINNT(ver) + add_definitions(-D_WIN32_WINNT=${ver}) +endif() + +# Create a revision file, containing the current git version info +include(VersionString) +write_version_header("${PROJECT_SOURCE_DIR}/src" LIB_NAME "libdssp") + +# Optionally use mrc to create resources +find_package(Mrc QUIET) + +set(CMAKE_THREAD_PREFER_PTHREAD) +set(THREADS_PREFER_PTHREAD_FLAG) +find_package(Threads) + +if(NOT PDB_REDO_META) + find_package(cifpp 5.1.0 REQUIRED) +endif() + +# The DSSP code is in a separate library, optionally to be used by others +add_library(dssp + ${PROJECT_SOURCE_DIR}/src/dssp.cpp + ${PROJECT_SOURCE_DIR}/include/dssp.hpp + ${PROJECT_SOURCE_DIR}/src/dssp-io.cpp + ${PROJECT_SOURCE_DIR}/src/dssp-io.hpp +) + +add_library(dssp::dssp ALIAS dssp) + +target_link_libraries(dssp PUBLIC cifpp::cifpp) + +target_include_directories(dssp + PUBLIC + "$" + "$" +) + +# Install rules +install(TARGETS dssp + EXPORT dsspTargets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + +if(MSVC AND BUILD_SHARED_LIBS) + install( + FILES $ + DESTINATION ${CMAKE_INSTALL_LIBDIR} + OPTIONAL) +endif() + +install(EXPORT dsspTargets + FILE "dsspTargets.cmake" + NAMESPACE dssp:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/dssp +) + +install( + FILES include/dssp.hpp + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + COMPONENT Devel +) + +set(CONFIG_TEMPLATE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cmake/dsspConfig.cmake.in) + +configure_package_config_file( + ${CONFIG_TEMPLATE_FILE} + ${CMAKE_CURRENT_BINARY_DIR}/dssp/dsspConfig.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/dssp +) + +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/dssp/dsspConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/dssp/dsspConfigVersion.cmake" + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/dssp + COMPONENT Devel +) + +set(dssp_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}) +set_target_properties(dssp PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${dssp_MAJOR_VERSION} + INTERFACE_dssp_MAJOR_VERSION ${dssp_MAJOR_VERSION}) + +set_property(TARGET dssp APPEND PROPERTY + COMPATIBLE_INTERFACE_STRING dssp_MAJOR_VERSION +) + +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/dssp/dsspConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion +) + +# pkgconfig support +set(prefix ${CMAKE_INSTALL_PREFIX}) +set(exec_prefix ${CMAKE_INSTALL_PREFIX}) +set(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) +set(includedir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/libdssp.pc.in + ${CMAKE_CURRENT_BINARY_DIR}/libdssp.pc.in @ONLY) +file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/libdssp.pc + INPUT ${CMAKE_CURRENT_BINARY_DIR}/libdssp.pc.in) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libdssp.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + +set(CIFPP_DATA_DIR "${CMAKE_INSTALL_FULL_DATADIR}/libcifpp") +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/mmcif_pdbx/dssp-extension.dic" + DESTINATION ${CIFPP_DATA_DIR}) diff --git a/cmake/dsspConfig.cmake.in b/libdssp/cmake/dsspConfig.cmake.in similarity index 100% rename from cmake/dsspConfig.cmake.in rename to libdssp/cmake/dsspConfig.cmake.in diff --git a/cmake/libdssp.pc.in b/libdssp/cmake/libdssp.pc.in similarity index 100% rename from cmake/libdssp.pc.in rename to libdssp/cmake/libdssp.pc.in diff --git a/include/dssp.hpp b/libdssp/include/dssp.hpp similarity index 100% rename from include/dssp.hpp rename to libdssp/include/dssp.hpp diff --git a/mmcif_pdbx/dssp-extension.dic b/libdssp/mmcif_pdbx/dssp-extension.dic similarity index 100% rename from mmcif_pdbx/dssp-extension.dic rename to libdssp/mmcif_pdbx/dssp-extension.dic diff --git a/src/dssp-io.cpp b/libdssp/src/dssp-io.cpp similarity index 99% rename from src/dssp-io.cpp rename to libdssp/src/dssp-io.cpp index 4e3cdb7..f33a8a3 100644 --- a/src/dssp-io.cpp +++ b/libdssp/src/dssp-io.cpp @@ -35,7 +35,6 @@ #include #include - // -------------------------------------------------------------------- std::string ResidueToDSSPLine(const dssp::residue_info &info) @@ -158,7 +157,7 @@ void writeDSSP(const dssp &dssp, std::ostream &os) std::time_t today = system_clock::to_time_t(system_clock::now()); std::tm *tm = std::gmtime(&today); - std::string version = kVersionNumber; + std::string version = klibdsspVersionNumber; if (version.length() < 10) version.insert(version.end(), 10 - version.length(), ' '); @@ -875,9 +874,11 @@ void annotateDSSP(cif::datablock &db, const dssp &dssp, bool writeOther, bool wr } auto &software = db["software"]; - software.emplace({ { "pdbx_ordinal", software.get_unique_id("") }, + software.emplace({ + { "pdbx_ordinal", software.get_unique_id("") }, { "name", "dssp" }, - { "version", kVersionNumber }, - { "date", kBuildDate }, - { "classification", "model annotation" } }); + { "version", klibdsspVersionNumber }, + { "date", klibdsspRevisionDate }, + { "classification", "model annotation" } + }); } diff --git a/src/dssp-io.hpp b/libdssp/src/dssp-io.hpp similarity index 100% rename from src/dssp-io.hpp rename to libdssp/src/dssp-io.hpp diff --git a/src/dssp.cpp b/libdssp/src/dssp.cpp similarity index 100% rename from src/dssp.cpp rename to libdssp/src/dssp.cpp diff --git a/test/unit-test-dssp.cpp b/test/unit-test-dssp.cpp index b394668..e627a43 100644 --- a/test/unit-test-dssp.cpp +++ b/test/unit-test-dssp.cpp @@ -30,7 +30,7 @@ #include #include "dssp.hpp" -#include "dssp-io.hpp" +#include "../libdssp/src/dssp-io.hpp" #include "revision.hpp" #include