1# Copyright (c) 2017, 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# Build TARGET_NAME (a static library) from "convenience libraries"
24#     -DTARGET_NAME=${TARGET}
25#     -DTARGET_LOC=$<TARGET_FILE:${TARGET}>
26#     -DCFG_INTDIR=${CMAKE_CFG_INTDIR}
27
28SET(APPLE   "@APPLE@")
29SET(LINUX   "@LINUX@")
30SET(MSVC    "@MSVC@")
31SET(SOLARIS "@SOLARIS@")
32SET(UNIX    "@UNIX@")
33
34SET(MYLIBS "@MYLIBS@")
35SET(MYSQL_CMAKE_SCRIPT_DIR "@MYSQL_CMAKE_SCRIPT_DIR@")
36
37SET(CMAKE_AR "@CMAKE_AR@")
38SET(CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@")
39SET(CMAKE_COMMAND "@CMAKE_COMMAND@")
40SET(CMAKE_CXX_CREATE_STATIC_LIBRARY "@CMAKE_CXX_CREATE_STATIC_LIBRARY@")
41SET(CMAKE_C_CREATE_STATIC_LIBRARY "@CMAKE_C_CREATE_STATIC_LIBRARY@")
42SET(CMAKE_LINKER "@CMAKE_LINKER@")
43SET(CMAKE_RANLIB "@CMAKE_RANLIB@")
44SET(CMAKE_STATIC_LINKER_FLAGS "@CMAKE_STATIC_LINKER_FLAGS@")
45
46# MESSAGE(STATUS "merge_archives MYLIBS ${MYLIBS}")
47# MESSAGE(STATUS "merge_archives TARGET_LINK_FLAGS ${TARGET_LINK_FLAGS}")
48# MESSAGE(STATUS "merge_archives TARGET_LOC ${TARGET_LOC}")
49# MESSAGE(STATUS "merge_archives TARGET_NAME ${TARGET_NAME}")
50#
51# MESSAGE(STATUS "merge_archives CMAKE_AR ${CMAKE_AR}")
52# MESSAGE(STATUS "merge_archives CMAKE_BINARY_DIR ${CMAKE_BINARY_DIR}")
53# MESSAGE(STATUS "merge_archives CMAKE_COMMAND ${CMAKE_COMMAND}")
54# MESSAGE(STATUS "merge_archives CMAKE_CXX_CREATE_STATIC_LIBRARY ${CMAKE_CXX_CREATE_STATIC_LIBRARY}")
55# MESSAGE(STATUS "merge_archives CMAKE_C_CREATE_STATIC_LIBRARY ${CMAKE_C_CREATE_STATIC_LIBRARY}")
56# MESSAGE(STATUS "merge_archives CMAKE_LINKER ${CMAKE_LINKER}")
57# MESSAGE(STATUS "merge_archives CMAKE_RANLIB ${CMAKE_RANLIB}")
58# MESSAGE(STATUS "merge_archives CMAKE_STATIC_LINKER_FLAGS ${CMAKE_STATIC_LINKER_FLAGS}")
59
60SET(LIB_LOCATIONS)
61FOREACH(LIB ${MYLIBS})
62  SET(FILENAME "${CMAKE_BINARY_DIR}/archive_output_directory")
63  SET(FILENAME "${FILENAME}/${CFG_INTDIR}/lib_location_${LIB}")
64  FILE(READ ${FILENAME} CONTENT)
65  STRING(REGEX REPLACE "\n" "" LIB_LOCATION ${CONTENT})
66  LIST(APPEND LIB_LOCATIONS ${LIB_LOCATION})
67# MESSAGE(STATUS "LIB ${LIB} LIB_LOCATION ${LIB_LOCATION}")
68ENDFOREACH()
69
70MACRO(CONFIGURE_FILE_CONTENT content file)
71 SET(CMAKE_CONFIGURABLE_FILE_CONTENT
72  "${content}")
73 CONFIGURE_FILE(
74  ${MYSQL_CMAKE_SCRIPT_DIR}/configurable_file_content.in
75  ${file}
76  @ONLY)
77ENDMACRO()
78
79# Remove the "dummy" library, created from the empty ${TARGET}_depends.c
80EXECUTE_PROCESS(
81  COMMAND ${CMAKE_COMMAND} -E remove ${TARGET_LOC}
82  )
83
84IF(MSVC)
85  # See CMAKE_CXX_CREATE_STATIC_LIBRARY
86  FIND_PROGRAM(LINK_IN_PATH "link.exe")
87  MESSAGE(STATUS "merge_archives linker in PATH is ${LINK_IN_PATH}")
88
89  EXECUTE_PROCESS(
90    COMMAND ${CMAKE_LINKER} "/lib" "/NOLOGO" "${CMAKE_STATIC_LINKER_FLAGS}"
91    "/OUT:${TARGET_LOC}" ${LIB_LOCATIONS}
92    RESULT_VARIABLE link_result
93    OUTPUT_FILE     link_output_file
94    ERROR_FILE      link_error_file
95    )
96  MESSAGE(STATUS "link_result is ${link_result}")
97  IF(link_result)
98    MESSAGE(WARNING "Retrying link with ${LINK_IN_PATH}")
99    EXECUTE_PROCESS(
100      COMMAND ${LINK_IN_PATH} "/lib" "/NOLOGO" "${CMAKE_STATIC_LINKER_FLAGS}"
101      "/OUT:${TARGET_LOC}" ${LIB_LOCATIONS}
102      RESULT_VARIABLE link_result
103      )
104  ENDIF()
105
106ELSEIF(APPLE)
107  # libtool handles it for us
108  EXECUTE_PROCESS(
109    COMMAND /usr/bin/libtool -static -o ${TARGET_LOC} ${LIB_LOCATIONS}
110    )
111ELSEIF(LINUX)
112  # First create a "thin" archive, then convert it to a normal one.
113  SET(CONTENT "create ${TARGET_LOC}\n")
114  SET(CONTENT "${CONTENT}addlib ${TARGET_LOC}\n")
115  SET(CONTENT "${CONTENT}save\n")
116  SET(CONTENT "${CONTENT}end\n")
117  CONFIGURE_FILE_CONTENT(
118    ${CONTENT}
119    "${CMAKE_BINARY_DIR}/archive_output_directory/cmake_ar_m_${TARGET_NAME}")
120  EXECUTE_PROCESS(
121    COMMAND ${CMAKE_AR} cqT ${TARGET_LOC} ${LIB_LOCATIONS}
122    )
123  EXECUTE_PROCESS(
124    COMMAND ${CMAKE_AR} -M
125    INPUT_FILE
126    "${CMAKE_BINARY_DIR}/archive_output_directory/cmake_ar_m_${TARGET_NAME}"
127    )
128  EXECUTE_PROCESS(
129    COMMAND ${CMAKE_RANLIB} ${TARGET_LOC}
130    )
131ELSEIF(UNIX)
132  # freebsd and solaris, run 'ar -x' on all libraries,
133  # followed by 'ar -r' on all .o files
134  SET(TEMP_DIR
135   "${CMAKE_BINARY_DIR}/archive_output_directory/merge_archives_${TARGET_NAME}")
136  MAKE_DIRECTORY(${TEMP_DIR})
137  FOREACH(LIB ${LIB_LOCATIONS})
138    GET_FILENAME_COMPONENT(NAME_NO_EXT ${LIB} NAME_WE)
139    SET(TEMP_SUBDIR ${TEMP_DIR}/${NAME_NO_EXT})
140    MAKE_DIRECTORY(${TEMP_SUBDIR})
141    # Extract files into a sub-directory
142    EXECUTE_PROCESS(
143      COMMAND ${CMAKE_AR} -x ${LIB}
144      WORKING_DIRECTORY ${TEMP_SUBDIR}
145      )
146    FILE(GLOB_RECURSE LIB_OBJECTS "${TEMP_SUBDIR}/*")
147    SET(OBJECTS ${OBJECTS} ${LIB_OBJECTS})
148  ENDFOREACH()
149
150  # Use relative paths, makes command line shorter.
151  FOREACH(OBJ ${OBJECTS})
152    FILE(RELATIVE_PATH OBJ ${TEMP_DIR} ${OBJ})
153    FILE(TO_NATIVE_PATH ${OBJ} OBJ)
154    SET(ALL_OBJECTS ${ALL_OBJECTS} ${OBJ})
155  ENDFOREACH()
156
157  EXECUTE_PROCESS(
158    COMMAND ${CMAKE_AR} -r ${TARGET_LOC} ${ALL_OBJECTS}
159    WORKING_DIRECTORY ${TEMP_DIR}
160    )
161  EXECUTE_PROCESS(
162    COMMAND ${CMAKE_RANLIB} ${TARGET_LOC}
163    )
164
165  # Cleanup
166  FILE(REMOVE_RECURSE ${TEMP_DIR})
167ELSE()
168  MESSAGE(FATAL_ERROR "Don't know how to merge libraries.")
169ENDIF()
170