1# Copyright (c) 2009, 2010, 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 as published by
5# the Free Software Foundation; version 2 of the License.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program; if not, write to the Free Software
14# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1335  USA
15
16
17# This file exports macros that emulate some functionality found  in GNU libtool
18# on Unix systems. One such feature is convenience libraries. In this context,
19# convenience library is a static library that can be linked to shared library
20# On systems that force position-independent code, linking into shared library
21# normally requires compilation with a special flag (often -fPIC). To enable
22# linking static libraries to shared, we compile source files that come into
23# static library with the PIC flag (${CMAKE_SHARED_LIBRARY_C_FLAGS} in CMake)
24# Some systems, like Windows or OSX do not need special compilation (Windows
25# never uses PIC and OSX always uses it).
26#
27# The intention behind convenience libraries is simplify the build and to reduce
28# excessive recompiles.
29
30# Except for convenience libraries, this file provides macros to merge static
31# libraries (we need it for mysqlclient) and to create shared library out of
32# convenience libraries(again, for mysqlclient)
33
34# Following macros are exported
35# - ADD_CONVENIENCE_LIBRARY(target source1...sourceN)
36# This macro creates convenience library. The functionality is similar to
37# ADD_LIBRARY(target STATIC source1...sourceN), the difference is that resulting
38# library can always be linked to shared library
39#
40# - MERGE_LIBRARIES(target [STATIC|SHARED|MODULE]  [linklib1 .... linklibN]
41#  [EXPORTS exported_func1 .... exported_func_N]
42#  [OUTPUT_NAME output_name]
43# This macro merges several static libraries into a single one or creates a shared
44# library from several convenience libraries
45
46# Important global flags
47# - WITH_PIC : If set, it is assumed that everything is compiled as position
48# independent code (that is CFLAGS/CMAKE_C_FLAGS contain -fPIC or equivalent)
49# If defined, ADD_CONVENIENCE_LIBRARY does not add PIC flag to compile flags
50#
51# - DISABLE_SHARED: If set, it is assumed that shared libraries are not produced
52# during the build. ADD_CONVENIENCE_LIBRARY does not add anything to compile flags
53
54
55GET_FILENAME_COMPONENT(MYSQL_CMAKE_SCRIPT_DIR ${CMAKE_CURRENT_LIST_FILE} PATH)
56IF(WIN32 OR CYGWIN OR APPLE OR WITH_PIC OR DISABLE_SHARED OR NOT CMAKE_SHARED_LIBRARY_C_FLAGS)
57 SET(_SKIP_PIC 1)
58ENDIF()
59
60INCLUDE(CMakeParseArguments)
61# CREATE_EXPORTS_FILE (VAR target api_functions)
62# Internal macro, used to create source file for shared libraries that
63# otherwise consists entirely of "convenience" libraries. On Windows,
64# also exports API functions as dllexport. On unix, creates a dummy file
65# that references all exports and this prevents linker from creating an
66# empty library(there are unportable alternatives, --whole-archive)
67MACRO(CREATE_EXPORTS_FILE VAR TARGET API_FUNCTIONS)
68  IF(WIN32)
69    SET(DUMMY ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_dummy.c)
70    SET(EXPORTS ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_exports.def)
71    CONFIGURE_FILE_CONTENT("" ${DUMMY})
72    SET(CONTENT "EXPORTS\n")
73    FOREACH(FUNC ${API_FUNCTIONS})
74      SET(CONTENT "${CONTENT} ${FUNC}\n")
75    ENDFOREACH()
76    CONFIGURE_FILE_CONTENT(${CONTENT} ${EXPORTS})
77    SET(${VAR} ${DUMMY} ${EXPORTS})
78  ELSE()
79    SET(EXPORTS ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_exports_file.cc)
80    SET(CONTENT)
81    FOREACH(FUNC ${API_FUNCTIONS})
82      SET(CONTENT "${CONTENT} extern void* ${FUNC}\;\n")
83    ENDFOREACH()
84    SET(CONTENT "${CONTENT} void *${TARGET}_api_funcs[] = {\n")
85    FOREACH(FUNC ${API_FUNCTIONS})
86     SET(CONTENT "${CONTENT} &${FUNC},\n")
87    ENDFOREACH()
88    SET(CONTENT "${CONTENT} (void *)0\n}\;")
89    CONFIGURE_FILE_CONTENT(${CONTENT} ${EXPORTS})
90    # Avoid "function redeclared as variable" error
91    # when using gcc/clang option -flto(link time optimization)
92    IF(" ${CMAKE_C_FLAGS} ${CMAKE_CXX_FLAGS} " MATCHES " -flto")
93      SET_SOURCE_FILES_PROPERTIES(${EXPORTS} PROPERTIES COMPILE_FLAGS "-fno-lto")
94    ENDIF()
95    SET(${VAR} ${EXPORTS})
96  ENDIF()
97ENDMACRO()
98
99
100# MYSQL_ADD_CONVENIENCE_LIBRARY(name source1...sourceN)
101# Create static library that can be linked to shared library.
102# On systems that force position-independent code, adds -fPIC or
103# equivalent flag to compile flags.
104MACRO(ADD_CONVENIENCE_LIBRARY)
105  SET(TARGET ${ARGV0})
106  SET(SOURCES ${ARGN})
107  LIST(REMOVE_AT SOURCES 0)
108  ADD_LIBRARY(${TARGET} STATIC ${SOURCES})
109  IF(NOT _SKIP_PIC)
110    SET_TARGET_PROPERTIES(${TARGET} PROPERTIES  COMPILE_FLAGS
111    "${CMAKE_SHARED_LIBRARY_C_FLAGS}")
112  ENDIF()
113ENDMACRO()
114
115
116# Write content to file, using CONFIGURE_FILE
117# The advantage compared to FILE(WRITE) is that timestamp
118# does not change if file already has the same content
119MACRO(CONFIGURE_FILE_CONTENT content file)
120 SET(CMAKE_CONFIGURABLE_FILE_CONTENT
121  "${content}\n")
122 CONFIGURE_FILE(
123  ${MYSQL_CMAKE_SCRIPT_DIR}/configurable_file_content.in
124  ${file}
125  @ONLY)
126ENDMACRO()
127
128# Merge static libraries into a big static lib. The resulting library
129# should not not have dependencies on other static libraries.
130# We use it in MariaDB to merge mysys,dbug,vio etc into the embedded server
131# mariadbd.
132
133MACRO(MERGE_STATIC_LIBS TARGET OUTPUT_NAME LIBS_TO_MERGE)
134  # To produce a library we need at least one source file.
135  # It is created by ADD_CUSTOM_COMMAND below and will helps
136  # also help to track dependencies.
137  SET(SOURCE_FILE ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_depends.c)
138  ADD_LIBRARY(${TARGET} STATIC ${SOURCE_FILE})
139  SET_TARGET_PROPERTIES(${TARGET} PROPERTIES OUTPUT_NAME ${OUTPUT_NAME})
140  IF(NOT _SKIP_PIC)
141    SET_TARGET_PROPERTIES(${TARGET} PROPERTIES  COMPILE_FLAGS
142    "${CMAKE_SHARED_LIBRARY_C_FLAGS}")
143  ENDIF()
144
145  SET(OSLIBS)
146  FOREACH(LIB ${LIBS_TO_MERGE})
147    IF(NOT TARGET ${LIB})
148       # 3rd party library like libz.so. Make sure that everything
149       # that links to our library links to this one as well.
150       LIST(APPEND OSLIBS ${LIB})
151    ELSE()
152      GET_TARGET_PROPERTY(LIB_TYPE ${LIB} TYPE)
153      # This is a target in current project
154      # (can be a static or shared lib)
155      IF(LIB_TYPE STREQUAL "STATIC_LIBRARY")
156        SET(STATIC_TGTS ${STATIC_TGTS} ${LIB})
157        SET(STATIC_LIBS ${STATIC_LIBS} $<TARGET_FILE:${LIB}>)
158        ADD_DEPENDENCIES(${TARGET} ${LIB})
159        # Extract dependent OS libraries
160        GET_DEPENDEND_OS_LIBS(${LIB} LIB_OSLIBS)
161        LIST(APPEND OSLIBS ${LIB_OSLIBS})
162      ELSE()
163        # This is a shared library our static lib depends on.
164        LIST(APPEND OSLIBS ${LIB})
165      ENDIF()
166    ENDIF()
167  ENDFOREACH()
168  # With static libraries the order matter to some linkers.
169  # REMOVE_DUPLICATES will keep the first entry and because
170  # the linker requirement we want to keep the last.
171  IF(STATIC_LIBS)
172    LIST(REVERSE STATIC_LIBS)
173    LIST(REMOVE_DUPLICATES STATIC_LIBS)
174    LIST(REVERSE STATIC_LIBS)
175  ENDIF()
176  IF(OSLIBS)
177    LIST(REVERSE OSLIBS)
178    LIST(REMOVE_DUPLICATES OSLIBS)
179    LIST(REVERSE OSLIBS)
180    TARGET_LINK_LIBRARIES(${TARGET} LINK_PRIVATE ${OSLIBS})
181  ENDIF()
182
183  # Make the generated dummy source file depended on all static input
184  # libs. If input lib changes,the source file is touched
185  # which causes the desired effect (relink).
186  ADD_CUSTOM_COMMAND(
187    OUTPUT  ${SOURCE_FILE}
188    COMMAND ${CMAKE_COMMAND}  -E touch ${SOURCE_FILE}
189    DEPENDS ${STATIC_TGTS})
190
191  IF(MSVC)
192    # To merge libs, just pass them to lib.exe command line.
193    SET(LINKER_EXTRA_FLAGS "")
194    FOREACH(LIB ${STATIC_LIBS})
195      SET(LINKER_EXTRA_FLAGS "${LINKER_EXTRA_FLAGS} ${LIB}")
196    ENDFOREACH()
197    SET_TARGET_PROPERTIES(${TARGET} PROPERTIES STATIC_LIBRARY_FLAGS
198      "${LINKER_EXTRA_FLAGS}")
199  ELSE()
200    IF(APPLE)
201      # Use OSX's libtool to merge archives (ihandles universal
202      # binaries properly)
203      ADD_CUSTOM_COMMAND(TARGET ${TARGET} POST_BUILD
204        COMMAND rm $<TARGET_FILE:${TARGET}>
205        COMMAND libtool -static -o $<TARGET_FILE:${TARGET}>
206        ${STATIC_LIBS}
207      )
208    ELSE()
209      # Generic Unix, Cygwin or MinGW. In post-build step, call
210      # script, that uses a MRI script to append static archives.
211      IF(CMAKE_VERSION VERSION_LESS "3.0")
212        SET(MRI_SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}.mri")
213      ELSE()
214        SET(MRI_SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}-$<CONFIG>.mri")
215      ENDIF()
216      SET(MRI_SCRIPT_TPL "${MRI_SCRIPT}.tpl")
217
218      SET(SCRIPT_CONTENTS "CREATE $<TARGET_FILE:${TARGET}>\n")
219      FOREACH(LIB ${STATIC_LIBS})
220        SET(SCRIPT_CONTENTS "${SCRIPT_CONTENTS}ADDLIB ${LIB}\n")
221      ENDFOREACH()
222      FILE(WRITE ${MRI_SCRIPT_TPL} "${SCRIPT_CONTENTS}\nSAVE\nEND\n")
223      FILE(GENERATE OUTPUT ${MRI_SCRIPT} INPUT ${MRI_SCRIPT_TPL})
224
225      ADD_CUSTOM_COMMAND(TARGET ${TARGET} POST_BUILD
226        DEPENDS ${MRI_SCRIPT}
227        COMMAND ${CMAKE_COMMAND}
228        ARGS
229          -DTARGET_SCRIPT="${MRI_SCRIPT}"
230          -DTOP_DIR="${CMAKE_BINARY_DIR}"
231          -DCMAKE_AR="${CMAKE_AR}"
232          -P "${MYSQL_CMAKE_SCRIPT_DIR}/merge_archives_unix.cmake"
233        COMMAND ${CMAKE_RANLIB}
234        ARGS $<TARGET_FILE:${TARGET}>
235      )
236      SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ${MRI_SCRIPT_TPL})
237      SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ${MRI_SCRIPT}.mri)
238    ENDIF()
239  ENDIF()
240ENDMACRO()
241
242# Create libs from libs.
243# Merges static libraries, creates shared libraries out of convenience libraries.
244# MERGE_LIBRARIES(target [STATIC|SHARED|MODULE]
245#  [linklib1 .... linklibN]
246#  [EXPORTS exported_func1 .... exportedFuncN]
247#  [OUTPUT_NAME output_name]
248#)
249MACRO(MERGE_LIBRARIES)
250  CMAKE_PARSE_ARGUMENTS(ARG
251    "STATIC;SHARED;MODULE;NOINSTALL"
252    "OUTPUT_NAME;COMPONENT;VERSION;SOVERSION"
253    "EXPORTS"
254    ${ARGN}
255  )
256  LIST(GET ARG_UNPARSED_ARGUMENTS 0 TARGET)
257  SET(LIBS ${ARG_UNPARSED_ARGUMENTS})
258  LIST(REMOVE_AT LIBS 0)
259  IF(ARG_STATIC)
260    IF (NOT ARG_OUTPUT_NAME)
261      SET(ARG_OUTPUT_NAME ${TARGET})
262    ENDIF()
263    MERGE_STATIC_LIBS(${TARGET} ${ARG_OUTPUT_NAME} "${LIBS}")
264  ELSEIF(ARG_SHARED OR ARG_MODULE)
265    IF(ARG_SHARED)
266      SET(LIBTYPE SHARED)
267    ELSE()
268      SET(LIBTYPE MODULE)
269    ENDIF()
270    # check for non-PIC libraries
271    IF(NOT _SKIP_PIC)
272      FOREACH(LIB ${LIBS})
273        GET_TARGET_PROPERTY(LTYPE ${LIB} TYPE)
274        IF(LTYPE STREQUAL "STATIC_LIBRARY")
275          GET_TARGET_PROPERTY(LIB_COMPILE_FLAGS ${LIB} COMPILE_FLAGS)
276          STRING(REPLACE "${CMAKE_SHARED_LIBRARY_C_FLAGS}"
277            "<PIC_FLAG>" LIB_COMPILE_FLAGS "${LIB_COMPILE_FLAGS}")
278          IF(NOT LIB_COMPILE_FLAGS MATCHES "<PIC_FLAG>")
279            MESSAGE(FATAL_ERROR
280            "Attempted to link non-PIC static library ${LIB} to shared library ${TARGET}\n"
281            "Please use ADD_CONVENIENCE_LIBRARY, instead of ADD_LIBRARY for ${LIB}"
282            )
283          ENDIF()
284        ENDIF()
285      ENDFOREACH()
286    ENDIF()
287    CREATE_EXPORTS_FILE(SRC ${TARGET} "${ARG_EXPORTS}")
288    IF(NOT ARG_NOINSTALL)
289      ADD_VERSION_INFO(${TARGET} SHARED SRC)
290    ENDIF()
291    IF(ARG_VERSION)
292      SET(VERS VERSION ${ARG_VERSION})
293    ENDIF()
294    ADD_LIBRARY(${TARGET} ${LIBTYPE} ${SRC})
295    IF (ARG_VERSION)
296      SET_TARGET_PROPERTIES(${TARGET} PROPERTIES VERSION  ${ARG_VERSION})
297    ENDIF()
298    IF (ARG_SOVERSION)
299      SET_TARGET_PROPERTIES(${TARGET} PROPERTIES SOVERSION  ${ARG_VERSION})
300    ENDIF()
301    TARGET_LINK_LIBRARIES(${TARGET} LINK_PRIVATE ${LIBS})
302    IF(ARG_OUTPUT_NAME)
303      SET_TARGET_PROPERTIES(${TARGET} PROPERTIES OUTPUT_NAME "${ARG_OUTPUT_NAME}")
304    ENDIF()
305  ELSE()
306    MESSAGE(FATAL_ERROR "Unknown library type")
307  ENDIF()
308  IF(NOT ARG_NOINSTALL)
309    IF(ARG_COMPONENT)
310      SET(COMP COMPONENT ${ARG_COMPONENT})
311    ENDIF()
312    MYSQL_INSTALL_TARGETS(${TARGET} DESTINATION "${INSTALL_LIBDIR}" ${COMP})
313  ENDIF()
314  IF(ARG_SHARED AND LINK_FLAG_NO_UNDEFINED)
315    # Do not allow undefined symbols in shared libraries
316    GET_TARGET_PROPERTY(TARGET_LINK_FLAGS ${TARGET} LINK_FLAGS)
317    IF(NOT TARGET_LINK_FLAGS)
318      SET(TARGET_LINK_FLAGS)
319    ENDIF()
320    SET_TARGET_PROPERTIES(${TARGET} PROPERTIES LINK_FLAGS
321      "${TARGET_LINK_FLAGS} ${LINK_FLAG_NO_UNDEFINED}")
322  ENDIF()
323ENDMACRO()
324
325FUNCTION(GET_DEPENDEND_OS_LIBS target result)
326  GET_TARGET_PROPERTY(DEPS ${target} LINK_LIBRARIES)
327  IF(DEPS)
328    FOREACH(lib ${DEPS})
329      IF(NOT TARGET ${lib})
330        SET(ret ${ret} ${lib})
331      ENDIF()
332    ENDFOREACH()
333  ENDIF()
334  SET(${result} ${ret} PARENT_SCOPE)
335ENDFUNCTION()
336
337INCLUDE(CheckCCompilerFlag)
338
339SET(VISIBILITY_HIDDEN_FLAG)
340
341IF(CMAKE_C_COMPILER_ID MATCHES "SunPro")
342  SET(VISIBILITY_HIDDEN_FLAG "-xldscope=hidden")
343ELSEIF(UNIX)
344  CHECK_C_COMPILER_FLAG("-fvisibility=hidden" HAVE_VISIBILITY_HIDDEN)
345  IF(HAVE_VISIBILITY_HIDDEN)
346    SET(VISIBILITY_HIDDEN_FLAG "-fvisibility=hidden")
347  ENDIF()
348ENDIF()
349
350# We try to hide the symbols in bundled libraries to avoid name clashes with
351# other libraries like openssl.
352FUNCTION(RESTRICT_SYMBOL_EXPORTS target)
353  IF(VISIBILITY_HIDDEN_FLAG)
354    GET_TARGET_PROPERTY(COMPILE_FLAGS ${target} COMPILE_FLAGS)
355    IF(NOT COMPILE_FLAGS)
356      # Avoid COMPILE_FLAGS-NOTFOUND
357      SET(COMPILE_FLAGS)
358    ENDIF()
359    SET_TARGET_PROPERTIES(${target} PROPERTIES
360      COMPILE_FLAGS "${COMPILE_FLAGS} ${VISIBILITY_HIDDEN_FLAG}")
361  ENDIF()
362ENDFUNCTION()
363
364# The MSVC /GL flag, used for link-time code generation
365# creates objects files with a format not readable by tools
366# i.e exporting all symbols is not possible with IPO
367# To workaround this, we disable INTERPROCEDURAL_OPTIMIZATION
368# for some static libraries.
369
370FUNCTION (MAYBE_DISABLE_IPO target)
371  IF(MSVC AND NOT CLANG_CL)
372    SET_TARGET_PROPERTIES(${target} PROPERTIES INTERPROCEDURAL_OPTIMIZATION OFF)
373  ENDIF()
374ENDFUNCTION()
375