Approach to enable static linkage

Linking statically might be useful, especially
when linking Windows applications since MinGW
is less buggy then.
This commit is contained in:
Martchus 2016-07-22 01:35:32 +02:00
parent a3e9174476
commit 189a6fe6ba
6 changed files with 110 additions and 27 deletions

View File

@ -73,6 +73,7 @@ set(CMAKE_MODULE_FILES
cmake/modules/Doxygen.cmake
cmake/modules/ListToString.cmake
cmake/modules/ShellCompletion.cmake
cmake/modules/3rdParty.cmake
)
set(CMAKE_TEMPLATE_FILES
cmake/templates/Config.cmake.in
@ -100,7 +101,7 @@ set(META_PROJECT_VARNAME CPP_UTILITIES)
set(META_APP_NAME "C++ Utilities")
set(META_APP_AUTHOR "Martchus")
set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}")
set(META_APP_DESCRIPTION "Common C++ classes and routines used by my applications such as argument parser, IO and conversion utilities.")
set(META_APP_DESCRIPTION "Common C++ classes and routines used by my applications such as argument parser, IO and conversion utilities")
set(META_VERSION_MAJOR 4)
set(META_VERSION_MINOR 0)
set(META_VERSION_PATCH 0)

View File

@ -0,0 +1,63 @@
if(NOT DEFINED EXTERNAL_LIBRARIES_EXISTS)
set(EXTERNAL_LIBRARIES_EXISTS true)
macro(use_external_library_from_package NAME VERSION INCLUDE_VAR LIBRARY_VAR LINKAGE REQUIRED)
# need to set CMAKE_FIND_LIBRARY_SUFFIXES temporarily to be able to find static libs, save the current value to be able to restore
set(DEFAULT_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
# handle arguments VERSION and REQUIRED
if("${VERSION}" STREQUAL "ANY_VERSION")
set(${NAME}_COMPATIBLE_VERSION "")
else()
set(${NAME}_COMPATIBLE_VERSION ${VERSION})
endif()
if("${REQUIRED}" STREQUAL "OPTIONAL")
set(${NAME}_REQUIRED "")
elseif("${REQUIRED}" STREQUAL "REQUIRED")
set(${NAME}_REQUIRED "REQUIRED")
else()
message(FATAL_ERROR "Invalid use of use_external_library; must specify either REQUIRED or OPTIONAL.")
endif()
# find dynamic library
if(WIN32)
set(CMAKE_FIND_LIBRARY_SUFFIXES .so)
else()
set(CMAKE_FIND_LIBRARY_SUFFIXES .dll.a .dll)
endif()
find_package(${NAME} ${${NAME}_COMPATIBLE_VERSION})
include_directories(${${INCLUDE_VAR}})
set(${NAME}_DYNAMIC_LIB ${${LIBRARY_VAR}})
set(${${LIBRARY_VAR}} "")
# find static library
if(WIN32)
set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a)
else()
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
endif()
find_package(${NAME} ${${NAME}_COMPATIBLE_VERSION})
set(${NAME}_STATIC_LIB ${${LIBRARY_VAR}})
# add library to list of libraries to link against when building dynamic libraries or applications
if(${NAME}_STATIC_LIB AND (("${LINKAGE}" STREQUAL "AUTO_LINKAGE" AND ((STATIC_LINKAGE AND "${META_PROJECT_TYPE}" STREQUAL "application") OR (STATIC_LIBRARY_LINKAGE AND ("${META_PROJECT_TYPE}" STREQUAL "" OR "${META_PROJECT_TYPE}" STREQUAL "library")))) OR ("${LINKAGE}" STREQUAL "STATIC")))
list(APPEND LIBRARIES ${${NAME}_STATIC_LIB})
message(STATUS "Linking ${META_PROJECT_NAME} statically against external library ${NAME}.")
elseif(${NAME}_DYNAMIC_LIB AND ("${LINKAGE}" STREQUAL "AUTO_LINKAGE" OR ("${LINKAGE}" STREQUAL "SHARED")))
list(APPEND LIBRARIES ${${NAME}_DYNAMIC_LIB})
message(STATUS "Linking ${META_PROJECT_NAME} dynamically against external library ${NAME}.")
else()
if(${REQUIRED})
message(FATAL_ERROR "External library ${NAME} required by ${META_PROJECT_NAME} is not available for the specified linkage ${LINKAGE}.")
else()
message(WARNING "External library ${NAME} required by ${META_PROJECT_NAME} is not available for the specified linkage ${LINKAGE}.")
endif()
endif()
# add library to list of libraries to be provided as transitive dependencies when building static libraries
list(APPEND STATIC_LIBRARIES ${${LIBRARY_VAR}})
# restore altered CMAKE_FIND_LIBRARY_SUFFIXES
set(CMAKE_FIND_LIBRARY_SUFFIXES ${DEFAULT_CMAKE_FIND_LIBRARY_SUFFIXES})
set(DEFAULT_CMAKE_FIND_LIBRARY_SUFFIXES "")
endmacro()
endif()

