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