aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt64
-rw-r--r--DefineOptions.cmake6
-rw-r--r--cmake/Modules/ExtractSymbols.cmake88
-rw-r--r--cmake/Modules/FindABIMap.cmake394
-rw-r--r--cmake/Modules/GenerateMap.cmake118
-rw-r--r--cmake/Modules/GetFilesList.cmake59
-rwxr-xr-xobj/build_make.sh8
-rw-r--r--src/ABI/current2
-rw-r--r--src/CMakeLists.txt44
9 files changed, 779 insertions, 4 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e2a04c26..66c7fa64 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -81,6 +81,13 @@ if (BSD OR SOLARIS OR OSX)
find_package(Argp)
endif (BSD OR SOLARIS OR OSX)
+# Disable symbol versioning in non UNIX platforms
+if (UNIX)
+ find_package(ABIMap)
+else (UNIX)
+ set(WITH_SYMBOL_VERSIONING OFF)
+endif (UNIX)
+
# config.h checks
include(ConfigureChecks.cmake)
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
@@ -132,6 +139,60 @@ if (UNIT_TESTING)
add_subdirectory(tests)
endif (UNIT_TESTING)
+### SOURCE PACKAGE
+if (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
+ # Get the current ABI version from source
+ get_filename_component(current_abi_path
+ "${CMAKE_SOURCE_DIR}/src/ABI/current"
+ ABSOLUTE)
+
+ # Check if the ABI version should be updated
+ file(READ ${current_abi_path} CURRENT_ABI_CONTENT)
+ string(STRIP "${CURRENT_ABI_CONTENT}" CURRENT_ABI_VERSION)
+
+ if (LIBRARY_VERSION VERSION_GREATER CURRENT_ABI_VERSION)
+ set(UPDATE_ABI TRUE)
+ endif ()
+
+ if (UPDATE_ABI)
+ message(STATUS "Library version bumped to ${LIBRARY_VERSION}: Updating ABI")
+
+ # Get the list of header files
+ get_file_list("${PROJECT_NAME}_header_list"
+ DIRECTORIES "${CMAKE_SOURCE_DIR}/include/libssh"
+ FILES_PATTERNS "*.h")
+
+ # Extract the symbols marked as "LIBSSH_API" from the header files
+ extract_symbols(${PROJECT_NAME}.symbols
+ HEADERS_LIST_FILE "${PROJECT_NAME}_header_list"
+ FILTER_PATTERN "LIBSSH_API"
+ COPY_TO "${CMAKE_SOURCE_DIR}/src/ABI/${PROJECT_NAME}-${LIBRARY_VERSION}.symbols")
+
+ if (WITH_ABI_BREAK)
+ set(ALLOW_ABI_BREAK "BREAK_ABI")
+ endif()
+
+ # Target we can depend on in 'make dist'
+ set(_SYMBOL_TARGET "${PROJECT_NAME}.map")
+
+ # Set the path to the current map file
+ set(MAP_PATH "${CMAKE_SOURCE_DIR}/src/${_SYMBOL_TARGET}")
+
+ # Generate the symbol version map file
+ generate_map_file(${_SYMBOL_TARGET}
+ SYMBOLS "${PROJECT_NAME}.symbols"
+ RELEASE_NAME_VERSION ${PROJECT_NAME}_${LIBRARY_VERSION}
+ CURRENT_MAP ${MAP_PATH}
+ COPY_TO ${MAP_PATH}
+ FINAL
+ ${ALLOW_ABI_BREAK})
+
+ # Write the current version to the source
+ file(WRITE ${current_abi_path} ${LIBRARY_VERSION})
+ endif(UPDATE_ABI)
+endif (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
+
+add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source DEPENDS ${_SYMBOL_TARGET})
message(STATUS "********************************************")
message(STATUS "********** ${PROJECT_NAME} build options : **********")
@@ -158,5 +219,8 @@ else (WITH_INTERNAL_DOC)
message(STATUS "Public API documentation generation")
endif (WITH_INTERNAL_DOC)
message(STATUS "Benchmarks: ${WITH_BENCHMARKS}")
+message(STATUS "Symbol versioning: ${WITH_SYMBOL_VERSIONING}")
+message(STATUS "Allow ABI break: ${WITH_ABI_BREAK}")
+message(STATUS "Release is final: ${WITH_FINAL}")
message(STATUS "********************************************")
diff --git a/DefineOptions.cmake b/DefineOptions.cmake
index 77808276..eb60b097 100644
--- a/DefineOptions.cmake
+++ b/DefineOptions.cmake
@@ -16,6 +16,8 @@ option(SERVER_TESTING "Build with server tests; requires openssh and dropbear" O
option(WITH_BENCHMARKS "Build benchmarks tools" OFF)
option(WITH_EXAMPLES "Build examples" ON)
option(WITH_NACL "Build with libnacl (curve25519)" ON)
+option(WITH_SYMBOL_VERSIONING "Build with symbol versioning" ON)
+option(WITH_ABI_BREAK "Allow ABI break" OFF)
option(FUZZ_TESTING "Build with fuzzer for the server" OFF)
if (WITH_ZLIB)
set(WITH_LIBZ ON)
@@ -34,3 +36,7 @@ endif (UNIT_TESTING)
if (WITH_NACL)
set(WITH_NACL ON)
endif (WITH_NACL)
+
+if (WITH_ABI_BREAK)
+ set(WITH_SYMBOL_VERSIONING ON)
+endif (WITH_ABI_BREAK)
diff --git a/cmake/Modules/ExtractSymbols.cmake b/cmake/Modules/ExtractSymbols.cmake
new file mode 100644
index 00000000..d37778e1
--- /dev/null
+++ b/cmake/Modules/ExtractSymbols.cmake
@@ -0,0 +1,88 @@
+#
+# Copyright (c) 2018 Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
+#
+# Redistribution and use is allowed according to the terms of the New
+# BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+#
+
+#.rst:
+# ExtractSymbols
+# --------------
+#
+# This is a helper script for FindABImap.cmake.
+#
+# Extract symbols from header files and output a list to a file.
+# This script is run in build time to extract symbols from the provided header
+# files. This way, symbols added or removed can be checked and used to update
+# the symbol version script.
+#
+# All symbols followed by the character ``'('`` are extracted. If a
+# ``FILTER_PATTERN`` is provided, only the lines containing the given string are
+# considered.
+#
+# Expected defined variables
+# --------------------------
+#
+# ``HEADERS_LIST_FILE``:
+# Required, expects a file containing the list of header files to be parsed.
+#
+# ``OUTPUT_PATH``:
+# Required, expects the output file path.
+#
+# Optionally defined variables
+# ----------------------------
+#
+# ``FILTER_PATTERN``:
+# Expects a string. Only lines containing the given string will be considered
+# when extracting symbols.
+#
+
+if (NOT DEFINED OUTPUT_PATH)
+ message(SEND_ERROR "OUTPUT_PATH not defined")
+endif()
+
+if (NOT DEFINED HEADERS_LIST_FILE)
+ message(SEND_ERROR "HEADERS not defined")
+endif()
+
+file(READ ${HEADERS_LIST_FILE} HEADERS_LIST)
+
+set(symbols)
+foreach(header ${HEADERS_LIST})
+
+ # Filter only lines containing the FILTER_PATTERN
+ file(STRINGS ${header} contain_filter
+ REGEX "^.*${FILTER_PATTERN}.*[(]"
+ )
+
+ # Remove function-like macros
+ foreach(line ${contain_filter})
+ if (NOT ${line} MATCHES ".*#[ ]*define")
+ list(APPEND not_macro ${line})
+ endif()
+ endforeach()
+
+ set(functions)
+
+ # Get only the function names followed by '('
+ foreach(line ${not_macro})
+ string(REGEX MATCHALL "[a-zA-Z0-9_]+[ ]*[(]" func ${line})
+ list(APPEND functions ${func})
+ endforeach()
+
+ set(extracted_symbols)
+
+ # Remove '('
+ foreach(line ${functions})
+ string(REGEX REPLACE "[(]" "" symbol ${line})
+ string(STRIP "${symbol}" symbol)
+ list(APPEND extracted_symbols ${symbol})
+ endforeach()
+
+ list(APPEND symbols ${extracted_symbols})
+endforeach()
+
+list(REMOVE_DUPLICATES symbols)
+
+file(WRITE ${OUTPUT_PATH} "${symbols}")
diff --git a/cmake/Modules/FindABIMap.cmake b/cmake/Modules/FindABIMap.cmake
new file mode 100644
index 00000000..78bfa36a
--- /dev/null
+++ b/cmake/Modules/FindABIMap.cmake
@@ -0,0 +1,394 @@
+#
+# Copyright (c) 2018 Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
+#
+# Redistribution and use is allowed according to the terms of the New
+# BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+#
+
+#.rst:
+# FindABIMap
+# ----------
+#
+# This file provides functions to generate the symbol version script. It uses
+# the ``abimap`` tool to generate and update the linker script file. It can be
+# installed by calling::
+#
+# $ pip install abimap
+#
+# The ``function generate_map_file`` generates a symbol version script
+# containing the provided symbols. It defines a custom command which sets
+# ``target_name`` as its ``OUTPUT``.
+#
+# The experimental function ``extract_symbols()`` is provided as a simple
+# parser to extract the symbols from C header files. It simply extracts symbols
+# followed by an opening '``(``'. It is recommended to use a filter pattern to
+# select the lines to be considered. It defines a custom command which sets
+# ``target_name`` as its output.
+#
+# The helper function ``get_files_list()`` is provided to find files given a
+# name pattern. It defines a custom command which sets ``target_name`` as its
+# output.
+#
+# Functions provided
+# ------------------
+#
+# ::
+#
+# generate_map_file(target_name
+# RELEASE_NAME_VERSION release_name
+# SYMBOLS symbols_file
+# [CURRENT_MAP cur_map]
+# [FINAL]
+# [BREAK_ABI]
+# [COPY_TO output]
+# )
+#
+# ``target_name``:
+# Required, expects the name of the file to receive the generated symbol
+# version script. It should be added as a dependency for the library. Use the
+# linker option ``--version-script filename`` to add the version information
+# to the symbols when building the library.
+#
+# ``RELEASE_NAME_VERSION``:
+# Required, expects a string containing the name and version information to be
+# added to the symbols in the format ``lib_name_1_2_3``.
+#
+# ``SYMBOLS``:
+# Required, expects a file containing the list of symbols to be added to the
+# symbol version script.
+#
+# ``CURRENT_MAP``:
+# Optional. If given, the new set of symbols will be checked against the
+# ones contained in the ``cur_map`` file and updated properly. If an
+# incompatible change is detected and ``BREAK_ABI`` is not defined, the build
+# will fail.
+#
+# ``FINAL``:
+# Optional. If given, will provide the ``--final`` option to ``abimap`` tool,
+# which will mark the modified release in the symbol version script with a
+# special comment, preventing later changes. This option should be set when
+# creating a library release and the resulting map file should be stored with
+# the source code.
+#
+# ``BREAK_ABI``:
+# Optional. If provided, will use ``abimap`` ``--allow-abi-break`` option, which
+# accepts incompatible changes to the set of symbols. This is necessary if any
+# previously existing symbol were removed.
+#
+# ``COPY_TO``:
+# Optional, expects a string containing the path to where the generated
+# map file will be copied.
+#
+# Example:
+#
+# .. code-block:: cmake
+#
+# find_package(ABIMap)
+# generate_map_file("lib.map"
+# RELEASE_NAME_VERSION "lib_1_0_0"
+# SYMBOLS "symbol1;symbol2"
+# )
+#
+# This example would result in the symbol version script to be created in
+# ``${CMAKE_CURRENT_BINARY_DIR}/lib.map`` containing the provided symbols.
+#
+# ::
+#
+# get_files_list(target_name
+# DIRECTORIES dir1 [dir2 ...]
+# FILES_PATTERNS exp1 [exp2 ...]
+# [COPY_TO output]
+# )
+#
+# ``target_name``:
+# Required, expects the name of the target to be created. A file named after
+# the string given in ``target_name`` will be created in
+# ``${CMAKE_CURRENT_BINARY_DIR}`` to receive the list of files found.
+#
+# ``DIRECTORIES``:
+# Required, expects a list of directories paths. Only absolute paths are
+# supported.
+#
+# ``FILES_PATTERN``:
+# Required, expects a list of matching expressions to find the files to be
+# considered.
+#
+# ``COPY_TO``:
+# Optional, expects a string containing the path to where the file containing
+# the list of files will be copied.
+#
+# This command searches the directories provided in ``DIRECTORIES`` for files
+# matching any of the patterns provided in ``FILES_PATTERNS``. The obtained list
+# is written to the path specified by ``output``.
+#
+# Example:
+#
+# .. code-block:: cmake
+#
+# find_package(ABIMap)
+# get_files_list(target
+# DIRECTORIES "/include/mylib"
+# FILES_PATTERNS "*.h"
+# COPY_TO "my_list.txt"
+# )
+#
+# Consider that ``/include/mylib`` contains 3 files, ``h1.h``, ``h2.h``, and
+# ``h3.hpp``
+#
+# Will result in a file ``my_list.txt`` containing::
+#
+# ``h1.h;h2.h``
+#
+# ::
+#
+# extract_symbols(target_name
+# HEADERS_LIST_FILE headers_list
+# [FILTER_PATTERN pattern]
+# [COPY_TO output]
+# )
+#
+# ``target_name``:
+# Required, expects the name of the target to be created. A file named after
+# the string given in ``target_name`` will be created in
+# ``${CMAKE_CURRENT_BINARY_DIR}`` to receive the list of symbols.
+#
+# ``HEADERS_LIST_FILE``:
+# Required, expects a path to a file containing the list of header files to be
+# parsed.
+#
+# ``FILTER_PATTERN``:
+# Optional, expects a string. Only the lines containing the filter pattern
+# will be considered.
+#
+# ``COPY_TO``:
+# Optional, expects a string containing the path to where the file containing
+# the found symbols will be copied.
+#
+# This command extracts the symbols from the files listed in
+# ``headers_list`` and write them on the ``output`` file. If ``pattern``
+# is provided, then only the lines containing the string given in ``pattern``
+# will be considered. It is recommended to provide a ``FILTER_PATTERN`` to mark
+# the lines containing exported function declaration, since this function is
+# experimental and can return wrong symbols when parsing the header files.
+#
+# Example:
+#
+# .. code-block:: cmake
+#
+# find_package(ABIMap)
+# extract_symbols("lib.symbols"
+# HEADERS_LIST_FILE "headers_list"
+# FILTER_PATTERN "API_FUNCTION"
+# )
+#
+# Where headers_list contains::
+#
+# header1.h;header2.h
+#
+# Where ``header1.h`` contains::
+#
+# API_FUNCTION int exported_func1(int a, int b);
+#
+# ``header2.h`` contains::
+#
+# API_FUNCTION int exported_func2(int a);
+#
+# int private_func2(int b);
+#
+# Will result in a file ``lib.symbols`` in ``${CMAKE_CURRENT_BINARY_DIR}`` containing::
+#
+# ``exported_func1;exported_func2``
+#
+
+# Search for python which is required
+find_package(PythonInterp REQUIRED)
+
+# Search for abimap tool used to generate the map files
+find_program(ABIMAP_EXECUTABLE NAMES abimap DOC "path to the abimap executable")
+mark_as_advanced(ABIMAP_EXECUTABLE)
+
+if (NOT ABIMAP_EXECUTABLE AND UNIX)
+ message(STATUS "Could not find `abimap` in PATH."
+ " It can be found in PyPI as `abimap`"
+ " (try `pip install abimap`)")
+else ()
+ set(ABIMAP_FOUND TRUE)
+endif ()
+
+# Define helper scripts
+set(_EXTRACT_SYMBOLS_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/ExtractSymbols.cmake)
+set(_GENERATE_MAP_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/GenerateMap.cmake)
+set(_GET_FILES_LIST_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/GetFilesList.cmake)
+
+function(get_file_list _TARGET_NAME)
+
+ set(one_value_arguments
+ COPY_TO
+ )
+
+ set(multi_value_arguments
+ DIRECTORIES
+ FILES_PATTERNS
+ )
+
+ cmake_parse_arguments(_get_files_list
+ ""
+ "${one_value_arguments}"
+ "${multi_value_arguments}"
+ ${ARGN}
+ )
+
+ # The DIRS argument is required
+ if (NOT DEFINED _get_files_list_DIRECTORIES)
+ message(FATAL_ERROR "No directories paths provided. Provide a list of"
+ " directories paths containing header files."
+ )
+ endif()
+
+ # The FILES_PATTERNS argument is required
+ if (NOT DEFINED _get_files_list_FILES_PATTERNS)
+ message(FATAL_ERROR "No matching expressions provided. Provide a list"
+ " of matching patterns for the header files."
+ )
+ endif()
+
+ get_filename_component(_get_files_list_OUTPUT_PATH
+ "${CMAKE_CURRENT_BINARY_DIR}/${_TARGET_NAME}"
+ ABSOLUTE
+ )
+
+ add_custom_command(
+ OUTPUT ${_TARGET_NAME}
+ COMMAND ${CMAKE_COMMAND}
+ -DOUTPUT_PATH="${_get_files_list_OUTPUT_PATH}"
+ -DDIRECTORIES="${_get_files_list_DIRECTORIES}"
+ -DFILES_PATTERNS="${_get_files_list_FILES_PATTERNS}"
+ -P ${_GET_FILES_LIST_SCRIPT}
+ COMMENT
+ "Searching for files"
+ )
+
+ if (DEFINED _get_files_list_COPY_TO)
+ # Copy the generated file back to the COPY_TO
+ add_custom_target(copy_headers_list_${TARGET_NAME} ALL
+ COMMAND
+ ${CMAKE_COMMAND} -E copy_if_different ${_TARGET_NAME} ${_get_files_list_COPY_TO}
+ DEPENDS "${_TARGET_NAME}"
+ COMMENT "Copying ${_TARGET_NAME} to ${_get_files_list_COPY_TO}"
+ )
+ endif()
+endfunction()
+
+function(extract_symbols _TARGET_NAME)
+
+ set(one_value_arguments
+ FILTER_PATTERN
+ HEADERS_LIST_FILE
+ COPY_TO
+ )
+
+ set(multi_value_arguments
+ )
+
+ cmake_parse_arguments(_extract_symbols
+ ""
+ "${one_value_arguments}"
+ "${multi_value_arguments}"
+ ${ARGN}
+ )
+
+ # The HEADERS_LIST_FILE argument is required
+ if (NOT DEFINED _extract_symbols_HEADERS_LIST_FILE)
+ message(FATAL_ERROR "No header files given. Provide a list of header"
+ " files containing exported symbols."
+ )
+ endif()
+
+ get_filename_component(_extract_symbols_OUTPUT_PATH
+ "${CMAKE_CURRENT_BINARY_DIR}/${_TARGET_NAME}"
+ ABSOLUTE
+ )
+
+ add_custom_target(${_TARGET_NAME}
+ COMMAND ${CMAKE_COMMAND}
+ -DOUTPUT_PATH="${_extract_symbols_OUTPUT_PATH}"
+ -DHEADERS_LIST_FILE="${_extract_symbols_HEADERS_LIST_FILE}"
+ -DFILTER_PATTERN=${_extract_symbols_FILTER_PATTERN}
+ -P ${_EXTRACT_SYMBOLS_SCRIPT}
+ DEPENDS ${_extract_symbols_HEADERS_LIST_FILE}
+ COMMENT "Extracting symbols from headers")
+
+ if (DEFINED _extract_symbols_COPY_TO)
+ file(READ "${CMAKE_CURRENT_BINARY_DIR}/${_TARGET_NAME}" SYMBOL_CONTENT)
+ string(REPLACE ";" "\n" SYMBOL_CONTENT_NEW "${SYMBOL_CONTENT}")
+ file(WRITE "${_extract_symbols_COPY_TO}" "${SYMBOL_CONTENT_NEW}")
+ endif()
+endfunction()
+
+function(generate_map_file _TARGET_NAME)
+
+ set(options
+ FINAL
+ BREAK_ABI
+ )
+
+ set(one_value_arguments
+ RELEASE_NAME_VERSION
+ SYMBOLS
+ CURRENT_MAP
+ COPY_TO
+ )
+
+ set(multi_value_arguments
+ )
+
+ cmake_parse_arguments(_generate_map_file
+ "${options}"
+ "${one_value_arguments}"
+ "${multi_value_arguments}"
+ ${ARGN}
+ )
+
+ if (NOT DEFINED _generate_map_file_SYMBOLS)
+ message(FATAL_ERROR "No symbols file provided."
+ )
+ endif()
+
+ if (NOT DEFINED _generate_map_file_RELEASE_NAME_VERSION)
+ message(FATAL_ERROR "Release name and version not provided."
+ " (e.g. libname_1_0_0"
+ )
+ endif()
+
+ # Set generated map file path
+ get_filename_component(_generate_map_file_OUTPUT_PATH
+ "${CMAKE_CURRENT_BINARY_DIR}/${_TARGET_NAME}"
+ ABSOLUTE
+ )
+
+ add_custom_command(
+ OUTPUT ${_TARGET_NAME}
+ COMMAND ${CMAKE_COMMAND}
+ -DABIMAP_EXECUTABLE=${ABIMAP_EXECUTABLE}
+ -DSYMBOLS="${_generate_map_file_SYMBOLS}"
+ -DCURRENT_MAP=${_generate_map_file_CURRENT_MAP}
+ -DOUTPUT_PATH="${_generate_map_file_OUTPUT_PATH}"
+ -DFINAL=${_generate_map_file_FINAL}
+ -DBREAK_ABI=${_generate_map_file_BREAK_ABI}
+ -DRELEASE_NAME_VERSION=${_generate_map_file_RELEASE_NAME_VERSION}
+ -P ${_GENERATE_MAP_SCRIPT}
+ DEPENDS ${_generate_map_file_SYMBOLS}
+ COMMENT "Generating the map ${_TARGET_NAME}"
+ )
+
+ if (DEFINED _generate_map_file_COPY_TO)
+ # Copy the generated map back to the COPY_TO
+ add_custom_target(copy_map_${_TARGET_NAME} ALL
+ COMMAND
+ ${CMAKE_COMMAND} -E copy_if_different ${_TARGET_NAME} ${_generate_map_file_COPY_TO}
+ DEPENDS "${_TARGET_NAME}"
+ COMMENT "Copying ${_TARGET_NAME} to ${_generate_map_file_COPY_TO}"
+ )
+ endif()
+endfunction()
diff --git a/cmake/Modules/GenerateMap.cmake b/cmake/Modules/GenerateMap.cmake
new file mode 100644
index 00000000..c22dfbc3
--- /dev/null
+++ b/cmake/Modules/GenerateMap.cmake
@@ -0,0 +1,118 @@
+#
+# Copyright (c) 2018 Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
+#
+# Redistribution and use is allowed according to the terms of the New
+# BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+#
+
+#.rst:
+# GenerateMap
+# -----------
+#
+# This is a helper script for FindABImap.cmake.
+#
+# Generates a symbols version script using the abimap tool.
+# This script is run in build time to use the correct command depending on the
+# existence of the file provided ``CURRENT_MAP``.
+#
+# If the file exists, the ``abimap update`` subcommand is used to update the
+# existing map. Otherwise, the ``abimap new`` subcommand is used to create a new
+# map file.
+#
+# If the file provided in ``CURRENT_MAP`` exists, it is copied to the
+# ``OUTPUT_PATH`` before updating.
+# This is required because ``abimap`` do not generate output if no symbols were
+# changed when updating an existing file.
+#
+# Expected defined variables
+# --------------------------
+#
+# ``SYMBOLS``:
+# Required file containing the symbols to be used as input. Usually this is
+# the ``OUTPUT`` generated by ``extract_symbols()`` function provided in
+# FindABImap.cmake
+#
+# ``RELEASE_NAME_VERSION``:
+# Required, expects the library name and version information to be added to
+# the symbols in the format ``library_name_1_2_3``
+#
+# ``CURRENT_MAP``:
+# Required, expects the path to the current map file (or the path were it
+# should be)
+#
+# ``OUTPUT_PATH``:
+# Required, expects the output file path.
+#
+# ``ABIMAP_EXECUTABLE``:
+# Required, expects the path to the ``abimap`` tool.
+#
+# Optionally defined variables
+# ----------------------------
+#
+# ``FINAL``:
+# If defined, will mark the modified set of symbols in the symbol version
+# script as final, preventing later changes using ``abimap``.
+#
+# ``BREAK_ABI``:
+# If defined, the build will not fail if symbols were removed.
+# If defined and a symbol is removed, a new release is created containing
+# all symbols from all released versions. This makes an incompatible release.
+#
+
+if (NOT DEFINED RELEASE_NAME_VERSION)
+ message(SEND_ERROR "RELEASE_NAME_VERSION not defined")
+endif()
+
+if (NOT DEFINED SYMBOLS)
+ message(SEND_ERROR "SYMBOLS not defined")
+endif()
+
+if (NOT DEFINED CURRENT_MAP)
+ message(SEND_ERROR "CURRENT_MAP not defined")
+endif()
+
+if (NOT DEFINED OUTPUT_PATH)
+ message(SEND_ERROR "OUTPUT_PATH not defined")
+endif()
+
+if (NOT ABIMAP_EXECUTABLE)
+ message(SEND_ERROR "ABIMAP_EXECUTABLE not defined")
+endif()
+
+set(ARGS_LIST)
+
+if (FINAL)
+ list(APPEND ARGS_LIST "--final")
+endif()
+
+if (EXISTS ${CURRENT_MAP})
+ if (BREAK_ABI)
+ list(APPEND ARGS_LIST "--allow-abi-break")
+ endif()
+
+ execute_process(
+ COMMAND
+ ${CMAKE_COMMAND} -E copy_if_different ${CURRENT_MAP} ${OUTPUT_PATH}
+ COMMAND
+ ${ABIMAP_EXECUTABLE} update ${ARGS_LIST}
+ -r ${RELEASE_NAME_VERSION}
+ -i ${SYMBOLS}
+ -o ${OUTPUT_PATH}
+ ${CURRENT_MAP}
+ RESULT_VARIABLE result
+ )
+else ()
+ execute_process(
+ COMMAND
+ ${ABIMAP_EXECUTABLE} new ${ARGS_LIST}
+ -r ${RELEASE_NAME_VERSION}
+ -i ${SYMBOLS}
+ -o ${OUTPUT_PATH}
+ RESULT_VARIABLE result
+ )
+endif()
+
+if (NOT "${result}" STREQUAL "0")
+ message(SEND_ERROR "Map generation failed")
+endif()
diff --git a/cmake/Modules/GetFilesList.cmake b/cmake/Modules/GetFilesList.cmake
new file mode 100644
index 00000000..e3e8a2a8
--- /dev/null
+++ b/cmake/Modules/GetFilesList.cmake
@@ -0,0 +1,59 @@
+#
+# Copyright (c) 2018 Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
+#
+# Redistribution and use is allowed according to the terms of the New
+# BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+#
+
+#.rst:
+# GetFilesList
+# ------------
+#
+# This is a helper script for FindABImap.cmake.
+#
+# Search in the provided directories for files matching the provided pattern.
+# The list of files is then written to the output file.
+#
+# Expected defined variables
+# --------------------------
+#
+# ``DIRECTORIES``:
+# Required, expects a list of directories paths.
+#
+# ``FILES_PATTERNS``:
+# Required, expects a list of patterns to be used to search files
+#
+# ``OUTPUT_PATH``:
+# Required, expects the output file path.
+
+if (NOT DEFINED DIRECTORIES)
+ message(SEND_ERROR "DIRECTORIES not defined")
+endif()
+
+if (NOT DEFINED FILES_PATTERNS)
+ message(SEND_ERROR "FILES_PATTERNS not defined")
+endif()
+
+if (NOT DEFINED OUTPUT_PATH)
+ message(SEND_ERROR "OUTPUT_PATH not defined")
+endif()
+
+string(REPLACE " " ";" DIRECTORIES_LIST "${DIRECTORIES}")
+string(REPLACE " " ";" FILES_PATTERNS_LIST "${FILES_PATTERNS}")
+
+# Create the list of expressions for the files
+set(glob_expressions)
+foreach(dir ${DIRECTORIES_LIST})
+ foreach(exp ${FILES_PATTERNS_LIST})
+ list(APPEND glob_expressions
+ "${dir}/${exp}"
+ )
+ endforeach()
+endforeach()
+
+# Create the list of files
+file(GLOB files ${glob_expressions})
+
+# Write to the output
+file(WRITE ${OUTPUT_PATH} "${files}")
diff --git a/obj/build_make.sh b/obj/build_make.sh
index a030ed71..7c559141 100755
--- a/obj/build_make.sh
+++ b/obj/build_make.sh
@@ -63,7 +63,7 @@ function clean_build_dir() {
function usage () {
echo "Usage: `basename $0` [--prefix /install_prefix|--build [debug|final]|--clean|--verbose|--libsuffix (32|64)|--help|--clang|--cmakedir /directory|--make
-(gmake|make)|--ccompiler (gcc|cc)|--withstaticlib|--unittesting|--clientunittesting|--withserver]"
+(gmake|make)|--ccompiler(gcc|cc)|--withstaticlib|--unittesting|--clientunittesting|--withserver|--withoutsymbolversioning]"
cleanup_and_exit
}
@@ -145,6 +145,12 @@ while test -n "$1"; do
*-withserver)
OPTIONS="${OPTIONS} -DWITH_SERVER=ON"
;;
+ *-withoutsymbolversioning)
+ OPTIONS="${OPTIONS} -DWITH_SYMBOL_VERSIONING=OFF"
+ ;;
+ *-finalrelease)
+ OPTIONS="${OPTIONS} -DWITH_FINAL=ON"
+ ;;
----noarg)
echo "$ARG does not take an argument"
cleanup_and_exit
diff --git a/src/ABI/current b/src/ABI/current
index ae153944..a84947d6 100644
--- a/src/ABI/current
+++ b/src/ABI/current
@@ -1 +1 @@
-4.5.0 \ No newline at end of file
+4.5.0
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6cf44158..e5746b15 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,5 +1,3 @@
-project(libssh-library C)
-
set(LIBSSH_PUBLIC_INCLUDE_DIRS
${libssh_SOURCE_DIR}/include
CACHE INTERNAL "libssh public include directories"
@@ -265,10 +263,52 @@ include_directories(
${LIBSSH_PRIVATE_INCLUDE_DIRS}
)
+# Set the path to the default map file
+set(MAP_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.map")
+
+if (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
+ # Get the list of header files
+ get_file_list("dev_header_list"
+ DIRECTORIES "${LIBSSH_PUBLIC_INCLUDE_DIRS}/libssh"
+ FILES_PATTERNS "*.h")
+
+ # Extract the symbols marked as "LIBSSH_API" from the header files
+ extract_symbols("${PROJECT_NAME}_dev.symbols"
+ HEADERS_LIST_FILE "dev_header_list"
+ FILTER_PATTERN "LIBSSH_API")
+
+ if (WITH_ABI_BREAK)
+ set(ALLOW_ABI_BREAK "BREAK_ABI")
+ endif()
+
+ # Generate the symbol version map file
+ generate_map_file("${PROJECT_NAME}_dev.map"
+ SYMBOLS "${PROJECT_NAME}_dev.symbols"
+ RELEASE_NAME_VERSION ${PROJECT_NAME}_AFTER_${LIBRARY_VERSION}
+ CURRENT_MAP ${MAP_PATH}
+ ${ALLOW_ABI_BREAK})
+
+ set(libssh_SRCS
+ ${libssh_SRCS}
+ ${PROJECT_NAME}_dev.map
+ )
+endif (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
+
add_library(${LIBSSH_SHARED_LIBRARY} SHARED ${libssh_SRCS})
target_link_libraries(${LIBSSH_SHARED_LIBRARY} ${LIBSSH_LINK_LIBRARIES})
+if (WITH_SYMBOL_VERSIONING)
+ if (ABIMAP_FOUND)
+ # Change path to devel map file
+ set(MAP_PATH "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_dev.map")
+ endif (ABIMAP_FOUND)
+
+ set_target_properties(${LIBSSH_SHARED_LIBRARY}
+ PROPERTIES LINK_FLAGS
+ "-Wl,--version-script,\"${MAP_PATH}\"")
+endif (WITH_SYMBOL_VERSIONING)
+
set_target_properties(
${LIBSSH_SHARED_LIBRARY}
PROPERTIES