View File

@ -1,9 +1,9 @@
# before including this module, BasicConfig must be included
# set the windows extension to "exe", this is required by the mingw-w64 specific WindowsResources module
if(MINGW)
# set the windows extension to "exe", this is required by the Windows specific WindowsResources module
if(WIN32)
set(WINDOWS_EXT "exe")
endif(MINGW)
endif(WIN32)
# add target for building the application
add_executable(${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX} ${GUI_TYPE} ${HEADER_FILES} ${SRC_FILES} ${WIDGETS_FILES} ${QML_FILES} ${RES_FILES} ${QM_FILES} ${WINDOWS_ICON_PATH})

View File

@ -69,3 +69,7 @@ if(LOGGING_ENABLED)
add_definitions(-DLOGGING_ENABLED)
message(STATUS "Logging is enabled.")
endif()
# options for forcing static linkage when building applications or dynamic libraries
option(STATIC_LINKAGE "forces static linkage when building applications" OFF)
option(STATIC_LIBRARY_LINKAGE "forces static linkage when building dynamic libraries" OFF)

View File

@ -25,27 +25,6 @@ set(LIB_INSTALL_DESTINATION "${CMAKE_INSTALL_PREFIX}/lib${SELECTED_LIB_SUFFIX}")
set(CMAKE_MODULE_INSTALL_DESTINATION "${CMAKE_INSTALL_PREFIX}/share/${META_PROJECT_NAME}/cmake/modules")
set(CMAKE_CONFIG_INSTALL_DESTINATION "${CMAKE_INSTALL_PREFIX}/share/${META_PROJECT_NAME}/cmake")
# create the CMake config file from the template
configure_package_config_file(
"${CONFIG_TEMPLATE_FILE}"
"${CMAKE_CURRENT_BINARY_DIR}/${META_PROJECT_NAME}Config.cmake"
INSTALL_DESTINATION
"${CMAKE_CONFIG_INSTALL_DESTINATION}"
PATH_VARS
CMAKE_MODULE_INSTALL_DESTINATION
CMAKE_CONFIG_INSTALL_DESTINATION
HEADER_INSTALL_DESTINATION
BIN_INSTALL_DESTINATION
LIB_INSTALL_DESTINATION
)
# write the CMake version config file
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/${META_PROJECT_NAME}ConfigVersion.cmake
VERSION "${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_PATCH}"
COMPATIBILITY SameMajorVersion
)
# remove library prefix when building with mingw-w64 (just for consistency with qmake)
if(MINGW)
set(CMAKE_SHARED_LIBRARY_PREFIX "")
@ -77,15 +56,37 @@ endif()
if(BUILD_STATIC_LIBS)
add_library(${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX}_static STATIC ${HEADER_FILES} ${SRC_FILES} ${WIDGETS_FILES} ${QML_FILES} ${RES_FILES} ${QM_FILES} ${WINDOWS_ICON_PATH})
# add target link libraries for the static lib also because otherwise Qt header files can not be located
target_link_libraries(${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX}_static ${LIBRARIES})
target_link_libraries(${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX}_static ${STATIC_LIBRARIES})
set_target_properties(${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX}_static PROPERTIES
VERSION ${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_PATCH}
SOVERSION ${META_VERSION_MAJOR}
OUTPUT_NAME ${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX}
CXX_STANDARD 11
)
set(META_LIB_DEPENDS ${${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX}_static_LIB_DEPENDS}) # used in config file
endif()
# create the CMake config file from the template
configure_package_config_file(
"${CONFIG_TEMPLATE_FILE}"
"${CMAKE_CURRENT_BINARY_DIR}/${META_PROJECT_NAME}Config.cmake"
INSTALL_DESTINATION
"${CMAKE_CONFIG_INSTALL_DESTINATION}"
PATH_VARS
CMAKE_MODULE_INSTALL_DESTINATION
CMAKE_CONFIG_INSTALL_DESTINATION
HEADER_INSTALL_DESTINATION
BIN_INSTALL_DESTINATION
LIB_INSTALL_DESTINATION
)
# write the CMake version config file
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/${META_PROJECT_NAME}ConfigVersion.cmake
VERSION "${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_PATCH}"
COMPATIBILITY SameMajorVersion
)
# add install target for the CMake config files
install(
FILES

View File

@ -1,6 +1,10 @@
@PACKAGE_INIT@
set(@META_PROJECT_VARNAME@_HAS_LIBS "@BUILD_SHARED_LIBS@")
set(@META_PROJECT_VARNAME@_LIBS "@META_PROJECT_NAME@")
set(@META_PROJECT_VARNAME@_HAS_STATIC_LIBS "@BUILD_STATIC_LIBS@")
set(@META_PROJECT_VARNAME@_STATIC_LIBS "@META_PROJECT_NAME@.a")
set(@META_PROJECT_VARNAME@_STATIC_LIBS_DEPENDS @META_LIB_DEPENDS@)
set(@META_PROJECT_VARNAME@_INCLUDE_DIRS "@PACKAGE_HEADER_INSTALL_DESTINATION@")
set(@META_PROJECT_VARNAME@_BIN_DIR "@PACKAGE_BIN_INSTALL_DESTINATION@")
set(@META_PROJECT_VARNAME@_LIB_DIR "@PACKAGE_LIB_INSTALL_DESTINATION@")
@ -10,6 +14,16 @@ set(@META_PROJECT_VARNAME@_CONFIG_DIRS "@PACKAGE_CMAKE_CONFIG_INSTALL_DESTINATIO
macro(use_@META_PROJECT_VARNAME@)
include_directories(BEFORE SYSTEM ${@META_PROJECT_VARNAME@_INCLUDE_DIRS})
link_directories(${@META_PROJECT_VARNAME@_LIB_DIR})
# add library to list of libraries to link against when building dynamic libraries or applications
if(@META_PROJECT_VARNAME@_HAS_STATIC_LIBS AND ((NOT ARGV0 AND ((STATIC_LINKAGE AND "${META_PROJECT_TYPE}" STREQUAL "application") OR (STATIC_LIBRARY_LINKAGE AND ("${META_PROJECT_TYPE}" STREQUAL "" OR "${META_PROJECT_TYPE}" STREQUAL "library")))) OR ("${ARGV0}" STREQUAL "STATIC")))
list(APPEND LIBRARIES ${@META_PROJECT_VARNAME@_STATIC_LIBS} ${@META_PROJECT_VARNAME@_STATIC_LIBS_DEPENDS})
elseif(@META_PROJECT_VARNAME@_HAS_LIBS AND (NOT ARGV0 OR ("${ARGV0}" STREQUAL "SHARED")))
list(APPEND LIBRARIES ${@META_PROJECT_VARNAME@_LIBS})
else()
message(ERROR "Specified linkage ${ARGV0} is not available.")
endif()
# add library to list of libraries to be provided as transitive dependencies when building static libraries
list(APPEND STATIC_LIBRARIES ${@META_PROJECT_VARNAME@_STATIC_LIBS} ${@META_PROJECT_VARNAME@_STATIC_LIBS_DEPENDS})
# make CMake modules of the project available
list(APPEND CMAKE_MODULE_PATH ${@META_PROJECT_VARNAME@_MODULE_DIRS})
endmacro()