1# Copyright (c) 2009, 2021, Oracle and/or its affiliates.
2#
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License, version 2.0,
5# as published by the Free Software Foundation.
6#
7# This program is also distributed with certain software (including
8# but not limited to OpenSSL) that is licensed under separate terms,
9# as designated in a particular file or component or in included license
10# documentation.  The authors of MySQL hereby grant you an additional
11# permission to link the program and your derivative works with the
12# separately licensed software that they have included with MySQL.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License, version 2.0, for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22
23
24# This file exports macros that emulate some functionality found  in GNU libtool
25# on Unix systems. One such feature is convenience libraries. In this context,
26# convenience library is a static library that can be linked to shared library
27# On systems that force position-independent code, linking into shared library
28# normally requires compilation with a special flag (often -fPIC). To enable
29# linking static libraries to shared, we compile source files that come into
30# static library with the PIC flag (${CMAKE_SHARED_LIBRARY_C_FLAGS} in CMake)
31# Some systems, like Windows or OSX do not need special compilation (Windows
32# never uses PIC and OSX always uses it).
33#
34# The intention behind convenience libraries is simplify the build and to reduce
35# excessive recompiles.
36
37# Except for convenience libraries, this file provides macros to merge static
38# libraries (we need it for mysqlclient) and to create shared library out of
39# convenience libraries(again, for mysqlclient)
40
41# Important global flags
42# - WITH_PIC : If set, it is assumed that everything is compiled as position
43# independent code (that is CFLAGS/CMAKE_C_FLAGS contain -fPIC or equivalent)
44# If defined, ADD_CONVENIENCE_LIBRARY does not add PIC flag to compile flags
45#
46# - DISABLE_SHARED: If set, it is assumed that shared libraries are not produced
47# during the build. ADD_CONVENIENCE_LIBRARY does not add anything to compile flags
48
49
50GET_FILENAME_COMPONENT(MYSQL_CMAKE_SCRIPT_DIR ${CMAKE_CURRENT_LIST_FILE} PATH)
51IF(WIN32 OR APPLE OR WITH_PIC OR DISABLE_SHARED OR NOT CMAKE_SHARED_LIBRARY_C_FLAGS)
52 SET(_SKIP_PIC 1)
53ENDIF()
54
55INCLUDE(${MYSQL_CMAKE_SCRIPT_DIR}/cmake_parse_arguments.cmake)
56# CREATE_EXPORT_FILE (VAR target api_functions)
57# Internal macro, used on Windows to export API functions as dllexport.
58# Returns a list of extra files that should be linked into the library
59# (in the variable pointed to by VAR).
60MACRO(CREATE_EXPORT_FILE VAR TARGET API_FUNCTIONS)
61  SET(DUMMY ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_dummy.cc)
62  CONFIGURE_FILE_CONTENT("" ${DUMMY})
63  IF(WIN32)
64    SET(EXPORTS ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_exports.def)
65    SET(CONTENT "EXPORTS\n")
66    FOREACH(FUNC ${API_FUNCTIONS})
67      SET(CONTENT "${CONTENT} ${FUNC}\n")
68    ENDFOREACH()
69    CONFIGURE_FILE_CONTENT(${CONTENT} ${EXPORTS})
70    SET(${VAR} ${DUMMY} ${EXPORTS})
71  ELSE()
72    SET(${VAR} ${DUMMY})
73  ENDIF()
74ENDMACRO()
75
76
77# ADD_CONVENIENCE_LIBRARY(name source1...sourceN)
78# Create static library that can be merged with other libraries.
79# On systems that force position-independent code, adds -fPIC or
80# equivalent flag to compile flags.
81MACRO(ADD_CONVENIENCE_LIBRARY)
82  SET(TARGET ${ARGV0})
83  SET(SOURCES ${ARGN})
84  LIST(REMOVE_AT SOURCES 0)
85  ADD_LIBRARY(${TARGET} STATIC ${SOURCES})
86  IF(NOT _SKIP_PIC)
87    SET_TARGET_PROPERTIES(${TARGET} PROPERTIES POSITION_INDEPENDENT_CODE ON)
88  ENDIF()
89
90  # Collect all static libraries in the same directory
91  SET_TARGET_PROPERTIES(${TARGET} PROPERTIES
92    ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/archive_output_directory)
93
94  # Keep track of known convenience libraries, in a global scope.
95  SET(KNOWN_CONVENIENCE_LIBRARIES
96    ${KNOWN_CONVENIENCE_LIBRARIES} ${TARGET} CACHE INTERNAL "" FORCE)
97
98  # Generate a cmake file which will save the name of the library.
99  CONFIGURE_FILE(
100    ${MYSQL_CMAKE_SCRIPT_DIR}/save_archive_location.cmake.in
101    ${CMAKE_BINARY_DIR}/archive_output_directory/lib_location_${TARGET}.cmake
102    @ONLY)
103  ADD_CUSTOM_COMMAND(TARGET ${TARGET} POST_BUILD
104    COMMAND ${CMAKE_COMMAND}
105    -DTARGET_NAME=${TARGET}
106    -DTARGET_LOC=$<TARGET_FILE:${TARGET}>
107    -DCFG_INTDIR=${CMAKE_CFG_INTDIR}
108    -P ${CMAKE_BINARY_DIR}/archive_output_directory/lib_location_${TARGET}.cmake
109    )
110ENDMACRO()
111
112
113# An IMPORTED library can also be merged.
114MACRO(ADD_IMPORTED_LIBRARY TARGET LOC)
115  ADD_LIBRARY(${TARGET} STATIC IMPORTED)
116  SET_TARGET_PROPERTIES(${TARGET} PROPERTIES IMPORTED_LOCATION ${LOC})
117  SET(KNOWN_CONVENIENCE_LIBRARIES
118    ${KNOWN_CONVENIENCE_LIBRARIES} ${TARGET} CACHE INTERNAL "" FORCE)
119  CONFIGURE_FILE(
120    ${MYSQL_CMAKE_SCRIPT_DIR}/save_archive_location.cmake.in
121    ${CMAKE_BINARY_DIR}/archive_output_directory/lib_location_${TARGET}.cmake
122    @ONLY)
123  ADD_CUSTOM_TARGET(${TARGET}_location
124    COMMAND ${CMAKE_COMMAND}
125    -DTARGET_NAME=${TARGET}
126    -DTARGET_LOC=$<TARGET_FILE:${TARGET}>
127    -DCFG_INTDIR=${CMAKE_CFG_INTDIR}
128    -P ${CMAKE_BINARY_DIR}/archive_output_directory/lib_location_${TARGET}.cmake
129    )
130ENDMACRO()
131
132# Write content to file, using CONFIGURE_FILE
133# The advantage compared to FILE(WRITE) is that timestamp
134# does not change if file already has the same content
135MACRO(CONFIGURE_FILE_CONTENT content file)
136 SET(CMAKE_CONFIGURABLE_FILE_CONTENT
137  "${content}\n")
138 CONFIGURE_FILE(
139  ${MYSQL_CMAKE_SCRIPT_DIR}/configurable_file_content.in
140  ${file}
141  @ONLY)
142ENDMACRO()
143
144# Create libs from libs.
145# Merges static libraries, creates shared libraries out of convenience libraries.
146MACRO(MERGE_LIBRARIES_SHARED)
147  MYSQL_PARSE_ARGUMENTS(ARG
148    "EXPORTS;OUTPUT_NAME;COMPONENT"
149    "SKIP_INSTALL"
150    ${ARGN}
151  )
152  LIST(GET ARG_DEFAULT_ARGS 0 TARGET)
153  SET(LIBS ${ARG_DEFAULT_ARGS})
154  LIST(REMOVE_AT LIBS 0)
155
156    SET(LIBTYPE SHARED)
157    # check for non-PIC libraries
158    IF(NOT _SKIP_PIC)
159      FOREACH(LIB ${LIBS})
160        GET_TARGET_PROPERTY(${LIB} TYPE LIBTYPE)
161        IF(LIBTYPE STREQUAL "STATIC_LIBRARY")
162          GET_TARGET_PROPERTY(LIB COMPILE_FLAGS LIB_COMPILE_FLAGS)
163          IF(NOT LIB_COMPILE_FLAGS MATCHES "<PIC_FLAG>")
164            MESSAGE(FATAL_ERROR
165            "Attempted to link non-PIC static library ${LIB} to shared library ${TARGET}\n"
166            "Please use ADD_CONVENIENCE_LIBRARY, instead of ADD_LIBRARY for ${LIB}"
167            )
168          ENDIF()
169        ENDIF()
170      ENDFOREACH()
171    ENDIF()
172    CREATE_EXPORT_FILE(SRC ${TARGET} "${ARG_EXPORTS}")
173    IF(UNIX)
174      # Mark every export as explicitly needed, so that ld won't remove the .a files
175      # containing them. This has a similar effect as --Wl,--no-whole-archive,
176      # but is more focused.
177      FOREACH(SYMBOL ${ARG_EXPORTS})
178        IF(APPLE)
179          SET(export_link_flags "${export_link_flags} -Wl,-u,_${SYMBOL}")
180        ELSE()
181          SET(export_link_flags "${export_link_flags} -Wl,-u,${SYMBOL}")
182        ENDIF()
183      ENDFOREACH()
184    ENDIF()
185    IF(NOT ARG_SKIP_INSTALL)
186      ADD_VERSION_INFO(${TARGET} SHARED SRC)
187    ENDIF()
188    ADD_LIBRARY(${TARGET} ${LIBTYPE} ${SRC})
189    TARGET_LINK_LIBRARIES(${TARGET} ${LIBS})
190    IF(ARG_OUTPUT_NAME)
191      SET_TARGET_PROPERTIES(
192        ${TARGET} PROPERTIES OUTPUT_NAME "${ARG_OUTPUT_NAME}")
193    ENDIF()
194    SET_TARGET_PROPERTIES(
195      ${TARGET} PROPERTIES LINK_FLAGS "${export_link_flags}")
196
197  IF(NOT ARG_SKIP_INSTALL)
198    IF(ARG_COMPONENT)
199      SET(COMP COMPONENT ${ARG_COMPONENT})
200    ENDIF()
201
202    MYSQL_INSTALL_TARGETS(${TARGET} DESTINATION "${INSTALL_LIBDIR}" ${COMP})
203
204  ENDIF()
205  SET_TARGET_PROPERTIES(${TARGET} PROPERTIES LINK_INTERFACE_LIBRARIES "")
206ENDMACRO()
207
208
209FUNCTION(GET_DEPENDEND_OS_LIBS target result)
210  SET(deps ${${target}_LIB_DEPENDS})
211  IF(deps)
212   FOREACH(lib ${deps})
213     # Filter out keywords for used for debug vs optimized builds
214     IF(NOT lib MATCHES "general" AND
215        NOT lib MATCHES "debug" AND
216        NOT lib MATCHES "optimized")
217      LIST(FIND KNOWN_CONVENIENCE_LIBRARIES ${lib} FOUNDIT)
218      IF(FOUNDIT LESS 0)
219        SET(ret ${ret} ${lib})
220      ENDIF()
221    ENDIF()
222   ENDFOREACH()
223  ENDIF()
224  SET(${result} ${ret} PARENT_SCOPE)
225ENDFUNCTION()
226
227
228MACRO(MERGE_CONVENIENCE_LIBRARIES)
229  MYSQL_PARSE_ARGUMENTS(ARG
230    "OUTPUT_NAME;COMPONENT"
231    "SKIP_INSTALL"
232    ${ARGN}
233    )
234  LIST(GET ARG_DEFAULT_ARGS 0 TARGET)
235  SET(LIBS ${ARG_DEFAULT_ARGS})
236  LIST(REMOVE_AT LIBS 0)
237
238  SET(SOURCE_FILE
239    ${CMAKE_BINARY_DIR}/archive_output_directory/${TARGET}_depends.c)
240  ADD_LIBRARY(${TARGET} STATIC ${SOURCE_FILE})
241  IF(ARG_OUTPUT_NAME)
242    SET_TARGET_PROPERTIES(${TARGET} PROPERTIES OUTPUT_NAME "${ARG_OUTPUT_NAME}")
243  ENDIF()
244
245  # Collect all static libraries in the same directory
246  SET_TARGET_PROPERTIES(${TARGET} PROPERTIES
247    ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/archive_output_directory)
248
249  # Go though the list of libraries.
250  # Known convenience libraries should have type "STATIC_LIBRARY"
251  # We assume that that unknown libraries (type "LIB_TYPE-NOTFOUND")
252  # are operating system libraries, to be linked with TARGET
253  SET(OSLIBS)
254  SET(MYLIBS)
255  FOREACH(LIB ${LIBS})
256    GET_TARGET_PROPERTY(LIB_TYPE ${LIB} TYPE)
257    IF(LIB_TYPE STREQUAL "STATIC_LIBRARY")
258      LIST(FIND KNOWN_CONVENIENCE_LIBRARIES ${LIB} FOUNDIT)
259      IF(FOUNDIT LESS 0)
260        MESSAGE(STATUS "Known libs : ${KNOWN_CONVENIENCE_LIBRARIES}")
261        MESSAGE(FATAL_ERROR "Unknown static library ${LIB} FOUNDIT ${FOUNDIT}")
262      ELSE()
263        ADD_DEPENDENCIES(${TARGET} ${LIB})
264        GET_TARGET_PROPERTY(loc ${LIB} IMPORTED_LOCATION)
265        IF(loc)
266          ADD_DEPENDENCIES(${TARGET} ${LIB}_location)
267        ENDIF()
268        LIST(APPEND MYLIBS ${LIB})
269        GET_DEPENDEND_OS_LIBS(${LIB} LIB_OSLIBS)
270        IF(LIB_OSLIBS)
271          # MESSAGE(STATUS "GET_DEPENDEND_OS_LIBS ${LIB} : ${LIB_OSLIBS}")
272          LIST(APPEND OSLIBS ${LIB_OSLIBS})
273        ENDIF()
274      ENDIF()
275    ELSE()
276      # 3rd party library like libz.so. Make sure that everything
277      # that links to our library links to this one as well.
278      LIST(APPEND OSLIBS ${LIB})
279    ENDIF()
280    # MESSAGE(STATUS "LIB ${LIB} LIB_TYPE ${LIB_TYPE}")
281  ENDFOREACH()
282
283  IF(OSLIBS)
284    LIST(REMOVE_DUPLICATES OSLIBS)
285    TARGET_LINK_LIBRARIES(${TARGET} ${OSLIBS})
286    MESSAGE(STATUS "Library ${TARGET} depends on OSLIBS ${OSLIBS}")
287  ENDIF()
288
289  # Make the generated dummy source file depended on all static input
290  # libs. If input lib changes,the source file is touched
291  # which causes the desired effect (relink).
292  ADD_CUSTOM_COMMAND(
293    OUTPUT  ${SOURCE_FILE}
294    COMMAND ${CMAKE_COMMAND}  -E touch ${SOURCE_FILE}
295    DEPENDS ${MYLIBS}
296    )
297
298  MESSAGE(STATUS "MERGE_CONVENIENCE_LIBRARIES TARGET ${TARGET}")
299  MESSAGE(STATUS "MERGE_CONVENIENCE_LIBRARIES LIBS ${LIBS}")
300  MESSAGE(STATUS "MERGE_CONVENIENCE_LIBRARIES MYLIBS ${MYLIBS}")
301
302  CONFIGURE_FILE(
303    ${MYSQL_CMAKE_SCRIPT_DIR}/merge_archives.cmake.in
304    ${CMAKE_BINARY_DIR}/archive_output_directory/lib_merge_${TARGET}.cmake
305    @ONLY)
306  ADD_CUSTOM_COMMAND(TARGET ${TARGET} POST_BUILD
307    COMMAND ${CMAKE_COMMAND}
308    -DTARGET_NAME=${TARGET}
309    -DTARGET_LOC=$<TARGET_FILE:${TARGET}>
310    -DCFG_INTDIR=${CMAKE_CFG_INTDIR}
311    -P ${CMAKE_BINARY_DIR}/archive_output_directory/lib_merge_${TARGET}.cmake
312    COMMENT "Merging library ${TARGET}"
313    )
314
315  IF(NOT ARG_SKIP_INSTALL)
316    IF(ARG_COMPONENT)
317      SET(COMP COMPONENT ${ARG_COMPONENT})
318    ENDIF()
319    MYSQL_INSTALL_TARGETS(${TARGET} DESTINATION "${INSTALL_LIBDIR}" ${COMP})
320  ENDIF()
321ENDMACRO()
322