1# Additional CMake macros
2#
3# Copyright (C) 2015-2018 Jarosław Staniek <staniek@kde.org>
4#
5# Redistribution and use is allowed according to the terms of the BSD license.
6# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
7
8if(__kexi_macros)
9  return()
10endif()
11set(__kexi_macros YES)
12
13#unused: include(KDbCreateSharedDataClasses) # from KDb
14include(CheckFunctionExists)
15include(GenerateExportHeader)
16include(GetGitRevisionDescription)
17include(MacroBoolTo01)
18include(KexiAddSimpleOption)
19
20string(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPER)
21string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWER)
22string(COMPARE EQUAL "${CMAKE_CXX_COMPILER_ID}" "Clang" CMAKE_COMPILER_IS_CLANG)
23
24# Keep apps in the same bin dir so resources that are kept relative to this dir can be found
25# without installing.
26set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
27
28macro(ensure_out_of_source_build _extra_message)
29    string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" _isBuildInSource)
30    if(isBuildInSource)
31        message(FATAL_ERROR "Compiling ${PROJECT_NAME} inside the source directory is not possible. "
32                            "${_extra_message}")
33    endif()
34    unset(_isBuildInSource)
35endmacro()
36
37# Sets RELEASE_BUILD to TRUE for release builds
38macro(detect_release_build)
39    if(NOT DEFINED RELEASE_BUILD)
40        # estimate mode by CMAKE_BUILD_TYPE content if not set on cmdline
41        string(TOLOWER "${CMAKE_BUILD_TYPE}" _CMAKE_BUILD_TYPE_TOLOWER)
42        set(_RELEASE_BUILD_TYPES "release" "relwithdebinfo" "minsizerel")
43        list(FIND _RELEASE_BUILD_TYPES "${CMAKE_BUILD_TYPE_TOLOWER}" INDEX)
44        if (INDEX EQUAL -1)
45            set(RELEASE_BUILD FALSE)
46        else()
47            set(RELEASE_BUILD TRUE)
48        endif()
49        unset(_RELEASE_BUILD_TYPES)
50        unset(_CMAKE_BUILD_TYPE_TOLOWER)
51    endif()
52endmacro()
53
54if(WIN32)
55    set(LIB_INSTALL_DIR ${LIB_INSTALL_DIR}
56                        RUNTIME DESTINATION ${BIN_INSTALL_DIR}
57                        LIBRARY ${INSTALL_TARGETS_DEFAULT_ARGS}
58                        ARCHIVE ${INSTALL_TARGETS_DEFAULT_ARGS} )
59endif()
60
61set(ICONS_INSTALL_DIR "${DATA_INSTALL_DIR}/${KEXI_BASE_PATH}/icons")
62
63# Fetches git revision and branch from the source dir of the current build if possible.
64# Sets ${PROJECT_NAME_UPPER}_GIT_SHA1_STRING and ${PROJECT_NAME_UPPER}_GIT_BRANCH_STRING variables.
65# If git information is not available but ${CMAKE_SOURCE_DIR}/GIT_VERSION file exists,
66# it is parsed. This file can be created by scripts while preparing tarballs and is
67# supposed to contain two lines: hash and branch.
68macro(get_git_revision_and_branch)
69  set(${PROJECT_NAME_UPPER}_GIT_SHA1_STRING "")
70  set(${PROJECT_NAME_UPPER}_GIT_BRANCH_STRING "")
71  get_git_head_revision(GIT_REFSPEC ${PROJECT_NAME_UPPER}_GIT_SHA1_STRING)
72  get_git_branch(${PROJECT_NAME_UPPER}_GIT_BRANCH_STRING)
73  if(NOT ${PROJECT_NAME_UPPER}_GIT_SHA1_STRING OR NOT ${PROJECT_NAME_UPPER}_GIT_BRANCH_STRING)
74    if(EXISTS "${CMAKE_SOURCE_DIR}/GIT_VERSION")
75      file(READ "${CMAKE_SOURCE_DIR}/GIT_VERSION" _ver)
76      string(REGEX REPLACE "\n" ";" _ver "${_ver}")
77      list(GET _ver 0 ${PROJECT_NAME_UPPER}_GIT_SHA1_STRING)
78      list(GET _ver 1 ${PROJECT_NAME_UPPER}_GIT_BRANCH_STRING)
79    endif()
80  endif()
81  if(${PROJECT_NAME_UPPER}_GIT_SHA1_STRING OR ${PROJECT_NAME_UPPER}_GIT_BRANCH_STRING)
82    string(SUBSTRING ${${PROJECT_NAME_UPPER}_GIT_SHA1_STRING} 0 7 ${PROJECT_NAME_UPPER}_GIT_SHA1_STRING)
83  else()
84    set(${PROJECT_NAME_UPPER}_GIT_SHA1_STRING "")
85    set(${PROJECT_NAME_UPPER}_GIT_BRANCH_STRING "")
86  endif()
87endmacro()
88
89# Adds ${PROJECT_NAME_UPPER}_UNFINISHED option. If it is ON, unfinished features
90# (useful for testing but may confuse end-user) are compiled-in.
91# This option is OFF by default.
92macro(add_unfinished_features_option)
93  simple_option(${PROJECT_NAME_UPPER}_UNFINISHED
94                "Include unfinished features (useful for testing but may confuse end-user)" OFF)
95endmacro()
96
97# Adds commands that generate ${_filename}${KEXI_DISTRIBUTION_VERSION}.pc file
98# out of ${_filename}.pc.cmake file and installs the .pc file to ${LIB_INSTALL_DIR}/pkgconfig.
99# These commands are not executed for WIN32.
100# ${CMAKE_SOURCE_DIR}/${_filename}.pc.cmake should exist.
101macro(add_pc_file _filename)
102  if (NOT WIN32)
103    set(_name ${_filename}${KEXI_DISTRIBUTION_VERSION})
104    configure_file(${CMAKE_SOURCE_DIR}/${_filename}.pc.cmake ${CMAKE_BINARY_DIR}/${_name}.pc @ONLY)
105    install(FILES ${CMAKE_BINARY_DIR}/${_name}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
106  endif()
107endmacro()
108
109# Sets detailed version information for library co-installability.
110# - adds PROJECT_STABLE_VERSION_MAJOR to the lib name
111# - sets VERSION to PROJECT_STABLE_VERSION_MAJOR.PROJECT_STABLE_VERSION_MINOR.PROJECT_STABLE_VERSION_RELEASE
112# - sets SOVERSION to KEXI_DISTRIBUTION_VERSION
113# - sets OUTPUT_NAME to ${_target}${KEXI_DISTRIBUTION_VERSION}
114# - sets ${_target_upper}_BASE_NAME variable to the final lib name
115# - sets ${_target_upper}_BASE_NAME_LOWER variable to the final lib name, lowercase
116# - sets ${_target_upper}_INCLUDE_INSTALL_DIR to include dir for library headers
117# - (where _target_upper is uppercase ${_target}
118macro(set_coinstallable_lib_version _target)
119    set(_name ${_target}${KEXI_DISTRIBUTION_VERSION})
120    set(_version "${PROJECT_STABLE_VERSION_MAJOR}.${PROJECT_STABLE_VERSION_MINOR}.${PROJECT_STABLE_VERSION_RELEASE}")
121    set(_soversion ${KEXI_DISTRIBUTION_VERSION})
122    set_target_properties(${_target}
123        PROPERTIES VERSION ${_version}
124                   SOVERSION ${_soversion}
125                   EXPORT_NAME ${_target}
126                   OUTPUT_NAME ${_name}
127    )
128    string(TOUPPER ${_target} _target_upper)
129    string(TOUPPER ${_target_upper}_BASE_NAME _var)
130    set(${_var} ${_name})
131    string(TOLOWER ${_name} ${_var}_LOWER)
132    set(${_target_upper}_INCLUDE_INSTALL_DIR ${INCLUDE_INSTALL_DIR}/${_name})
133    unset(_soversion)
134    unset(_version)
135    unset(_target_upper)
136    unset(_var)
137endmacro()
138
139# Combines add_library() with set_coinstallable_lib_version()
140macro(kexi_add_library)
141    set(args ${ARGV})
142    list(GET args 0 _target)
143    add_library(${args})
144    set_coinstallable_lib_version(${_target})
145    unset(_target)
146endmacro()
147
148# Sets detailed version information for executable co-installability.
149# - sets OUTPUT_NAME to ${_target}-${KEXI_DISTRIBUTION_VERSION}
150macro(set_coinstallable_executable_version _target)
151    set_target_properties(${_target}
152        PROPERTIES OUTPUT_NAME ${_target}-${KEXI_DISTRIBUTION_VERSION}
153    )
154endmacro()
155
156# Combines add_executable() with set_coinstallable_executable_version()
157macro(kexi_add_executable)
158    set(args ${ARGV})
159    list(GET args 0 _target)
160    add_executable(${args})
161    set_coinstallable_executable_version(${_target})
162    unset(_target)
163endmacro()
164
165# Adds custom target that updates given file in the current working dir using specified
166# command and adds its source files to the project files.
167# The target is not executed by default, if dependencies to/from other targets are needed
168# they can be set separately using add_dependencies().
169# Execution of the command shows status "Updating <filename>".
170# Options:
171#   TARGET - name of the new custom target
172#   FILE - <filename> - name of the file that is updated using the command
173#   COMMAND <cmd> [args...] - command to be executed
174#   SOURCES [files...] - source files that are used by the command
175function(add_update_file_target)
176    set(options)
177    set(oneValueArgs TARGET FILE)
178    set(multiValueArgs COMMAND SOURCES)
179    cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
180    add_custom_target(${ARG_TARGET}
181        COMMAND ${ARG_COMMAND}
182        SOURCES ${ARG_SOURCES}
183        DEPENDS ${ARG_SOURCES}
184        WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
185        COMMENT "Updating ${ARG_FILE}"
186        VERBATIM
187    )
188endfunction()
189
190if(WIN32)
191    set(_chmod_name attrib)
192else()
193    set(_chmod_name chmod)
194endif()
195find_program(kexi_chmod_program ${_chmod_name} DOC "chmod program")
196if(kexi_chmod_program)
197    message(STATUS "Found program for changing file permissions: ${kexi_chmod_program}")
198else()
199    message(WARNING "Could not find \"${_chmod_name}\" program for changing file permissions")
200endif()
201
202# Sets file or directory read-only for all (non-root) users.
203# The _path should exist. If it is not absolute, ${CMAKE_CURRENT_SOURCE_DIR} path is prepended.
204function(kexi_set_file_read_only _path)
205    if(NOT kexi_chmod_program)
206        return()
207    endif()
208    if(IS_ABSOLUTE ${_path})
209        set(_fullpath ${_path})
210    else()
211        set(_fullpath ${CMAKE_CURRENT_SOURCE_DIR}/${_path})
212    endif()
213    if(NOT EXISTS ${_fullpath})
214        message(FATAL_ERROR "File or directory \"${_fullpath}\" does not exist")
215        return()
216    endif()
217    if(WIN32)
218        set(_command "${kexi_chmod_program}" +R "${_fullpath}")
219    else()
220        set(_command "${kexi_chmod_program}" a-w "${_fullpath}")
221    endif()
222    execute_process(
223        COMMAND ${_command}
224        RESULT_VARIABLE _result
225        OUTPUT_VARIABLE _output
226        ERROR_VARIABLE _output
227    )
228    if(NOT _result EQUAL 0)
229        message(FATAL_ERROR "Command failed (${_result}): ${_command}\n\nOutput:\n${_output}")
230    endif()
231endfunction()
232
233# Adds example KEXI project (.kexi file)
234# - sets it read-only in the source directory
235# - installs to ${KEXI_EXAMPLES_INSTALL_DIR} as read-only for everyone
236macro(kexi_add_example_project _path)
237    kexi_set_file_read_only(${_path})
238    install(FILES ${_path} DESTINATION ${KEXI_EXAMPLES_INSTALL_DIR}
239            PERMISSIONS OWNER_READ GROUP_READ WORLD_READ)
240endmacro()
241