diff --git a/CMakeLists.txt b/CMakeLists.txt index 16f607c0..e5722ad7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,15 +2,47 @@ cmake_minimum_required(VERSION 2.8.6) project(toxcore) include(CTest) +set(CMAKE_MODULE_PATH ${toxcore_SOURCE_DIR}/cmake) + +################################################################################ +# +# :: Version management +# +################################################################################ + # This version is for the entire project. All libraries (core, av, ...) move in # versions in a synchronised way. set(PROJECT_VERSION_MAJOR "0") set(PROJECT_VERSION_MINOR "1") set(PROJECT_VERSION_PATCH "4") -set(PROJECT_VERSION - "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") +set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") + +# Update versions in various places +# This must be run before setting SOVERSION, because SOVERSION is read from +# a file generated by this script +find_program(SHELL NAMES sh dash bash zsh) +if(SHELL) + execute_process( + COMMAND ${SHELL} ${toxcore_SOURCE_DIR}/other/version-sync + ${toxcore_SOURCE_DIR} + ${PROJECT_VERSION_MAJOR} + ${PROJECT_VERSION_MINOR} + ${PROJECT_VERSION_PATCH}) +endif() + +# set .so library version / following libtool scheme +# https://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info +file(STRINGS ${toxcore_SOURCE_DIR}/so.version SOVERSION_CURRENT REGEX "^CURRENT=[0-9]+$") +string(SUBSTRING "${SOVERSION_CURRENT}" 8 -1 SOVERSION_CURRENT) +file(STRINGS ${toxcore_SOURCE_DIR}/so.version SOVERSION_REVISION REGEX "^REVISION=[0-9]+$") +string(SUBSTRING "${SOVERSION_REVISION}" 9 -1 SOVERSION_REVISION) +file(STRINGS ${toxcore_SOURCE_DIR}/so.version SOVERSION_AGE REGEX "^AGE=[0-9]+$") +string(SUBSTRING "${SOVERSION_AGE}" 4 -1 SOVERSION_AGE) +# account for some libtool magic, see other/version-sync script for details +math(EXPR SOVERSION_MAJOR ${SOVERSION_CURRENT}-${SOVERSION_AGE}) +set(SOVERSION "${SOVERSION_MAJOR}.${SOVERSION_AGE}.${SOVERSION_REVISION}") +message("SOVERSION: ${SOVERSION}") -set(CMAKE_MODULE_PATH ${toxcore_SOURCE_DIR}/cmake) ################################################################################ # @@ -591,23 +623,6 @@ if(BUILD_TOXAV) DESTINATION "include/tox") endif() -################################################################################ -# -# :: Update versions in various places -# -################################################################################ - -find_program(SHELL NAMES sh dash bash zsh) - -if(SHELL) - execute_process( - COMMAND ${SHELL} ${toxcore_SOURCE_DIR}/other/version-sync - ${toxcore_SOURCE_DIR} - ${PROJECT_VERSION_MAJOR} - ${PROJECT_VERSION_MINOR} - ${PROJECT_VERSION_PATCH}) -endif() - ################################################################################ # # :: Strict ABI diff --git a/cmake/ModulePackage.cmake b/cmake/ModulePackage.cmake index f6e7e31a..38f841ba 100644 --- a/cmake/ModulePackage.cmake +++ b/cmake/ModulePackage.cmake @@ -56,10 +56,8 @@ function(add_module lib) add_library(${lib}_shared SHARED ${ARGN}) set_target_properties(${lib}_shared PROPERTIES OUTPUT_NAME ${lib} - VERSION ${PROJECT_VERSION} - # While on 0.x, the x behaves like the major version. 0.2 will be - # incompatible with 0.1. Change this, when releasing 1.0! - SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + VERSION ${SOVERSION} + SOVERSION ${SOVERSION_MAJOR} ) install(TARGETS ${lib}_shared DESTINATION "lib") endif() diff --git a/other/version-sync b/other/version-sync index 3fb1aa80..fdfe91d9 100755 --- a/other/version-sync +++ b/other/version-sync @@ -17,7 +17,9 @@ update() { if diff "$file" "$file.updated-version"; then rm "$file.updated-version" else - mv "$file.updated-version" "$file" + # use cat > and rm instead of move to keep file permissions + cat "$file.updated-version" > "$file" + rm "$file.updated-version" fi } @@ -26,3 +28,99 @@ update 'configure.ac' 's/AC_INIT(\[tox\], \[.*\])/AC_INIT([tox], ['$VER'])/' update 'toxcore/tox.api.h' 's/\(const VERSION_MAJOR *= \).*;/\1'$MAJOR';/' update 'toxcore/tox.api.h' 's/\(const VERSION_MINOR *= \).*;/\1'$MINOR';/' update 'toxcore/tox.api.h' 's/\(const VERSION_PATCH *= \).*;/\1'$PATCH';/' + +# +# calculating the SO version +# +# The SO version reflects changes in the ABI compatibility of the libary [1]. +# The general convention on this is that the SO version is a monotonically +# increasing number. The major version reflects breaking changes and the minor +# number reflect non-breaking updates [2]. +# +# The SO version for tox libraries consists of two parts: `A.B`. +# - incrementing A reflects an ABI breaking change. +# - incrementing B reflects a non-ABI-breaking update. B is set to 0 when A is incremented. +# +# As the tox versioning scheme directly reflects ABI compatibility, we can use it +# to construct the SO version. +# +# In the `0.y.z` release cycle, breaking changes are allowed in every increment of `y`, +# so we can build the SO version just by taking `y.z`. +# In the `x.y.z` release cycle with `x > 0` the SO version must be calculated by taking +# the major of the tox version and add a hardcoded number that is the last A of the 0.y.z +# release cycle. +# +# References: +# +# [1]: https://autotools.io/libtool/version.html +# [2]: http://www.ibm.com/developerworks/linux/library/l-shlibs/index.html#N1006E +# + +# the last major version number from the 0.x release cycle +# this must be constant starting from the 1.0 release +LAST_SOMAJOR=1 + +if [ $MAJOR -eq 0 ]; then + SOMAJOR=$MINOR + SOMINOR=$PATCH + + # update lastmajor above + update 'other/version-sync' 's/^\(LAST_SOMAJOR=\).*/\1'$SOMAJOR'/' +else + SOMAJOR=$(expr $MAJOR + $LAST_SOMAJOR) + SOMINOR=$MINOR +fi + +# +# libtool has a quite cryptic implementation of the versioning system, which also +# changes between systems, see https://github.com/lxde/lxqt/issues/488#issuecomment-238084222 +# +# .so library version, following the libtool scheme: +# +# current:revision:age +# +# current: increment if interfaces have been added, removed or changed +# revision: increment if source code has changed, set to zero if current is +# incremented +# age: increment if interfaces have been added, set to zero if +# interfaces have been removed or changed +# +# For a full reference see: +# https://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info +# +# Passing such a version string to libtool will generate the following version number +# on the libary binary file on GNU/Linux: +# +# (current - age).(age).(revision) +# +# We do not want to use a separate version numbering for the library because the package versioning is equally good: +# +# Semver non-breaking: 0.y.(z+1) or x.(y+1).0: +# +# This would mean to increment current and age, which leave the major of SOVERSION the same. +# Revision is incremented. +# +# Semver breaking: 0.(y+1).0 or (x+1).0.0: +# +# This would mean to increment current, set age and revision to zero. +# +# Thus to make libtool use our version, we have to pass (major + minor):patch:minor as current:revision:age to get: +# +# (current - age).(age).(revision) +# <=> (major + minor - minor).minor.patch +# <=> major.minor.patch +# + +if [ $MAJOR -eq 0 ]; then + LIBTOOL_CURRENT=$(expr $SOMAJOR + $SOMINOR) + LIBTOOL_AGE=$SOMINOR + LIBTOOL_REVISION=0 +else + LIBTOOL_CURRENT=$(expr $SOMAJOR + $SOMINOR) + LIBTOOL_AGE=$SOMINOR + LIBTOOL_REVISION=$PATCH +fi + +update 'so.version' 's/^\(CURRENT=\).*/\1'$LIBTOOL_CURRENT'/' +update 'so.version' 's/^\(AGE=\).*/\1'$LIBTOOL_AGE'/' +update 'so.version' 's/^\(REVISION=\).*/\1'$LIBTOOL_REVISION'/'